From 5d016ea3f75b642338604ac89c7556da96a8fd83 Mon Sep 17 00:00:00 2001 From: Anita Zhang Date: Mar 18 2021 00:09:12 +0000 Subject: 247.3-4: backport a parsing fix; reenable tests - Backport PR #18955 (Fixes fstab parsing) - FB only backport PR #18886 (systemd-shutdown logs to /dev/console not stderr) - Reenable tests by disabling LTO (work around binutils bug) --- diff --git a/SOURCES/18886.patch b/SOURCES/18886.patch new file mode 100644 index 0000000..2dc80ae --- /dev/null +++ b/SOURCES/18886.patch @@ -0,0 +1,56 @@ +From f975f1cc748929942188ae1490cf8480f8a64877 Mon Sep 17 00:00:00 2001 +From: Anita Zhang +Date: Thu, 4 Mar 2021 19:56:16 -0800 +Subject: [PATCH 1/2] shutdown: set always_reopen_console + +Back in v232 systemd-shutdown would log to /dev/console. However after +the addition of always_reopen_console (v233) it would log to STDERR. +This caused some debugging issues as container systemd-shutdown logs +weren't being logged to console as the arg `--log-target=console` suggested. + +Since it appears that always_reopen_console was intended for pid1, set +it in systemd-shutdown as well so logs will go to /dev/console. +--- + src/shutdown/shutdown.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/src/shutdown/shutdown.c b/src/shutdown/shutdown.c +index 0d07865542e..c1fdc885afb 100644 +--- a/src/shutdown/shutdown.c ++++ b/src/shutdown/shutdown.c +@@ -322,6 +322,9 @@ int main(int argc, char *argv[]) { + log_set_prohibit_ipc(true); + log_parse_environment(); + ++ if (getpid_cached() == 1) ++ log_set_always_reopen_console(true); ++ + r = parse_argv(argc, argv); + if (r < 0) + goto error; + +From 016f36ae72611210d6517b37429bfbdc26c5e31c Mon Sep 17 00:00:00 2001 +From: Anita Zhang +Date: Thu, 4 Mar 2021 20:00:05 -0800 +Subject: [PATCH 2/2] shutdown: log on container exit + +--- + src/shutdown/shutdown.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/src/shutdown/shutdown.c b/src/shutdown/shutdown.c +index c1fdc885afb..06b6618ff4c 100644 +--- a/src/shutdown/shutdown.c ++++ b/src/shutdown/shutdown.c +@@ -559,8 +559,10 @@ int main(int argc, char *argv[]) { + sync_with_progress(); + + if (streq(arg_verb, "exit")) { +- if (in_container) ++ if (in_container) { ++ log_info("Exiting container."); + return arg_exit_code; ++ } + + cmd = RB_POWER_OFF; /* We cannot exit() on the host, fallback on another method. */ + } diff --git a/SOURCES/18955.patch b/SOURCES/18955.patch new file mode 100644 index 0000000..b6a3953 --- /dev/null +++ b/SOURCES/18955.patch @@ -0,0 +1,1168 @@ +From 1677b88d01729f514dd17145e3aefaa5db6cdf95 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Wed, 10 Mar 2021 11:49:02 +0100 +Subject: [PATCH 1/9] fstab-generator: do not propagate error if we fail to + canonicalize + +r is used for the return value of the function, so we shouldn't +use it a non-fatal check. +--- + src/fstab-generator/fstab-generator.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/src/fstab-generator/fstab-generator.c b/src/fstab-generator/fstab-generator.c +index 0910a9aa61b..7cb4ea286dc 100644 +--- a/src/fstab-generator/fstab-generator.c ++++ b/src/fstab-generator/fstab-generator.c +@@ -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 + +From 924f65030529d5a232c2be4ab6e2642dfdc2ea71 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Wed, 10 Mar 2021 13:20:47 +0100 +Subject: [PATCH 2/9] generators: warn but ignore failure to write timeouts + +When we failed to split the options (because of disallowed quoting syntax, which +might be a bug in its own), we would silently fail. Instead, let's emit a warning. +Since we ignore the value if we cannot parse it anyway, let's ignore this error +too. +--- + src/shared/generator.c | 8 ++++++-- + 1 file changed, 6 insertions(+), 2 deletions(-) + +diff --git a/src/shared/generator.c b/src/shared/generator.c +index 8b95c772db1..41922d67d8c 100644 +--- a/src/shared/generator.c ++++ b/src/shared/generator.c +@@ -216,8 +216,12 @@ 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; ++ 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) { + +From 5fa2da125157a1beca508792ee5d9be833c2c0cb Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Wed, 10 Mar 2021 13:35:26 +0100 +Subject: [PATCH 3/9] shared/fstab-util: immediately drop empty options again +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +In the conversion from strv_split() to strv_split_full() done in +7bb553bb98a57b4e03804f8192bdc5a534325582, EXTRACT_DONT_COALESCE_SEPARATORS was +added. I think this was just by mistake… We never look for "empty options", so +whether we immediately ignore the extra separator or store the empty string in +strv, should make no difference. +--- + src/shared/fstab-util.c | 2 +- + src/test/test-fstab-util.c | 6 +++++- + 2 files changed, 6 insertions(+), 2 deletions(-) + +diff --git a/src/shared/fstab-util.c b/src/shared/fstab-util.c +index 292b97cd692..1ddcd371cfc 100644 +--- a/src/shared/fstab-util.c ++++ b/src/shared/fstab-util.c +@@ -140,7 +140,7 @@ int fstab_filter_options(const char *opts, const char *names, + break; + } + } else { +- r = strv_split_full(&stor, opts, ",", EXTRACT_DONT_COALESCE_SEPARATORS | EXTRACT_UNESCAPE_SEPARATORS); ++ r = strv_split_full(&stor, opts, ",", EXTRACT_UNESCAPE_SEPARATORS); + if (r < 0) + return r; + +diff --git a/src/test/test-fstab-util.c b/src/test/test-fstab-util.c +index 222ffbb2a75..ebbdd05ca62 100644 +--- a/src/test/test-fstab-util.c ++++ b/src/test/test-fstab-util.c +@@ -91,9 +91,13 @@ static void test_fstab_filter_options(void) { + 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); + +- /* check function will NULL args */ ++ /* check function with NULL args */ + do_fstab_filter_options(NULL, "opt\0", 0, NULL, NULL, ""); + do_fstab_filter_options("", "opt\0", 0, NULL, NULL, ""); ++ ++ /* unnecessary comma separators */ ++ do_fstab_filter_options("opt=x,,,,", "opt\0", 1, "opt", "x", ""); ++ do_fstab_filter_options(",,,opt=x,,,,", "opt\0", 1, "opt", "x", ""); + } + + static void test_fstab_find_pri(void) { + +From 8723c716c795b4083372b11dd7065bca2aadbc70 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Wed, 10 Mar 2021 14:23:23 +0100 +Subject: [PATCH 4/9] basic/extract_word: try to explain what the various + options do + +A test for stripping of escaped backslashes without any flags was explicitly +added back in 4034a06ddb82ec9868cd52496fef2f5faa25575f. So it seems to be on +purpose, though I would say that this is at least surprising and hence deserves +a comment. + +In test-extract-word, add tests for standalone EXTRACT_UNESCAPE_SEPARATORS. +Only behaviour combined with EXTRACT_CUNESCAPE was tested. +--- + src/basic/extract-word.h | 16 +++++++++------- + src/test/test-extract-word.c | 21 +++++++++++++++++++++ + 2 files changed, 30 insertions(+), 7 deletions(-) + +diff --git a/src/basic/extract-word.h b/src/basic/extract-word.h +index d1de32e5806..3c1e7d98b64 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_CUNESCAPE_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/test/test-extract-word.c b/src/test/test-extract-word.c +index 56b516fe40a..f718556d399 100644 +--- a/src/test/test-extract-word.c ++++ b/src/test/test-extract-word.c +@@ -344,6 +344,27 @@ 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 = "\\:"; + assert_se(extract_first_word(&p, &t, ":", EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS) == 1); + assert_se(streq(t, ":")); + +From 76c4e48ee603593822b3076c4cf5b63768ec55e3 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Wed, 10 Mar 2021 15:17:56 +0100 +Subject: [PATCH 5/9] basic/extract-word: allow escape character to be escaped + +With EXTRACT_UNESCAPE_SEPARATORS, backslash is used to escape the separator. +But it wasn't possible to insert the backslash itself. Let's allow this and +add test. +--- + src/basic/extract-word.c | 4 ++-- + src/test/test-extract-word.c | 24 ++++++++++++++++++++++++ + 2 files changed, 26 insertions(+), 2 deletions(-) + +diff --git a/src/basic/extract-word.c b/src/basic/extract-word.c +index 4e4e7e8ce93..06b813c031a 100644 +--- a/src/basic/extract-word.c ++++ b/src/basic/extract-word.c +@@ -102,8 +102,8 @@ 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) { + s[sz++] = '\\'; +diff --git a/src/test/test-extract-word.c b/src/test/test-extract-word.c +index f718556d399..217c600dac6 100644 +--- a/src/test/test-extract-word.c ++++ b/src/test/test-extract-word.c +@@ -365,6 +365,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_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, ":")); +@@ -386,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); + + +From 3141089f53274849ecedb84aacc6a35fd679d3c2 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Wed, 10 Mar 2021 15:39:47 +0100 +Subject: [PATCH 6/9] basic/extract-word: rename flag + +The flag enables "relaxed mode" for all kinds of unescaping, not just c-unescaping. +--- + src/basic/extract-word.c | 16 ++++++++-------- + src/basic/extract-word.h | 2 +- + src/resolve/resolved-conf.c | 2 +- + src/test/test-extract-word.c | 22 +++++++++++----------- + src/test/test-strv.c | 4 ++-- + 5 files changed, 23 insertions(+), 23 deletions(-) + +diff --git a/src/basic/extract-word.c b/src/basic/extract-word.c +index 06b813c031a..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; +@@ -105,7 +105,7 @@ int extract_first_word(const char **p, char **ret, const char *separators, Extra + (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 3c1e7d98b64..0e9e77e93d3 100644 +--- a/src/basic/extract-word.h ++++ b/src/basic/extract-word.h +@@ -6,7 +6,7 @@ + typedef enum ExtractFlags { + EXTRACT_RELAX = 1 << 0, /* Allow unbalanced quote and eat up trailing backslash. */ + EXTRACT_CUNESCAPE = 1 << 1, /* Unescape known escape sequences. */ +- EXTRACT_CUNESCAPE_RELAX = 1 << 2, /* Allow and keep unknown escape sequences, allow and keep trailing backslash. */ ++ 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 */ +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/test/test-extract-word.c b/src/test/test-extract-word.c +index 217c600dac6..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)); +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("\\"))); + } + + +From 0264b404b9f193b70a19db0f600cf6bab3a05368 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Wed, 10 Mar 2021 16:53:38 +0100 +Subject: [PATCH 7/9] shared/fstab-util: pass through the escape character +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +… when not used to escape the separator (,) or the escape character (\). +This mostly restores behaviour from before 0645b83a40d1c782f173c4d8440ab2fc82a75006, +but still allows "," to be escaped. + +Partially fixes #18952. +--- + src/shared/fstab-util.c | 20 ++++++++++++-------- + src/test/test-fstab-util.c | 4 ++++ + 2 files changed, 16 insertions(+), 8 deletions(-) + +diff --git a/src/shared/fstab-util.c b/src/shared/fstab-util.c +index 1ddcd371cfc..8dc1733c0de 100644 +--- a/src/shared/fstab-util.c ++++ b/src/shared/fstab-util.c +@@ -97,16 +97,18 @@ int fstab_filter_options(const char *opts, const char *names, + 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) { +@@ -140,7 +142,9 @@ int fstab_filter_options(const char *opts, const char *names, + break; + } + } else { +- r = strv_split_full(&stor, opts, ",", EXTRACT_UNESCAPE_SEPARATORS); ++ /* 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; + +diff --git a/src/test/test-fstab-util.c b/src/test/test-fstab-util.c +index ebbdd05ca62..3a7ec170d65 100644 +--- a/src/test/test-fstab-util.c ++++ b/src/test/test-fstab-util.c +@@ -98,6 +98,10 @@ static void test_fstab_filter_options(void) { + /* unnecessary comma separators */ + do_fstab_filter_options("opt=x,,,,", "opt\0", 1, "opt", "x", ""); + do_fstab_filter_options(",,,opt=x,,,,", "opt\0", 1, "opt", "x", ""); ++ ++ /* escaped characters */ ++ do_fstab_filter_options("opt1=\\\\,opt2=\\xff", "opt1\0", 1, "opt1", "\\", "opt2=\\xff"); ++ do_fstab_filter_options("opt1=\\\\,opt2=\\xff", "opt2\0", 1, "opt2", "\\xff", "opt1=\\"); + } + + static void test_fstab_find_pri(void) { + +From ff0c31bc2722eed528eae6644a104e85ed97f2f1 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Thu, 11 Mar 2021 10:37:36 +0100 +Subject: [PATCH 8/9] 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. +--- + src/core/mount.c | 2 +- + src/cryptsetup/cryptsetup-generator.c | 9 +- + src/fstab-generator/fstab-generator.c | 2 +- + src/shared/fstab-util.c | 124 +++++++++++++---------- + src/shared/fstab-util.h | 12 ++- + src/shared/generator.c | 2 +- + src/test/test-fstab-util.c | 139 +++++++++++++++----------- + 7 files changed, 169 insertions(+), 121 deletions(-) + +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 7cb4ea286dc..b454a5980d4 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) +diff --git a/src/shared/fstab-util.c b/src/shared/fstab-util.c +index 8dc1733c0de..6674ed4a19f 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 @@ int fstab_filter_options(const char *opts, const char *names, + 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) +diff --git a/src/shared/fstab-util.h b/src/shared/fstab-util.h +index 1a602cb56b2..97f40221afb 100644 +--- a/src/shared/fstab-util.h ++++ b/src/shared/fstab-util.h +@@ -10,12 +10,18 @@ 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_filter_options( ++ const char *opts, ++ const char *names, ++ const char **ret_namefound, ++ char **ret_value, ++ char ***ret_values, ++ char **ret_filtered); + + int fstab_extract_values(const char *opts, const char *name, char ***values); + + 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 +32,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 41922d67d8c..5b9c4325271 100644 +--- a/src/shared/generator.c ++++ b/src/shared/generator.c +@@ -215,7 +215,7 @@ int generator_write_timeouts( + + r = fstab_filter_options(opts, "comment=systemd.device-timeout\0" + "x-systemd.device-timeout\0", +- NULL, &timeout, filtered); ++ NULL, &timeout, NULL, filtered); + if (r < 0) { + log_warning_errno(r, "Failed to parse fstab options, ignoring: %m"); + return 0; +diff --git a/src/test/test-fstab-util.c b/src/test/test-fstab-util.c +index 3a7ec170d65..d2f20185265 100644 +--- a/src/test/test-fstab-util.c ++++ b/src/test/test-fstab-util.c +@@ -6,102 +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,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\\,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("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("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,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("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, 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, 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, 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, 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, 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 with NULL args */ +- do_fstab_filter_options(NULL, "opt\0", 0, NULL, NULL, ""); +- do_fstab_filter_options("", "opt\0", 0, NULL, NULL, ""); ++ 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, "opt", "x", ""); +- do_fstab_filter_options(",,,opt=x,,,,", "opt\0", 1, "opt", "x", ""); ++ 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, "opt1", "\\", "opt2=\\xff"); +- do_fstab_filter_options("opt1=\\\\,opt2=\\xff", "opt2\0", 1, "opt2", "\\xff", "opt1=\\"); ++ 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) { + +From d6cef552dcb4764a89269ce9603eb21f348d911a Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Thu, 11 Mar 2021 11:10:32 +0100 +Subject: [PATCH 9/9] fstab-generator: get rid of fstab_extract_values() + +This was a parallel implementation of option parsing that didn't +support escaping of separators. Let's port this over to the common code. + +Fixes #18952. +--- + src/fstab-generator/fstab-generator.c | 14 ++++++------- + src/shared/fstab-util.c | 29 --------------------------- + src/shared/fstab-util.h | 2 -- + 3 files changed, 7 insertions(+), 38 deletions(-) + +diff --git a/src/fstab-generator/fstab-generator.c b/src/fstab-generator/fstab-generator.c +index b454a5980d4..8c1087a9a33 100644 +--- a/src/fstab-generator/fstab-generator.c ++++ b/src/fstab-generator/fstab-generator.c +@@ -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; + +diff --git a/src/shared/fstab-util.c b/src/shared/fstab-util.c +index 6674ed4a19f..7fd3d9c2c34 100644 +--- a/src/shared/fstab-util.c ++++ b/src/shared/fstab-util.c +@@ -210,35 +210,6 @@ int fstab_filter_options( + 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; +diff --git a/src/shared/fstab-util.h b/src/shared/fstab-util.h +index 97f40221afb..6b596baafa1 100644 +--- a/src/shared/fstab-util.h ++++ b/src/shared/fstab-util.h +@@ -18,8 +18,6 @@ int fstab_filter_options( + char ***ret_values, + char **ret_filtered); + +-int fstab_extract_values(const char *opts, const char *name, char ***values); +- + static inline bool fstab_test_option(const char *opts, const char *names) { + return !!fstab_filter_options(opts, names, NULL, NULL, NULL, NULL); + } diff --git a/SOURCES/disable-broken-tests-for-binutils-bug.patch b/SOURCES/disable-broken-tests-for-binutils-bug.patch deleted file mode 100644 index fc77cb1..0000000 --- a/SOURCES/disable-broken-tests-for-binutils-bug.patch +++ /dev/null @@ -1,63 +0,0 @@ -diff -Naur a/src/test/meson.build b/src/test/meson.build ---- a/src/test/meson.build 2021-02-02 07:29:47.000000000 -0800 -+++ b/src/test/meson.build 2021-02-19 10:58:19.188785027 -0800 -@@ -61,11 +61,6 @@ - libmount, - libblkid]], - -- [['src/test/test-emergency-action.c'], -- [libcore, -- libshared], -- []], -- - [['src/test/test-chown-rec.c'], - [libcore, - libshared], -@@ -522,24 +517,6 @@ - [], - []], - -- [['src/test/test-tables.c', -- 'src/shared/test-tables.h', -- 'src/journal/journald-server.c', -- 'src/journal/journald-server.h'], -- [libcore, -- libjournal_core, -- libudev_core, -- libudev_static, -- libsystemd_network, -- libshared], -- [threads, -- libseccomp, -- libmount, -- libxz, -- liblz4, -- libblkid], -- '', '', [], libudev_core_includes], -- - [['src/test/test-prioq.c'], - [], - []], -@@ -621,11 +598,6 @@ - [], - []], - -- [['src/test/test-cgroup-cpu.c'], -- [libcore, -- libshared], -- []], -- - [['src/test/test-cgroup-unit-default.c'], - [libcore, - libshared], -@@ -1168,10 +1140,6 @@ - [], - []], - -- [['src/analyze/test-verify.c', 'src/analyze/analyze-verify.c', 'src/analyze/analyze-verify.h'], -- [libcore, libshared], -- []], -- - [['src/login/test-inhibit.c'], - [], - [], diff --git a/SOURCES/fa67d9c0d652dc41574b546f542909e9c8157237.patch b/SOURCES/fa67d9c0d652dc41574b546f542909e9c8157237.patch new file mode 100644 index 0000000..51d09b1 --- /dev/null +++ b/SOURCES/fa67d9c0d652dc41574b546f542909e9c8157237.patch @@ -0,0 +1,49 @@ +From fa67d9c0d652dc41574b546f542909e9c8157237 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Tue, 12 Jan 2021 21:36:54 +0100 +Subject: [PATCH] extract-word: don't rely on C's downgrade-to-bool feature for + chars + +The `quote` char variable ectually contains a character, not a pointer +or boolean. hence do an explicit comparison rather than rely on C's +downgrade to bool feature, as per our coding style. +--- + src/basic/extract-word.c | 9 ++++----- + 1 file changed, 4 insertions(+), 5 deletions(-) + +diff --git a/src/basic/extract-word.c b/src/basic/extract-word.c +index 76b3fe12e3b..4104dac9a74 100644 +--- a/src/basic/extract-word.c ++++ b/src/basic/extract-word.c +@@ -20,11 +20,10 @@ + int extract_first_word(const char **p, char **ret, const char *separators, ExtractFlags flags) { + _cleanup_free_ char *s = NULL; + size_t allocated = 0, sz = 0; +- char c; +- int r; +- + char quote = 0; /* 0 or ' or " */ + bool backslash = false; /* whether we've just seen a backslash */ ++ char c; ++ int r; + + assert(p); + assert(ret); +@@ -71,7 +70,7 @@ int extract_first_word(const char **p, char **ret, const char *separators, Extra + + if (c == 0) { + if ((flags & EXTRACT_CUNESCAPE_RELAX) && +- (!quote || flags & EXTRACT_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 + * output. +@@ -116,7 +115,7 @@ int extract_first_word(const char **p, char **ret, const char *separators, Extra + + backslash = false; + +- } else if (quote) { /* inside either single or double quotes */ ++ } else if (quote != 0) { /* inside either single or double quotes */ + for (;; (*p)++, c = **p) { + if (c == 0) { + if (flags & EXTRACT_RELAX) diff --git a/SPECS/systemd.spec b/SPECS/systemd.spec index 8e5d699..859e47d 100644 --- a/SPECS/systemd.spec +++ b/SPECS/systemd.spec @@ -16,12 +16,12 @@ # cryptsetup, e.g. when re-building cryptsetup on a json-c SONAME-bump. %bcond_with bootstrap %bcond_without tests -%bcond_without lto +%bcond_with lto Name: systemd Url: https://www.freedesktop.org/wiki/Software/systemd Version: 247.3 -Release: 3%{?dist} +Release: 4%{?dist} # For a breakdown of the licensing, see README License: LGPLv2+ and MIT and GPLv2+ Summary: System and Service Manager @@ -71,13 +71,17 @@ Patch0001: https://github.com/systemd/systemd/pull/17872.patch %if 0%{?facebook} # 17495: Fixes BPF pinning post-coldplug Patch0002: https://github.com/systemd/systemd/pull/17495.patch +# 18886: systemd-shutdown logs to /dev/console not stderr +Patch0003: https://github.com/systemd/systemd/pull/18886.patch %endif +# Commit to make #18955 apply cleanly +Patch0004: https://github.com/systemd/systemd/commit/fa67d9c0d652dc41574b546f542909e9c8157237.patch +#18955: Fixes fstab parsing +Patch0005: https://github.com/systemd/systemd/pull/18955.patch # Downstream-only patches (0500–9999) # https://github.com/systemd/systemd/pull/17050 Patch0501: https://github.com/systemd/systemd/pull/17050/commits/f58b96d3e8d1cb0dd3666bc74fa673918b586612.patch -# workaround for https://pagure.io/centos-sig-hyperscale/sig/issue/13 -Patch0502: disable-broken-tests-for-binutils-bug.patch %ifarch %{ix86} x86_64 aarch64 %global have_gnu_efi 1 @@ -870,6 +874,11 @@ fi %files tests -f .file-list-tests %changelog +* Wed Mar 17 2021 Anita Zhang - 247.3-4 +- Backport PR #18955 (Fixes fstab parsing) +- FB only backport PR #18886 (systemd-shutdown logs to /dev/console not stderr) +- Reenable tests by disabling LTO (work around binutils bug) + * Wed Feb 24 2021 Davide Cavalca - 247.3-3 - Remove careinversion usage to make the package usable on older mock versions