summaryrefslogtreecommitdiff
path: root/src/shared/fstab-util.c
diff options
context:
space:
mode:
authorZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>2021-03-11 10:37:36 +0100
committerZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>2021-03-11 11:25:15 +0100
commitff0c31bc2722eed528eae6644a104e85ed97f2f1 (patch)
treec01a605e52a302aa15779003c90f4dfaa2a9c2ca /src/shared/fstab-util.c
parent0264b404b9f193b70a19db0f600cf6bab3a05368 (diff)
downloadsystemd-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.c124
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)