diff --git a/src/shared/fstab-util.c b/src/shared/fstab-util.c index 25e229bf3e..a4f5e348ab 100644 --- a/src/shared/fstab-util.c +++ b/src/shared/fstab-util.c @@ -200,6 +200,34 @@ int fstab_is_mount_point_full(const char *where, const char *path) { #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, @@ -234,8 +262,10 @@ int fstab_filter_options( _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; @@ -257,10 +287,18 @@ int fstab_filter_options( } 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 @@ -270,7 +308,7 @@ int fstab_filter_options( } if (ret_filtered) { - filtered = strv_join_full(filtered_strv, ",", NULL, /* escape_separator= */ true); + filtered = strv_join(filtered_strv, ","); if (!filtered) return -ENOMEM; } diff --git a/src/test/test-fstab-util.c b/src/test/test-fstab-util.c index 773b1f9799..63b70863e6 100644 --- a/src/test/test-fstab-util.c +++ b/src/test/test-fstab-util.c @@ -125,7 +125,7 @@ TEST(fstab_filter_options) { /* 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) {