diff options
author | Zbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl> | 2021-03-11 10:37:36 +0100 |
---|---|---|
committer | Zbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl> | 2021-03-11 11:25:15 +0100 |
commit | ff0c31bc2722eed528eae6644a104e85ed97f2f1 (patch) | |
tree | c01a605e52a302aa15779003c90f4dfaa2a9c2ca /src/shared/fstab-util.c | |
parent | 0264b404b9f193b70a19db0f600cf6bab3a05368 (diff) | |
download | systemd-ff0c31bc2722eed528eae6644a104e85ed97f2f1.tar.gz |
shared/fstab-util: teach fstab_filter_options() a mode where all values are returned
Apart from tests, the new argument isn't used anywhere, so there should be no
functional change. Note that the two arms of the big conditional are switched, so the
diff is artificially inflated. The actual code change is rather small. I dropped the
path which extracts ret_value manually, because it wasn't supporting unescaping of the
escape character properly.
Diffstat (limited to 'src/shared/fstab-util.c')
-rw-r--r-- | src/shared/fstab-util.c | 124 |
1 files changed, 70 insertions, 54 deletions
diff --git a/src/shared/fstab-util.c b/src/shared/fstab-util.c index 8dc1733c0d..6674ed4a19 100644 --- a/src/shared/fstab-util.c +++ b/src/shared/fstab-util.c @@ -79,21 +79,80 @@ int fstab_is_mount_point(const char *mount) { return false; } -int fstab_filter_options(const char *opts, const char *names, - const char **ret_namefound, char **ret_value, char **ret_filtered) { +int fstab_filter_options( + const char *opts, + const char *names, + const char **ret_namefound, + char **ret_value, + char ***ret_values, + char **ret_filtered) { + const char *name, *namefound = NULL, *x; - _cleanup_strv_free_ char **stor = NULL; - _cleanup_free_ char *v = NULL, **strv = NULL; + _cleanup_strv_free_ char **stor = NULL, **values = NULL; + _cleanup_free_ char *value = NULL, **filtered = NULL; int r; assert(names && *names); + assert(!(ret_value && ret_values)); if (!opts) goto answer; - /* If !ret_value and !ret_filtered, this function is not allowed to fail. */ + /* Finds any options matching 'names', and returns: + * - the last matching option name in ret_namefound, + * - the last matching value in ret_value, + * - any matching values in ret_values, + * - the rest of the option string in ret_filtered. + * + * If !ret_value and !ret_values and !ret_filtered, this function is not allowed to fail. + * + * Returns negative on error, true if any matching options were found, false otherwise. */ + + if (ret_filtered || ret_value || ret_values) { + /* For backwards compatibility, we need to pass-through escape characters. + * The only ones we "consume" are the ones used as "\," or "\\". */ + r = strv_split_full(&stor, opts, ",", EXTRACT_UNESCAPE_SEPARATORS | EXTRACT_UNESCAPE_RELAX); + if (r < 0) + return r; + + filtered = memdup(stor, sizeof(char*) * (strv_length(stor) + 1)); + if (!filtered) + return -ENOMEM; + + char **t = filtered; + for (char **s = t; *s; s++) { + NULSTR_FOREACH(name, names) { + x = startswith(*s, name); + if (!x) + continue; + /* Match name, but when ret_values, only when followed by assignment. */ + if (*x == '=' || (!ret_values && *x == '\0')) + goto found; + } + + *t = *s; + t++; + continue; + found: + /* Keep the last occurrence found */ + namefound = name; + + if (ret_value || ret_values) { + assert(IN_SET(*x, '=', '\0')); - if (!ret_filtered) { + if (ret_value) { + r = free_and_strdup(&value, *x == '=' ? x + 1 : NULL); + if (r < 0) + return r; + } else if (*x) { + r = strv_extend(&values, x + 1); + if (r < 0) + return r; + } + } + } + *t = NULL; + } else for (const char *word = opts;;) { const char *end = word; @@ -121,17 +180,6 @@ int fstab_filter_options(const char *opts, const char *names, x = word + strlen(name); if (IN_SET(*x, '\0', '=', ',')) { namefound = name; - if (ret_value) { - bool eq = *x == '='; - assert(eq || IN_SET(*x, ',', '\0')); - - r = free_and_strndup(&v, - eq ? x + 1 : NULL, - eq ? end - x - 1 : 0); - if (r < 0) - return r; - } - break; } } @@ -141,40 +189,6 @@ int fstab_filter_options(const char *opts, const char *names, else break; } - } else { - /* For backwards compatibility, we need to pass-through escape characters. - * The only ones we "consume" are the ones used as "\," or "\\". */ - r = strv_split_full(&stor, opts, ",", EXTRACT_UNESCAPE_SEPARATORS | EXTRACT_UNESCAPE_RELAX); - if (r < 0) - return r; - - strv = memdup(stor, sizeof(char*) * (strv_length(stor) + 1)); - if (!strv) - return -ENOMEM; - - char **t = strv; - for (char **s = strv; *s; s++) { - NULSTR_FOREACH(name, names) { - x = startswith(*s, name); - if (x && IN_SET(*x, '\0', '=')) - goto found; - } - - *t = *s; - t++; - continue; - found: - /* Keep the last occurrence found */ - namefound = name; - if (ret_value) { - assert(IN_SET(*x, '=', '\0')); - r = free_and_strdup(&v, *x == '=' ? x + 1 : NULL); - if (r < 0) - return r; - } - } - *t = NULL; - } answer: if (ret_namefound) @@ -182,14 +196,16 @@ answer: if (ret_filtered) { char *f; - f = strv_join_full(strv, ",", NULL, true); + f = strv_join_full(filtered, ",", NULL, true); if (!f) return -ENOMEM; *ret_filtered = f; } if (ret_value) - *ret_value = TAKE_PTR(v); + *ret_value = TAKE_PTR(value); + if (ret_values) + *ret_values = TAKE_PTR(values); return !!namefound; } @@ -229,7 +245,7 @@ int fstab_find_pri(const char *options, int *ret) { assert(ret); - r = fstab_filter_options(options, "pri\0", NULL, &opt, NULL); + r = fstab_filter_options(options, "pri\0", NULL, &opt, NULL, NULL); if (r < 0) return r; if (r == 0 || !opt) |