diff options
-rw-r--r-- | util-linux/mount.c | 82 |
1 files changed, 50 insertions, 32 deletions
diff --git a/util-linux/mount.c b/util-linux/mount.c index d27d65f80..d7ca7da37 100644 --- a/util-linux/mount.c +++ b/util-linux/mount.c @@ -1760,43 +1760,61 @@ static int singlemount(struct mntent *mp, int ignore_busy) return rc; } -/* -O support - * Unlike -t, -O should interpret "no" prefix differently: - * -t noa,b,c = -t no(a,b,c) = mount all except fs'es with types a,b, and c - * -O noa,b,c = -O noa,b,c = mount all with without option a, - * or with option b or c. - * But for now we do not support -O a,b,c at all (only -O a). - * - * Another difference from -t support (match_fstype) is that - * we need to examine the _list_ of options in fsopt, not just a string. - */ -static int match_opt(const char *fs_opt, const char *O_opt) +// -O support +// -O interprets a list of filter options which select whether a mount +// point will be mounted: only mounts with options matching *all* filtering +// options will be selected. +// By default each -O filter option must be present in the list of mount +// options, but if it is prefixed by "no" then it must be absent. +// For example, +// -O a,nob,c matches -o a,c but fails to match -o a,b,c +// (and also fails to match -o a because -o c is absent). +// +// It is different from -t in that each option is matched exactly; a leading +// "no" at the beginning of one option does not negate the rest. +static int match_opt(const char *fs_opt_in, const char *O_opt) { - int match = 1; - int len; - if (!O_opt) - return match; - - if (O_opt[0] == 'n' && O_opt[1] == 'o') { - match--; - O_opt += 2; - } - - len = strlen(O_opt); - while (1) { - if (strncmp(fs_opt, O_opt, len) == 0 - && (fs_opt[len] == '\0' || fs_opt[len] == ',') - ) { - return match; + return 1; + + while (*O_opt) { + const char *fs_opt = fs_opt_in; + int O_len; + int match; + + // If option begins with "no" then treat as an inverted match: + // matching is a failure + match = 0; + if (O_opt[0] == 'n' && O_opt[1] == 'o') { + match = 1; + O_opt += 2; + } + // Isolate the current O option + O_len = strchrnul(O_opt, ',') - O_opt; + // Check for a match against existing options + while (1) { + if (strncmp(fs_opt, O_opt, O_len) == 0 + && (fs_opt[O_len] == '\0' || fs_opt[O_len] == ',') + ) { + if (match) + return 0; // "no" prefix, but option found + match = 1; // current O option found, go check next one + break; + } + fs_opt = strchr(fs_opt, ','); + if (!fs_opt) + break; + fs_opt++; } - fs_opt = strchr(fs_opt, ','); - if (!fs_opt) + if (match == 0) + return 0; // match wanted but not found + if (O_opt[O_len] == '\0') // end? break; - fs_opt++; + // Step to the next O option + O_opt += O_len + 1; } - - return !match; + // If we get here then everything matched + return 1; } // Parse options, if necessary parse fstab/mtab, and call singlemount for |