--test-opts in combination with --all mounts only those filesystems with options matching the given set of options.
Note that the semantic of the inverting "no" prefix differs from --types: While --types=nonfs,ufs means neither nfs nor ufs, --test-opts=nofoo,bar means not foo, but bar. * utils/mount.c (test_opts): New variable. (test_opts_len): Likewise. (parse_opt): Handle -O, --test-opts. (match_options): New function. (main): Use match_options as filter. --- utils/mount.c | 62 +++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 60 insertions(+), 2 deletions(-) diff --git a/utils/mount.c b/utils/mount.c index f8928f1..07077a5 100644 --- a/utils/mount.c +++ b/utils/mount.c @@ -39,6 +39,8 @@ static int fake; static char *options; static size_t options_len; static mach_msg_timeout_t timeout; +static char *test_opts; +static size_t test_opts_len; static enum { mount, query } mode; static enum { qf_standard, qf_fstab, qf_translator } query_format; @@ -57,6 +59,8 @@ static const struct argp_option argp_opts[] = {"remount", 0, 0, OPTION_ALIAS}, {"verbose", 'v', 0, 0, "Give more detailed information"}, {"no-mtab", 'n', 0, 0, "Do not update /etc/mtab"}, + {"test-opts", 'O', "OPTIONS", 0, + "Only mount fstab entries matching the given set of options"}, {"fake", 'f', 0, 0, "Do not actually mount, just pretend"}, {0, 0} }; @@ -122,6 +126,12 @@ parse_opt (int key, char *arg, struct argp_state *state) fake = 1; break; + case 'O': + err = argz_create_sep (arg, ',', &test_opts, &test_opts_len); + if (err) + argp_failure (state, 100, ENOMEM, "%s", arg); + break; + case ARGP_KEY_ARG: if (mountpoint == 0) /* One arg: mountpoint */ mountpoint = arg; @@ -192,6 +202,49 @@ static const struct argp_child argp_kids[] = { 0 } }; static struct argp argp = { argp_opts, parse_opt, args_doc, doc, argp_kids }; +/* Check whether the given mount entry matches the given set of + options. + + Returns 0 if foo is in the options vector but nofoo is in test_opts. + Returns 0 if foo is in test_opts but foo is not in the options vector. */ +int +match_options (struct mntent *mntent) +{ + char *opts; + size_t opts_len; + + error_t err = argz_create_sep (mntent->mnt_opts, ',', &opts, &opts_len); + if (err) + error (3, err, "parsing mount options failed"); + + for (char *test = test_opts; + test; test = argz_next (test_opts, test_opts_len, test)) + { + char *needle = test; + int inverse = strncmp("no", needle, 2) == 0; + if (inverse) + needle += 2; + + int match = 0; + for (char *opt = opts; opt; opt = argz_next (opts, opts_len, opt)) + { + if (strcmp (opt, needle) == 0) { + if (inverse) + return 0; /* foo in opts, nofoo in test_opts. */ + + /* foo in opts, foo in test_opts, record match. */ + match = 1; + } + } + + if (! inverse && ! match) + return 0; /* No foo in opts, but foo in test_opts. */ + } + + /* If no conflicting test_opt was encountered, return success. */ + return 1; +} + /* Mount one filesystem. */ static error_t do_mount (struct fs *fs, int remount) @@ -615,8 +668,13 @@ main (int argc, char **argv) case mount: for (fs = fstab->entries; fs; fs = fs->next) { - if (fstab_params.do_all && hasmntopt (&fs->mntent, MNTOPT_NOAUTO)) - continue; + if (fstab_params.do_all) { + if (hasmntopt (&fs->mntent, MNTOPT_NOAUTO)) + continue; + + if (! match_options (&fs->mntent)) + continue; + } err |= do_mount (fs, remount); } break; -- 1.7.10.4