From: Karel Zak Date: Tue, 23 Feb 2010 14:04:52 +0000 (+0100) Subject: libmount: add mnt_match_{fstype,options} functions X-Git-Url: https://err.no/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=abc9c0f79059fd017a2220975f105b17be26aab7;p=util-linux libmount: add mnt_match_{fstype,options} functions Signed-off-by: Karel Zak --- diff --git a/shlibs/mount/src/Makefile.am b/shlibs/mount/src/Makefile.am index 5d80779e..4e17cfe1 100644 --- a/shlibs/mount/src/Makefile.am +++ b/shlibs/mount/src/Makefile.am @@ -43,7 +43,7 @@ uninstall-hook: # tests noinst_PROGRAMS = test_version test_cache test_optstr test_optls test_lock \ - test_tab + test_tab test_utils tests_cppflags = $(AM_CPPFLAGS) -DTEST_PROGRAM tests_ldadd = .libs/libmount.a $(ul_libblkid_la) @@ -70,3 +70,7 @@ test_lock_LDADD = $(tests_ldadd) test_tab_SOURCES = tab_parse.c tab.c test_tab_CPPFLAGS = $(tests_cppflags) test_tab_LDADD = $(tests_ldadd) + +test_utils_SOURCES = utils.c +test_utils_CPPFLAGS = $(tests_cppflags) +test_utils_LDADD = $(tests_ldadd) diff --git a/shlibs/mount/src/mount.h.in b/shlibs/mount/src/mount.h.in index b4c9bc53..6bea2a17 100644 --- a/shlibs/mount/src/mount.h.in +++ b/shlibs/mount/src/mount.h.in @@ -111,6 +111,8 @@ extern int mnt_get_library_version(const char **ver_string); extern int mnt_fstype_is_netfs(const char *type); extern int mnt_fstype_is_pseudofs(const char *type); extern int mnt_open_device(const char *devname, int flags); +extern int mnt_match_fstype(const char *type, const char *pattern); +extern int mnt_match_options(const char *optstr, const char *pattern); /* cache.c */ extern mnt_cache *mnt_new_cache(void); diff --git a/shlibs/mount/src/utils.c b/shlibs/mount/src/utils.c index fbdfadb8..fb9ffe8d 100644 --- a/shlibs/mount/src/utils.c +++ b/shlibs/mount/src/utils.c @@ -128,6 +128,135 @@ int mnt_fstype_is_netfs(const char *type) 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. @@ -206,3 +335,36 @@ char *mnt_get_username(const uid_t uid) 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, " FS types matching" }, + { "--match-options", test_match_options, " options matching" }, + { NULL } + }; + + return mnt_run_test(tss, argc, argv); +} + +#endif /* TEST_PROGRAM */