return 0;
}
+/**
+ * mnt_match_fstype:
+ * @type: filesystem type
+ * @pattern: filesystem name or comma delimitted list of names
+ *
+ * The @pattern list of filesystem can be prefixed with a global
+ * "no" prefix to invert matching of the whole list. The "no" could
+ * also used for individual items in the @pattern list.
+ *
+ * "nofoo,bar" has the same meaning as "nofoo,nobar"
+ *
+ * "bar" : "nofoo,bar" -> False (global "no" prefix)
+ * "bar" : "foo,bar" -> True
+ * "bar" : "foo,nobar" -> False
+ *
+ * Returns: 1 if type is matching, else 0. This function also returns
+ * 0 if @pattern is NULL and @type is non-NULL.
+ */
+int mnt_match_fstype(const char *type, const char *pattern)
+{
+ int no = 0; /* negated types list */
+ int len;
+ const char *p;
+
+ if (!pattern && !type)
+ return 1;
+ if (!pattern)
+ return 0;
+
+ if (!strncmp(pattern, "no", 2)) {
+ no = 1;
+ pattern += 2;
+ }
+
+ /* Does type occur in types, separated by commas? */
+ len = strlen(type);
+ p = pattern;
+ while(1) {
+ if (!strncmp(p, "no", 2) && !strncmp(p+2, type, len) &&
+ (p[len+2] == 0 || p[len+2] == ','))
+ return 0;
+ if (strncmp(p, type, len) == 0 && (p[len] == 0 || p[len] == ','))
+ return !no;
+ p = strchr(p,',');
+ if (!p)
+ break;
+ p++;
+ }
+ return no;
+}
+
+
+/* Returns 1 if needle found or noneedle not found in haystack
+ * Otherwise returns 0
+ */
+static int check_option(const char *haystack, size_t len,
+ const char *needle, size_t needle_len)
+{
+ const char *p;
+ int no = 0;
+
+ if (needle_len >= 2 && !strncmp(needle, "no", 2)) {
+ no = 1;
+ needle += 2;
+ needle_len -= 2;
+ }
+
+ for (p = haystack; p && p < haystack + len; p++) {
+ char *sep = strchr(p, ',');
+ size_t plen = sep ? sep - p : len - (p - haystack);
+
+ if (plen == needle_len) {
+ if (!strncmp(p, needle, plen))
+ return !no; /* foo or nofoo was found */
+ }
+ p += plen;
+ }
+
+ return no; /* foo or nofoo was not found */
+}
+
+/**
+ * mnt_match_options:
+ * @optstr: options string
+ * @pattern: comma delimitted list of options
+ *
+ * The "no" could used for individual items in the @options list. The "no"
+ * prefix does not have a global meanning.
+ *
+ * Unlike fs type matching, nonetdev,user and nonetdev,nouser have
+ * DIFFERENT meanings; each option is matched explicitly as specified.
+ *
+ * xxx,yyy,zzz : nozzz -> False
+ * xxx,yyy,zzz : xxx,noeee -> True
+ *
+ * Returns: 1 if pattern is matching, else 0. This function also returns 0
+ * if @pattern is NULL and @optstr is non-NULL.
+ */
+int mnt_match_options(const char *optstr, const char *pattern)
+{
+ const char *p;
+ size_t len, optstr_len = 0;
+
+ if (!pattern && !optstr)
+ return 1;
+ if (!pattern)
+ return 0;
+
+ len = strlen(pattern);
+ if (optstr)
+ optstr_len = strlen(optstr);
+
+ for (p = pattern; p < pattern + len; p++) {
+ char *sep = strchr(p, ',');
+ size_t plen = sep ? sep - p : len - (p - pattern);
+
+ if (!plen)
+ continue; /* if two ',' appear in a row */
+
+ if (!check_option(optstr, optstr_len, p, plen))
+ return 0; /* any match failure means failure */
+
+ p += plen;
+ }
+
+ /* no match failures in list means success */
+ return 1;
+}
+
/*
* Reallocates its first arg @s - typical use: s = mnt_strconcat3(s,t,u);
* Returns reallocated @s ion succes or NULL in case of error.
free(buf);
return username;
}
+
+#ifdef TEST_PROGRAM
+int test_match_fstype(struct mtest *ts, int argc, char *argv[])
+{
+ char *type = argv[1];
+ char *pattern = argv[2];
+
+ printf("%s\n", mnt_match_fstype(type, pattern) ? "MATCH" : "NOT-MATCH");
+ return 0;
+}
+
+int test_match_options(struct mtest *ts, int argc, char *argv[])
+{
+ char *optstr = argv[1];
+ char *pattern = argv[2];
+
+ printf("%s\n", mnt_match_options(optstr, pattern) ? "MATCH" : "NOT-MATCH");
+ return 0;
+}
+
+
+int main(int argc, char *argv[])
+{
+ struct mtest tss[] = {
+ { "--match-fstype", test_match_fstype, "<type> <pattern> FS types matching" },
+ { "--match-options", test_match_options, "<options> <pattern> options matching" },
+ { NULL }
+ };
+
+ return mnt_run_test(tss, argc, argv);
+}
+
+#endif /* TEST_PROGRAM */