]> git.ipfire.org Git - thirdparty/util-linux.git/commitdiff
umount: add -R, --recursive option
authorDave Reisner <dreisner@archlinux.org>
Wed, 7 Nov 2012 18:02:28 +0000 (13:02 -0500)
committerKarel Zak <kzak@redhat.com>
Tue, 13 Nov 2012 15:46:07 +0000 (16:46 +0100)
This allows unmounting of an entire tree of filesystems, which might be
of particular interest for a shutdown initramfs.

[kzak@redhat.com: - always return MOUNT_EX_* codes
                  - cosmetic changes on coding style]

Signed-off-by: Dave Reisner <dreisner@archlinux.org>
Signed-off-by: Karel Zak <kzak@redhat.com>
sys-utils/umount.8
sys-utils/umount.c

index bdd10a5295e89073395583978d5a434c0880f161..b8d43587674ef5cdf9b95648d731414f43558774 100644 (file)
@@ -109,6 +109,10 @@ Each option can be prefixed with
 .B no
 to specify options for which no action should be taken.
 .TP
+\fB\-R\fR, \fB\-\-recursive\fR
+Recursively unmount each directory specified. Recursion for each directory will
+stop if any unmount operation in the chain fails for any reason.
+.TP
 \fB\-r\fR, \fB\-\-read\-only\fR
 In case unmounting fails, try to remount read-only.
 .TP
index 38a2fc8f2e594c8650ee95609167562a8137bdc7..196a511ba6c421ecef0f2331761719d7b9084412 100644 (file)
@@ -35,6 +35,7 @@
 #include "optutils.h"
 #include "exitcodes.h"
 #include "closestream.h"
+#include "pathnames.h"
 
 static int table_parser_errcb(struct libmnt_table *tb __attribute__((__unused__)),
                        const char *filename, int line)
@@ -88,6 +89,7 @@ static void __attribute__((__noreturn__)) usage(FILE *out)
        " -l, --lazy              detach the filesystem now, and cleanup all later\n"));
        fprintf(out, _(
        " -O, --test-opts <list>  limit the set of filesystems (use with -a)\n"
+       " -R, --recursive         recursively unmount a target with all its children\n"
        " -r, --read-only         In case unmounting fails, try to remount read-only\n"
        " -t, --types <list>      limit the set of filesystem types\n"
        " -v, --verbose           say what is being done\n"));
@@ -300,9 +302,75 @@ static int umount_one(struct libmnt_context *cxt, const char *spec)
        return rc;
 }
 
+static int umount_do_recurse(struct libmnt_context *cxt,
+               struct libmnt_table *tb, struct libmnt_fs *parent)
+{
+       int rc;
+       struct libmnt_fs *child;
+       const char *target = mnt_fs_get_target(parent);
+       struct libmnt_iter *itr = mnt_new_iter(MNT_ITER_BACKWARD);
+
+       if (!itr)
+               err(MOUNT_EX_SYSERR, _("libmount iterator allocation failed"));
+       /*
+        * umount all childern
+        */
+       for (;;) {
+               rc = mnt_table_next_child_fs(tb, itr, parent, &child);
+               if (rc < 0) {
+                       warnx(_("failed to get child fs of %s"), target);
+                       rc = MOUNT_EX_SOFTWARE;
+                       goto done;
+               } else if (rc == 1)
+                       break;          /* no more children */
+
+               rc = umount_do_recurse(cxt, tb, child);
+               if (rc != MOUNT_EX_SUCCESS)
+                       goto done;
+       }
+
+       rc = umount_one(cxt, target);
+done:
+       mnt_free_iter(itr);
+       return rc;
+}
+
+static int umount_recursive(struct libmnt_context *cxt, const char *spec)
+{
+       struct libmnt_table *tb;
+       int rc;
+
+       tb = mnt_new_table();
+       if (!tb)
+               err(MOUNT_EX_SYSERR, _("libmount table allocation failed"));
+       /*
+        * Don't use mtab here. The recursive umount depends on child-parent
+        * relationship defined by mountinfo file.
+        */
+       if (mnt_table_parse_file(tb, _PATH_PROC_MOUNTINFO)) {
+               warn(_("failed to parse %s"), _PATH_PROC_MOUNTINFO);
+               rc = MOUNT_EX_SOFTWARE;
+       } else {
+               struct libmnt_fs *fs;
+
+               fs = mnt_table_find_target(tb, spec, MNT_ITER_BACKWARD);
+               if (fs)
+                       rc = umount_do_recurse(cxt, tb, fs);
+               else {
+                       rc = MOUNT_EX_USAGE;
+                       warnx(access(spec, F_OK) == 0 ?
+                                       _("%s: not mounted") :
+                                       _("%s: not found"), spec);
+               }
+       }
+
+       mnt_free_table(tb);
+       return rc;
+}
+
 int main(int argc, char **argv)
 {
-       int c, rc = 0, all = 0;
+       int c, rc = 0, all = 0, recursive = 0;
        struct libmnt_context *cxt;
        char *types = NULL;
 
@@ -321,6 +389,7 @@ int main(int argc, char **argv)
                { "no-canonicalize", 0, 0, 'c' },
                { "no-mtab", 0, 0, 'n' },
                { "read-only", 0, 0, 'r' },
+               { "recursive", 0, 0, 'R' },
                { "test-opts", 1, 0, 'O' },
                { "types", 1, 0, 't' },
                { "verbose", 0, 0, 'v' },
@@ -341,7 +410,7 @@ int main(int argc, char **argv)
 
        mnt_context_set_tables_errcb(cxt, table_parser_errcb);
 
-       while ((c = getopt_long(argc, argv, "acdfhilnrO:t:vV",
+       while ((c = getopt_long(argc, argv, "acdfhilnRrO:t:vV",
                                        longopts, NULL)) != -1) {
 
 
@@ -380,6 +449,9 @@ int main(int argc, char **argv)
                case 'r':
                        mnt_context_enable_rdonly_umount(cxt, TRUE);
                        break;
+               case 'R':
+                       recursive = TRUE;
+                       break;
                case 'O':
                        if (mnt_context_set_options_pattern(cxt, optarg))
                                err(MOUNT_EX_SYSERR, _("failed to set options pattern"));
@@ -412,8 +484,13 @@ int main(int argc, char **argv)
        } else if (argc < 1) {
                usage(stderr);
 
-       } else while (argc--)
-               rc += umount_one(cxt, *argv++);
+       } else if (recursive) {
+               while (argc--)
+                       rc += umount_recursive(cxt, *argv++);
+       } else {
+               while (argc--)
+                       rc += umount_one(cxt, *argv++);
+       }
 
        mnt_free_context(cxt);
        return rc;