aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRob Landley <rob@landley.net>2013-09-04 01:40:41 -0500
committerRob Landley <rob@landley.net>2013-09-04 01:40:41 -0500
commitf514143a3321866636c3da8c60df8f2a176607a8 (patch)
tree69ee9f9cbc2668fedd5eb0a7cf594c751f2ac751
parent8fdcfdb4479dff7a993a25a63253f0e749fd99fe (diff)
downloadtoybox-f514143a3321866636c3da8c60df8f2a176607a8.tar.gz
First pass at umount, not quite done yet.
-rw-r--r--toys/lsb/umount.c151
1 files changed, 151 insertions, 0 deletions
diff --git a/toys/lsb/umount.c b/toys/lsb/umount.c
new file mode 100644
index 00000000..51f3024d
--- /dev/null
+++ b/toys/lsb/umount.c
@@ -0,0 +1,151 @@
+/* umount.c - Unmount a mount point.
+ *
+ * Copyright 2012 Rob Landley <rob@landley.net>
+ *
+ * See http://refspecs.linuxfoundation.org/LSB_4.1.0/LSB-Core-generic/LSB-Core-generic/umount.html
+ *
+ * Note: -n (/etc/mtab) is obsolete, /proc/mounts replaced it. Neither chroot
+ * nor per-process mount namespaces can work sanely with mtab. The kernel
+ * tracks mount points now, a userspace application can't do so anymore.
+
+USE_UMOUNT(NEWTOY(umount, "ndDflrat*v", TOYFLAG_BIN|TOYFLAG_STAYROOT))
+
+config UMOUNT
+ bool "umount"
+ default y
+ help
+ usage: umount [-a [-t TYPE[,TYPE...]]] [-vrfD] [DIR...]
+
+ Unmount the listed filesystems.
+
+ -a Unmount all mounts in /proc/mounts instead of command line list
+ -t Restrict "all" to mounts of TYPE (or use "noTYPE" to skip)
+ -D Don't free loopback device(s).
+ -f Force unmount.
+ -l Lazy unmount (detach from filesystem now, close when last user does).
+ -r Remount read only if unmounting fails.
+ -v Verbose
+*/
+
+#define FOR_umount
+#include "toys.h"
+
+GLOBALS(
+ struct arg_list *t;
+
+ char *types;
+)
+
+// todo
+// borrow df code to identify filesystem?
+// umount -a from fstab
+// umount when getpid() not 0, according to fstab
+// lookup mount: losetup -d, bind, file, block
+
+// TODO
+// loopback delete
+// fstab -o user
+
+// Realloc *old with oldstring,newstring
+
+void comma_collate(char **old, char *new)
+{
+ char *temp, *atold = *old;
+
+ // Only add a comma if old string didn't end with one
+ if (atold && *atold) {
+ char *comma = ",";
+
+ if (atold[strlen(atold)-1] == ',') comma = "";
+ temp = xmsprintf("%s%s%s", atold, comma, new);
+ } else temp = xstrdup(new);
+ free (atold);
+ *old = temp;
+}
+
+void arg_comma_collate(char **old, struct arg_list *arg)
+{
+ while (arg) {
+ comma_collate(old, arg->arg);
+ arg = arg->next;
+ }
+}
+
+char *comma_iterate(char **list, int *len)
+{
+ char *start = *list, *end;
+
+ if (!*list) return 0;
+ if (!(end = strchr(*list, ','))) {
+ *len = strlen(*list);
+ *list = 0;
+ } else *list += (*len = end-start)+1;
+
+ return start;
+}
+
+static void do_umount(char *dir, int flags)
+{
+ if (!umount2(dir, flags)) {
+ if (toys.optflags & FLAG_v) printf("%s unmounted", dir);
+ return;
+ }
+ if (toys.optflags & FLAG_r) {
+ if (!mount("", *toys.optargs, "", MS_REMOUNT|MS_RDONLY, "")) {
+ if (toys.optflags & FLAG_v) printf("%s remounted ro", dir);
+ return;
+ }
+ }
+ perror_msg("%s", dir);
+}
+
+void umount_main(void)
+{
+ int flags=0;
+
+ if (!toys.optc && !(toys.optflags & FLAG_a))
+ error_exit("Need 1 arg or -a");
+
+ if (toys.optflags & FLAG_f) flags |= MNT_FORCE;
+ if (toys.optflags & FLAG_l) flags |= MNT_DETACH;
+
+ for (; *toys.optargs; toys.optargs++) do_umount(*toys.optargs, flags);
+
+ if (toys.optflags & FLAG_a) {
+ struct mtab_list *mlsave, *ml;
+ char *typestr = 0;
+
+ if (TT.t) arg_comma_collate(&typestr, TT.t);
+
+ // Loop through mounted filesystems
+ for (mlsave = ml = xgetmountlist(0); ml; ml = ml->next) {
+ if (TT.t) {
+ char *type, *types = typestr;
+ int len, skip = strncmp(types, "no", 2);
+
+ // Loop through -t filters
+ for (;;) {
+ if (!(type = comma_iterate(&types, &len))) break;
+ if (!skip) {
+ if (strncmp(type, "no", 2)) error_exit("bad -t");
+ if (!strncmp(type+2, ml->type, len-2)) {
+ skip = 1;
+ break;
+ }
+ } else if (!strncmp(type, ml->type, len) && !ml->type[len]) {
+ skip = 0;
+ break;
+ }
+ }
+ if (skip) continue;
+ }
+ do_umount(ml->dir, flags);
+ }
+ if (CFG_TOYBOX_FREE) {
+ free(typestr);
+ llist_traverse(mlsave, free);
+ }
+
+ return;
+ }
+}