[PATCH] umount: add -R, --recursive option

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This allows unmounting of an entire tree of filesystems, which might be
of particular interest for a shutdown initramfs.

Signed-off-by: Dave Reisner <dreisner@xxxxxxxxxxxxx>
---
 sys-utils/umount.8 |  4 +++
 sys-utils/umount.c | 81 +++++++++++++++++++++++++++++++++++++++++++++++++++---
 2 files changed, 81 insertions(+), 4 deletions(-)

diff --git a/sys-utils/umount.8 b/sys-utils/umount.8
index bdd10a5..b8d4358 100644
--- a/sys-utils/umount.8
+++ b/sys-utils/umount.8
@@ -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
diff --git a/sys-utils/umount.c b/sys-utils/umount.c
index 38a2fc8..d107a49 100644
--- a/sys-utils/umount.c
+++ b/sys-utils/umount.c
@@ -88,6 +88,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 +301,71 @@ 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 *mountinfo, 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 == NULL)
+		err(MOUNT_EX_SYSERR, _("libmount iterator allocation failed"));
+
+	for (;;) {
+		rc = mnt_table_next_child_fs(mountinfo, itr, parent, &child);
+		if (rc == -1)
+			warn(_("failed to get child fs of %s"), target);
+
+		if (rc != 0)
+			break;
+
+		rc = umount_do_recurse(cxt, mountinfo, child);
+		if (rc != 0)
+			break;
+	}
+
+	/* stop on any hard failure */
+	if (rc != -1 && rc != 32)
+		rc = umount_one(cxt, target);
+
+	mnt_free_iter(itr);
+
+	return rc;
+}
+
+static int umount_recursive(struct libmnt_context *cxt, const char *spec)
+{
+	struct libmnt_table *mountinfo;
+	struct libmnt_fs *fs;
+	int rc = 32; /* ENOENT */
+
+	mountinfo = mnt_new_table();
+	if (mountinfo == NULL)
+		err(MOUNT_EX_SYSERR, _("libmount table allocation failed"));
+
+	if (mnt_table_parse_mtab(mountinfo, "/proc/self/mountifo") < 0) {
+		warn("failed to parse /proc/self/mountifo");
+		goto finish;
+	}
+
+	fs = mnt_table_find_target(mountinfo, spec, MNT_ITER_BACKWARD);
+	if (fs)
+		rc = umount_do_recurse(cxt, mountinfo, fs);
+	else
+		warnx(access(spec, F_OK) == 0 ?
+				_("%s: not mounted") :
+				_("%s: not found"), spec);
+
+finish:
+	mnt_free_table(mountinfo);
+
+	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 +384,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 +405,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 +444,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 +479,14 @@ 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;
-- 
1.8.0

--
To unsubscribe from this list: send the line "unsubscribe util-linux" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [Netdev]     [Ethernet Bridging]     [Linux Wireless]     [Kernel Newbies]     [Security]     [Linux for Hams]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux RAID]     [Linux Admin]     [Samba]

  Powered by Linux