[prev in list] [next in list] [prev in thread] [next in thread] 

List:       busybox
Subject:    [PATCH v2] umount: Implement -O option to unmount by mount options
From:       soeren () soeren-tempel ! net
Date:       2023-03-03 16:00:17
Message-ID: 20230303160016.4785-1-soeren () soeren-tempel ! net
[Download RAW message or body]

From: Sören Tempel <soeren@soeren-tempel.net>

This commit adds an implementation of the umount -O option, as provided
by util-linux's mount(8) implementation, to BusyBox. Similar to -t, the
option is intended to be used in conjunction with -a thereby allowing
users to filter which file systems are unmounted by mount options.
Multiple options can be specified with -O, all of which need to match.
Each option can be prefixed with `no` to indicate that no action should
be taken for a mount point with this mount option. The "no" prefix
interpretation can be disabled using the "+" prefix.

At Alpine, this feature is often requested by users as the OpenRC
netmount service uses `umount -a -O _netdev` to amount all network
file systems [1] [2].

This implementation is functionally equivalent to the util-linux
implementation with the exception that it implements no special handling
for `key="value"` mount options to keep the implementation simple.
Therefore, filesystems mounted with options like `foo="bar"` won't
be matched by `umount -a -O foo`.

[1]: https://gitlab.alpinelinux.org/alpine/aports/-/issues/9923
[2]: https://gitlab.alpinelinux.org/alpine/aports/-/issues/13789

Signed-off-by: Sören Tempel <soeren@soeren-tempel.net>
---
Changes since v1:

  * Fix a typo during parsing of no keyword (n0 -> no)
  * Treat alone "no" as an error (as done in util-linux)
  * Implement support for the "+" prefix to bypass the "no" keyword

This version of the patch has been tested against the util-linux
implementation using KLEE: https://github.com/nmeum/umount-test-opts

 include/libbb.h      |  1 +
 libbb/Kbuild.src     |  1 +
 libbb/match_fsopts.c | 69 ++++++++++++++++++++++++++++++++++++++++++++
 util-linux/umount.c  | 10 +++++--
 4 files changed, 78 insertions(+), 3 deletions(-)
 create mode 100644 libbb/match_fsopts.c

diff --git a/include/libbb.h b/include/libbb.h
index cca33a177..ad41adec8 100644
--- a/include/libbb.h
+++ b/include/libbb.h
@@ -1586,6 +1586,7 @@ const struct hwtype *get_hwntype(int type) FAST_FUNC;
 
 
 extern int fstype_matches(const char *fstype, const char *comma_list) FAST_FUNC;
+extern int fsopts_matches(const char *opts_list, const char *reqopts_list) \
FAST_FUNC;  #ifdef HAVE_MNTENT_H
 extern struct mntent *find_mount_point(const char *name, int subdir_too) FAST_FUNC;
 #endif
diff --git a/libbb/Kbuild.src b/libbb/Kbuild.src
index 653025e56..4bb8260b9 100644
--- a/libbb/Kbuild.src
+++ b/libbb/Kbuild.src
@@ -120,6 +120,7 @@ lib-y += xrealloc_vector.o
 
 lib-$(CONFIG_MOUNT) += match_fstype.o
 lib-$(CONFIG_UMOUNT) += match_fstype.o
+lib-$(CONFIG_UMOUNT) += match_fsopts.o
 
 lib-$(CONFIG_FEATURE_UTMP) += utmp.o
 
diff --git a/libbb/match_fsopts.c b/libbb/match_fsopts.c
new file mode 100644
index 000000000..b1cc85c3c
--- /dev/null
+++ b/libbb/match_fsopts.c
@@ -0,0 +1,69 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Match fsopts for use in mount unmount -O.
+ *
+ * Returns 1 for a match, otherwise 0.
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this source tree.
+ */
+
+#include "libbb.h"
+
+static int fsopt_matches(const char *opts_list, const char *opt, size_t optlen)
+{
+	int match = 1;
+
+	if (optlen >= 2 && opt[0] == 'n' && opt[1] == 'o') {
+		match--;
+		opt += 2; optlen -= 2;
+	}
+
+	/* The alone "no" is an error, all matching ends with False. */
+	if (optlen == 0)
+		return 0;
+
+	/* The "no" prefix interpretation can be disabled by the "+" prefix. */
+	if (match && optlen > 1 && *opt == '+') {
+		opt++; optlen--;
+	}
+
+	while (1) {
+		if (strncmp(opts_list, opt, optlen) == 0) {
+			const char *after_opt = opts_list + optlen;
+			if (*after_opt == '\0' || *after_opt == ',')
+				return match;
+		}
+
+		opts_list = strchr(opts_list, ',');
+		if (!opts_list)
+			break;
+		opts_list++;
+	}
+
+	return !match;
+}
+
+/* This function implements the mnt_match_options function from libmount. */
+int FAST_FUNC fsopts_matches(const char *opts_list, const char *reqopts_list)
+{
+	if (!reqopts_list)
+		return 1; /* no options requested, match anything */
+
+	while (1) {
+		size_t len;
+		const char *comma = strchr(reqopts_list, ',');
+		if (!comma)
+			len = strlen(reqopts_list);
+		else
+			len = comma - reqopts_list;
+
+		if (len && !fsopt_matches(opts_list, reqopts_list, len))
+			return 0;
+
+		if (!comma)
+			break;
+		reqopts_list = ++comma;
+	}
+
+	return 1;
+}
diff --git a/util-linux/umount.c b/util-linux/umount.c
index 23da32868..7a54cafb0 100644
--- a/util-linux/umount.c
+++ b/util-linux/umount.c
@@ -41,7 +41,7 @@
 //kbuild:lib-$(CONFIG_UMOUNT) += umount.o
 
 //usage:#define umount_trivial_usage
-//usage:       "[-rlf"IF_FEATURE_MTAB_SUPPORT("m")IF_FEATURE_MOUNT_LOOP("d")IF_FEATURE_UMOUNT_ALL("a")"] \
[-t FSTYPE] FILESYSTEM|DIRECTORY" +//usage:       \
"[-rlf"IF_FEATURE_MTAB_SUPPORT("m")IF_FEATURE_MOUNT_LOOP("d")IF_FEATURE_UMOUNT_ALL("a")"] \
[-t FSTYPE] [-O FSOPT] FILESYSTEM|DIRECTORY"  //usage:#define umount_full_usage \
"\n\n"  //usage:       "Unmount filesystems\n"
 //usage:	IF_FEATURE_UMOUNT_ALL(
@@ -57,6 +57,7 @@
 //usage:     "\n	-d	Free loop device if it has been used"
 //usage:	)
 //usage:     "\n	-t FSTYPE[,...]	Unmount only these filesystem type(s)"
+//usage:     "\n	-O FSOPT[,...]	Unmount only filesystem mounted with the given \
options"  //usage:
 //usage:#define umount_example_usage
 //usage:       "$ umount /dev/hdc1\n"
@@ -82,7 +83,7 @@ static struct mntent *getmntent_r(FILE* stream, struct mntent* \
result,  #endif
 
 /* ignored: -c -v -i */
-#define OPTION_STRING           "fldnrat:" "cvi"
+#define OPTION_STRING           "fldnrat:O:" "cvi"
 #define OPT_FORCE               (1 << 0) // Same as MNT_FORCE
 #define OPT_LAZY                (1 << 1) // Same as MNT_DETACH
 #define OPT_FREELOOP            (1 << 2)
@@ -96,6 +97,7 @@ int umount_main(int argc UNUSED_PARAM, char **argv)
 	int doForce;
 	struct mntent me;
 	FILE *fp;
+	char *opts = NULL;
 	char *fstype = NULL;
 	int status = EXIT_SUCCESS;
 	unsigned opt;
@@ -105,7 +107,7 @@ int umount_main(int argc UNUSED_PARAM, char **argv)
 		struct mtab_list *next;
 	} *mtl, *m;
 
-	opt = getopt32(argv, OPTION_STRING, &fstype);
+	opt = getopt32(argv, OPTION_STRING, &fstype, &opts);
 	//argc -= optind;
 	argv += optind;
 
@@ -133,6 +135,8 @@ int umount_main(int argc UNUSED_PARAM, char **argv)
 			/* Match fstype (fstype==NULL matches always) */
 			if (!fstype_matches(me.mnt_type, fstype))
 				continue;
+			if (!fsopts_matches(me.mnt_opts, opts))
+				continue;
 			m = xzalloc(sizeof(*m));
 			m->next = mtl;
 			m->device = xstrdup(me.mnt_fsname);
_______________________________________________
busybox mailing list
busybox@busybox.net
http://lists.busybox.net/mailman/listinfo/busybox


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic