summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--util-linux/mount.c82
1 files changed, 50 insertions, 32 deletions
diff --git a/util-linux/mount.c b/util-linux/mount.c
index d27d65f..d7ca7da 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