#endif
}
+static char* fstab_unescape_option(const char *s) {
+ /* Undo the fstab option escaping: "\," -> ",", "\\" -> "\", and keep any
+ * other "\x" verbatim (matches EXTRACT_UNESCAPE_SEPARATORS|EXTRACT_UNESCAPE_RELAX). */
+ char *ret, *e;
+
+ assert(s);
+
+ ret = new(char, strlen(s) + 1);
+ if (!ret)
+ return NULL;
+
+ e = ret;
+ for (const char *p = s; *p; p++) {
+ if (*p == '\\' && p[1] != '\0') {
+ if (IN_SET(p[1], ',', '\\')) {
+ *e++ = p[1];
+ p++;
+ continue;
+ }
+ /* Keep the backslash and the following character verbatim. */
+ *e++ = *p++;
+ }
+ *e++ = *p;
+ }
+ *e = '\0';
+ return ret;
+}
+
int fstab_filter_options(
const char *opts,
const char *names,
_cleanup_free_ char **filtered_strv = NULL; /* strings are owned by 'opts_split' */
/* 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(&opts_split, opts, ",", EXTRACT_UNESCAPE_SEPARATORS|EXTRACT_UNESCAPE_RELAX);
+ * The only ones we "consume" are the ones used as "\," or "\\". The option
+ * values are not unescaped by strv_split_full() here; matching option values are
+ * unescaped manually below so that callers keep getting the unescaped form. */
+ r = strv_split_full(&opts_split, opts, ",", EXTRACT_UNESCAPE_RELAX);
if (r < 0)
return r;
}
if (found) {
+ _cleanup_free_ char *unescaped = NULL;
+
+ if ((ret_value && *x == '=') || ret_values) {
+ unescaped = fstab_unescape_option(x + 1);
+ if (!unescaped)
+ return -ENOMEM;
+ }
+
if (ret_value)
- r = free_and_strdup(&value, *x == '=' ? x + 1 : NULL);
+ r = free_and_replace(value, unescaped);
else if (ret_values)
- r = strv_extend(&values, x + 1);
+ r = strv_extend(&values, unescaped);
else
r = 0;
} else
}
if (ret_filtered) {
- filtered = strv_join_full(filtered_strv, ",", NULL, /* escape_separator= */ true);
+ filtered = strv_join(filtered_strv, ",");
if (!filtered)
return -ENOMEM;
}
/* escaped characters */
do_fstab_filter_options("opt1=\\\\,opt2=\\xff", "opt1\0", 1, 1, "opt1", "\\", "\\", "opt2=\\xff");
- do_fstab_filter_options("opt1=\\\\,opt2=\\xff", "opt2\0", 1, 1, "opt2", "\\xff", "\\xff", "opt1=\\");
+ do_fstab_filter_options("opt1=\\\\,opt2=\\xff", "opt2\0", 1, 1, "opt2", "\\xff", "\\xff", "opt1=\\\\");
}
TEST(fstab_find_pri) {