From 13ee1c911657bb55f7e624470d9a275540cd6720 Mon Sep 17 00:00:00 2001 From: Dave Reisner Date: Wed, 7 Nov 2012 13:02:28 -0500 Subject: umount: add -R, --recursive option 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 Signed-off-by: Karel Zak --- sys-utils/umount.c | 85 +++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 81 insertions(+), 4 deletions(-) (limited to 'sys-utils/umount.c') diff --git a/sys-utils/umount.c b/sys-utils/umount.c index 38a2fc8f2..196a511ba 100644 --- a/sys-utils/umount.c +++ b/sys-utils/umount.c @@ -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 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 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; -- cgit v1.2.3-55-g7522