Skip to content

Commit

Permalink
libmount: reimplement mnt_match_options()
Browse files Browse the repository at this point in the history
Let's use optstr.c functions to parse pattern and options strings.
It's more robust that the old original mount(8) code and it supports
quotes in the options strings.

Signed-off-by: Karel Zak <kzak@redhat.com>
  • Loading branch information
karelzak committed Dec 20, 2016
1 parent 421cfd3 commit db17f20
Show file tree
Hide file tree
Showing 3 changed files with 80 additions and 93 deletions.
2 changes: 1 addition & 1 deletion libmount/docs/libmount-sections.txt
Original file line number Diff line number Diff line change
Expand Up @@ -287,6 +287,7 @@ mnt_optstr_prepend_option
mnt_optstr_remove_option
mnt_optstr_set_option
mnt_split_optstr
mnt_match_options
</SECTION>

<SECTION>
Expand Down Expand Up @@ -377,7 +378,6 @@ mnt_get_swaps_path
mnt_has_regular_mtab
mnt_mangle
mnt_match_fstype
mnt_match_options
mnt_tag_is_valid
mnt_unmangle
</SECTION>
Expand Down
79 changes: 79 additions & 0 deletions libmount/src/optstr.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include <selinux/context.h>
#endif

#include "strutils.h"
#include "mountP.h"

/*
Expand Down Expand Up @@ -1079,6 +1080,84 @@ int mnt_optstr_fix_user(char **optstr)
return rc;
}

/**
* mnt_match_options:
* @optstr: options string
* @pattern: comma delimited list of options
*
* The "no" could be used for individual items in the @options list. The "no"
* prefix does not have a global meaning.
*
* Unlike fs type matching, nonetdev,user and nonetdev,nouser have
* DIFFERENT meanings; each option is matched explicitly as specified.
*
* The "no" prefix interpretation could be disabled by the "+" prefix, for example
* "+noauto" matches if @optstr literally contains the "noauto" string.
*
* "xxx,yyy,zzz" : "nozzz" -> False
*
* "xxx,yyy,zzz" : "xxx,noeee" -> True
*
* "bar,zzz" : "nofoo" -> True (does not contain "foo")
*
* "nofoo,bar" : "nofoo" -> True (does not contain "foo")
*
* "nofoo,bar" : "+nofoo" -> True (contains "nofoo")
*
* "bar,zzz" : "+nofoo" -> False (does not contain "nofoo")
*
*
* 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)
{
char *name, *pat = (char *) pattern;
char *buf;
size_t namesz = 0, valsz = 0;
int match = 1;

if (!pattern && !optstr)
return 1;
if (!pattern)
return 0;

buf = malloc(strlen(pattern) + 1);
if (!buf)
return 0;

/* walk on pattern string
*/
while (match && !mnt_optstr_next_option(&pat, &name, &namesz, NULL, &valsz)) {
char *val;
size_t sz;
int no = 0;

if (*name == '+')
name++, namesz--;
else if ((no = (startswith(name, "no") != NULL)))
name += 2, namesz -= 2;

xstrncpy(buf, name, namesz + 1);

switch (mnt_optstr_get_option(optstr, buf, &val, &sz)) {
case 0: /* found */
match = no == 0 ? 1 : 0;
break;
case 1: /* not found */
match = no == 1 ? 1 : 0;
break;
default: /* parse error */
match = 0;
break;
}

}

free(buf);
return match;
}

#ifdef TEST_PROGRAM

static int test_append(struct libmnt_test *ts, int argc, char *argv[])
Expand Down
92 changes: 0 additions & 92 deletions libmount/src/utils.c
Original file line number Diff line number Diff line change
Expand Up @@ -430,98 +430,6 @@ int mnt_match_fstype(const char *type, const char *pattern)
return match_fstype(type, pattern);
}


/* 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 >= 1 && *needle == '+') {
needle++;
needle_len--;
} else 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 ? (size_t) (sep - p) :
len - (p - haystack);

if (plen == needle_len && !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 delimited list of options
*
* The "no" could be used for individual items in the @options list. The "no"
* prefix does not have a global meaning.
*
* Unlike fs type matching, nonetdev,user and nonetdev,nouser have
* DIFFERENT meanings; each option is matched explicitly as specified.
*
* The "no" prefix interpretation could be disabled by the "+" prefix, for example
* "+noauto" matches if @optstr literally contains the "noauto" string.
*
* "xxx,yyy,zzz" : "nozzz" -> False
*
* "xxx,yyy,zzz" : "xxx,noeee" -> True
*
* "bar,zzz" : "nofoo" -> True
*
* "nofoo,bar" : "+nofoo" -> True
*
* "bar,zzz" : "+nofoo" -> False
*
*
* 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 ? (size_t) (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;
}

void mnt_free_filesystems(char **filesystems)
{
char **p;
Expand Down

0 comments on commit db17f20

Please sign in to comment.