diff --git a/src/basic/extract-word.c b/src/basic/extract-word.c
index 4e4e7e8ce93..d1af11318a8 100644
--- a/src/basic/extract-word.c
+++ b/src/basic/extract-word.c
@@ -69,14 +69,14 @@ int extract_first_word(const char **p, char **ret, const char *separators, Extra
                                 return -ENOMEM;
 
                         if (c == 0) {
-                                if ((flags & EXTRACT_CUNESCAPE_RELAX) &&
+                                if ((flags & EXTRACT_UNESCAPE_RELAX) &&
                                     (quote == 0 || flags & EXTRACT_RELAX)) {
                                         /* If we find an unquoted trailing backslash and we're in
-                                         * EXTRACT_CUNESCAPE_RELAX mode, keep it verbatim in the
+                                         * EXTRACT_UNESCAPE_RELAX mode, keep it verbatim in the
                                          * output.
                                          *
                                          * Unbalanced quotes will only be allowed in EXTRACT_RELAX
-                                         * mode, EXTRACT_CUNESCAPE_RELAX mode does not allow them.
+                                         * mode, EXTRACT_UNESCAPE_RELAX mode does not allow them.
                                          */
                                         s[sz++] = '\\';
                                         goto finish_force_terminate;
@@ -102,10 +102,10 @@ int extract_first_word(const char **p, char **ret, const char *separators, Extra
                                         else
                                                 sz += utf8_encode_unichar(s + sz, u);
                                 } else if ((flags & EXTRACT_UNESCAPE_SEPARATORS) &&
-                                           strchr(separators, **p))
-                                        /* An escaped separator char */
+                                           (strchr(separators, **p) || **p == '\\'))
+                                        /* An escaped separator char or the escape char itself */
                                         s[sz++] = c;
-                                else if (flags & EXTRACT_CUNESCAPE_RELAX) {
+                                else if (flags & EXTRACT_UNESCAPE_RELAX) {
                                         s[sz++] = '\\';
                                         s[sz++] = c;
                                 } else
@@ -196,7 +196,7 @@ int extract_first_word_and_warn(
                 const char *rvalue) {
 
         /* Try to unquote it, if it fails, warn about it and try again
-         * but this time using EXTRACT_CUNESCAPE_RELAX to keep the
+         * but this time using EXTRACT_UNESCAPE_RELAX to keep the
          * backslashes verbatim in invalid escape sequences. */
 
         const char *save;
@@ -207,11 +207,11 @@ int extract_first_word_and_warn(
         if (r >= 0)
                 return r;
 
-        if (r == -EINVAL && !(flags & EXTRACT_CUNESCAPE_RELAX)) {
+        if (r == -EINVAL && !(flags & EXTRACT_UNESCAPE_RELAX)) {
 
-                /* Retry it with EXTRACT_CUNESCAPE_RELAX. */
+                /* Retry it with EXTRACT_UNESCAPE_RELAX. */
                 *p = save;
-                r = extract_first_word(p, ret, separators, flags|EXTRACT_CUNESCAPE_RELAX);
+                r = extract_first_word(p, ret, separators, flags|EXTRACT_UNESCAPE_RELAX);
                 if (r >= 0) {
                         /* It worked this time, hence it must have been an invalid escape sequence. */
                         log_syntax(unit, LOG_WARNING, filename, line, EINVAL, "Ignoring unknown escape sequences: \"%s\"", *ret);
diff --git a/src/basic/extract-word.h b/src/basic/extract-word.h
index d1de32e5806..0e9e77e93d3 100644
--- a/src/basic/extract-word.h
+++ b/src/basic/extract-word.h
@@ -4,13 +4,15 @@
 #include "macro.h"
 
 typedef enum ExtractFlags {
-        EXTRACT_RELAX                    = 1 << 0,
-        EXTRACT_CUNESCAPE                = 1 << 1,
-        EXTRACT_CUNESCAPE_RELAX          = 1 << 2,
-        EXTRACT_UNESCAPE_SEPARATORS      = 1 << 3,
-        EXTRACT_UNQUOTE                  = 1 << 4,
-        EXTRACT_DONT_COALESCE_SEPARATORS = 1 << 5,
-        EXTRACT_RETAIN_ESCAPE            = 1 << 6,
+        EXTRACT_RELAX                    = 1 << 0, /* Allow unbalanced quote and eat up trailing backslash. */
+        EXTRACT_CUNESCAPE                = 1 << 1, /* Unescape known escape sequences. */
+        EXTRACT_UNESCAPE_RELAX           = 1 << 2, /* Allow and keep unknown escape sequences, allow and keep trailing backslash. */
+        EXTRACT_UNESCAPE_SEPARATORS      = 1 << 3, /* Unescape separators (those specified, or whitespace by default). */
+        EXTRACT_UNQUOTE                  = 1 << 4, /* Remove quoting with "" and ''. */
+        EXTRACT_DONT_COALESCE_SEPARATORS = 1 << 5, /* Don't treat multiple adjacent separators as one */
+        EXTRACT_RETAIN_ESCAPE            = 1 << 6, /* Treat escape character '\' as any other character without special meaning */
+
+        /* Note that if no flags are specified, escaped escape characters will be silently stripped. */
 } ExtractFlags;
 
 int extract_first_word(const char **p, char **ret, const char *separators, ExtractFlags flags);
diff --git a/src/core/mount.c b/src/core/mount.c
index 23b558859c2..ca5d0939a18 100644
--- a/src/core/mount.c
+++ b/src/core/mount.c
@@ -1019,7 +1019,7 @@ static void mount_enter_mounting(Mount *m) {
         if (p) {
                 _cleanup_free_ char *opts = NULL;
 
-                r = fstab_filter_options(p->options, "nofail\0" "noauto\0" "auto\0", NULL, NULL, &opts);
+                r = fstab_filter_options(p->options, "nofail\0" "noauto\0" "auto\0", NULL, NULL, NULL, &opts);
                 if (r < 0)
                         goto fail;
 
diff --git a/src/cryptsetup/cryptsetup-generator.c b/src/cryptsetup/cryptsetup-generator.c
index 74f739b5139..98c8408da54 100644
--- a/src/cryptsetup/cryptsetup-generator.c
+++ b/src/cryptsetup/cryptsetup-generator.c
@@ -301,7 +301,9 @@ static int create_disk(
         netdev = fstab_test_option(options, "_netdev\0");
         attach_in_initrd = fstab_test_option(options, "x-initrd.attach\0");
 
-        keyfile_can_timeout = fstab_filter_options(options, "keyfile-timeout\0", NULL, &keyfile_timeout_value, NULL);
+        keyfile_can_timeout = fstab_filter_options(options,
+                                                   "keyfile-timeout\0",
+                                                   NULL, &keyfile_timeout_value, NULL, NULL);
         if (keyfile_can_timeout < 0)
                 return log_error_errno(keyfile_can_timeout, "Failed to parse keyfile-timeout= option value: %m");
 
@@ -310,11 +312,12 @@ static int create_disk(
                 "header\0",
                 NULL,
                 &header_path,
+                NULL,
                 headerdev ? &filtered_header : NULL);
         if (detached_header < 0)
                 return log_error_errno(detached_header, "Failed to parse header= option value: %m");
 
-        tmp = fstab_filter_options(options, "tmp\0", NULL, &tmp_fstype, NULL);
+        tmp = fstab_filter_options(options, "tmp\0", NULL, &tmp_fstype, NULL, NULL);
         if (tmp < 0)
                 return log_error_errno(tmp, "Failed to parse tmp= option value: %m");
 
@@ -602,7 +605,7 @@ static int filter_header_device(const char *options,
         assert(ret_headerdev);
         assert(ret_filtered_headerdev_options);
 
-        r = fstab_filter_options(options, "header\0", NULL, &headerspec, &filtered_headerspec);
+        r = fstab_filter_options(options, "header\0", NULL, &headerspec, NULL, &filtered_headerspec);
         if (r < 0)
                 return log_error_errno(r, "Failed to parse header= option value: %m");
 
diff --git a/src/fstab-generator/fstab-generator.c b/src/fstab-generator/fstab-generator.c
index 0910a9aa61b..8c1087a9a33 100644
--- a/src/fstab-generator/fstab-generator.c
+++ b/src/fstab-generator/fstab-generator.c
@@ -200,7 +200,7 @@ static int write_timeout(
         usec_t u;
         int r;
 
-        r = fstab_filter_options(opts, filter, NULL, &timeout, NULL);
+        r = fstab_filter_options(opts, filter, NULL, &timeout, NULL, NULL);
         if (r < 0)
                 return log_warning_errno(r, "Failed to parse options: %m");
         if (r == 0)
@@ -241,7 +241,7 @@ static int write_dependency(
         assert(f);
         assert(opts);
 
-        r = fstab_extract_values(opts, filter, &names);
+        r = fstab_filter_options(opts, filter, NULL, NULL, &names, NULL);
         if (r < 0)
                 return log_warning_errno(r, "Failed to parse options: %m");
         if (r == 0)
@@ -274,17 +274,17 @@ static int write_dependency(
 
 static int write_after(FILE *f, const char *opts) {
         return write_dependency(f, opts,
-                                "x-systemd.after", "After=%1$s\n");
+                                "x-systemd.after\0", "After=%1$s\n");
 }
 
 static int write_requires_after(FILE *f, const char *opts) {
         return write_dependency(f, opts,
-                                "x-systemd.requires", "After=%1$s\nRequires=%1$s\n");
+                                "x-systemd.requires\0", "After=%1$s\nRequires=%1$s\n");
 }
 
 static int write_before(FILE *f, const char *opts) {
         return write_dependency(f, opts,
-                                "x-systemd.before", "Before=%1$s\n");
+                                "x-systemd.before\0", "Before=%1$s\n");
 }
 
 static int write_requires_mounts_for(FILE *f, const char *opts) {
@@ -295,7 +295,7 @@ static int write_requires_mounts_for(FILE *f, const char *opts) {
         assert(f);
         assert(opts);
 
-        r = fstab_extract_values(opts, "x-systemd.requires-mounts-for", &paths);
+        r = fstab_filter_options(opts, "x-systemd.requires-mounts-for\0", NULL, NULL, &paths, NULL);
         if (r < 0)
                 return log_warning_errno(r, "Failed to parse options: %m");
         if (r == 0)
@@ -376,11 +376,11 @@ static int add_mount(
             mount_point_ignore(where))
                 return 0;
 
-        r = fstab_extract_values(opts, "x-systemd.wanted-by", &wanted_by);
+        r = fstab_filter_options(opts, "x-systemd.wanted-by\0", NULL, NULL, &wanted_by, NULL);
         if (r < 0)
                 return r;
 
-        r = fstab_extract_values(opts, "x-systemd.required-by", &required_by);
+        r = fstab_filter_options(opts, "x-systemd.required-by\0", NULL, NULL, &required_by, NULL);
         if (r < 0)
                 return r;
 
@@ -611,11 +611,11 @@ static int parse_fstab(bool initrd) {
                          * /etc/fstab. So we canonicalize here. Note that we use CHASE_NONEXISTENT to handle the case
                          * where a symlink refers to another mount target; this works assuming the sub-mountpoint
                          * target is the final directory. */
-                        r = chase_symlinks(where, initrd ? "/sysroot" : NULL,
+                        k = chase_symlinks(where, initrd ? "/sysroot" : NULL,
                                            CHASE_PREFIX_ROOT | CHASE_NONEXISTENT,
                                            &canonical_where, NULL);
-                        if (r < 0) /* If we can't canonicalize we continue on as if it wasn't a symlink */
-                                log_debug_errno(r, "Failed to read symlink target for %s, ignoring: %m", where);
+                        if (k < 0) /* If we can't canonicalize we continue on as if it wasn't a symlink */
+                                log_debug_errno(k, "Failed to read symlink target for %s, ignoring: %m", where);
                         else if (streq(canonical_where, where)) /* If it was fully canonicalized, suppress the change */
                                 canonical_where = mfree(canonical_where);
                         else
diff --git a/src/resolve/resolved-conf.c b/src/resolve/resolved-conf.c
index f2a33162517..87d1794a741 100644
--- a/src/resolve/resolved-conf.c
+++ b/src/resolve/resolved-conf.c
@@ -348,7 +348,7 @@ int config_parse_dnssd_txt(
                 int r;
 
                 r = extract_first_word(&rvalue, &word, NULL,
-                                       EXTRACT_UNQUOTE|EXTRACT_CUNESCAPE|EXTRACT_CUNESCAPE_RELAX);
+                                       EXTRACT_UNQUOTE|EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_RELAX);
                 if (r == 0)
                         break;
                 if (r == -ENOMEM)
diff --git a/src/shared/fstab-util.c b/src/shared/fstab-util.c
index 292b97cd692..7fd3d9c2c34 100644
--- a/src/shared/fstab-util.c
+++ b/src/shared/fstab-util.c
@@ -79,34 +79,95 @@ 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) {
+        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_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;
 
-                        /* Look for an *non-escaped* comma separator. Only commas can be escaped, so "\," is
-                         * the only valid escape sequence, so we can do a very simple test here. */
+                        /* Look for a *non-escaped* comma separator. Only commas and backslashes can be
+                         * escaped, so "\," and "\\" are the only valid escape sequences, and we can do a
+                         * very simple test here. */
                         for (;;) {
-                                size_t n = strcspn(end, ",");
+                                end += strcspn(end, ",\\");
 
-                                end += n;
-                                if (n > 0 && end[-1] == '\\')
-                                        end++;
-                                else
+                                if (IN_SET(*end, ',', '\0'))
                                         break;
+                                assert(*end == '\\');
+                                end ++;                 /* Skip the backslash */
+                                if (*end != '\0')
+                                        end ++;         /* Skip the escaped char, but watch out for a trailing commma */
                         }
 
                         NULSTR_FOREACH(name, names) {
@@ -119,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;
                                 }
                         }
@@ -139,38 +189,6 @@ int fstab_filter_options(const char *opts, const char *names,
                         else
                                 break;
                 }
-        } else {
-                r = strv_split_full(&stor, opts, ",", EXTRACT_DONT_COALESCE_SEPARATORS | EXTRACT_UNESCAPE_SEPARATORS);
-                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)
@@ -178,54 +196,27 @@ 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;
 }
 
-int fstab_extract_values(const char *opts, const char *name, char ***values) {
-        _cleanup_strv_free_ char **optsv = NULL, **res = NULL;
-        char **s;
-
-        assert(opts);
-        assert(name);
-        assert(values);
-
-        optsv = strv_split(opts, ",");
-        if (!optsv)
-                return -ENOMEM;
-
-        STRV_FOREACH(s, optsv) {
-                char *arg;
-                int r;
-
-                arg = startswith(*s, name);
-                if (!arg || *arg != '=')
-                        continue;
-                r = strv_extend(&res, arg + 1);
-                if (r < 0)
-                        return r;
-        }
-
-        *values = TAKE_PTR(res);
-
-        return !!*values;
-}
-
 int fstab_find_pri(const char *options, int *ret) {
         _cleanup_free_ char *opt = NULL;
         int r, pri;
 
         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)
diff --git a/src/shared/fstab-util.h b/src/shared/fstab-util.h
index 1a602cb56b2..6b596baafa1 100644
--- a/src/shared/fstab-util.h
+++ b/src/shared/fstab-util.h
@@ -10,12 +10,16 @@ bool fstab_is_extrinsic(const char *mount, const char *opts);
 int fstab_is_mount_point(const char *mount);
 int fstab_has_fstype(const char *fstype);
 
-int fstab_filter_options(const char *opts, const char *names, const char **namefound, char **value, char **filtered);
-
-int fstab_extract_values(const char *opts, const char *name, char ***values);
+int fstab_filter_options(
+                const char *opts,
+                const char *names,
+                const char **ret_namefound,
+                char **ret_value,
+                char ***ret_values,
+                char **ret_filtered);
 
 static inline bool fstab_test_option(const char *opts, const char *names) {
-        return !!fstab_filter_options(opts, names, NULL, NULL, NULL);
+        return !!fstab_filter_options(opts, names, NULL, NULL, NULL, NULL);
 }
 
 int fstab_find_pri(const char *options, int *ret);
@@ -26,7 +30,7 @@ static inline bool fstab_test_yes_no_option(const char *opts, const char *yes_no
         /* If first name given is last, return 1.
          * If second name given is last or neither is found, return 0. */
 
-        assert_se(fstab_filter_options(opts, yes_no, &opt, NULL, NULL) >= 0);
+        assert_se(fstab_filter_options(opts, yes_no, &opt, NULL, NULL, NULL) >= 0);
 
         return opt == yes_no;
 }
diff --git a/src/shared/generator.c b/src/shared/generator.c
index 8b95c772db1..5b9c4325271 100644
--- a/src/shared/generator.c
+++ b/src/shared/generator.c
@@ -215,9 +215,13 @@ int generator_write_timeouts(
 
         r = fstab_filter_options(opts, "comment=systemd.device-timeout\0"
                                        "x-systemd.device-timeout\0",
-                                 NULL, &timeout, filtered);
-        if (r <= 0)
-                return r;
+                                 NULL, &timeout, NULL, filtered);
+        if (r < 0) {
+                log_warning_errno(r, "Failed to parse fstab options, ignoring: %m");
+                return 0;
+        }
+        if (r == 0)
+                return 0;
 
         r = parse_sec_fix_0(timeout, &u);
         if (r < 0) {
diff --git a/src/test/test-extract-word.c b/src/test/test-extract-word.c
index 56b516fe40a..f1085266df2 100644
--- a/src/test/test-extract-word.c
+++ b/src/test/test-extract-word.c
@@ -172,19 +172,19 @@ static void test_extract_first_word(void) {
         assert_se(isempty(p));
 
         p = original = "fooo\\";
-        assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE_RELAX) > 0);
+        assert_se(extract_first_word(&p, &t, NULL, EXTRACT_UNESCAPE_RELAX) > 0);
         assert_se(streq(t, "fooo\\"));
         free(t);
         assert_se(isempty(p));
 
         p = original = "fooo\\";
-        assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE_RELAX|EXTRACT_RELAX) > 0);
+        assert_se(extract_first_word(&p, &t, NULL, EXTRACT_UNESCAPE_RELAX|EXTRACT_RELAX) > 0);
         assert_se(streq(t, "fooo\\"));
         free(t);
         assert_se(isempty(p));
 
         p = original = "fooo\\";
-        assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE|EXTRACT_CUNESCAPE_RELAX) > 0);
+        assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_RELAX) > 0);
         assert_se(streq(t, "fooo\\"));
         free(t);
         assert_se(isempty(p));
@@ -230,17 +230,17 @@ static void test_extract_first_word(void) {
         assert_se(isempty(p));
 
         p = original = "\"foo\\";
-        assert_se(extract_first_word(&p, &t, NULL, EXTRACT_UNQUOTE|EXTRACT_CUNESCAPE_RELAX) == -EINVAL);
+        assert_se(extract_first_word(&p, &t, NULL, EXTRACT_UNQUOTE|EXTRACT_UNESCAPE_RELAX) == -EINVAL);
         assert_se(p == original + 5);
 
         p = original = "\"foo\\";
-        assert_se(extract_first_word(&p, &t, NULL, EXTRACT_UNQUOTE|EXTRACT_CUNESCAPE_RELAX|EXTRACT_RELAX) > 0);
+        assert_se(extract_first_word(&p, &t, NULL, EXTRACT_UNQUOTE|EXTRACT_UNESCAPE_RELAX|EXTRACT_RELAX) > 0);
         assert_se(streq(t, "foo\\"));
         free(t);
         assert_se(isempty(p));
 
         p = original = "\"foo\\";
-        assert_se(extract_first_word(&p, &t, NULL, EXTRACT_UNQUOTE|EXTRACT_CUNESCAPE|EXTRACT_CUNESCAPE_RELAX|EXTRACT_RELAX) > 0);
+        assert_se(extract_first_word(&p, &t, NULL, EXTRACT_UNQUOTE|EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_RELAX|EXTRACT_RELAX) > 0);
         assert_se(streq(t, "foo\\"));
         free(t);
         assert_se(isempty(p));
@@ -252,13 +252,13 @@ static void test_extract_first_word(void) {
         assert_se(p == original + 10);
 
         p = original = "fooo\\ bar quux";
-        assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE_RELAX) > 0);
+        assert_se(extract_first_word(&p, &t, NULL, EXTRACT_UNESCAPE_RELAX) > 0);
         assert_se(streq(t, "fooo bar"));
         free(t);
         assert_se(p == original + 10);
 
         p = original = "fooo\\ bar quux";
-        assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE_RELAX|EXTRACT_RELAX) > 0);
+        assert_se(extract_first_word(&p, &t, NULL, EXTRACT_UNESCAPE_RELAX|EXTRACT_RELAX) > 0);
         assert_se(streq(t, "fooo bar"));
         free(t);
         assert_se(p == original + 10);
@@ -268,7 +268,7 @@ static void test_extract_first_word(void) {
         assert_se(p == original + 5);
 
         p = original = "fooo\\ bar quux";
-        assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE|EXTRACT_CUNESCAPE_RELAX) > 0);
+        assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_RELAX) > 0);
         assert_se(streq(t, "fooo\\ bar"));
         free(t);
         assert_se(p == original + 10);
@@ -278,13 +278,13 @@ static void test_extract_first_word(void) {
         assert_se(p == original + 1);
 
         p = original = "\\w+@\\K[\\d.]+";
-        assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE|EXTRACT_CUNESCAPE_RELAX) > 0);
+        assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_RELAX) > 0);
         assert_se(streq(t, "\\w+@\\K[\\d.]+"));
         free(t);
         assert_se(isempty(p));
 
         p = original = "\\w+\\b";
-        assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE|EXTRACT_CUNESCAPE_RELAX) > 0);
+        assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_RELAX) > 0);
         assert_se(streq(t, "\\w+\b"));
         free(t);
         assert_se(isempty(p));
@@ -344,6 +344,39 @@ static void test_extract_first_word(void) {
         free(t);
         assert_se(p == NULL);
 
+        p = "\\:";
+        assert_se(extract_first_word(&p, &t, ":", EXTRACT_UNESCAPE_SEPARATORS) == 1);
+        assert_se(streq(t, ":"));
+        free(t);
+        assert_se(p == NULL);
+
+        p = "a\\:b";
+        assert_se(extract_first_word(&p, &t, ":", EXTRACT_UNESCAPE_SEPARATORS) == 1);
+        assert_se(streq(t, "a:b"));
+        free(t);
+        assert_se(p == NULL);
+
+        p = "a\\ b:c";
+        assert_se(extract_first_word(&p, &t, WHITESPACE ":", EXTRACT_UNESCAPE_SEPARATORS) == 1);
+        assert_se(streq(t, "a b"));
+        free(t);
+        assert_se(extract_first_word(&p, &t, WHITESPACE ":", EXTRACT_UNESCAPE_SEPARATORS) == 1);
+        assert_se(streq(t, "c"));
+        free(t);
+        assert_se(p == NULL);
+
+        p = "a\\ b:c\\x";
+        assert_se(extract_first_word(&p, &t, ":", EXTRACT_UNESCAPE_SEPARATORS) == -EINVAL);
+
+        p = "a\\\\ b:c\\\\x";
+        assert_se(extract_first_word(&p, &t, ":", EXTRACT_UNESCAPE_SEPARATORS) == 1);
+        assert_se(streq(t, "a\\ b"));
+        free(t);
+        assert_se(extract_first_word(&p, &t, ":", EXTRACT_UNESCAPE_SEPARATORS) == 1);
+        assert_se(streq(t, "c\\x"));
+        free(t);
+        assert_se(p == NULL);
+
         p = "\\:";
         assert_se(extract_first_word(&p, &t, ":", EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS) == 1);
         assert_se(streq(t, ":"));
@@ -365,6 +398,18 @@ static void test_extract_first_word(void) {
         free(t);
         assert_se(p == NULL);
 
+        p = "a\\ b:c\\x";
+        assert_se(extract_first_word(&p, &t, ":", EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS) == -EINVAL);
+
+        p = "a\\\\ b:c\\\\x";
+        assert_se(extract_first_word(&p, &t, ":", EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS) == 1);
+        assert_se(streq(t, "a\\ b"));
+        free(t);
+        assert_se(extract_first_word(&p, &t, ":", EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS) == 1);
+        assert_se(streq(t, "c\\x"));
+        free(t);
+        assert_se(p == NULL);
+
         p = "\\:";
         assert_se(extract_first_word(&p, &t, ":", EXTRACT_CUNESCAPE) == -EINVAL);
 
diff --git a/src/test/test-fstab-util.c b/src/test/test-fstab-util.c
index 222ffbb2a75..d2f20185265 100644
--- a/src/test/test-fstab-util.c
+++ b/src/test/test-fstab-util.c
@@ -6,94 +6,125 @@
 #include "fstab-util.h"
 #include "log.h"
 #include "string-util.h"
+#include "strv.h"
 
 /*
-int fstab_filter_options(const char *opts, const char *names,
-                         const char **namefound, char **value, char **filtered);
+int fstab_filter_options(
+        const char *opts,
+        const char *names,
+        const char **ret_namefound,
+        const char **ret_value,
+        const char **ret_values,
+        char **ret_filtered);
 */
 
 static void do_fstab_filter_options(const char *opts,
                                     const char *remove,
                                     int r_expected,
+                                    int r_values_expected,
                                     const char *name_expected,
                                     const char *value_expected,
+                                    const char *values_expected,
                                     const char *filtered_expected) {
         int r;
         const char *name;
-        _cleanup_free_ char *value = NULL, *filtered = NULL;
+        _cleanup_free_ char *value = NULL, *filtered = NULL, *joined = NULL;
+        _cleanup_strv_free_ char **values = NULL;
 
-        r = fstab_filter_options(opts, remove, &name, &value, &filtered);
-        log_info("\"%s\" → %d, \"%s\", \"%s\", \"%s\", expected %d, \"%s\", \"%s\", \"%s\"",
-                 opts, r, name, value, filtered,
+        /* test mode which returns the last value */
+
+        r = fstab_filter_options(opts, remove, &name, &value, NULL, &filtered);
+        log_info("1: \"%s\" → %d, \"%s\", \"%s\", \"%s\", expected %d, \"%s\", \"%s\", \"%s\"",
+                 opts, r, strnull(name), value, filtered,
                  r_expected, name_expected, value_expected, filtered_expected ?: opts);
         assert_se(r == r_expected);
         assert_se(streq_ptr(name, name_expected));
         assert_se(streq_ptr(value, value_expected));
         assert_se(streq_ptr(filtered, filtered_expected ?: opts));
 
+        /* test mode which returns all the values */
+
+        r = fstab_filter_options(opts, remove, &name, NULL, &values, NULL);
+        assert_se(joined = strv_join(values, ":"));
+        log_info("2: \"%s\" → %d, \"%s\", \"%s\", expected %d, \"%s\", \"%s\"",
+                 opts, r, strnull(name), joined,
+                 r_values_expected, name_expected, values_expected);
+        assert_se(r == r_values_expected);
+        assert_se(streq_ptr(name, r_values_expected > 0 ? name_expected : NULL));
+        assert_se(streq_ptr(joined, values_expected));
+
         /* also test the malloc-less mode */
-        r = fstab_filter_options(opts, remove, &name, NULL, NULL);
-        log_info("\"%s\" → %d, \"%s\", expected %d, \"%s\"\n-",
-                 opts, r, name,
+        r = fstab_filter_options(opts, remove, &name, NULL, NULL, NULL);
+        log_info("3: \"%s\" → %d, \"%s\", expected %d, \"%s\"\n-",
+                 opts, r, strnull(name),
                  r_expected, name_expected);
         assert_se(r == r_expected);
         assert_se(streq_ptr(name, name_expected));
 }
 
 static void test_fstab_filter_options(void) {
-        do_fstab_filter_options("opt=0", "opt\0x-opt\0", 1, "opt", "0", "");
-        do_fstab_filter_options("opt=0", "x-opt\0opt\0", 1, "opt", "0", "");
-        do_fstab_filter_options("opt", "opt\0x-opt\0", 1, "opt", NULL, "");
-        do_fstab_filter_options("opt", "x-opt\0opt\0", 1, "opt", NULL, "");
-        do_fstab_filter_options("x-opt", "x-opt\0opt\0", 1, "x-opt", NULL, "");
+        do_fstab_filter_options("opt=0", "opt\0x-opt\0", 1, 1, "opt", "0", "0", "");
+        do_fstab_filter_options("opt=0", "x-opt\0opt\0", 1, 1, "opt", "0", "0", "");
+        do_fstab_filter_options("opt", "opt\0x-opt\0", 1, 0, "opt", NULL, "", "");
+        do_fstab_filter_options("opt", "x-opt\0opt\0", 1, 0, "opt", NULL, "", "");
+        do_fstab_filter_options("x-opt", "x-opt\0opt\0", 1, 0, "x-opt", NULL, "", "");
 
-        do_fstab_filter_options("opt=0,other", "opt\0x-opt\0", 1, "opt", "0", "other");
-        do_fstab_filter_options("opt=0,other", "x-opt\0opt\0", 1, "opt", "0", "other");
-        do_fstab_filter_options("opt,other", "opt\0x-opt\0", 1, "opt", NULL, "other");
-        do_fstab_filter_options("opt,other", "x-opt\0opt\0", 1, "opt", NULL, "other");
-        do_fstab_filter_options("x-opt,other", "opt\0x-opt\0", 1, "x-opt", NULL, "other");
+        do_fstab_filter_options("opt=0,other", "opt\0x-opt\0", 1, 1, "opt", "0", "0", "other");
+        do_fstab_filter_options("opt=0,other", "x-opt\0opt\0", 1, 1, "opt", "0", "0", "other");
+        do_fstab_filter_options("opt,other", "opt\0x-opt\0", 1, 0, "opt", NULL, "", "other");
+        do_fstab_filter_options("opt,other", "x-opt\0opt\0", 1, 0, "opt", NULL, "", "other");
+        do_fstab_filter_options("x-opt,other", "opt\0x-opt\0", 1, 0, "x-opt", NULL, "", "other");
 
-        do_fstab_filter_options("opt=0\\,1,other", "opt\0x-opt\0", 1, "opt", "0,1", "other");
-        do_fstab_filter_options("opt=0,other,x-opt\\,foobar", "x-opt\0opt\0", 1, "opt", "0", "other,x-opt\\,foobar");
-        do_fstab_filter_options("opt,other,x-opt\\,part", "opt\0x-opt\0", 1, "opt", NULL, "other,x-opt\\,part");
-        do_fstab_filter_options("opt,other,part\\,x-opt", "x-opt\0opt\0", 1, "opt", NULL, "other,part\\,x-opt");
-        do_fstab_filter_options("opt,other\\,\\,\\,opt,x-part", "opt\0x-opt\0", 1, "opt", NULL, "other\\,\\,\\,opt,x-part");
+        do_fstab_filter_options("opt=0\\,1,other", "opt\0x-opt\0", 1, 1, "opt", "0,1", "0,1", "other");
+        do_fstab_filter_options("opt=0,other,x-opt\\,foobar", "x-opt\0opt\0", 1, 1, "opt", "0", "0", "other,x-opt\\,foobar");
+        do_fstab_filter_options("opt,other,x-opt\\,part", "opt\0x-opt\0", 1, 0, "opt", NULL, "", "other,x-opt\\,part");
+        do_fstab_filter_options("opt,other,part\\,x-opt", "x-opt\0opt\0", 1, 0, "opt", NULL, "", "other,part\\,x-opt");
+        do_fstab_filter_options("opt,other\\,\\,\\,opt,x-part", "opt\0x-opt\0", 1, 0, "opt", NULL, "", "other\\,\\,\\,opt,x-part");
 
-        do_fstab_filter_options("opto=0,other", "opt\0x-opt\0", 0, NULL, NULL, NULL);
-        do_fstab_filter_options("opto,other", "opt\0x-opt\0", 0, NULL, NULL, NULL);
-        do_fstab_filter_options("x-opto,other", "opt\0x-opt\0", 0, NULL, NULL, NULL);
+        do_fstab_filter_options("opto=0,other", "opt\0x-opt\0", 0, 0, NULL, NULL, "", NULL);
+        do_fstab_filter_options("opto,other", "opt\0x-opt\0", 0, 0, NULL, NULL, "", NULL);
+        do_fstab_filter_options("x-opto,other", "opt\0x-opt\0", 0, 0, NULL, NULL, "", NULL);
 
-        do_fstab_filter_options("first,opt=0", "opt\0x-opt\0", 1, "opt", "0", "first");
-        do_fstab_filter_options("first=1,opt=0", "opt\0x-opt\0", 1, "opt", "0", "first=1");
-        do_fstab_filter_options("first,opt=", "opt\0x-opt\0", 1, "opt", "", "first");
-        do_fstab_filter_options("first=1,opt", "opt\0x-opt\0", 1, "opt", NULL, "first=1");
-        do_fstab_filter_options("first=1,x-opt", "opt\0x-opt\0", 1, "x-opt", NULL, "first=1");
+        do_fstab_filter_options("first,opt=0", "opt\0x-opt\0", 1, 1, "opt", "0", "0", "first");
+        do_fstab_filter_options("first=1,opt=0", "opt\0x-opt\0", 1, 1, "opt", "0", "0", "first=1");
+        do_fstab_filter_options("first,opt=", "opt\0x-opt\0", 1, 1, "opt", "", "", "first");
+        do_fstab_filter_options("first=1,opt", "opt\0x-opt\0", 1, 0, "opt", NULL, "", "first=1");
+        do_fstab_filter_options("first=1,x-opt", "opt\0x-opt\0", 1, 0, "x-opt", NULL, "", "first=1");
 
-        do_fstab_filter_options("first,opt=0,last=1", "opt\0x-opt\0", 1, "opt", "0", "first,last=1");
-        do_fstab_filter_options("first=1,opt=0,last=2", "x-opt\0opt\0", 1, "opt", "0", "first=1,last=2");
-        do_fstab_filter_options("first,opt,last", "opt\0", 1, "opt", NULL, "first,last");
-        do_fstab_filter_options("first=1,opt,last", "x-opt\0opt\0", 1, "opt", NULL, "first=1,last");
-        do_fstab_filter_options("first=,opt,last", "opt\0noopt\0", 1, "opt", NULL, "first=,last");
+        do_fstab_filter_options("first,opt=0,last=1", "opt\0x-opt\0", 1, 1, "opt", "0", "0", "first,last=1");
+        do_fstab_filter_options("first=1,opt=0,last=2", "x-opt\0opt\0", 1, 1, "opt", "0", "0", "first=1,last=2");
+        do_fstab_filter_options("first,opt,last", "opt\0", 1, 0, "opt", NULL, "", "first,last");
+        do_fstab_filter_options("first=1,opt,last", "x-opt\0opt\0", 1, 0, "opt", NULL, "", "first=1,last");
+        do_fstab_filter_options("first=,opt,last", "opt\0noopt\0", 1, 0, "opt", NULL, "", "first=,last");
 
         /* check repeated options */
-        do_fstab_filter_options("first,opt=0,noopt=1,last=1", "opt\0noopt\0", 1, "noopt", "1", "first,last=1");
-        do_fstab_filter_options("first=1,opt=0,last=2,opt=1", "opt\0", 1, "opt", "1", "first=1,last=2");
-        do_fstab_filter_options("x-opt=0,x-opt=1", "opt\0x-opt\0", 1, "x-opt", "1", "");
-        do_fstab_filter_options("opt=0,x-opt=1", "opt\0x-opt\0", 1, "x-opt", "1", "");
+        do_fstab_filter_options("first,opt=0,noopt=1,last=1", "opt\0noopt\0", 1, 1, "noopt", "1", "0:1", "first,last=1");
+        do_fstab_filter_options("first=1,opt=0,last=2,opt=1", "opt\0", 1, 1, "opt", "1", "0:1", "first=1,last=2");
+        do_fstab_filter_options("x-opt=0,x-opt=1", "opt\0x-opt\0", 1, 1, "x-opt", "1", "0:1", "");
+        do_fstab_filter_options("opt=0,x-opt=1", "opt\0x-opt\0", 1, 1, "x-opt", "1", "0:1", "");
+        do_fstab_filter_options("opt=0,opt=1,opt=,opt=,opt=2", "opt\0noopt\0", 1, 1, "opt", "2", "0:1:::2", "");
 
         /* check that semicolons are not misinterpreted */
-        do_fstab_filter_options("opt=0;", "opt\0", 1, "opt", "0;", "");
-        do_fstab_filter_options("opt;=0", "x-opt\0opt\0noopt\0x-noopt\0", 0, NULL, NULL, NULL);
-        do_fstab_filter_options("opt;", "opt\0x-opt\0", 0, NULL, NULL, NULL);
+        do_fstab_filter_options("opt=0;", "opt\0", 1, 1, "opt", "0;", "0;", "");
+        do_fstab_filter_options("opt;=0", "x-opt\0opt\0noopt\0x-noopt\0", 0, 0, NULL, NULL, "", NULL);
+        do_fstab_filter_options("opt;", "opt\0x-opt\0", 0, 0, NULL, NULL, "", NULL);
 
         /* check that spaces are not misinterpreted */
-        do_fstab_filter_options("opt=0 ", "opt\0", 1, "opt", "0 ", "");
-        do_fstab_filter_options("opt =0", "x-opt\0opt\0noopt\0x-noopt\0", 0, NULL, NULL, NULL);
-        do_fstab_filter_options(" opt ", "opt\0x-opt\0", 0, NULL, NULL, NULL);
+        do_fstab_filter_options("opt=0 ", "opt\0", 1, 1, "opt", "0 ", "0 ", "");
+        do_fstab_filter_options("opt =0", "x-opt\0opt\0noopt\0x-noopt\0", 0, 0, NULL, NULL, "", NULL);
+        do_fstab_filter_options(" opt ", "opt\0x-opt\0", 0, 0, NULL, NULL, "", NULL);
 
-        /* check function will NULL args */
-        do_fstab_filter_options(NULL, "opt\0", 0, NULL, NULL, "");
-        do_fstab_filter_options("", "opt\0", 0, NULL, NULL, "");
+        /* check function with NULL args */
+        do_fstab_filter_options(NULL, "opt\0", 0, 0, NULL, NULL, "", "");
+        do_fstab_filter_options("", "opt\0", 0, 0, NULL, NULL, "", "");
+
+        /* unnecessary comma separators */
+        do_fstab_filter_options("opt=x,,,,", "opt\0", 1, 1, "opt", "x", "x", "");
+        do_fstab_filter_options(",,,opt=x,,,,", "opt\0", 1, 1, "opt", "x", "x", "");
+
+        /* 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=\\");
 }
 
 static void test_fstab_find_pri(void) {
diff --git a/src/test/test-strv.c b/src/test/test-strv.c
index 162d8bed951..039bb2c78af 100644
--- a/src/test/test-strv.c
+++ b/src/test/test-strv.c
@@ -333,12 +333,12 @@ static void test_strv_split(void) {
         l = strv_free_erase(l);
 
         assert_se(strv_split_full(&l, "    'one'  \"  two\t three \"' four  five", NULL,
-                                     EXTRACT_UNQUOTE | EXTRACT_RELAX | EXTRACT_CUNESCAPE_RELAX) == 2);
+                                     EXTRACT_UNQUOTE | EXTRACT_RELAX | EXTRACT_UNESCAPE_RELAX) == 2);
         assert_se(strv_equal(l, (char**) input_table_quoted_joined));
 
         l = strv_free_erase(l);
 
-        assert_se(strv_split_full(&l, "\\", NULL, EXTRACT_UNQUOTE | EXTRACT_RELAX | EXTRACT_CUNESCAPE_RELAX) == 1);
+        assert_se(strv_split_full(&l, "\\", NULL, EXTRACT_UNQUOTE | EXTRACT_RELAX | EXTRACT_UNESCAPE_RELAX) == 1);
         assert_se(strv_equal(l, STRV_MAKE("\\")));
 }