summaryrefslogtreecommitdiffstats
path: root/sys-utils/umount.c
diff options
context:
space:
mode:
authorDave Reisner2012-11-07 19:02:28 +0100
committerKarel Zak2012-11-13 16:46:07 +0100
commit13ee1c911657bb55f7e624470d9a275540cd6720 (patch)
tree83622de39a0ed854320aa9113f79aa43d678a75a /sys-utils/umount.c
parentlscpu: make read_topology() more robust to avoid SIGFPE (diff)
downloadkernel-qcow2-util-linux-13ee1c911657bb55f7e624470d9a275540cd6720.tar.gz
kernel-qcow2-util-linux-13ee1c911657bb55f7e624470d9a275540cd6720.tar.xz
kernel-qcow2-util-linux-13ee1c911657bb55f7e624470d9a275540cd6720.zip
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 <dreisner@archlinux.org> Signed-off-by: Karel Zak <kzak@redhat.com>
Diffstat (limited to 'sys-utils/umount.c')
-rw-r--r--sys-utils/umount.c85
1 files changed, 81 insertions, 4 deletions
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 <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;