From: Sören Tempel <[email protected]> This commit adds a primitive 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.
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]. Discussion: * There is some minor code duplication between fsopt_matches and fstype_matches. Adding some sort of utility function to resolve this may allow for a further decrease in text segment size. * The semantics of -O are not well described in the util-linux mount(8) man page. Please review this carefully to ensure that the implementation proposed here is semantically equivalent to the one provided by util-linux. [1]: https://gitlab.alpinelinux.org/alpine/aports/-/issues/9923 [2]: https://gitlab.alpinelinux.org/alpine/aports/-/issues/13789 Signed-off-by: Sören Tempel <[email protected]> --- I haven't tested this extensively yet. Feedback is most welcome. include/libbb.h | 1 + libbb/Kbuild.src | 1 + libbb/match_fsopts.c | 59 ++++++++++++++++++++++++++++++++++++++++++++ util-linux/umount.c | 10 +++++--- 4 files changed, 68 insertions(+), 3 deletions(-) create mode 100644 libbb/match_fsopts.c diff --git a/include/libbb.h b/include/libbb.h index 6aeec249d..1a203861e 100644 --- a/include/libbb.h +++ b/include/libbb.h @@ -1585,6 +1585,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..fff236c7a --- /dev/null +++ b/libbb/match_fsopts.c @@ -0,0 +1,59 @@ +/* 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 FAST_FUNC fsopt_matches(const char *opts_list, const char *opt, size_t optlen) +{ + int match = 1; + + if (optlen > 2 && opt[0] == 'n' && opt[1] == '0') { + match--; + opt += 2; optlen -= 2; + } + + 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; +} + +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 [email protected] http://lists.busybox.net/mailman/listinfo/busybox
