diff --git a/0075-core-shorten-long-unit-names-that-are-based-on-paths.patch b/0075-core-shorten-long-unit-names-that-are-based-on-paths.patch new file mode 100644 index 0000000..305ebd1 --- /dev/null +++ b/0075-core-shorten-long-unit-names-that-are-based-on-paths.patch @@ -0,0 +1,275 @@ +From 4bc17b038971160f94321c7be9cd924b256d9ef8 Mon Sep 17 00:00:00 2001 +From: Michal Sekletar +Date: Tue, 15 Mar 2022 19:02:05 +0100 +Subject: [PATCH] core: shorten long unit names that are based on paths and + append path hash at the end + +Fixes #18077 + +(cherry picked from commit 1d0727e76fd5e9a07cc9991ec9a10ea1d78a99c7) + +Resolves: #2083493 +--- + src/basic/string-util.h | 23 ++++++----- + src/basic/unit-name.c | 86 ++++++++++++++++++++++++++++++++++++++- + src/basic/unit-name.h | 3 ++ + src/core/mount.c | 3 ++ + src/test/test-unit-name.c | 26 ++++++++++-- + 5 files changed, 125 insertions(+), 16 deletions(-) + +diff --git a/src/basic/string-util.h b/src/basic/string-util.h +index a1d88fbb95..ffb69e69cc 100644 +--- a/src/basic/string-util.h ++++ b/src/basic/string-util.h +@@ -10,17 +10,18 @@ + #include "string-util-fundamental.h" + + /* What is interpreted as whitespace? */ +-#define WHITESPACE " \t\n\r" +-#define NEWLINE "\n\r" +-#define QUOTES "\"\'" +-#define COMMENTS "#;" +-#define GLOB_CHARS "*?[" +-#define DIGITS "0123456789" +-#define LOWERCASE_LETTERS "abcdefghijklmnopqrstuvwxyz" +-#define UPPERCASE_LETTERS "ABCDEFGHIJKLMNOPQRSTUVWXYZ" +-#define LETTERS LOWERCASE_LETTERS UPPERCASE_LETTERS +-#define ALPHANUMERICAL LETTERS DIGITS +-#define HEXDIGITS DIGITS "abcdefABCDEF" ++#define WHITESPACE " \t\n\r" ++#define NEWLINE "\n\r" ++#define QUOTES "\"\'" ++#define COMMENTS "#;" ++#define GLOB_CHARS "*?[" ++#define DIGITS "0123456789" ++#define LOWERCASE_LETTERS "abcdefghijklmnopqrstuvwxyz" ++#define UPPERCASE_LETTERS "ABCDEFGHIJKLMNOPQRSTUVWXYZ" ++#define LETTERS LOWERCASE_LETTERS UPPERCASE_LETTERS ++#define ALPHANUMERICAL LETTERS DIGITS ++#define HEXDIGITS DIGITS "abcdefABCDEF" ++#define LOWERCASE_HEXDIGITS DIGITS "abcdef" + + static inline char* strstr_ptr(const char *haystack, const char *needle) { + if (!haystack || !needle) +diff --git a/src/basic/unit-name.c b/src/basic/unit-name.c +index 671e30a53f..6cba8ba140 100644 +--- a/src/basic/unit-name.c ++++ b/src/basic/unit-name.c +@@ -5,12 +5,17 @@ + #include + #include + ++#include "sd-id128.h" ++ + #include "alloc-util.h" + #include "glob-util.h" + #include "hexdecoct.h" + #include "memory-util.h" + #include "path-util.h" ++#include "random-util.h" ++#include "sparse-endian.h" + #include "special.h" ++#include "stdio-util.h" + #include "string-util.h" + #include "strv.h" + #include "unit-name.h" +@@ -31,6 +36,9 @@ + VALID_CHARS_WITH_AT \ + "[]!-*?" + ++#define LONG_UNIT_NAME_HASH_KEY SD_ID128_MAKE(ec,f2,37,fb,58,32,4a,32,84,9f,06,9b,0d,21,eb,9a) ++#define UNIT_NAME_HASH_LENGTH_CHARS 16 ++ + bool unit_name_is_valid(const char *n, UnitNameFlags flags) { + const char *e, *i, *at; + +@@ -507,6 +515,68 @@ int unit_name_template(const char *f, char **ret) { + return 0; + } + ++bool unit_name_is_hashed(const char *name) { ++ char *s; ++ ++ if (!unit_name_is_valid(name, UNIT_NAME_PLAIN)) ++ return false; ++ ++ assert_se(s = strrchr(name, '.')); ++ ++ if (s - name < UNIT_NAME_HASH_LENGTH_CHARS + 1) ++ return false; ++ ++ s -= UNIT_NAME_HASH_LENGTH_CHARS; ++ if (s[-1] != '_') ++ return false; ++ ++ for (size_t i = 0; i < UNIT_NAME_HASH_LENGTH_CHARS; i++) ++ if (!strchr(LOWERCASE_HEXDIGITS, s[i])) ++ return false; ++ ++ return true; ++} ++ ++int unit_name_hash_long(const char *name, char **ret) { ++ _cleanup_free_ char *n = NULL, *hash = NULL; ++ char *suffix; ++ le64_t h; ++ size_t len; ++ ++ if (strlen(name) < UNIT_NAME_MAX) ++ return -EMSGSIZE; ++ ++ suffix = strrchr(name, '.'); ++ if (!suffix) ++ return -EINVAL; ++ ++ if (unit_type_from_string(suffix+1) < 0) ++ return -EINVAL; ++ ++ h = htole64(siphash24_string(name, LONG_UNIT_NAME_HASH_KEY.bytes)); ++ ++ hash = hexmem(&h, sizeof(h)); ++ if (!hash) ++ return -ENOMEM; ++ ++ assert_se(strlen(hash) == UNIT_NAME_HASH_LENGTH_CHARS); ++ ++ len = UNIT_NAME_MAX - 1 - strlen(suffix+1) - UNIT_NAME_HASH_LENGTH_CHARS - 2; ++ assert(len > 0 && len < UNIT_NAME_MAX); ++ ++ n = strndup(name, len); ++ if (!n) ++ return -ENOMEM; ++ ++ if (!strextend(&n, "_", hash, suffix)) ++ return -ENOMEM; ++ assert_se(unit_name_is_valid(n, UNIT_NAME_PLAIN)); ++ ++ *ret = TAKE_PTR(n); ++ ++ return 0; ++} ++ + int unit_name_from_path(const char *path, const char *suffix, char **ret) { + _cleanup_free_ char *p = NULL, *s = NULL; + int r; +@@ -526,8 +596,17 @@ int unit_name_from_path(const char *path, const char *suffix, char **ret) { + if (!s) + return -ENOMEM; + +- if (strlen(s) >= UNIT_NAME_MAX) /* Return a slightly more descriptive error for this specific condition */ +- return -ENAMETOOLONG; ++ if (strlen(s) >= UNIT_NAME_MAX) { ++ _cleanup_free_ char *n = NULL; ++ ++ log_debug("Unit name \"%s\" too long, falling back to hashed unit name.", s); ++ ++ r = unit_name_hash_long(s, &n); ++ if (r < 0) ++ return r; ++ ++ free_and_replace(s, n); ++ } + + /* Refuse if this for some other reason didn't result in a valid name */ + if (!unit_name_is_valid(s, UNIT_NAME_PLAIN)) +@@ -581,6 +660,9 @@ int unit_name_to_path(const char *name, char **ret) { + if (r < 0) + return r; + ++ if (unit_name_is_hashed(name)) ++ return -ENAMETOOLONG; ++ + return unit_name_path_unescape(prefix, ret); + } + +diff --git a/src/basic/unit-name.h b/src/basic/unit-name.h +index b62b3e034e..eaa701e9f6 100644 +--- a/src/basic/unit-name.h ++++ b/src/basic/unit-name.h +@@ -44,6 +44,9 @@ int unit_name_replace_instance(const char *f, const char *i, char **ret); + + int unit_name_template(const char *f, char **ret); + ++int unit_name_hash_long(const char *name, char **ret); ++bool unit_name_is_hashed(const char *name); ++ + int unit_name_from_path(const char *path, const char *suffix, char **ret); + int unit_name_from_path_instance(const char *prefix, const char *path, const char *suffix, char **ret); + int unit_name_to_path(const char *name, char **ret); +diff --git a/src/core/mount.c b/src/core/mount.c +index 4d407ca4e5..d63884e47e 100644 +--- a/src/core/mount.c ++++ b/src/core/mount.c +@@ -622,6 +622,9 @@ static int mount_add_extras(Mount *m) { + + if (!m->where) { + r = unit_name_to_path(u->id, &m->where); ++ if (r == -ENAMETOOLONG) ++ log_unit_error_errno(u, r, "Failed to derive mount point path from unit name, because unit name is hashed. " ++ "Set \"Where=\" in the unit file explicitly."); + if (r < 0) + return r; + } +diff --git a/src/test/test-unit-name.c b/src/test/test-unit-name.c +index 8cd0e0b4a1..b6137333aa 100644 +--- a/src/test/test-unit-name.c ++++ b/src/test/test-unit-name.c +@@ -106,6 +106,7 @@ TEST(unit_name_replace_instance) { + + static void test_unit_name_from_path_one(const char *path, const char *suffix, const char *expected, int ret) { + _cleanup_free_ char *t = NULL; ++ int r; + + assert_se(unit_name_from_path(path, suffix, &t) == ret); + puts(strna(t)); +@@ -113,12 +114,31 @@ static void test_unit_name_from_path_one(const char *path, const char *suffix, c + + if (t) { + _cleanup_free_ char *k = NULL; +- assert_se(unit_name_to_path(t, &k) == 0); ++ ++ /* We don't support converting hashed unit names back to paths */ ++ r = unit_name_to_path(t, &k); ++ if (r == -ENAMETOOLONG) ++ return; ++ assert(r == 0); ++ + puts(strna(k)); + assert_se(path_equal(k, empty_to_root(path))); + } + } + ++TEST(unit_name_is_hashed) { ++ assert_se(!unit_name_is_hashed("")); ++ assert_se(!unit_name_is_hashed("foo@bar.service")); ++ assert_se(!unit_name_is_hashed("foo@.service")); ++ assert_se(unit_name_is_hashed("waldoaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa_7736d9ed33c2ec55.mount")); ++ assert_se(!unit_name_is_hashed("waldoaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa_7736D9ED33C2EC55.mount")); ++ assert_se(!unit_name_is_hashed("waldoaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa!7736d9ed33c2ec55.mount")); ++ assert_se(!unit_name_is_hashed("waldoaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa_7736d9gd33c2ec55.mount")); ++ assert_se(!unit_name_is_hashed("waldoaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa_.mount")); ++ assert_se(!unit_name_is_hashed("waldoaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa_2103e1466b87f7f7@waldo.mount")); ++ assert_se(!unit_name_is_hashed("waldoaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa_2103e1466b87f7f7@.mount")); ++} ++ + TEST(unit_name_from_path) { + test_unit_name_from_path_one("/waldo", ".mount", "waldo.mount", 0); + test_unit_name_from_path_one("/waldo/quuix", ".mount", "waldo-quuix.mount", 0); +@@ -128,7 +148,8 @@ TEST(unit_name_from_path) { + test_unit_name_from_path_one("///", ".mount", "-.mount", 0); + test_unit_name_from_path_one("/foo/../bar", ".mount", NULL, -EINVAL); + test_unit_name_from_path_one("/foo/./bar", ".mount", "foo-bar.mount", 0); +- test_unit_name_from_path_one("/waldoaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", ".mount", NULL, -ENAMETOOLONG); ++ test_unit_name_from_path_one("/waldoaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", ".mount", ++ "waldoaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa_7736d9ed33c2ec55.mount", 0); + } + + static void test_unit_name_from_path_instance_one(const char *pattern, const char *path, const char *suffix, const char *expected, int ret) { +@@ -156,7 +177,6 @@ TEST(unit_name_from_path_instance) { + test_unit_name_from_path_instance_one("waldo", "..", ".mount", NULL, -EINVAL); + test_unit_name_from_path_instance_one("waldo", "/foo", ".waldi", NULL, -EINVAL); + test_unit_name_from_path_instance_one("wa--ldo", "/--", ".mount", "wa--ldo@\\x2d\\x2d.mount", 0); +- test_unit_name_from_path_instance_one("waldoaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "/waldo", ".mount", NULL, -ENAMETOOLONG); + } + + static void test_unit_name_to_path_one(const char *unit, const char *path, int ret) { diff --git a/0076-tests-add-test-case-for-long-unit-names.patch b/0076-tests-add-test-case-for-long-unit-names.patch new file mode 100644 index 0000000..5a267c0 --- /dev/null +++ b/0076-tests-add-test-case-for-long-unit-names.patch @@ -0,0 +1,42 @@ +From 1121def1f02c847df894611e171a1025f859fb3d Mon Sep 17 00:00:00 2001 +From: Michal Sekletar +Date: Wed, 23 Mar 2022 13:35:44 +0100 +Subject: [PATCH] tests: add test case for long unit names + +(cherry picked from commit 2ef0101e0b2813e8c99fc8f137dbaa763ca16057) + +Related: #2083493 +--- + test/units/testsuite-60.sh | 19 +++++++++++++++++++ + 1 file changed, 19 insertions(+) + +diff --git a/test/units/testsuite-60.sh b/test/units/testsuite-60.sh +index eb174f00ed..239d7b0d4c 100755 +--- a/test/units/testsuite-60.sh ++++ b/test/units/testsuite-60.sh +@@ -8,6 +8,25 @@ systemd-analyze log-target journal + + NUM_DIRS=20 + ++# make sure we can handle mounts at very long paths such that mount unit name must be hashed to fall within our unit name limit ++LONGPATH="$(printf "/$(printf "x%0.s" {1..255})%0.s" {1..7})" ++LONGMNT="$(systemd-escape --suffix=mount --path "$LONGPATH")" ++TS="$(date '+%H:%M:%S')" ++ ++mkdir -p "$LONGPATH" ++mount -t tmpfs tmpfs "$LONGPATH" ++systemctl daemon-reload ++ ++# check that unit is active(mounted) ++systemctl --no-pager show -p SubState --value "$LONGPATH" | grep -q mounted ++ ++# check that relevant part of journal doesn't contain any errors related to unit ++[ "$(journalctl -b --since="$TS" --priority=err | grep -c "$LONGMNT")" = "0" ] ++ ++# check that we can successfully stop the mount unit ++systemctl stop "$LONGPATH" ++rm -rf "$LONGPATH" ++ + # mount/unmount enough times to trigger the /proc/self/mountinfo parsing rate limiting + + for ((i = 0; i < NUM_DIRS; i++)); do diff --git a/0077-tests-reflect-that-we-can-now-handle-devices-with-ve.patch b/0077-tests-reflect-that-we-can-now-handle-devices-with-ve.patch new file mode 100644 index 0000000..8f2e825 --- /dev/null +++ b/0077-tests-reflect-that-we-can-now-handle-devices-with-ve.patch @@ -0,0 +1,37 @@ +From 87e45d9c58c74ae7ba46f99a3f0e2db39cf345ff Mon Sep 17 00:00:00 2001 +From: Michal Sekletar +Date: Thu, 24 Mar 2022 19:24:16 +0100 +Subject: [PATCH] tests: reflect that we can now handle devices with very long + sysfs paths + +(cherry picked from commit b26f4f0028e27b6ad46ef9af56aac7571caa3a25) + +Related: #2083493 +--- + test/units/testsuite-64.sh | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/test/units/testsuite-64.sh b/test/units/testsuite-64.sh +index dc8b263b10..218b2ee8d1 100755 +--- a/test/units/testsuite-64.sh ++++ b/test/units/testsuite-64.sh +@@ -674,6 +674,7 @@ testcase_long_sysfs_path() { + echo "UUID=deadbeef-dead-dead-beef-222222222222 $mpoint ext4 defaults 0 0" >>/etc/fstab + systemctl daemon-reload + mount "$mpoint" ++ systemctl status "$mpoint" + test -e "$mpoint/test" + umount "$mpoint" + +@@ -684,9 +685,9 @@ testcase_long_sysfs_path() { + udevadm settle + + logfile="$(mktemp)" +- journalctl -b -q --no-pager -o short-monotonic -p info --grep "Device path.*vda.?' too long to fit into unit name" ++ [[ "$(journalctl -b -q --no-pager -o short-monotonic -p info --grep "Device path.*vda.?' too long to fit into unit name" | wc -l)" -eq 0 ]] + # Make sure we don't unnecessarily spam the log +- journalctl -b -q --no-pager -o short-monotonic -p info --grep "/sys/devices/.+/vda[0-9]?" _PID=1 + UNIT=systemd-udevd.service | tee "$logfile" ++ { journalctl -b -q --no-pager -o short-monotonic -p info --grep "/sys/devices/.+/vda[0-9]?" _PID=1 + UNIT=systemd-udevd.service || :;} | tee "$logfile" + [[ "$(wc -l <"$logfile")" -lt 10 ]] + + : >/etc/fstab diff --git a/0078-test-extend-the-hashed-unit-names-coverage-a-bit.patch b/0078-test-extend-the-hashed-unit-names-coverage-a-bit.patch new file mode 100644 index 0000000..e824455 --- /dev/null +++ b/0078-test-extend-the-hashed-unit-names-coverage-a-bit.patch @@ -0,0 +1,63 @@ +From c9fe9526f07ad24d29842fa853ee458b68660896 Mon Sep 17 00:00:00 2001 +From: Frantisek Sumsal +Date: Fri, 22 Apr 2022 18:03:14 +0200 +Subject: [PATCH] test: extend the "hashed" unit names coverage a bit + +Follow-up to #22759. + +(cherry picked from commit 98f8c316389177169c6599e67010ebb1789a6b26) + +Related: #2083493 +--- + test/units/testsuite-64.sh | 19 ++++++++++++++++--- + 1 file changed, 16 insertions(+), 3 deletions(-) + +diff --git a/test/units/testsuite-64.sh b/test/units/testsuite-64.sh +index 218b2ee8d1..5f9aeee261 100755 +--- a/test/units/testsuite-64.sh ++++ b/test/units/testsuite-64.sh +@@ -646,7 +646,7 @@ testcase_iscsi_lvm() { + } + + testcase_long_sysfs_path() { +- local link logfile mpoint ++ local cursor link logfile mpoint + local expected_symlinks=( + "/dev/disk/by-label/data_vol" + "/dev/disk/by-label/swap_vol" +@@ -657,6 +657,12 @@ testcase_long_sysfs_path() { + "/dev/disk/by-uuid/deadbeef-dead-dead-beef-222222222222" + ) + ++ # Create a cursor file to skip messages generated by udevd in initrd, as it ++ # might not be the same up-to-date version as we currently run (hence generating ++ # messages we check for later and making the test fail) ++ cursor="$(mktemp)" ++ journalctl --cursor-file="${cursor:?}" -n0 -q ++ + # Make sure the test device is connected and show its "wonderful" path + stat /sys/block/vda + readlink -f /sys/block/vda/dev +@@ -685,13 +691,20 @@ testcase_long_sysfs_path() { + udevadm settle + + logfile="$(mktemp)" +- [[ "$(journalctl -b -q --no-pager -o short-monotonic -p info --grep "Device path.*vda.?' too long to fit into unit name" | wc -l)" -eq 0 ]] ++ # Check state of affairs after https://github.com/systemd/systemd/pull/22759 ++ # Note: can't use `--cursor-file` here, since we don't want to update the cursor ++ # after using it ++ [[ "$(journalctl --after-cursor="$(<"$cursor")" -q --no-pager -o short-monotonic -p info --grep "Device path.*vda.?' too long to fit into unit name" | wc -l)" -eq 0 ]] ++ [[ "$(journalctl --after-cursor="$(<"$cursor")" -q --no-pager -o short-monotonic --grep "Unit name .*vda.?\.device\" too long, falling back to hashed unit name" | wc -l)" -gt 0 ]] ++ # Check if the respective "hashed" units exist and are active (plugged) ++ systemctl status --no-pager "$(readlink -f /sys/block/vda/vda1)" ++ systemctl status --no-pager "$(readlink -f /sys/block/vda/vda2)" + # Make sure we don't unnecessarily spam the log + { journalctl -b -q --no-pager -o short-monotonic -p info --grep "/sys/devices/.+/vda[0-9]?" _PID=1 + UNIT=systemd-udevd.service || :;} | tee "$logfile" + [[ "$(wc -l <"$logfile")" -lt 10 ]] + + : >/etc/fstab +- rm -fr "${logfile:?}" "${mpoint:?}" ++ rm -fr "${cursor:?}" "${logfile:?}" "${mpoint:?}" + } + + : >/failed diff --git a/0079-Revert-kernel-install-also-remove-modules.builtin.al.patch b/0079-Revert-kernel-install-also-remove-modules.builtin.al.patch new file mode 100644 index 0000000..a00c8c4 --- /dev/null +++ b/0079-Revert-kernel-install-also-remove-modules.builtin.al.patch @@ -0,0 +1,29 @@ +From 17f516c0714e05d3dea7f168304286658aead870 Mon Sep 17 00:00:00 2001 +From: Michal Sekletar +Date: Thu, 17 Mar 2022 12:35:35 +0100 +Subject: [PATCH] Revert "kernel-install: also remove + modules.builtin.alias.bin" + +This reverts commit fdcb1bf67371615f12c4b11283f2bd6a25bda019. + +Related: #2065061 + +[msekleta: this revert is done in order to make backporting easier, +patch will be reapplied later.] +--- + src/kernel-install/50-depmod.install | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/kernel-install/50-depmod.install b/src/kernel-install/50-depmod.install +index fd00c43632..2fd959865f 100644 +--- a/src/kernel-install/50-depmod.install ++++ b/src/kernel-install/50-depmod.install +@@ -36,7 +36,7 @@ case "$COMMAND" in + remove) + [ "$KERNEL_INSTALL_VERBOSE" -gt 0 ] && \ + echo "Removing /lib/modules/${KERNEL_VERSION}/modules.dep and associated files" +- exec rm -f /lib/modules/"${KERNEL_VERSION}"/modules.{alias{,.bin},builtin{,.alias}.bin,dep{,.bin},devname,softdep,symbols{,.bin}} ++ exec rm -f /lib/modules/"${KERNEL_VERSION}"/modules.{alias{,.bin},builtin.bin,dep{,.bin},devname,softdep,symbols{,.bin}} + ;; + *) + exit 0 diff --git a/0080-Revert-kernel-install-prefer-boot-over-boot-efi-for-.patch b/0080-Revert-kernel-install-prefer-boot-over-boot-efi-for-.patch new file mode 100644 index 0000000..95429ea --- /dev/null +++ b/0080-Revert-kernel-install-prefer-boot-over-boot-efi-for-.patch @@ -0,0 +1,29 @@ +From 3fae5c22831288c075e371e67ecc91968ab60d63 Mon Sep 17 00:00:00 2001 +From: Michal Sekletar +Date: Thu, 17 Mar 2022 12:37:57 +0100 +Subject: [PATCH] Revert "kernel-install: prefer /boot over /boot/efi for + $BOOT_ROOT" + +This reverts commit d0e98b7a1211412dccfcf4dcd2cc0772ac70b304. + +Related: #2065061 + +[msekleta: this revert is done in order to make backporting easier, +patch will be reapplied later.] +--- + src/kernel-install/kernel-install | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/kernel-install/kernel-install b/src/kernel-install/kernel-install +index d85852532b..b358b03b2f 100755 +--- a/src/kernel-install/kernel-install ++++ b/src/kernel-install/kernel-install +@@ -108,7 +108,7 @@ fi + [ -z "$MACHINE_ID" ] && MACHINE_ID="Default" + + [ -z "$BOOT_ROOT" ] && for suff in "$MACHINE_ID" "loader/entries"; do +- for pref in "/efi" "/boot" "/boot/efi" ; do ++ for pref in "/efi" "/boot/efi" "/boot"; do + if [ -d "$pref/$suff" ]; then + BOOT_ROOT="$pref" + break 2 diff --git a/0081-kernel-install-50-depmod-port-to-bin-sh.patch b/0081-kernel-install-50-depmod-port-to-bin-sh.patch new file mode 100644 index 0000000..952e1f0 --- /dev/null +++ b/0081-kernel-install-50-depmod-port-to-bin-sh.patch @@ -0,0 +1,60 @@ +From d90268728f268f4e5291d29bc2b899137cd7ddf5 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?=D0=BD=D0=B0=D0=B1?= +Date: Thu, 16 Dec 2021 14:35:17 +0100 +Subject: [PATCH] kernel-install: 50-depmod: port to /bin/sh + +(cherry picked from commit b3ceb3d9fff69b33b8665a0137f5177f72c45cc0) + +Related: #2065061 +--- + src/kernel-install/50-depmod.install | 28 +++++++++++++++------------- + 1 file changed, 15 insertions(+), 13 deletions(-) + +diff --git a/src/kernel-install/50-depmod.install b/src/kernel-install/50-depmod.install +index 2fd959865f..aa1f6b8e0e 100644 +--- a/src/kernel-install/50-depmod.install ++++ b/src/kernel-install/50-depmod.install +@@ -1,4 +1,4 @@ +-#!/usr/bin/env bash ++#!/bin/sh + # -*- mode: shell-script; indent-tabs-mode: nil; sh-basic-offset: 4; -*- + # ex: ts=8 sw=4 sts=4 et filetype=sh + # SPDX-License-Identifier: LGPL-2.1-or-later +@@ -20,23 +20,25 @@ + + COMMAND="$1" + KERNEL_VERSION="$2" +-ENTRY_DIR_ABS="$3" +-KERNEL_IMAGE="$4" +-INITRD_OPTIONS_START="5" +- +-[[ $KERNEL_VERSION ]] || exit 1 + + case "$COMMAND" in + add) +- [[ -d "/lib/modules/${KERNEL_VERSION}/kernel" ]] || exit 0 +- [ "$KERNEL_INSTALL_VERBOSE" -gt 0 ] && \ +- echo "Running depmod -a ${KERNEL_VERSION}" +- exec depmod -a "${KERNEL_VERSION}" ++ [ -d "/lib/modules/$KERNEL_VERSION/kernel" ] || exit 0 ++ [ "$KERNEL_INSTALL_VERBOSE" -gt 0 ] && echo "+depmod -a $KERNEL_VERSION" ++ exec depmod -a "$KERNEL_VERSION" + ;; + remove) +- [ "$KERNEL_INSTALL_VERBOSE" -gt 0 ] && \ +- echo "Removing /lib/modules/${KERNEL_VERSION}/modules.dep and associated files" +- exec rm -f /lib/modules/"${KERNEL_VERSION}"/modules.{alias{,.bin},builtin.bin,dep{,.bin},devname,softdep,symbols{,.bin}} ++ [ "$KERNEL_INSTALL_VERBOSE" -gt 0 ] && echo "Removing /lib/modules/$KERNEL_VERSION/modules.dep and associated files" ++ exec rm -f \ ++ "/lib/modules/$KERNEL_VERSION/modules.alias" \ ++ "/lib/modules/$KERNEL_VERSION/modules.alias.bin" \ ++ "/lib/modules/$KERNEL_VERSION/modules.builtin.bin" \ ++ "/lib/modules/$KERNEL_VERSION/modules.dep" \ ++ "/lib/modules/$KERNEL_VERSION/modules.dep.bin" \ ++ "/lib/modules/$KERNEL_VERSION/modules.devname" \ ++ "/lib/modules/$KERNEL_VERSION/modules.softdep" \ ++ "/lib/modules/$KERNEL_VERSION/modules.symbols" \ ++ "/lib/modules/$KERNEL_VERSION/modules.symbols.bin" + ;; + *) + exit 0 diff --git a/0082-kernel-install-90-loaderentry-port-to-bin-sh.patch b/0082-kernel-install-90-loaderentry-port-to-bin-sh.patch new file mode 100644 index 0000000..5502981 --- /dev/null +++ b/0082-kernel-install-90-loaderentry-port-to-bin-sh.patch @@ -0,0 +1,181 @@ +From 7b05dc8184e1a459d0a073dfe569560681525980 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?=D0=BD=D0=B0=D0=B1?= +Date: Thu, 16 Dec 2021 14:35:33 +0100 +Subject: [PATCH] kernel-install: 90-loaderentry: port to /bin/sh + +Also, forward the rm -f exit code on removal instead of swallowing it + +(cherry picked from commit 662f45e3ea9f6e933234b81bec532d584bda6ead) + +Related: #2065061 +--- + src/kernel-install/90-loaderentry.install | 110 +++++++++------------- + 1 file changed, 45 insertions(+), 65 deletions(-) + +diff --git a/src/kernel-install/90-loaderentry.install b/src/kernel-install/90-loaderentry.install +index 044eced3f0..35324e69a9 100644 +--- a/src/kernel-install/90-loaderentry.install ++++ b/src/kernel-install/90-loaderentry.install +@@ -1,4 +1,4 @@ +-#!/usr/bin/env bash ++#!/bin/sh + # -*- mode: shell-script; indent-tabs-mode: nil; sh-basic-offset: 4; -*- + # ex: ts=8 sw=4 sts=4 et filetype=sh + # SPDX-License-Identifier: LGPL-2.1-or-later +@@ -22,68 +22,53 @@ COMMAND="$1" + KERNEL_VERSION="$2" + ENTRY_DIR_ABS="$3" + KERNEL_IMAGE="$4" +-INITRD_OPTIONS_START="5" ++INITRD_OPTIONS_SHIFT=4 + +-if ! [[ $KERNEL_INSTALL_MACHINE_ID ]]; then +- exit 0 +-fi +- +-if [ "$KERNEL_INSTALL_LAYOUT" != "bls" ]; then +- exit 0 +-fi ++[ "$KERNEL_INSTALL_LAYOUT" = "bls" ] || exit 0 + + MACHINE_ID="$KERNEL_INSTALL_MACHINE_ID" + BOOT_ROOT="$KERNEL_INSTALL_BOOT_ROOT" + + BOOT_MNT="$(stat -c %m "$BOOT_ROOT")" +-if [[ "$BOOT_MNT" == '/' ]]; then ++if [ "$BOOT_MNT" = '/' ]; then + ENTRY_DIR="$ENTRY_DIR_ABS" + else + ENTRY_DIR="${ENTRY_DIR_ABS#$BOOT_MNT}" + fi + +-if [[ $COMMAND == remove ]]; then +- rm -f "$BOOT_ROOT/loader/entries/$MACHINE_ID-$KERNEL_VERSION.conf" +- rm -f "$BOOT_ROOT/loader/entries/$MACHINE_ID-$KERNEL_VERSION+"*".conf" +- exit 0 +-fi +- +-if ! [[ $COMMAND == add ]]; then +- exit 1 +-fi +- +-if ! [[ $KERNEL_IMAGE ]]; then +- exit 1 +-fi ++case "$COMMAND" in ++ remove) ++ exec rm -f \ ++ "$BOOT_ROOT/loader/entries/$MACHINE_ID-$KERNEL_VERSION.conf" \ ++ "$BOOT_ROOT/loader/entries/$MACHINE_ID-$KERNEL_VERSION+"*".conf" ++ ;; ++ add) ++ ;; ++ *) ++ exit 1 ++ ;; ++esac + +-if [[ -f /etc/os-release ]]; then ++if [ -r /etc/os-release ]; then + . /etc/os-release +-elif [[ -f /usr/lib/os-release ]]; then ++elif [ -r /usr/lib/os-release ]; then + . /usr/lib/os-release + fi + +-if ! [[ $PRETTY_NAME ]]; then +- PRETTY_NAME="Linux $KERNEL_VERSION" +-fi ++[ -n "$PRETTY_NAME" ] || PRETTY_NAME="Linux $KERNEL_VERSION" + +-if [[ -f /etc/kernel/cmdline ]]; then +- read -r -d '' -a BOOT_OPTIONS < /etc/kernel/cmdline +-elif [[ -f /usr/lib/kernel/cmdline ]]; then +- read -r -d '' -a BOOT_OPTIONS < /usr/lib/kernel/cmdline ++if [ -r /etc/kernel/cmdline ]; then ++ BOOT_OPTIONS="$(tr -s "$IFS" ' ' &2 + exit 1 + fi +@@ -106,43 +91,38 @@ install -g root -o root -m 0644 "$KERNEL_IMAGE" "$ENTRY_DIR_ABS/linux" || { + exit 1 + } + +-INITRD_OPTIONS=( "${@:${INITRD_OPTIONS_START}}" ) +- +-for initrd in "${INITRD_OPTIONS[@]}"; do +- if [[ -f "${initrd}" ]]; then +- initrd_basename="$(basename ${initrd})" +- [ "$KERNEL_INSTALL_VERBOSE" -gt 0 ] && \ +- echo "Installing $ENTRY_DIR_ABS/${initrd_basename}" +- install -g root -o root -m 0644 "${initrd}" "$ENTRY_DIR_ABS/${initrd_basename}" || { +- echo "Could not copy '${initrd}' to '$ENTRY_DIR_ABS/${initrd_basename}'." >&2 +- exit 1 +- } +- fi +-done ++shift "$INITRD_OPTIONS_SHIFT" ++for initrd; do ++ [ -f "$initrd" ] || continue + +-# If no initrd option is supplied, fall back to "initrd" which is +-# the name used by dracut when generating it in its kernel-install hook +-[[ ${#INITRD_OPTIONS[@]} == 0 ]] && INITRD_OPTIONS=( initrd ) ++ initrd_basename="${initrd##*/}" ++ [ "$KERNEL_INSTALL_VERBOSE" -gt 0 ] && echo "Installing $ENTRY_DIR_ABS/$initrd_basename" ++ install -g root -o root -m 0644 "$initrd" "$ENTRY_DIR_ABS/$initrd_basename" || { ++ echo "Could not copy '$initrd' to '$ENTRY_DIR_ABS/$initrd_basename'." >&2 ++ exit 1 ++ } ++done + + mkdir -p "${LOADER_ENTRY%/*}" || { + echo "Could not create loader entry directory '${LOADER_ENTRY%/*}'." >&2 + exit 1 + } + +-[ "$KERNEL_INSTALL_VERBOSE" -gt 0 ] && \ +- echo "Creating $LOADER_ENTRY" ++# Try "initrd", generated by dracut in its kernel-install hook, if no initrds were supplied ++[ $# -eq 0 ] && set -- "initrd" ++ ++[ "$KERNEL_INSTALL_VERBOSE" -gt 0 ] && echo "Creating $LOADER_ENTRY" + { + echo "title $PRETTY_NAME" + echo "version $KERNEL_VERSION" + echo "machine-id $MACHINE_ID" +- echo "options ${BOOT_OPTIONS[*]}" ++ echo "options $BOOT_OPTIONS" + echo "linux $ENTRY_DIR/linux" +- for initrd in "${INITRD_OPTIONS[@]}"; do +- [[ -f $ENTRY_DIR_ABS/$(basename ${initrd}) ]] && \ +- echo "initrd $ENTRY_DIR/$(basename ${initrd})" ++ for initrd; do ++ [ -f "$ENTRY_DIR_ABS/${initrd##*/}" ] && echo "initrd $ENTRY_DIR/${initrd##*/}" + done + : +-} > "$LOADER_ENTRY" || { ++} >"$LOADER_ENTRY" || { + echo "Could not create loader entry '$LOADER_ENTRY'." >&2 + exit 1 + } diff --git a/0083-kernel-install-fix-shellcheck.patch b/0083-kernel-install-fix-shellcheck.patch new file mode 100644 index 0000000..89094a2 --- /dev/null +++ b/0083-kernel-install-fix-shellcheck.patch @@ -0,0 +1,82 @@ +From 52f6eedb3bb4dc7a57fea6a8991b9058dedc8edc Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?=D0=BD=D0=B0=D0=B1?= +Date: Thu, 16 Dec 2021 14:37:53 +0100 +Subject: [PATCH] kernel-install: fix shellcheck + +(cherry picked from commit 0bb1cb1fce5ebf307501dec1679e37f0c0157be9) + +Related: #2065061 +--- + src/kernel-install/kernel-install | 22 +++++++++++----------- + 1 file changed, 11 insertions(+), 11 deletions(-) + +diff --git a/src/kernel-install/kernel-install b/src/kernel-install/kernel-install +index b358b03b2f..f6da0cf7a8 100755 +--- a/src/kernel-install/kernel-install ++++ b/src/kernel-install/kernel-install +@@ -26,8 +26,8 @@ usage() + echo " $0 [OPTIONS...] add KERNEL-VERSION KERNEL-IMAGE [INITRD-FILE ...]" + echo " $0 [OPTIONS...] remove KERNEL-VERSION" + echo "Options:" +- echo " -h,--help Print this help" +- echo " -v,--verbose Increase verbosity" ++ echo " -h, --help Print this help" ++ echo " -v, --verbose Increase verbosity" + } + + dropindirs_sort() +@@ -58,15 +58,15 @@ dropindirs_sort() + + export LC_COLLATE=C + +-for i in "$@"; do +- if [ "$i" == "--help" -o "$i" == "-h" ]; then ++for i; do ++ if [ "$i" = "--help" ] || [ "$i" = "-h" ]; then + usage + exit 0 + fi + done + + KERNEL_INSTALL_VERBOSE=0 +-if [ "$1" == "--verbose" -o "$1" == "-v" ]; then ++if [ "$1" = "--verbose" ] || [ "$1" = "-v" ]; then + shift + KERNEL_INSTALL_VERBOSE=1 + fi +@@ -185,13 +185,13 @@ case $COMMAND in + for f in "${PLUGINS[@]}"; do + if [[ -x $f ]]; then + [ "$KERNEL_INSTALL_VERBOSE" -gt 0 ] && \ +- echo "+$f add $KERNEL_VERSION $ENTRY_DIR_ABS $KERNEL_IMAGE ${INITRD_OPTIONS[@]}" ++ echo "+$f add $KERNEL_VERSION $ENTRY_DIR_ABS $KERNEL_IMAGE ${INITRD_OPTIONS[*]}" + "$f" add "$KERNEL_VERSION" "$ENTRY_DIR_ABS" "$KERNEL_IMAGE" "${INITRD_OPTIONS[@]}" + x=$? +- if [[ $x == $SKIP_REMAINING ]]; then ++ if [ $x -eq "$SKIP_REMAINING" ]; then + break + fi +- ((ret+=$x)) ++ ((ret+=x)) + fi + done + ;; +@@ -203,10 +203,10 @@ case $COMMAND in + echo "+$f remove $KERNEL_VERSION $ENTRY_DIR_ABS" + "$f" remove "$KERNEL_VERSION" "$ENTRY_DIR_ABS" + x=$? +- if [[ $x == $SKIP_REMAINING ]]; then ++ if [ $x -eq "$SKIP_REMAINING" ]; then + break + fi +- ((ret+=$x)) ++ ((ret+=x)) + fi + done + +@@ -222,4 +222,4 @@ case $COMMAND in + ;; + esac + +-exit $ret ++exit "$ret" diff --git a/0084-kernel-install-port-to-bin-sh.patch b/0084-kernel-install-port-to-bin-sh.patch new file mode 100644 index 0000000..db473f9 --- /dev/null +++ b/0084-kernel-install-port-to-bin-sh.patch @@ -0,0 +1,205 @@ +From 1f9eec4ab2a8a2213fec66194c537086e8242a0d Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?=D0=BD=D0=B0=D0=B1?= +Date: Thu, 16 Dec 2021 15:06:06 +0100 +Subject: [PATCH] kernel-install: port to /bin/sh + +(cherry picked from commit 76b1274a5cb54acaa4a0f0c2e570d751f9067c06) + +Related: #2065061 +--- + src/kernel-install/kernel-install | 109 ++++++++++++------------------ + 1 file changed, 43 insertions(+), 66 deletions(-) + +diff --git a/src/kernel-install/kernel-install b/src/kernel-install/kernel-install +index f6da0cf7a8..2e8f382d5f 100755 +--- a/src/kernel-install/kernel-install ++++ b/src/kernel-install/kernel-install +@@ -1,4 +1,4 @@ +-#!/usr/bin/env bash ++#!/bin/sh + # -*- mode: shell-script; indent-tabs-mode: nil; sh-basic-offset: 4; -*- + # ex: ts=8 sw=4 sts=4 et filetype=sh + # SPDX-License-Identifier: LGPL-2.1-or-later +@@ -18,7 +18,7 @@ + # You should have received a copy of the GNU Lesser General Public License + # along with systemd; If not, see . + +-SKIP_REMAINING=77 ++skip_remaining=77 + + usage() + { +@@ -32,24 +32,17 @@ usage() + + dropindirs_sort() + { +- local suffix=$1; shift +- local -a files +- local f d i +- +- readarray -t files <<<"$( +- for d in "$@"; do +- for i in "$d/"*"$suffix"; do +- if [[ -e "$i" ]]; then +- echo "${i##*/}" +- fi +- done +- done | sort -Vu +- )" +- +- for f in "${files[@]}"; do +- for d in "$@"; do +- if [[ -e "$d/$f" ]]; then +- echo "$d/$f" ++ suffix="$1" ++ shift ++ ++ for d; do ++ for i in "$d/"*"$suffix"; do ++ [ -e "$i" ] && echo "${i##*/}" ++ done ++ done | sort -Vu | while read -r f; do ++ for d; do ++ if [ -e "$d/$f" ]; then ++ [ -x "$d/$f" ] && echo "$d/$f" + continue 2 + fi + done +@@ -65,27 +58,25 @@ for i; do + fi + done + +-KERNEL_INSTALL_VERBOSE=0 ++export KERNEL_INSTALL_VERBOSE=0 + if [ "$1" = "--verbose" ] || [ "$1" = "-v" ]; then + shift + KERNEL_INSTALL_VERBOSE=1 + fi +-export KERNEL_INSTALL_VERBOSE + +-if [[ "${0##*/}" == 'installkernel' ]]; then +- COMMAND='add' +- # make install doesn't pass any parameter wrt initrd handling +- INITRD_OPTIONS=() ++if [ "${0##*/}" = "installkernel" ]; then ++ COMMAND=add ++ # make install doesn't pass any initrds + else + COMMAND="$1" +- shift +- INITRD_OPTIONS=( "${@:3}" ) ++ [ $# -ge 1 ] && shift + fi + + KERNEL_VERSION="$1" + KERNEL_IMAGE="$2" ++[ $# -ge 2 ] && shift 2 + +-if [[ ! $COMMAND ]] || [[ ! $KERNEL_VERSION ]]; then ++if [ -z "$COMMAND" ] || [ -z "$KERNEL_VERSION" ]; then + echo "Not enough arguments" >&2 + exit 1 + fi +@@ -99,12 +90,11 @@ fi + # Prefer to use an existing machine ID from /etc/machine-info or /etc/machine-id. If we're using the machine + # ID /etc/machine-id, try to persist it in /etc/machine-info. If no machine ID is found, try to generate + # a new machine ID in /etc/machine-info. If that fails, use "Default". +- +-[ -z "$MACHINE_ID" ] && [ -f /etc/machine-info ] && source /etc/machine-info && MACHINE_ID="$KERNEL_INSTALL_MACHINE_ID" +-[ -z "$MACHINE_ID" ] && [ -f /etc/machine-id ] && read -r MACHINE_ID >/etc/machine-info ++[ -z "$MACHINE_ID" ] && [ -r /etc/machine-info ] && . /etc/machine-info && MACHINE_ID="$KERNEL_INSTALL_MACHINE_ID" ++[ -z "$MACHINE_ID" ] && [ -r /etc/machine-id ] && read -r MACHINE_ID >/etc/machine-info + [ -z "$MACHINE_ID" ] && NEW_MACHINE_ID="$(systemd-id128 new)" && echo "KERNEL_INSTALL_MACHINE_ID=$NEW_MACHINE_ID" >>/etc/machine-info +-[ -z "$MACHINE_ID" ] && [ -f /etc/machine-info ] && source /etc/machine-info && MACHINE_ID="$KERNEL_INSTALL_MACHINE_ID" ++[ -z "$MACHINE_ID" ] && [ -r /etc/machine-info ] && . /etc/machine-info && MACHINE_ID="$KERNEL_INSTALL_MACHINE_ID" + [ -z "$MACHINE_ID" ] && MACHINE_ID="Default" + + [ -z "$BOOT_ROOT" ] && for suff in "$MACHINE_ID" "loader/entries"; do +@@ -125,11 +115,6 @@ done + [ -z "$BOOT_ROOT" ] && BOOT_ROOT="/boot" + + +-ENTRY_DIR_ABS="$BOOT_ROOT/$MACHINE_ID/$KERNEL_VERSION" +- +-export KERNEL_INSTALL_MACHINE_ID="$MACHINE_ID" +-export KERNEL_INSTALL_BOOT_ROOT="$BOOT_ROOT" +- + if [ -z "$layout" ]; then + # Administrative decision: if not present, some scripts generate into /boot. + if [ -d "$BOOT_ROOT/$MACHINE_ID" ]; then +@@ -152,21 +137,23 @@ MAKE_ENTRY_DIR_ABS=$? + + ret=0 + +-readarray -t PLUGINS <<<"$( ++PLUGINS="$( + dropindirs_sort ".install" \ + "/etc/kernel/install.d" \ + "/usr/lib/kernel/install.d" + )" ++IFS=" ++" + +-case $COMMAND in ++case "$COMMAND" in + add) +- if [[ ! "$KERNEL_IMAGE" ]]; then ++ if [ -z "$KERNEL_IMAGE" ]; then + echo "Command 'add' requires an argument" >&2 + exit 1 + fi + +- if [[ ! -f "$KERNEL_IMAGE" ]]; then +- echo "Kernel image argument ${KERNEL_IMAGE} not a file" >&2 ++ if ! [ -f "$KERNEL_IMAGE" ]; then ++ echo "Kernel image argument $KERNEL_IMAGE not a file" >&2 + exit 1 + fi + +@@ -182,32 +169,22 @@ case $COMMAND in + fi + fi + +- for f in "${PLUGINS[@]}"; do +- if [[ -x $f ]]; then +- [ "$KERNEL_INSTALL_VERBOSE" -gt 0 ] && \ +- echo "+$f add $KERNEL_VERSION $ENTRY_DIR_ABS $KERNEL_IMAGE ${INITRD_OPTIONS[*]}" +- "$f" add "$KERNEL_VERSION" "$ENTRY_DIR_ABS" "$KERNEL_IMAGE" "${INITRD_OPTIONS[@]}" +- x=$? +- if [ $x -eq "$SKIP_REMAINING" ]; then +- break +- fi +- ((ret+=x)) +- fi ++ for f in $PLUGINS; do ++ [ "$KERNEL_INSTALL_VERBOSE" -gt 0 ] && echo "+$f add $KERNEL_VERSION $ENTRY_DIR_ABS $KERNEL_IMAGE $*" ++ "$f" add "$KERNEL_VERSION" "$ENTRY_DIR_ABS" "$KERNEL_IMAGE" "$@" ++ err=$? ++ [ $err -eq $skip_remaining ] && break ++ ret=$(( ret + err )) + done + ;; + + remove) +- for f in "${PLUGINS[@]}"; do +- if [[ -x $f ]]; then +- [ "$KERNEL_INSTALL_VERBOSE" -gt 0 ] && \ +- echo "+$f remove $KERNEL_VERSION $ENTRY_DIR_ABS" +- "$f" remove "$KERNEL_VERSION" "$ENTRY_DIR_ABS" +- x=$? +- if [ $x -eq "$SKIP_REMAINING" ]; then +- break +- fi +- ((ret+=x)) +- fi ++ for f in $PLUGINS; do ++ [ "$KERNEL_INSTALL_VERBOSE" -gt 0 ] && echo "+$f remove $KERNEL_VERSION $ENTRY_DIR_ABS" ++ "$f" remove "$KERNEL_VERSION" "$ENTRY_DIR_ABS" ++ err=$? ++ [ $err -eq $skip_remaining ] && break ++ ret=$(( ret + err )) + done + + if [ "$MAKE_ENTRY_DIR_ABS" -eq 0 ]; then diff --git a/0085-kernel-install-90-loaderentry-error-out-on-nonexiste.patch b/0085-kernel-install-90-loaderentry-error-out-on-nonexiste.patch new file mode 100644 index 0000000..95d70d4 --- /dev/null +++ b/0085-kernel-install-90-loaderentry-error-out-on-nonexiste.patch @@ -0,0 +1,51 @@ +From bc1c914ebdec526151964c1aa3c2aeea0d4e2680 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?=D0=BD=D0=B0=D0=B1?= +Date: Fri, 17 Dec 2021 19:51:12 +0100 +Subject: [PATCH] kernel-install: 90-loaderentry: error out on nonexistent + initrds instead of swallowing them quietly + +(cherry picked from commit 742561efbe938c45936f2e4f5d81b3ff6b352882) + +Related: #2065061 +--- + src/kernel-install/90-loaderentry.install | 12 +++++++----- + 1 file changed, 7 insertions(+), 5 deletions(-) + +diff --git a/src/kernel-install/90-loaderentry.install b/src/kernel-install/90-loaderentry.install +index 35324e69a9..e588e72bf9 100644 +--- a/src/kernel-install/90-loaderentry.install ++++ b/src/kernel-install/90-loaderentry.install +@@ -93,7 +93,10 @@ install -g root -o root -m 0644 "$KERNEL_IMAGE" "$ENTRY_DIR_ABS/linux" || { + + shift "$INITRD_OPTIONS_SHIFT" + for initrd; do +- [ -f "$initrd" ] || continue ++ [ -f "$initrd" ] || { ++ echo "Initrd '$initrd' not a file." >&2 ++ exit 1 ++ } + + initrd_basename="${initrd##*/}" + [ "$KERNEL_INSTALL_VERBOSE" -gt 0 ] && echo "Installing $ENTRY_DIR_ABS/$initrd_basename" +@@ -108,9 +111,6 @@ mkdir -p "${LOADER_ENTRY%/*}" || { + exit 1 + } + +-# Try "initrd", generated by dracut in its kernel-install hook, if no initrds were supplied +-[ $# -eq 0 ] && set -- "initrd" +- + [ "$KERNEL_INSTALL_VERBOSE" -gt 0 ] && echo "Creating $LOADER_ENTRY" + { + echo "title $PRETTY_NAME" +@@ -119,8 +119,10 @@ mkdir -p "${LOADER_ENTRY%/*}" || { + echo "options $BOOT_OPTIONS" + echo "linux $ENTRY_DIR/linux" + for initrd; do +- [ -f "$ENTRY_DIR_ABS/${initrd##*/}" ] && echo "initrd $ENTRY_DIR/${initrd##*/}" ++ echo "initrd $ENTRY_DIR/${initrd##*/}" + done ++ # Try "initrd", generated by dracut in its kernel-install hook, if no initrds were supplied ++ [ $# -eq 0 ] && [ -f "$ENTRY_DIR_ABS/initrd" ] && echo "initrd $ENTRY_DIR/initrd" + : + } >"$LOADER_ENTRY" || { + echo "Could not create loader entry '$LOADER_ENTRY'." >&2 diff --git a/0086-kernel-install-don-t-pull-out-KERNEL_IMAGE.patch b/0086-kernel-install-don-t-pull-out-KERNEL_IMAGE.patch new file mode 100644 index 0000000..1913f15 --- /dev/null +++ b/0086-kernel-install-don-t-pull-out-KERNEL_IMAGE.patch @@ -0,0 +1,68 @@ +From 8a52c3a1797084956ddcd2acfb65a4023a4f0655 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?=D0=BD=D0=B0=D0=B1?= +Date: Mon, 20 Dec 2021 14:57:39 +0100 +Subject: [PATCH] kernel-install: don't pull out KERNEL_IMAGE + +It's part of the pack directly passed to scripts on add and ignored on +remove + +(cherry picked from commit af319a4b14bd05cd4c8460487f2c6d7a31b35640) + +Related: #2065061 +--- + src/kernel-install/kernel-install | 21 ++++++++++----------- + 1 file changed, 10 insertions(+), 11 deletions(-) + +diff --git a/src/kernel-install/kernel-install b/src/kernel-install/kernel-install +index 2e8f382d5f..097d6557f2 100755 +--- a/src/kernel-install/kernel-install ++++ b/src/kernel-install/kernel-install +@@ -72,15 +72,14 @@ else + [ $# -ge 1 ] && shift + fi + +-KERNEL_VERSION="$1" +-KERNEL_IMAGE="$2" +-[ $# -ge 2 ] && shift 2 +- +-if [ -z "$COMMAND" ] || [ -z "$KERNEL_VERSION" ]; then ++if [ $# -lt 1 ]; then + echo "Not enough arguments" >&2 + exit 1 + fi + ++KERNEL_VERSION="$1" ++shift ++ + if [ -r "/etc/kernel/install.conf" ]; then + . /etc/kernel/install.conf + elif [ -r "/usr/lib/kernel/install.conf" ]; then +@@ -147,13 +146,13 @@ IFS=" + + case "$COMMAND" in + add) +- if [ -z "$KERNEL_IMAGE" ]; then +- echo "Command 'add' requires an argument" >&2 ++ if [ $# -lt 1 ]; then ++ echo "Command 'add' requires a kernel image" >&2 + exit 1 + fi + +- if ! [ -f "$KERNEL_IMAGE" ]; then +- echo "Kernel image argument $KERNEL_IMAGE not a file" >&2 ++ if ! [ -f "$1" ]; then ++ echo "Kernel image argument $1 not a file" >&2 + exit 1 + fi + +@@ -170,8 +169,8 @@ case "$COMMAND" in + fi + + for f in $PLUGINS; do +- [ "$KERNEL_INSTALL_VERBOSE" -gt 0 ] && echo "+$f add $KERNEL_VERSION $ENTRY_DIR_ABS $KERNEL_IMAGE $*" +- "$f" add "$KERNEL_VERSION" "$ENTRY_DIR_ABS" "$KERNEL_IMAGE" "$@" ++ [ "$KERNEL_INSTALL_VERBOSE" -gt 0 ] && echo "+$f add $KERNEL_VERSION $ENTRY_DIR_ABS $*" ++ "$f" add "$KERNEL_VERSION" "$ENTRY_DIR_ABS" "$@" + err=$? + [ $err -eq $skip_remaining ] && break + ret=$(( ret + err )) diff --git a/0087-kernel-install-prefer-boot-over-boot-efi-for-BOOT_RO.patch b/0087-kernel-install-prefer-boot-over-boot-efi-for-BOOT_RO.patch new file mode 100644 index 0000000..5da86e6 --- /dev/null +++ b/0087-kernel-install-prefer-boot-over-boot-efi-for-BOOT_RO.patch @@ -0,0 +1,32 @@ +From 8bcb1df836fccb5ddb6fb071b022bfd490f94e11 Mon Sep 17 00:00:00 2001 +From: Adam Williamson +Date: Wed, 5 Jan 2022 14:07:14 -0800 +Subject: [PATCH] kernel-install: prefer /boot over /boot/efi for $BOOT_ROOT + +This restores the preference order from before 9e82a74. The code +previous to that change 'preferred' /boot over /boot/efi; that +commit changed it to check /boot/efi before checking /boot. +Changing this precedence could (and did, for me) have unexpected +effects - it seems safer to leave it how it was. + +Signed-off-by: Adam Williamson +(cherry picked from commit a5307e173bf86d695fe85b8e15e91126e8618a14) + +Related: #2065061 +--- + src/kernel-install/kernel-install | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/kernel-install/kernel-install b/src/kernel-install/kernel-install +index 097d6557f2..e56483ef96 100755 +--- a/src/kernel-install/kernel-install ++++ b/src/kernel-install/kernel-install +@@ -97,7 +97,7 @@ fi + [ -z "$MACHINE_ID" ] && MACHINE_ID="Default" + + [ -z "$BOOT_ROOT" ] && for suff in "$MACHINE_ID" "loader/entries"; do +- for pref in "/efi" "/boot/efi" "/boot"; do ++ for pref in "/efi" "/boot" "/boot/efi" ; do + if [ -d "$pref/$suff" ]; then + BOOT_ROOT="$pref" + break 2 diff --git a/0088-kernel-install-also-remove-modules.builtin.alias.bin.patch b/0088-kernel-install-also-remove-modules.builtin.alias.bin.patch new file mode 100644 index 0000000..ba2f56a --- /dev/null +++ b/0088-kernel-install-also-remove-modules.builtin.alias.bin.patch @@ -0,0 +1,26 @@ +From 491f0e55e1f1095b1d52d45e5753d5f1ea621231 Mon Sep 17 00:00:00 2001 +From: Yu Watanabe +Date: Sat, 15 Jan 2022 03:37:40 +0900 +Subject: [PATCH] kernel-install: also remove modules.builtin.alias.bin + +Fixes RHBZ#2016630. + +(cherry picked from commit 06006691b5c56b6123044179d934b3ed81c237ca) + +Related: #2065061 +--- + src/kernel-install/50-depmod.install | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/src/kernel-install/50-depmod.install b/src/kernel-install/50-depmod.install +index aa1f6b8e0e..be414f39d1 100644 +--- a/src/kernel-install/50-depmod.install ++++ b/src/kernel-install/50-depmod.install +@@ -33,6 +33,7 @@ case "$COMMAND" in + "/lib/modules/$KERNEL_VERSION/modules.alias" \ + "/lib/modules/$KERNEL_VERSION/modules.alias.bin" \ + "/lib/modules/$KERNEL_VERSION/modules.builtin.bin" \ ++ "/lib/modules/$KERNEL_VERSION/modules.builtin.alias.bin" \ + "/lib/modules/$KERNEL_VERSION/modules.dep" \ + "/lib/modules/$KERNEL_VERSION/modules.dep.bin" \ + "/lib/modules/$KERNEL_VERSION/modules.devname" \ diff --git a/0089-kernel-install-add-new-variable-KERNEL_INSTALL_INITR.patch b/0089-kernel-install-add-new-variable-KERNEL_INSTALL_INITR.patch new file mode 100644 index 0000000..120a52e --- /dev/null +++ b/0089-kernel-install-add-new-variable-KERNEL_INSTALL_INITR.patch @@ -0,0 +1,77 @@ +From 931ae9749924a396a78044f8b1536085ff574ae6 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Tue, 18 Jan 2022 17:40:13 +0100 +Subject: [PATCH] kernel-install: add new variable + $KERNEL_INSTALL_INITRD_GENERATOR + +The idea is that when not set, we do whatever we did in the past. But +with a new setting of initrd_generator=mkosi-initrd, mkosi-initrd will +generate an initrd. + +(cherry picked from commit 5c1b257faf87cb4f93aee8866f45a8cb98230af9) + +Related: #2065061 +--- + man/kernel-install.xml | 6 +++++- + src/kernel-install/install.conf | 1 + + src/kernel-install/kernel-install | 5 ++++- + 3 files changed, 10 insertions(+), 2 deletions(-) + +diff --git a/man/kernel-install.xml b/man/kernel-install.xml +index 83255bb932..bb76074d2e 100644 +--- a/man/kernel-install.xml ++++ b/man/kernel-install.xml +@@ -171,11 +171,15 @@ + KERNEL_INSTALL_BOOT_ROOT= is set for the plugins to the root directory (mount point, usually) of the hierarchy + where boot-loader entries, kernel images, and associated resources should be placed. Can be overridden by setting BOOT_ROOT=. + +- KERNEL_INSTALL_LAYOUT=bls|other|... specifies the installation layout. ++ KERNEL_INSTALL_LAYOUT=bls|other|... is set for the plugins to specify the installation layout. + Defaults to if $BOOT/MACHINE-ID exists, or otherwise. + Additional layout names may be defined by convention. If a plugin uses a special layout, + it's encouraged to declare its own layout name and configure layout= in install.conf upon initial installation. + ++ KERNEL_INSTALL_INITRD_GENERATOR=... is set for plugins to select the initrd generator. ++ This should be configured as initrd_generator= in install.conf. ++ ++ + + + bls +diff --git a/src/kernel-install/install.conf b/src/kernel-install/install.conf +index e4802e6fae..43b6e7d792 100644 +--- a/src/kernel-install/install.conf ++++ b/src/kernel-install/install.conf +@@ -8,3 +8,4 @@ + # See kernel-install(8) for details. + + #layout=bls|other|... ++#initrd_generator=dracut|... +diff --git a/src/kernel-install/kernel-install b/src/kernel-install/kernel-install +index e56483ef96..fe457c1070 100755 +--- a/src/kernel-install/kernel-install ++++ b/src/kernel-install/kernel-install +@@ -80,6 +80,9 @@ fi + KERNEL_VERSION="$1" + shift + ++layout= ++initrd_generator= ++ + if [ -r "/etc/kernel/install.conf" ]; then + . /etc/kernel/install.conf + elif [ -r "/usr/lib/kernel/install.conf" ]; then +@@ -123,12 +126,12 @@ if [ -z "$layout" ]; then + fi + fi + +- + ENTRY_DIR_ABS="$BOOT_ROOT/$MACHINE_ID/$KERNEL_VERSION" + + export KERNEL_INSTALL_MACHINE_ID="$MACHINE_ID" + export KERNEL_INSTALL_BOOT_ROOT="$BOOT_ROOT" + export KERNEL_INSTALL_LAYOUT="$layout" ++export KERNEL_INSTALL_INITRD_GENERATOR="$initrd_generator" + + [ "$layout" = "bls" ] + MAKE_ENTRY_DIR_ABS=$? diff --git a/0090-kernel-install-k-i-already-creates-ENTRY_DIR_ABS-no-.patch b/0090-kernel-install-k-i-already-creates-ENTRY_DIR_ABS-no-.patch new file mode 100644 index 0000000..071ac07 --- /dev/null +++ b/0090-kernel-install-k-i-already-creates-ENTRY_DIR_ABS-no-.patch @@ -0,0 +1,32 @@ +From 27b017353a06a22d42dc8bbabbaf602200730719 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Wed, 19 Jan 2022 12:10:37 +0100 +Subject: [PATCH] kernel-install: k-i already creates $ENTRY_DIR_ABS, no need + to do it again + +(cherry picked from commit a520d5dddb991cd713392d4de0e342e312547a2e) + +Related: #2065061 +--- + src/kernel-install/90-loaderentry.install | 8 ++------ + 1 file changed, 2 insertions(+), 6 deletions(-) + +diff --git a/src/kernel-install/90-loaderentry.install b/src/kernel-install/90-loaderentry.install +index e588e72bf9..7b768457c1 100644 +--- a/src/kernel-install/90-loaderentry.install ++++ b/src/kernel-install/90-loaderentry.install +@@ -78,12 +78,8 @@ else + fi + + if ! [ -d "$ENTRY_DIR_ABS" ]; then +- if [ "$KERNEL_INSTALL_VERBOSE" -gt 0 ]; then +- echo "+mkdir -v -p $ENTRY_DIR_ABS" +- mkdir -v -p "$ENTRY_DIR_ABS" +- else +- mkdir -p "$ENTRY_DIR_ABS" +- fi ++ echo "Error: entry directory '$ENTRY_DIR_ABS' does not exist" >&2 ++ exit 1 + fi + + install -g root -o root -m 0644 "$KERNEL_IMAGE" "$ENTRY_DIR_ABS/linux" || { diff --git a/0091-kernel-install-prefix-errors-with-Error-exit-immedia.patch b/0091-kernel-install-prefix-errors-with-Error-exit-immedia.patch new file mode 100644 index 0000000..0bd51bb --- /dev/null +++ b/0091-kernel-install-prefix-errors-with-Error-exit-immedia.patch @@ -0,0 +1,118 @@ +From 7e5ff353f8b35352f6c36233841754154b4f453b Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Wed, 19 Jan 2022 12:15:16 +0100 +Subject: [PATCH] kernel-install: prefix errors with "Error:", exit immediately +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +kernel-install would continue after errors… We don't want this, as it +makes the results totally unpredicatable. If we didn't install the kernel +or didn't do some important part of the setup, let's just return an error +and let the user deal with it. + +When looking at output, the error was often hard to distinguish, esp. +with -v. Add "Error:" everywhere to make the output easier to parse. + +(cherry picked from commit 680cec6b4ddb356d7dd087b197718712cb5c1662) + +Related: #2065061 +--- + src/kernel-install/90-loaderentry.install | 10 +++++----- + src/kernel-install/kernel-install | 12 ++++++------ + 2 files changed, 11 insertions(+), 11 deletions(-) + +diff --git a/src/kernel-install/90-loaderentry.install b/src/kernel-install/90-loaderentry.install +index 7b768457c1..6a396910cb 100644 +--- a/src/kernel-install/90-loaderentry.install ++++ b/src/kernel-install/90-loaderentry.install +@@ -83,27 +83,27 @@ if ! [ -d "$ENTRY_DIR_ABS" ]; then + fi + + install -g root -o root -m 0644 "$KERNEL_IMAGE" "$ENTRY_DIR_ABS/linux" || { +- echo "Could not copy '$KERNEL_IMAGE' to '$ENTRY_DIR_ABS/linux'." >&2 ++ echo "Error: could not copy '$KERNEL_IMAGE' to '$ENTRY_DIR_ABS/linux'." >&2 + exit 1 + } + + shift "$INITRD_OPTIONS_SHIFT" + for initrd; do + [ -f "$initrd" ] || { +- echo "Initrd '$initrd' not a file." >&2 ++ echo "Error: initrd '$initrd' not a file." >&2 + exit 1 + } + + initrd_basename="${initrd##*/}" + [ "$KERNEL_INSTALL_VERBOSE" -gt 0 ] && echo "Installing $ENTRY_DIR_ABS/$initrd_basename" + install -g root -o root -m 0644 "$initrd" "$ENTRY_DIR_ABS/$initrd_basename" || { +- echo "Could not copy '$initrd' to '$ENTRY_DIR_ABS/$initrd_basename'." >&2 ++ echo "Error: could not copy '$initrd' to '$ENTRY_DIR_ABS/$initrd_basename'." >&2 + exit 1 + } + done + + mkdir -p "${LOADER_ENTRY%/*}" || { +- echo "Could not create loader entry directory '${LOADER_ENTRY%/*}'." >&2 ++ echo "Error: could not create loader entry directory '${LOADER_ENTRY%/*}'." >&2 + exit 1 + } + +@@ -121,7 +121,7 @@ mkdir -p "${LOADER_ENTRY%/*}" || { + [ $# -eq 0 ] && [ -f "$ENTRY_DIR_ABS/initrd" ] && echo "initrd $ENTRY_DIR/initrd" + : + } >"$LOADER_ENTRY" || { +- echo "Could not create loader entry '$LOADER_ENTRY'." >&2 ++ echo "Error: could not create loader entry '$LOADER_ENTRY'." >&2 + exit 1 + } + exit 0 +diff --git a/src/kernel-install/kernel-install b/src/kernel-install/kernel-install +index fe457c1070..a73a205d79 100755 +--- a/src/kernel-install/kernel-install ++++ b/src/kernel-install/kernel-install +@@ -73,7 +73,7 @@ else + fi + + if [ $# -lt 1 ]; then +- echo "Not enough arguments" >&2 ++ echo "Error: not enough arguments" >&2 + exit 1 + fi + +@@ -150,12 +150,12 @@ IFS=" + case "$COMMAND" in + add) + if [ $# -lt 1 ]; then +- echo "Command 'add' requires a kernel image" >&2 ++ echo "Error: command 'add' requires a kernel image" >&2 + exit 1 + fi + + if ! [ -f "$1" ]; then +- echo "Kernel image argument $1 not a file" >&2 ++ echo "Error: kernel image argument $1 not a file" >&2 + exit 1 + fi + +@@ -165,9 +165,9 @@ case "$COMMAND" in + # to serve as the indication to use or to not use the BLS + if [ "$KERNEL_INSTALL_VERBOSE" -gt 0 ]; then + echo "+mkdir -v -p $ENTRY_DIR_ABS" +- mkdir -v -p "$ENTRY_DIR_ABS" ++ mkdir -v -p "$ENTRY_DIR_ABS" || exit 1 + else +- mkdir -p "$ENTRY_DIR_ABS" ++ mkdir -p "$ENTRY_DIR_ABS" || exit 1 + fi + fi + +@@ -196,7 +196,7 @@ case "$COMMAND" in + ;; + + *) +- echo "Unknown command '$COMMAND'" >&2 ++ echo "Error: unknown command '$COMMAND'" >&2 + exit 1 + ;; + esac diff --git a/0092-kernel-install-add-KERNEL_INSTALL_STAGING_AREA-direc.patch b/0092-kernel-install-add-KERNEL_INSTALL_STAGING_AREA-direc.patch new file mode 100644 index 0000000..8913774 --- /dev/null +++ b/0092-kernel-install-add-KERNEL_INSTALL_STAGING_AREA-direc.patch @@ -0,0 +1,108 @@ +From 0f4ea4aee6e404dfbd6e3c4bbfb4f805e4e257f6 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Wed, 19 Jan 2022 12:20:22 +0100 +Subject: [PATCH] kernel-install: add "$KERNEL_INSTALL_STAGING_AREA" directory + +The general approach of kernel-install was that each plugin would drop in some +files into the entry directory. But this doesn't scale well, because if we have +multiple initrd generators, or multiple initrds, each generator would need to +recreate the logic to put the generated files in the right place. + +Also, effective cleanup is impossible if anything goes wrong on the way, so we +could end up with unused files in $BOOT. + +So let's invert the process: plugins drop files into $KERNEL_INSTALL_STAGING_AREA, +and at the end 90-loaderentry.install DTRT with those files. + +This allow new plugins like 50-mkosi-initrd.install to be significantly simpler. + +(cherry picked from commit 367165a4069ac0c04882a05a8a80f6afb1e42760) + +Related: #2065061 +--- + man/kernel-install.xml | 4 ++++ + src/kernel-install/90-loaderentry.install | 13 ++++++++++--- + src/kernel-install/kernel-install | 10 ++++++++++ + 3 files changed, 24 insertions(+), 3 deletions(-) + +diff --git a/man/kernel-install.xml b/man/kernel-install.xml +index bb76074d2e..685617863e 100644 +--- a/man/kernel-install.xml ++++ b/man/kernel-install.xml +@@ -180,6 +180,10 @@ + This should be configured as initrd_generator= in install.conf. + + ++ KERNEL_INSTALL_STAGING_AREA=... is set for plugins to a path to a directory. ++ Plugins may drop files in that directory, and they will be installed as part of the loader entry, based ++ on the file name and extension. ++ + + + bls +diff --git a/src/kernel-install/90-loaderentry.install b/src/kernel-install/90-loaderentry.install +index 6a396910cb..0888c260e2 100644 +--- a/src/kernel-install/90-loaderentry.install ++++ b/src/kernel-install/90-loaderentry.install +@@ -18,6 +18,8 @@ + # You should have received a copy of the GNU Lesser General Public License + # along with systemd; If not, see . + ++shopt -s nullglob ++ + COMMAND="$1" + KERNEL_VERSION="$2" + ENTRY_DIR_ABS="$3" +@@ -88,7 +90,8 @@ install -g root -o root -m 0644 "$KERNEL_IMAGE" "$ENTRY_DIR_ABS/linux" || { + } + + shift "$INITRD_OPTIONS_SHIFT" +-for initrd; do ++# All files listed as arguments, and staged files called "initrd*" are installed as initrds. ++for initrd in "$@" "${KERNEL_INSTALL_STAGING_AREA}"/initrd*; do + [ -f "$initrd" ] || { + echo "Error: initrd '$initrd' not a file." >&2 + exit 1 +@@ -114,11 +117,15 @@ mkdir -p "${LOADER_ENTRY%/*}" || { + echo "machine-id $MACHINE_ID" + echo "options $BOOT_OPTIONS" + echo "linux $ENTRY_DIR/linux" +- for initrd; do ++ ++ have_initrd= ++ for initrd in "${@}" "${KERNEL_INSTALL_STAGING_AREA}"/initrd*; do + echo "initrd $ENTRY_DIR/${initrd##*/}" ++ have_initrd=yes + done ++ + # Try "initrd", generated by dracut in its kernel-install hook, if no initrds were supplied +- [ $# -eq 0 ] && [ -f "$ENTRY_DIR_ABS/initrd" ] && echo "initrd $ENTRY_DIR/initrd" ++ [ -z "$have_initrd" ] && [ -f "$ENTRY_DIR_ABS/initrd" ] && echo "initrd $ENTRY_DIR/initrd" + : + } >"$LOADER_ENTRY" || { + echo "Error: could not create loader entry '$LOADER_ENTRY'." >&2 +diff --git a/src/kernel-install/kernel-install b/src/kernel-install/kernel-install +index a73a205d79..8cfef3208d 100755 +--- a/src/kernel-install/kernel-install ++++ b/src/kernel-install/kernel-install +@@ -128,10 +128,20 @@ fi + + ENTRY_DIR_ABS="$BOOT_ROOT/$MACHINE_ID/$KERNEL_VERSION" + ++# Provide a directory where to store generated initrds ++cleanup() { ++ [ -n "$KERNEL_INSTALL_STAGING_AREA" ] && rm -rf "$KERNEL_INSTALL_STAGING_AREA" ++} ++ ++trap cleanup EXIT ++ ++KERNEL_INSTALL_STAGING_AREA="$(mktemp -d -t -p /tmp kernel-install.staging.XXXXXXX)" ++ + export KERNEL_INSTALL_MACHINE_ID="$MACHINE_ID" + export KERNEL_INSTALL_BOOT_ROOT="$BOOT_ROOT" + export KERNEL_INSTALL_LAYOUT="$layout" + export KERNEL_INSTALL_INITRD_GENERATOR="$initrd_generator" ++export KERNEL_INSTALL_STAGING_AREA + + [ "$layout" = "bls" ] + MAKE_ENTRY_DIR_ABS=$? diff --git a/0093-kernel-install-add-missing-log-line.patch b/0093-kernel-install-add-missing-log-line.patch new file mode 100644 index 0000000..da10435 --- /dev/null +++ b/0093-kernel-install-add-missing-log-line.patch @@ -0,0 +1,25 @@ +From 9f36dbd7cb7ca1f2e77ea6c1a3129988f346b287 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Wed, 19 Jan 2022 14:03:24 +0100 +Subject: [PATCH] kernel-install: add missing log line + +(cherry picked from commit 29f604131b2c0b82dca7d6ffaa5e6bc6a253620d) + +Related: #2065061 +--- + src/kernel-install/90-loaderentry.install | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/src/kernel-install/90-loaderentry.install b/src/kernel-install/90-loaderentry.install +index 0888c260e2..3edefdefb4 100644 +--- a/src/kernel-install/90-loaderentry.install ++++ b/src/kernel-install/90-loaderentry.install +@@ -40,6 +40,8 @@ fi + + case "$COMMAND" in + remove) ++ [ "$KERNEL_INSTALL_VERBOSE" -gt 0 ] && \ ++ echo "Removing $BOOT_ROOT/loader/entries/$MACHINE_ID-$KERNEL_VERSION*.conf" + exec rm -f \ + "$BOOT_ROOT/loader/entries/$MACHINE_ID-$KERNEL_VERSION.conf" \ + "$BOOT_ROOT/loader/entries/$MACHINE_ID-$KERNEL_VERSION+"*".conf" diff --git a/0094-kernel-install-don-t-try-to-persist-used-machine-ID-.patch b/0094-kernel-install-don-t-try-to-persist-used-machine-ID-.patch new file mode 100644 index 0000000..c13105e --- /dev/null +++ b/0094-kernel-install-don-t-try-to-persist-used-machine-ID-.patch @@ -0,0 +1,83 @@ +From 7738d7793bc83421536f9962c794633006613725 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Wed, 9 Feb 2022 13:59:36 +0100 +Subject: [PATCH] kernel-install: don't try to persist used machine ID locally + +This reworks the how machine ID used by the boot loader spec snippet +generation logic. Instead of persisting it automatically to /etc/ we'll +append it via systemd.machined_id= to the kernel command line, and thus +persist it in the generated boot loader spec snippets instead. This has +nice benefits: + + 1. We do not collide with read-only root + 2. The machine ID remains stable across factory reset, so that we can + safely recognize the path in $BOOT we drop our kernel images in + again, i.e. kernel updates will work correctly and safely across + kernel factory resets. + 3. Previously regular systems had different machine IDs while in + initrd and after booting into the host system. With this change + they will now have the same. + +This then drops implicit persisting of KERNEL_INSTALL_MACHINE_ID, as its +unnecessary then. The field is still honoured though, for compat +reasons. + +This also drops the "Default" fallback previously used, as it actually +is without effect, the randomized ID generation already took precedence +in all cases. This means $MACHNE_ID/KERNEL_INSTALL_MACHINE_ID are now +guaranteed to look like a proper machine ID, which is useful for us, +given you need it that way to be able to pass it to the +systemd.machine_id= kernel command line option. + +(cherry picked from commit 11ce3ea2f2219ab9c0700bcf7f8ed4312d80e937) + +Related: #2065061 +--- + src/kernel-install/90-loaderentry.install | 6 +++++- + src/kernel-install/kernel-install | 16 +++++++--------- + 2 files changed, 12 insertions(+), 10 deletions(-) + +diff --git a/src/kernel-install/90-loaderentry.install b/src/kernel-install/90-loaderentry.install +index 3edefdefb4..046771169c 100644 +--- a/src/kernel-install/90-loaderentry.install ++++ b/src/kernel-install/90-loaderentry.install +@@ -68,7 +68,11 @@ elif [ -r /usr/lib/kernel/cmdline ]; then + else + BOOT_OPTIONS="$(tr -s "$IFS" '\n' >/etc/machine-info +-[ -z "$MACHINE_ID" ] && NEW_MACHINE_ID="$(systemd-id128 new)" && echo "KERNEL_INSTALL_MACHINE_ID=$NEW_MACHINE_ID" >>/etc/machine-info +-[ -z "$MACHINE_ID" ] && [ -r /etc/machine-info ] && . /etc/machine-info && MACHINE_ID="$KERNEL_INSTALL_MACHINE_ID" +-[ -z "$MACHINE_ID" ] && MACHINE_ID="Default" ++# If /etc/machine-id is initialized we'll use it, otherwise we'll use a freshly ++# generated one. If the user configured an explicit machine ID to use in ++# /etc/machine-info to use for our purpose, we'll use that instead (for ++# compatibility). ++[ -z "$MACHINE_ID" ] && [ -r /etc/machine-info ] && . /etc/machine-info && MACHINE_ID="$KERNEL_INSTALL_MACHINE_ID" ++[ -z "$MACHINE_ID" ] && [ -r /etc/machine-id ] && read -r MACHINE_ID +Date: Wed, 9 Feb 2022 14:29:19 +0100 +Subject: [PATCH] kernel-install: add a new $ENTRY_TOKEN variable for naming + boot entries +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This cleans up naming of boot loader spec boot entries a bit (i.e. the +naming of the .conf snippet files, and the directory in $BOOT where the +kernel images and initrds are placed), and isolates it from the actual machine +ID concept. + +Previously there was a sinlge concept for both things, because typically +the entries are just named after the machine ID. However one could also +use a different identifier, i.e. not a 128bit ID in which cases issues +pop up everywhere. For example, the "machine-id" field in the generated +snippets would not be a machine ID anymore, and the newly added +systemd.machine_id= kernel parameter would possibly get passed invalid +data. + +Hence clean this up: + +$MACHINE_ID → always a valid 128bit ID. + +$ENTRY_TOKEN → usually the $MACHINE_ID but can be any other string too. +This is used to name the directory to put kernels/initrds in. It's also +used for naming the *.conf snippets that implement the Boot Loader Type +1 spec. + +(cherry picked from commit 3907044ffa568aedf076d0f9807489ec78f87502) + +Related: #2065061 +--- + src/kernel-install/90-loaderentry.install | 11 ++++++----- + src/kernel-install/kernel-install | 21 +++++++++++++++++---- + 2 files changed, 23 insertions(+), 9 deletions(-) + +diff --git a/src/kernel-install/90-loaderentry.install b/src/kernel-install/90-loaderentry.install +index 046771169c..46261a2c11 100644 +--- a/src/kernel-install/90-loaderentry.install ++++ b/src/kernel-install/90-loaderentry.install +@@ -29,6 +29,7 @@ INITRD_OPTIONS_SHIFT=4 + [ "$KERNEL_INSTALL_LAYOUT" = "bls" ] || exit 0 + + MACHINE_ID="$KERNEL_INSTALL_MACHINE_ID" ++ENTRY_TOKEN="$KERNEL_INSTALL_ENTRY_TOKEN" + BOOT_ROOT="$KERNEL_INSTALL_BOOT_ROOT" + + BOOT_MNT="$(stat -c %m "$BOOT_ROOT")" +@@ -41,10 +42,10 @@ fi + case "$COMMAND" in + remove) + [ "$KERNEL_INSTALL_VERBOSE" -gt 0 ] && \ +- echo "Removing $BOOT_ROOT/loader/entries/$MACHINE_ID-$KERNEL_VERSION*.conf" ++ echo "Removing $BOOT_ROOT/loader/entries/$ENTRY_TOKEN-$KERNEL_VERSION*.conf" + exec rm -f \ +- "$BOOT_ROOT/loader/entries/$MACHINE_ID-$KERNEL_VERSION.conf" \ +- "$BOOT_ROOT/loader/entries/$MACHINE_ID-$KERNEL_VERSION+"*".conf" ++ "$BOOT_ROOT/loader/entries/$ENTRY_TOKEN-$KERNEL_VERSION.conf" \ ++ "$BOOT_ROOT/loader/entries/$ENTRY_TOKEN-$KERNEL_VERSION+"*".conf" + ;; + add) + ;; +@@ -80,9 +81,9 @@ if [ -r /etc/kernel/tries ]; then + echo "/etc/kernel/tries does not contain an integer." >&2 + exit 1 + fi +- LOADER_ENTRY="$BOOT_ROOT/loader/entries/$MACHINE_ID-$KERNEL_VERSION+$TRIES.conf" ++ LOADER_ENTRY="$BOOT_ROOT/loader/entries/$ENTRY_TOKEN-$KERNEL_VERSION+$TRIES.conf" + else +- LOADER_ENTRY="$BOOT_ROOT/loader/entries/$MACHINE_ID-$KERNEL_VERSION.conf" ++ LOADER_ENTRY="$BOOT_ROOT/loader/entries/$ENTRY_TOKEN-$KERNEL_VERSION.conf" + fi + + if ! [ -d "$ENTRY_DIR_ABS" ]; then +diff --git a/src/kernel-install/kernel-install b/src/kernel-install/kernel-install +index e94aa79bc6..75a31c62d4 100755 +--- a/src/kernel-install/kernel-install ++++ b/src/kernel-install/kernel-install +@@ -97,7 +97,19 @@ fi + [ -z "$MACHINE_ID" ] && [ -r /etc/machine-id ] && read -r MACHINE_ID +Date: Wed, 9 Feb 2022 14:44:48 +0100 +Subject: [PATCH] kernel-install: only generate systemd.boot_id= in kernel + command line if used for naming the boot loader spec files/dirs + +Now that we can distinguish the naming of the boot loader spec +dirs/files and the machine ID let's tweak the logic for suffixing the +kernel cmdline with systemd.boot_id=: let's only do that when we +actually need the boot ID for naming these dirs/files. If we don't, +let's not bother. + +This should be beneficial for "golden" images that shall not carry any +machine IDs at all, i.e acquire their identity only once the final +userspace is actually reached. + +(cherry picked from commit 953b61004c37948dcd897265b56c1613bc73b9f9) + +Related: #2065061 +--- + src/kernel-install/90-loaderentry.install | 18 +++++++++++++----- + 1 file changed, 13 insertions(+), 5 deletions(-) + +diff --git a/src/kernel-install/90-loaderentry.install b/src/kernel-install/90-loaderentry.install +index 46261a2c11..c1d69aa824 100644 +--- a/src/kernel-install/90-loaderentry.install ++++ b/src/kernel-install/90-loaderentry.install +@@ -70,10 +70,15 @@ else + BOOT_OPTIONS="$(tr -s "$IFS" '\n' +Date: Thu, 10 Feb 2022 14:27:22 +0100 +Subject: [PATCH] kernel-install: search harder for kernel image/initrd drop-in + dir + +If not explicitly configured, let's search a bit harder for the +ENTRY_TOKEN, and let's try the machine ID, the IMAGE_ID and ID fields of +/etc/os-release and finally "Default", all below potential $XBOOTLDR. + +(cherry picked from commit 6637cf9db67237857279262d93ee0e39023c5b85) + +Related: #2065061 +--- + src/kernel-install/kernel-install | 27 ++++++++++++++++++++++++--- + 1 file changed, 24 insertions(+), 3 deletions(-) + +diff --git a/src/kernel-install/kernel-install b/src/kernel-install/kernel-install +index 75a31c62d4..c42c40592a 100755 +--- a/src/kernel-install/kernel-install ++++ b/src/kernel-install/kernel-install +@@ -103,29 +103,50 @@ fi + # for naming the .conf boot loader spec entry. Typically this is just the + # machine ID, but it can be anything else, too, if we are told so. + [ -z "$ENTRY_TOKEN" ] && [ -r /etc/kernel/entry-token ] && read -r ENTRY_TOKEN +Date: Thu, 10 Feb 2022 14:37:37 +0100 +Subject: [PATCH] kernel-install: add new "inspect" verb, showing paths and + parameters we discovered + +(cherry picked from commit c73cf4184441d3cc37a5e2195938f07420ec38b7) + +Related: #2065061 +--- + src/kernel-install/kernel-install | 29 +++++++++++++++++++++++------ + 1 file changed, 23 insertions(+), 6 deletions(-) + +diff --git a/src/kernel-install/kernel-install b/src/kernel-install/kernel-install +index c42c40592a..b8099bd12c 100755 +--- a/src/kernel-install/kernel-install ++++ b/src/kernel-install/kernel-install +@@ -25,6 +25,7 @@ usage() + echo "Usage:" + echo " $0 [OPTIONS...] add KERNEL-VERSION KERNEL-IMAGE [INITRD-FILE ...]" + echo " $0 [OPTIONS...] remove KERNEL-VERSION" ++ echo " $0 [OPTIONS...] inspect" + echo "Options:" + echo " -h, --help Print this help" + echo " -v, --verbose Increase verbosity" +@@ -72,13 +73,17 @@ else + [ $# -ge 1 ] && shift + fi + +-if [ $# -lt 1 ]; then +- echo "Error: not enough arguments" >&2 +- exit 1 +-fi ++if [ "$COMMAND" = "inspect" ]; then ++ KERNEL_VERSION="" ++else ++ if [ $# -lt 1 ]; then ++ echo "Error: not enough arguments" >&2 ++ exit 1 ++ fi + +-KERNEL_VERSION="$1" +-shift ++ KERNEL_VERSION="$1" ++ shift ++fi + + layout= + initrd_generator= +@@ -237,6 +242,18 @@ case "$COMMAND" in + fi + ;; + ++ inspect) ++ echo "KERNEL_INSTALL_MACHINE_ID: $KERNEL_INSTALL_MACHINE_ID" ++ echo "KERNEL_INSTALL_ENTRY_TOKEN: $KERNEL_INSTALL_ENTRY_TOKEN" ++ echo "KERNEL_INSTALL_BOOT_ROOT: $KERNEL_INSTALL_BOOT_ROOT" ++ echo "KERNEL_INSTALL_LAYOUT: $KERNEL_INSTALL_LAYOUT" ++ echo "KERNEL_INSTALL_INITRD_GENERATOR: $KERNEL_INSTALL_INITRD_GENERATOR" ++ echo "ENTRY_DIR_ABS: $KERNEL_INSTALL_BOOT_ROOT/$ENTRY_TOKEN/\$KERNEL_VERSION" ++ ++ # Assert that ENTRY_DIR_ABS actually matches what we are printing here ++ [ "${ENTRY_DIR_ABS%/*}" = "$KERNEL_INSTALL_BOOT_ROOT/$ENTRY_TOKEN" ] || { echo "Assertion didn't pass." >&2; exit 1; } ++ ++ ;; + *) + echo "Error: unknown command '$COMMAND'" >&2 + exit 1 diff --git a/0099-ci-Mergify-configuration-update.patch b/0099-ci-Mergify-configuration-update.patch new file mode 100644 index 0000000..992cdf9 --- /dev/null +++ b/0099-ci-Mergify-configuration-update.patch @@ -0,0 +1,97 @@ +From caf80cd558222a08687e8db95e3e1fcad0d69946 Mon Sep 17 00:00:00 2001 +From: Jan Macku +Date: Mon, 30 May 2022 15:19:16 +0200 +Subject: [PATCH] ci(Mergify): configuration update + +Add rules for `needs-ci` label management + +RHEL-only + +Related: #2087652 +--- + .mergify.yml | 76 ++++++++++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 76 insertions(+) + create mode 100644 .mergify.yml + +diff --git a/.mergify.yml b/.mergify.yml +new file mode 100644 +index 0000000000..c06e0fb1be +--- /dev/null ++++ b/.mergify.yml +@@ -0,0 +1,76 @@ ++# doc: https://docs.mergify.com ++--- ++ ++pull_request_rules: ++ - name: Add `needs-ci` label on CI fail ++ conditions: ++ - or: ++ # Build test ++ - -check-success=build (gcc, 10, bfd) ++ - -check-success=build (gcc, 11, gold) ++ - -check-success=build (clang, 11, bfd) ++ - -check-success=build (clang, 12, gold) ++ - -check-success=build (clang, 13, lld) ++ # Unit tests ++ - -check-success=build (GCC, auto) ++ - -check-success=build (GCC_ASAN_UBSAN, auto) ++ - -check-success=build (CLANG, auto) ++ - -check-success=build (CLANG_ASAN_UBSAN, auto) ++ - -check-success=build (GCC, openssl) ++ - -check-success=build (CLANG, gcrypt) ++ # CentOS CI ++ - -check-success=CentOS CI (CentOS Stream 9) ++ - -check-success=CentOS CI (CentOS Stream 9 + sanitizers) ++ # LGTM ++ - and: ++ - "-check-success=LGTM analysis: JavaScript" ++ - "-check-neutral=LGTM analysis: JavaScript" ++ - and: ++ - "-check-success=LGTM analysis: Python" ++ - "-check-neutral=LGTM analysis: Python" ++ - and: ++ - "-check-success=LGTM analysis: C/C++" ++ - "-check-neutral=LGTM analysis: Python" ++ # Packit ++ - -check-success=rpm-build:centos-stream-9-aarch64 ++ - -check-success=rpm-build:centos-stream-9-x86_64 ++ actions: ++ label: ++ add: ++ - needs-ci ++ ++ - name: Remove `needs-ci` label on CI success ++ conditions: ++ # Build test ++ - check-success=build (gcc, 10, bfd) ++ - check-success=build (gcc, 11, gold) ++ - check-success=build (clang, 11, bfd) ++ - check-success=build (clang, 12, gold) ++ - check-success=build (clang, 13, lld) ++ # Unit tests ++ - check-success=build (GCC, auto) ++ - check-success=build (GCC_ASAN_UBSAN, auto) ++ - check-success=build (CLANG, auto) ++ - check-success=build (CLANG_ASAN_UBSAN, auto) ++ - check-success=build (GCC, openssl) ++ - check-success=build (CLANG, gcrypt) ++ # CentOS CI ++ - check-success=CentOS CI (CentOS Stream 9) ++ - check-success=CentOS CI (CentOS Stream 9 + sanitizers) ++ # LGTM ++ - or: ++ - "check-success=LGTM analysis: JavaScript" ++ - "check-neutral=LGTM analysis: JavaScript" ++ - or: ++ - "check-success=LGTM analysis: Python" ++ - "check-neutral=LGTM analysis: Python" ++ - or: ++ - "check-success=LGTM analysis: C/C++" ++ - "check-neutral=LGTM analysis: Python" ++ # Packit ++ - check-success=rpm-build:centos-stream-9-aarch64 ++ - check-success=rpm-build:centos-stream-9-x86_64 ++ actions: ++ label: ++ remove: ++ - needs-ci diff --git a/0100-ci-Mergify-fix-copy-paste-bug.patch b/0100-ci-Mergify-fix-copy-paste-bug.patch new file mode 100644 index 0000000..b907dea --- /dev/null +++ b/0100-ci-Mergify-fix-copy-paste-bug.patch @@ -0,0 +1,34 @@ +From 14b8f663049a902aac962f9a522595df9db6b6bc Mon Sep 17 00:00:00 2001 +From: David Tardon +Date: Mon, 6 Jun 2022 15:39:22 +0200 +Subject: [PATCH] ci(Mergify): fix copy&paste bug + +RHEL-only + +Related: #2087652 +--- + .mergify.yml | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/.mergify.yml b/.mergify.yml +index c06e0fb1be..b7852b201c 100644 +--- a/.mergify.yml ++++ b/.mergify.yml +@@ -30,7 +30,7 @@ pull_request_rules: + - "-check-neutral=LGTM analysis: Python" + - and: + - "-check-success=LGTM analysis: C/C++" +- - "-check-neutral=LGTM analysis: Python" ++ - "-check-neutral=LGTM analysis: C/C++" + # Packit + - -check-success=rpm-build:centos-stream-9-aarch64 + - -check-success=rpm-build:centos-stream-9-x86_64 +@@ -66,7 +66,7 @@ pull_request_rules: + - "check-neutral=LGTM analysis: Python" + - or: + - "check-success=LGTM analysis: C/C++" +- - "check-neutral=LGTM analysis: Python" ++ - "check-neutral=LGTM analysis: C/C++" + # Packit + - check-success=rpm-build:centos-stream-9-aarch64 + - check-success=rpm-build:centos-stream-9-x86_64 diff --git a/0101-shared-Fix-memory-leak-in-bus_append_execute_propert.patch b/0101-shared-Fix-memory-leak-in-bus_append_execute_propert.patch new file mode 100644 index 0000000..9b8fcce --- /dev/null +++ b/0101-shared-Fix-memory-leak-in-bus_append_execute_propert.patch @@ -0,0 +1,26 @@ +From 18b0bc42dc097af6147324deef100c41dedfa755 Mon Sep 17 00:00:00 2001 +From: Daan De Meyer +Date: Mon, 9 May 2022 09:50:32 +0200 +Subject: [PATCH] shared: Fix memory leak in bus_append_execute_property() + +Fixes #23317 + +(cherry picked from commit 2aaf6d407e8541985a15b7106abf6fbdfed0766a) +Related: #2087652 +--- + src/shared/bus-unit-util.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c +index dcce530c99..ef134bcee4 100644 +--- a/src/shared/bus-unit-util.c ++++ b/src/shared/bus-unit-util.c +@@ -1952,7 +1952,7 @@ static int bus_append_execute_property(sd_bus_message *m, const char *field, con + path_simplify(source); + + if (isempty(destination)) { +- r = strv_extend(&sources, TAKE_PTR(source)); ++ r = strv_consume(&sources, TAKE_PTR(source)); + if (r < 0) + return bus_log_create_error(r); + } else { diff --git a/0102-fuzz-no-longer-skip-empty-files.patch b/0102-fuzz-no-longer-skip-empty-files.patch new file mode 100644 index 0000000..b6f91c3 --- /dev/null +++ b/0102-fuzz-no-longer-skip-empty-files.patch @@ -0,0 +1,187 @@ +From 0235f9ea3d221aba513f4b6215418bf554e02791 Mon Sep 17 00:00:00 2001 +From: Evgeny Vereshchagin +Date: Mon, 3 Jan 2022 12:31:07 +0000 +Subject: [PATCH] fuzz: no longer skip empty files + +Empty files and empty strings seem to have triggered various +issues in the past so it seems they shouldn't be ignore by the +fuzzers just because fmemopen can't handle them. + +Prompted by https://github.com/systemd/systemd/pull/21939#issuecomment-1003113669 + +(cherry picked from commit 5df66d7d68006615abb4c4d3b1ebad545af4dd72) +Related: #2087652 +--- + src/core/fuzz-unit-file.c | 6 +----- + src/fuzz/fuzz-env-file.c | 5 ++--- + src/fuzz/fuzz-hostname-setup.c | 6 +----- + src/fuzz/fuzz-json.c | 6 +----- + src/fuzz/fuzz.h | 9 +++++++++ + src/nspawn/fuzz-nspawn-oci.c | 6 +----- + src/nspawn/fuzz-nspawn-settings.c | 6 +----- + 7 files changed, 16 insertions(+), 28 deletions(-) + +diff --git a/src/core/fuzz-unit-file.c b/src/core/fuzz-unit-file.c +index aef29f4cf7..780dd3988d 100644 +--- a/src/core/fuzz-unit-file.c ++++ b/src/core/fuzz-unit-file.c +@@ -2,7 +2,6 @@ + + #include "conf-parser.h" + #include "fd-util.h" +-#include "fileio.h" + #include "fuzz.h" + #include "install.h" + #include "load-fragment.h" +@@ -22,10 +21,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { + const char *name; + long offset; + +- if (size == 0) +- return 0; +- +- f = fmemopen_unlocked((char*) data, size, "re"); ++ f = data_to_file(data, size); + assert_se(f); + + if (read_line(f, LINE_MAX, &p) < 0) +diff --git a/src/fuzz/fuzz-env-file.c b/src/fuzz/fuzz-env-file.c +index e0dac260b0..3b3e625608 100644 +--- a/src/fuzz/fuzz-env-file.c ++++ b/src/fuzz/fuzz-env-file.c +@@ -4,7 +4,6 @@ + + #include "alloc-util.h" + #include "env-file.h" +-#include "fileio.h" + #include "fd-util.h" + #include "fuzz.h" + #include "strv.h" +@@ -13,10 +12,10 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { + _cleanup_fclose_ FILE *f = NULL; + _cleanup_strv_free_ char **rl = NULL, **rlp = NULL; + +- if (size == 0 || size > 65535) ++ if (size > 65535) + return 0; + +- f = fmemopen_unlocked((char*) data, size, "re"); ++ f = data_to_file(data, size); + assert_se(f); + + /* We don't want to fill the logs with messages about parse errors. +diff --git a/src/fuzz/fuzz-hostname-setup.c b/src/fuzz/fuzz-hostname-setup.c +index b8d36da54a..d7c23eef12 100644 +--- a/src/fuzz/fuzz-hostname-setup.c ++++ b/src/fuzz/fuzz-hostname-setup.c +@@ -2,7 +2,6 @@ + + #include "alloc-util.h" + #include "fd-util.h" +-#include "fileio.h" + #include "fuzz.h" + #include "hostname-setup.h" + +@@ -10,10 +9,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { + _cleanup_fclose_ FILE *f = NULL; + _cleanup_free_ char *ret = NULL; + +- if (size == 0) +- return 0; +- +- f = fmemopen_unlocked((char*) data, size, "re"); ++ f = data_to_file(data, size); + assert_se(f); + + /* We don't want to fill the logs with messages about parse errors. +diff --git a/src/fuzz/fuzz-json.c b/src/fuzz/fuzz-json.c +index f9a0e818c4..ad7460c6fd 100644 +--- a/src/fuzz/fuzz-json.c ++++ b/src/fuzz/fuzz-json.c +@@ -1,7 +1,6 @@ + /* SPDX-License-Identifier: LGPL-2.1-or-later */ + + #include "alloc-util.h" +-#include "fileio.h" + #include "fd-util.h" + #include "fuzz.h" + #include "json.h" +@@ -12,10 +11,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { + _cleanup_fclose_ FILE *f = NULL, *g = NULL; + _cleanup_(json_variant_unrefp) JsonVariant *v = NULL; + +- if (size == 0) +- return 0; +- +- f = fmemopen_unlocked((char*) data, size, "re"); ++ f = data_to_file(data, size); + assert_se(f); + + if (json_parse_file(f, NULL, 0, &v, NULL, NULL) < 0) +diff --git a/src/fuzz/fuzz.h b/src/fuzz/fuzz.h +index 579b0eed73..d7cbb0bb16 100644 +--- a/src/fuzz/fuzz.h ++++ b/src/fuzz/fuzz.h +@@ -4,5 +4,14 @@ + #include + #include + ++#include "fileio.h" ++ + /* The entry point into the fuzzer */ + int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size); ++ ++static inline FILE* data_to_file(const uint8_t *data, size_t size) { ++ if (size == 0) ++ return fopen("/dev/null", "re"); ++ else ++ return fmemopen_unlocked((char*) data, size, "re"); ++} +diff --git a/src/nspawn/fuzz-nspawn-oci.c b/src/nspawn/fuzz-nspawn-oci.c +index cfebf65c00..91f2a81dfc 100644 +--- a/src/nspawn/fuzz-nspawn-oci.c ++++ b/src/nspawn/fuzz-nspawn-oci.c +@@ -2,7 +2,6 @@ + + #include "alloc-util.h" + #include "fd-util.h" +-#include "fileio.h" + #include "fuzz.h" + #include "nspawn-oci.h" + +@@ -10,10 +9,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { + _cleanup_fclose_ FILE *f = NULL; + _cleanup_(settings_freep) Settings *s = NULL; + +- if (size == 0) +- return 0; +- +- f = fmemopen_unlocked((char*) data, size, "re"); ++ f = data_to_file(data, size); + assert_se(f); + + /* We don't want to fill the logs with messages about parse errors. +diff --git a/src/nspawn/fuzz-nspawn-settings.c b/src/nspawn/fuzz-nspawn-settings.c +index bd98ed26e8..6b91e1506e 100644 +--- a/src/nspawn/fuzz-nspawn-settings.c ++++ b/src/nspawn/fuzz-nspawn-settings.c +@@ -2,7 +2,6 @@ + + #include "alloc-util.h" + #include "fd-util.h" +-#include "fileio.h" + #include "fuzz.h" + #include "nspawn-settings.h" + +@@ -10,10 +9,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { + _cleanup_fclose_ FILE *f = NULL; + _cleanup_(settings_freep) Settings *s = NULL; + +- if (size == 0) +- return 0; +- +- f = fmemopen_unlocked((char*) data, size, "re"); ++ f = data_to_file(data, size); + assert_se(f); + + /* We don't want to fill the logs with messages about parse errors. diff --git a/0103-networkctl-open-the-bus-just-once.patch b/0103-networkctl-open-the-bus-just-once.patch new file mode 100644 index 0000000..d36d4d0 --- /dev/null +++ b/0103-networkctl-open-the-bus-just-once.patch @@ -0,0 +1,276 @@ +From 3852f94de9582dc1acb44844579873cd0e2f3162 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Tue, 11 Jan 2022 15:12:42 +0100 +Subject: [PATCH] networkctl: open the bus just once + +We'd connect to the bus twice: the first time to check networkd namespace, +and then the second time to do the deed we were asked to do. It's nicer +to open the bus just once, for efficience and also to avoid the open call +in all functions. + +An ASSERT_PTR helper is added: +- sd_bus *bus = userdata; + ... +- assert(bus); ++ sd_bus *bus = ASSERT_PTR(userdata); + ... + +It can be used in other place too, but I'm leaving that for a later +refactoring. + +(cherry picked from commit d821e40ca96d2b14216f7a18e4512364bfb83628) +Related: #2087652 +--- + src/fundamental/macro-fundamental.h | 8 ++++ + src/network/networkctl.c | 74 ++++++++++------------------- + 2 files changed, 33 insertions(+), 49 deletions(-) + +diff --git a/src/fundamental/macro-fundamental.h b/src/fundamental/macro-fundamental.h +index f87839d47b..d597c743bb 100644 +--- a/src/fundamental/macro-fundamental.h ++++ b/src/fundamental/macro-fundamental.h +@@ -66,6 +66,14 @@ + #define free(a) FreePool(a) + #endif + ++/* This passes the argument through after (if asserts are enabled) checking that it is not null. */ ++#define ASSERT_PTR(expr) \ ++ ({ \ ++ typeof(expr) _expr_ = (expr); \ ++ assert(_expr_); \ ++ _expr_; \ ++ }) ++ + #if defined(static_assert) + #define assert_cc(expr) \ + static_assert(expr, #expr) +diff --git a/src/network/networkctl.c b/src/network/networkctl.c +index 68dd4b185c..c35f851bdb 100644 +--- a/src/network/networkctl.c ++++ b/src/network/networkctl.c +@@ -79,17 +79,12 @@ static bool arg_full = false; + static unsigned arg_lines = 10; + static JsonFormatFlags arg_json_format_flags = JSON_FORMAT_OFF; + +-static int get_description(JsonVariant **ret) { ++static int get_description(sd_bus *bus, JsonVariant **ret) { + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; +- _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL; + const char *text = NULL; + int r; + +- r = sd_bus_open_system(&bus); +- if (r < 0) +- return log_error_errno(r, "Failed to connect system bus: %m"); +- + r = bus_call_method(bus, bus_network_mgr, "Describe", &error, &reply, NULL); + if (r < 0) + return log_error_errno(r, "Failed to get description: %s", bus_error_message(&error, r)); +@@ -105,11 +100,11 @@ static int get_description(JsonVariant **ret) { + return 0; + } + +-static int dump_manager_description(void) { ++static int dump_manager_description(sd_bus *bus) { + _cleanup_(json_variant_unrefp) JsonVariant *v = NULL; + int r; + +- r = get_description(&v); ++ r = get_description(bus, &v); + if (r < 0) + return r; + +@@ -117,14 +112,14 @@ static int dump_manager_description(void) { + return 0; + } + +-static int dump_link_description(char **patterns) { ++static int dump_link_description(sd_bus *bus, char **patterns) { + _cleanup_(json_variant_unrefp) JsonVariant *v = NULL; + _cleanup_free_ bool *matched_patterns = NULL; + JsonVariant *i; + size_t c = 0; + int r; + +- r = get_description(&v); ++ r = get_description(bus, &v); + if (r < 0) + return r; + +@@ -790,6 +785,7 @@ static int acquire_link_info(sd_bus *bus, sd_netlink *rtnl, char **patterns, Lin + } + + static int list_links(int argc, char *argv[], void *userdata) { ++ sd_bus *bus = ASSERT_PTR(userdata); + _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL; + _cleanup_(link_info_array_freep) LinkInfo *links = NULL; + _cleanup_(table_unrefp) Table *table = NULL; +@@ -798,9 +794,9 @@ static int list_links(int argc, char *argv[], void *userdata) { + + if (arg_json_format_flags != JSON_FORMAT_OFF) { + if (arg_all || argc <= 1) +- return dump_manager_description(); ++ return dump_manager_description(bus); + else +- return dump_link_description(strv_skip(argv, 1)); ++ return dump_link_description(bus, strv_skip(argv, 1)); + } + + r = sd_netlink_open(&rtnl); +@@ -2383,7 +2379,7 @@ static int system_status(sd_netlink *rtnl, sd_hwdb *hwdb) { + } + + static int link_status(int argc, char *argv[], void *userdata) { +- _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL; ++ sd_bus *bus = ASSERT_PTR(userdata); + _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL; + _cleanup_(sd_hwdb_unrefp) sd_hwdb *hwdb = NULL; + _cleanup_(link_info_array_freep) LinkInfo *links = NULL; +@@ -2391,17 +2387,13 @@ static int link_status(int argc, char *argv[], void *userdata) { + + if (arg_json_format_flags != JSON_FORMAT_OFF) { + if (arg_all || argc <= 1) +- return dump_manager_description(); ++ return dump_manager_description(bus); + else +- return dump_link_description(strv_skip(argv, 1)); ++ return dump_link_description(bus, strv_skip(argv, 1)); + } + + pager_open(arg_pager_flags); + +- r = sd_bus_open_system(&bus); +- if (r < 0) +- return log_error_errno(r, "Failed to connect system bus: %m"); +- + r = sd_netlink_open(&rtnl); + if (r < 0) + return log_error_errno(r, "Failed to connect to netlink: %m"); +@@ -2738,14 +2730,10 @@ static int link_renew_one(sd_bus *bus, int index, const char *name) { + } + + static int link_renew(int argc, char *argv[], void *userdata) { +- _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL; ++ sd_bus *bus = ASSERT_PTR(userdata); + _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL; + int index, k = 0, r; + +- r = sd_bus_open_system(&bus); +- if (r < 0) +- return log_error_errno(r, "Failed to connect system bus: %m"); +- + for (int i = 1; i < argc; i++) { + index = rtnl_resolve_interface_or_warn(&rtnl, argv[i]); + if (index < 0) +@@ -2772,14 +2760,10 @@ static int link_force_renew_one(sd_bus *bus, int index, const char *name) { + } + + static int link_force_renew(int argc, char *argv[], void *userdata) { +- _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL; ++ sd_bus *bus = ASSERT_PTR(userdata); + _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL; + int k = 0, r; + +- r = sd_bus_open_system(&bus); +- if (r < 0) +- return log_error_errno(r, "Failed to connect system bus: %m"); +- + for (int i = 1; i < argc; i++) { + int index = rtnl_resolve_interface_or_warn(&rtnl, argv[i]); + if (index < 0) +@@ -2794,14 +2778,10 @@ static int link_force_renew(int argc, char *argv[], void *userdata) { + } + + static int verb_reload(int argc, char *argv[], void *userdata) { ++ sd_bus *bus = ASSERT_PTR(userdata); + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; +- _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL; + int r; + +- r = sd_bus_open_system(&bus); +- if (r < 0) +- return log_error_errno(r, "Failed to connect system bus: %m"); +- + r = bus_call_method(bus, bus_network_mgr, "Reload", &error, NULL, NULL); + if (r < 0) + return log_error_errno(r, "Failed to reload network settings: %m"); +@@ -2810,17 +2790,13 @@ static int verb_reload(int argc, char *argv[], void *userdata) { + } + + static int verb_reconfigure(int argc, char *argv[], void *userdata) { ++ sd_bus *bus = ASSERT_PTR(userdata); + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; +- _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL; + _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL; + _cleanup_set_free_ Set *indexes = NULL; + int index, r; + void *p; + +- r = sd_bus_open_system(&bus); +- if (r < 0) +- return log_error_errno(r, "Failed to connect system bus: %m"); +- + indexes = set_new(NULL); + if (!indexes) + return log_oom(); +@@ -2968,7 +2944,7 @@ static int parse_argv(int argc, char *argv[]) { + return 1; + } + +-static int networkctl_main(int argc, char *argv[]) { ++static int networkctl_main(sd_bus *bus, int argc, char *argv[]) { + static const Verb verbs[] = { + { "list", VERB_ANY, VERB_ANY, VERB_DEFAULT, list_links }, + { "status", VERB_ANY, VERB_ANY, 0, link_status }, +@@ -2984,20 +2960,15 @@ static int networkctl_main(int argc, char *argv[]) { + {} + }; + +- return dispatch_verb(argc, argv, verbs, NULL); ++ return dispatch_verb(argc, argv, verbs, bus); + } + +-static int check_netns_match(void) { ++static int check_netns_match(sd_bus *bus) { + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; +- _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL; + struct stat st; + uint64_t id; + int r; + +- r = sd_bus_open_system(&bus); +- if (r < 0) +- return log_error_errno(r, "Failed to connect system bus: %m"); +- + r = sd_bus_get_property_trivial( + bus, + "org.freedesktop.network1", +@@ -3035,6 +3006,7 @@ static void warn_networkd_missing(void) { + } + + static int run(int argc, char* argv[]) { ++ _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL; + int r; + + log_setup(); +@@ -3043,13 +3015,17 @@ static int run(int argc, char* argv[]) { + if (r <= 0) + return r; + +- r = check_netns_match(); ++ r = sd_bus_open_system(&bus); ++ if (r < 0) ++ return log_error_errno(r, "Failed to connect system bus: %m"); ++ ++ r = check_netns_match(bus); + if (r < 0) + return r; + + warn_networkd_missing(); + +- return networkctl_main(argc, argv); ++ return networkctl_main(bus, argc, argv); + } + + DEFINE_MAIN_FUNCTION(run); diff --git a/0104-json-align-table.patch b/0104-json-align-table.patch new file mode 100644 index 0000000..d058681 --- /dev/null +++ b/0104-json-align-table.patch @@ -0,0 +1,55 @@ +From ee588179205de7c1584bd45bd22ec59028f11405 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Mon, 9 May 2022 10:24:36 +0200 +Subject: [PATCH] json: align table + +(cherry picked from commit 9674b089cfb1f75653579e83735e049ddcbbed7e) +Related: #2087652 +--- + src/shared/json.c | 18 ++++++++---------- + 1 file changed, 8 insertions(+), 10 deletions(-) + +diff --git a/src/shared/json.c b/src/shared/json.c +index dff95eda26..6375b87a0b 100644 +--- a/src/shared/json.c ++++ b/src/shared/json.c +@@ -4754,7 +4754,6 @@ bool json_variant_is_sorted(JsonVariant *v) { + } + + int json_variant_unbase64(JsonVariant *v, void **ret, size_t *ret_size) { +- + if (!json_variant_is_string(v)) + return -EINVAL; + +@@ -4762,7 +4761,6 @@ int json_variant_unbase64(JsonVariant *v, void **ret, size_t *ret_size) { + } + + int json_variant_unhex(JsonVariant *v, void **ret, size_t *ret_size) { +- + if (!json_variant_is_string(v)) + return -EINVAL; + +@@ -4770,15 +4768,15 @@ int json_variant_unhex(JsonVariant *v, void **ret, size_t *ret_size) { + } + + static const char* const json_variant_type_table[_JSON_VARIANT_TYPE_MAX] = { +- [JSON_VARIANT_STRING] = "string", +- [JSON_VARIANT_INTEGER] = "integer", ++ [JSON_VARIANT_STRING] = "string", ++ [JSON_VARIANT_INTEGER] = "integer", + [JSON_VARIANT_UNSIGNED] = "unsigned", +- [JSON_VARIANT_REAL] = "real", +- [JSON_VARIANT_NUMBER] = "number", +- [JSON_VARIANT_BOOLEAN] = "boolean", +- [JSON_VARIANT_ARRAY] = "array", +- [JSON_VARIANT_OBJECT] = "object", +- [JSON_VARIANT_NULL] = "null", ++ [JSON_VARIANT_REAL] = "real", ++ [JSON_VARIANT_NUMBER] = "number", ++ [JSON_VARIANT_BOOLEAN] = "boolean", ++ [JSON_VARIANT_ARRAY] = "array", ++ [JSON_VARIANT_OBJECT] = "object", ++ [JSON_VARIANT_NULL] = "null", + }; + + DEFINE_STRING_TABLE_LOOKUP(json_variant_type, JsonVariantType); diff --git a/0105-fuzz-json-optionally-allow-logging-and-output.patch b/0105-fuzz-json-optionally-allow-logging-and-output.patch new file mode 100644 index 0000000..c3e3f22 --- /dev/null +++ b/0105-fuzz-json-optionally-allow-logging-and-output.patch @@ -0,0 +1,60 @@ +From 3087505025b78b80951ab3a5f496eb255f1a9a21 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Mon, 9 May 2022 10:41:36 +0200 +Subject: [PATCH] fuzz-json: optionally allow logging and output +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Similarly to other fuzzers… this makes development easier. + +(cherry picked from commit 9ad955ce40e244a52984c68ae2a6b151d918b4a8) +Related: #2087652 +--- + src/fuzz/fuzz-json.c | 19 ++++++++++++++----- + 1 file changed, 14 insertions(+), 5 deletions(-) + +diff --git a/src/fuzz/fuzz-json.c b/src/fuzz/fuzz-json.c +index ad7460c6fd..648a6d441d 100644 +--- a/src/fuzz/fuzz-json.c ++++ b/src/fuzz/fuzz-json.c +@@ -1,6 +1,7 @@ + /* SPDX-License-Identifier: LGPL-2.1-or-later */ + + #include "alloc-util.h" ++#include "env-util.h" + #include "fd-util.h" + #include "fuzz.h" + #include "json.h" +@@ -10,18 +11,26 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { + size_t out_size; + _cleanup_fclose_ FILE *f = NULL, *g = NULL; + _cleanup_(json_variant_unrefp) JsonVariant *v = NULL; ++ int r; ++ ++ /* Disable most logging if not running standalone */ ++ if (!getenv("SYSTEMD_LOG_LEVEL")) ++ log_set_max_level(LOG_CRIT); + + f = data_to_file(data, size); + assert_se(f); + +- if (json_parse_file(f, NULL, 0, &v, NULL, NULL) < 0) ++ r = json_parse_file(f, NULL, 0, &v, NULL, NULL); ++ if (r < 0) { ++ log_debug_errno(r, "failed to parse input: %m"); + return 0; ++ } + +- g = open_memstream_unlocked(&out, &out_size); +- assert_se(g); ++ if (getenv_bool("SYSTEMD_FUZZ_OUTPUT") <= 0) ++ assert_se(g = open_memstream_unlocked(&out, &out_size)); + +- json_variant_dump(v, 0, g, NULL); +- json_variant_dump(v, JSON_FORMAT_PRETTY|JSON_FORMAT_COLOR|JSON_FORMAT_SOURCE, g, NULL); ++ json_variant_dump(v, 0, g ?: stdout, NULL); ++ json_variant_dump(v, JSON_FORMAT_PRETTY|JSON_FORMAT_COLOR|JSON_FORMAT_SOURCE, g ?: stdout, NULL); + + return 0; + } diff --git a/0106-shared-json-reduce-scope-of-variables.patch b/0106-shared-json-reduce-scope-of-variables.patch new file mode 100644 index 0000000..f9f2214 --- /dev/null +++ b/0106-shared-json-reduce-scope-of-variables.patch @@ -0,0 +1,435 @@ +From 272d6e85877bb436709ed54c02d3b68101e0438d Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Mon, 9 May 2022 11:01:32 +0200 +Subject: [PATCH] shared/json: reduce scope of variables + +(cherry picked from commit a4669764f7329d1e8a3d364db519500355cea5f0) +Related: #2087652 +--- + src/shared/json.c | 133 +++++++++++++++++++--------------------------- + 1 file changed, 54 insertions(+), 79 deletions(-) + +diff --git a/src/shared/json.c b/src/shared/json.c +index 6375b87a0b..d35874f8e3 100644 +--- a/src/shared/json.c ++++ b/src/shared/json.c +@@ -574,9 +574,6 @@ int json_variant_new_array(JsonVariant **ret, JsonVariant **array, size_t n) { + } + + int json_variant_new_array_bytes(JsonVariant **ret, const void *p, size_t n) { +- JsonVariant *v; +- size_t i; +- + assert_return(ret, -EINVAL); + if (n == 0) { + *ret = JSON_VARIANT_MAGIC_EMPTY_ARRAY; +@@ -584,7 +581,7 @@ int json_variant_new_array_bytes(JsonVariant **ret, const void *p, size_t n) { + } + assert_return(p, -EINVAL); + +- v = new(JsonVariant, n + 1); ++ JsonVariant *v = new(JsonVariant, n + 1); + if (!v) + return -ENOMEM; + +@@ -595,7 +592,7 @@ int json_variant_new_array_bytes(JsonVariant **ret, const void *p, size_t n) { + .depth = 1, + }; + +- for (i = 0; i < n; i++) { ++ for (size_t i = 0; i < n; i++) { + JsonVariant *w = v + 1 + i; + + *w = (JsonVariant) { +@@ -790,12 +787,9 @@ static void json_variant_free_inner(JsonVariant *v, bool force_sensitive) { + return; + } + +- if (IN_SET(v->type, JSON_VARIANT_ARRAY, JSON_VARIANT_OBJECT)) { +- size_t i; +- +- for (i = 0; i < v->n_elements; i++) ++ if (IN_SET(v->type, JSON_VARIANT_ARRAY, JSON_VARIANT_OBJECT)) ++ for (size_t i = 0; i < v->n_elements; i++) + json_variant_free_inner(v + 1 + i, sensitive); +- } + + if (sensitive) + explicit_bzero_safe(v, json_variant_size(v)); +@@ -839,11 +833,9 @@ JsonVariant *json_variant_unref(JsonVariant *v) { + } + + void json_variant_unref_many(JsonVariant **array, size_t n) { +- size_t i; +- + assert(array || n == 0); + +- for (i = 0; i < n; i++) ++ for (size_t i = 0; i < n; i++) + json_variant_unref(array[i]); + } + +@@ -1218,8 +1210,6 @@ mismatch: + } + + JsonVariant *json_variant_by_key_full(JsonVariant *v, const char *key, JsonVariant **ret_key) { +- size_t i; +- + if (!v) + goto not_found; + if (!key) +@@ -1241,6 +1231,7 @@ JsonVariant *json_variant_by_key_full(JsonVariant *v, const char *key, JsonVaria + while (b > a) { + JsonVariant *p; + const char *f; ++ size_t i; + int c; + + i = (a + b) / 2; +@@ -1264,7 +1255,7 @@ JsonVariant *json_variant_by_key_full(JsonVariant *v, const char *key, JsonVaria + } + + /* The variant is not sorted, hence search for the field linearly */ +- for (i = 0; i < v->n_elements; i += 2) { ++ for (size_t i = 0; i < v->n_elements; i += 2) { + JsonVariant *p; + + p = json_variant_dereference(v + 1 + i); +@@ -1335,34 +1326,28 @@ bool json_variant_equal(JsonVariant *a, JsonVariant *b) { + return true; + + case JSON_VARIANT_ARRAY: { +- size_t i, n; +- +- n = json_variant_elements(a); ++ size_t n = json_variant_elements(a); + if (n != json_variant_elements(b)) + return false; + +- for (i = 0; i < n; i++) { ++ for (size_t i = 0; i < n; i++) + if (!json_variant_equal(json_variant_by_index(a, i), json_variant_by_index(b, i))) + return false; +- } + + return true; + } + + case JSON_VARIANT_OBJECT: { +- size_t i, n; +- +- n = json_variant_elements(a); ++ size_t n = json_variant_elements(a); + if (n != json_variant_elements(b)) + return false; + + /* Iterate through all keys in 'a' */ +- for (i = 0; i < n; i += 2) { ++ for (size_t i = 0; i < n; i += 2) { + bool found = false; +- size_t j; + + /* Match them against all keys in 'b' */ +- for (j = 0; j < n; j += 2) { ++ for (size_t j = 0; j < n; j += 2) { + JsonVariant *key_b; + + key_b = json_variant_by_index(b, j); +@@ -1470,16 +1455,14 @@ static int print_source(FILE *f, JsonVariant *v, JsonFormatFlags flags, bool whi + DECIMAL_STR_MAX(unsigned) -1; + + if (whitespace) { +- size_t i, n; +- +- n = 1 + (v->source ? strlen(v->source->name) : 0) + +- ((v->source && (v->line > 0 || v->column > 0)) ? 1 : 0) + +- (v->line > 0 ? w : 0) + +- (((v->source || v->line > 0) && v->column > 0) ? 1 : 0) + +- (v->column > 0 ? k : 0) + +- 2; +- +- for (i = 0; i < n; i++) ++ size_t n = 1 + (v->source ? strlen(v->source->name) : 0) + ++ ((v->source && (v->line > 0 || v->column > 0)) ? 1 : 0) + ++ (v->line > 0 ? w : 0) + ++ (((v->source || v->line > 0) && v->column > 0) ? 1 : 0) + ++ (v->column > 0 ? k : 0) + ++ 2; ++ ++ for (size_t i = 0; i < n; i++) + fputc(' ', f); + } else { + fputc('[', f); +@@ -1631,10 +1614,7 @@ static int json_format(FILE *f, JsonVariant *v, JsonFormatFlags flags, const cha + break; + + case JSON_VARIANT_ARRAY: { +- size_t i, n; +- +- n = json_variant_elements(v); +- ++ size_t n = json_variant_elements(v); + if (n == 0) + fputs("[]", f); + else { +@@ -1653,7 +1633,7 @@ static int json_format(FILE *f, JsonVariant *v, JsonFormatFlags flags, const cha + fputc('[', f); + } + +- for (i = 0; i < n; i++) { ++ for (size_t i = 0; i < n; i++) { + JsonVariant *e; + + assert_se(e = json_variant_by_index(v, i)); +@@ -1687,10 +1667,7 @@ static int json_format(FILE *f, JsonVariant *v, JsonFormatFlags flags, const cha + } + + case JSON_VARIANT_OBJECT: { +- size_t i, n; +- +- n = json_variant_elements(v); +- ++ size_t n = json_variant_elements(v); + if (n == 0) + fputs("{}", f); + else { +@@ -1709,7 +1686,7 @@ static int json_format(FILE *f, JsonVariant *v, JsonFormatFlags flags, const cha + fputc('{', f); + } + +- for (i = 0; i < n; i += 2) { ++ for (size_t i = 0; i < n; i += 2) { + JsonVariant *e; + + e = json_variant_by_index(v, i); +@@ -1826,7 +1803,7 @@ void json_variant_dump(JsonVariant *v, JsonFormatFlags flags, FILE *f, const cha + int json_variant_filter(JsonVariant **v, char **to_remove) { + _cleanup_(json_variant_unrefp) JsonVariant *w = NULL; + _cleanup_free_ JsonVariant **array = NULL; +- size_t i, n = 0, k = 0; ++ size_t n = 0, k = 0; + int r; + + assert(v); +@@ -1839,7 +1816,7 @@ int json_variant_filter(JsonVariant **v, char **to_remove) { + if (strv_isempty(to_remove)) + return 0; + +- for (i = 0; i < json_variant_elements(*v); i += 2) { ++ for (size_t i = 0; i < json_variant_elements(*v); i += 2) { + JsonVariant *p; + + p = json_variant_by_index(*v, i); +@@ -1881,7 +1858,7 @@ int json_variant_filter(JsonVariant **v, char **to_remove) { + int json_variant_set_field(JsonVariant **v, const char *field, JsonVariant *value) { + _cleanup_(json_variant_unrefp) JsonVariant *field_variant = NULL, *w = NULL; + _cleanup_free_ JsonVariant **array = NULL; +- size_t i, k = 0; ++ size_t k = 0; + int r; + + assert(v); +@@ -1896,7 +1873,7 @@ int json_variant_set_field(JsonVariant **v, const char *field, JsonVariant *valu + if (!json_variant_is_object(*v)) + return -EINVAL; + +- for (i = 0; i < json_variant_elements(*v); i += 2) { ++ for (size_t i = 0; i < json_variant_elements(*v); i += 2) { + JsonVariant *p; + + p = json_variant_by_index(*v, i); +@@ -2007,7 +1984,7 @@ int json_variant_set_field_strv(JsonVariant **v, const char *field, char **l) { + int json_variant_merge(JsonVariant **v, JsonVariant *m) { + _cleanup_(json_variant_unrefp) JsonVariant *w = NULL; + _cleanup_free_ JsonVariant **array = NULL; +- size_t v_elements, m_elements, i, k; ++ size_t v_elements, m_elements, k; + bool v_blank, m_blank; + int r; + +@@ -2040,7 +2017,7 @@ int json_variant_merge(JsonVariant **v, JsonVariant *m) { + return -ENOMEM; + + k = 0; +- for (i = 0; i < v_elements; i += 2) { ++ for (size_t i = 0; i < v_elements; i += 2) { + JsonVariant *u; + + u = json_variant_by_index(*v, i); +@@ -2054,7 +2031,7 @@ int json_variant_merge(JsonVariant **v, JsonVariant *m) { + array[k++] = json_variant_by_index(*v, i + 1); + } + +- for (i = 0; i < m_elements; i++) ++ for (size_t i = 0; i < m_elements; i++) + array[k++] = json_variant_by_index(m, i); + + r = json_variant_new_object(&w, array, k); +@@ -2089,19 +2066,17 @@ int json_variant_append_array(JsonVariant **v, JsonVariant *element) { + if (blank) + r = json_variant_new_array(&nv, (JsonVariant*[]) { element }, 1); + else { +- _cleanup_free_ JsonVariant **array = NULL; +- size_t i; +- +- array = new(JsonVariant*, json_variant_elements(*v) + 1); ++ _cleanup_free_ JsonVariant **array = new(JsonVariant*, json_variant_elements(*v) + 1); + if (!array) + return -ENOMEM; + +- for (i = 0; i < json_variant_elements(*v); i++) ++ size_t size = json_variant_elements(*v); ++ for (size_t i = 0; i < size; i++) + array[i] = json_variant_by_index(*v, i); + +- array[i] = element; ++ array[size] = element; + +- r = json_variant_new_array(&nv, array, i + 1); ++ r = json_variant_new_array(&nv, array, size + 1); + } + if (r < 0) + return r; +@@ -2116,7 +2091,6 @@ int json_variant_append_array(JsonVariant **v, JsonVariant *element) { + + int json_variant_strv(JsonVariant *v, char ***ret) { + char **l = NULL; +- size_t n, i; + bool sensitive; + int r; + +@@ -2136,12 +2110,12 @@ int json_variant_strv(JsonVariant *v, char ***ret) { + + sensitive = v->sensitive; + +- n = json_variant_elements(v); ++ size_t n = json_variant_elements(v); + l = new(char*, n+1); + if (!l) + return -ENOMEM; + +- for (i = 0; i < n; i++) { ++ for (size_t i = 0; i < n; i++) { + JsonVariant *e; + + assert_se(e = json_variant_by_index(v, i)); +@@ -2160,7 +2134,7 @@ int json_variant_strv(JsonVariant *v, char ***ret) { + } + } + +- l[i] = NULL; ++ l[n] = NULL; + *ret = TAKE_PTR(l); + + return 0; +@@ -2847,7 +2821,7 @@ static int json_parse_internal( + unsigned *column, + bool continue_end) { + +- size_t n_stack = 1, i; ++ size_t n_stack = 1; + unsigned line_buffer = 0, column_buffer = 0; + void *tokenizer_state = NULL; + JsonStack *stack = NULL; +@@ -3186,7 +3160,7 @@ done: + r = 0; + + finish: +- for (i = 0; i < n_stack; i++) ++ for (size_t i = 0; i < n_stack; i++) + json_stack_release(stack + i); + + free(stack); +@@ -3229,7 +3203,7 @@ int json_parse_file_at(FILE *f, int dir_fd, const char *path, JsonParseFlags fla + + int json_buildv(JsonVariant **ret, va_list ap) { + JsonStack *stack = NULL; +- size_t n_stack = 1, i; ++ size_t n_stack = 1; + int r; + + assert_return(ret, -EINVAL); +@@ -4147,7 +4121,7 @@ done: + r = 0; + + finish: +- for (i = 0; i < n_stack; i++) ++ for (size_t i = 0; i < n_stack; i++) + json_stack_release(stack + i); + + free(stack); +@@ -4231,8 +4205,7 @@ int json_log_internal( + } + + int json_dispatch(JsonVariant *v, const JsonDispatch table[], JsonDispatchCallback bad, JsonDispatchFlags flags, void *userdata) { +- const JsonDispatch *p; +- size_t i, n, m; ++ size_t m; + int r, done = 0; + bool *found; + +@@ -4245,14 +4218,16 @@ int json_dispatch(JsonVariant *v, const JsonDispatch table[], JsonDispatchCallba + return -EINVAL; + } + +- for (p = table, m = 0; p->name; p++) ++ m = 0; ++ for (const JsonDispatch *p = table; p->name; p++) + m++; + + found = newa0(bool, m); + +- n = json_variant_elements(v); +- for (i = 0; i < n; i += 2) { ++ size_t n = json_variant_elements(v); ++ for (size_t i = 0; i < n; i += 2) { + JsonVariant *key, *value; ++ const JsonDispatch *p; + + assert_se(key = json_variant_by_index(v, i)); + assert_se(value = json_variant_by_index(v, i+1)); +@@ -4326,7 +4301,7 @@ int json_dispatch(JsonVariant *v, const JsonDispatch table[], JsonDispatchCallba + } + } + +- for (p = table; p->name; p++) { ++ for (const JsonDispatch *p = table; p->name; p++) { + JsonDispatchFlags merged_flags = p->flags | flags; + + if ((merged_flags & JSON_MANDATORY) && !found[p-table]) { +@@ -4621,7 +4596,7 @@ static int json_cmp_strings(const void *x, const void *y) { + int json_variant_sort(JsonVariant **v) { + _cleanup_free_ JsonVariant **a = NULL; + JsonVariant *n = NULL; +- size_t i, m; ++ size_t m; + int r; + + assert(v); +@@ -4639,7 +4614,7 @@ int json_variant_sort(JsonVariant **v) { + if (!a) + return -ENOMEM; + +- for (i = 0; i < m; i++) ++ for (size_t i = 0; i < m; i++) + a[i] = json_variant_by_index(*v, i); + + qsort(a, m/2, sizeof(JsonVariant*)*2, json_cmp_strings); +@@ -4662,7 +4637,7 @@ int json_variant_sort(JsonVariant **v) { + int json_variant_normalize(JsonVariant **v) { + _cleanup_free_ JsonVariant **a = NULL; + JsonVariant *n = NULL; +- size_t i, j, m; ++ size_t i, m; + int r; + + assert(v); +@@ -4714,7 +4689,7 @@ int json_variant_normalize(JsonVariant **v) { + r = 1; + + finish: +- for (j = 0; j < i; j++) ++ for (size_t j = 0; j < i; j++) + json_variant_unref(a[j]); + + return r; diff --git a/0107-fuzz-json-also-do-sorting-and-normalizing-and-other-.patch b/0107-fuzz-json-also-do-sorting-and-normalizing-and-other-.patch new file mode 100644 index 0000000..10a1b24 --- /dev/null +++ b/0107-fuzz-json-also-do-sorting-and-normalizing-and-other-.patch @@ -0,0 +1,97 @@ +From 495eb07a2d8aa7f19b775b4508466fecb1b3ce50 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Mon, 9 May 2022 11:07:06 +0200 +Subject: [PATCH] fuzz-json: also do sorting and normalizing and other easy + calls + +(cherry picked from commit a2c5735dd80e19d2d525f9be322395530096cbe2) +Related: #2087652 +--- + src/fuzz/fuzz-json.c | 75 ++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 75 insertions(+) + +diff --git a/src/fuzz/fuzz-json.c b/src/fuzz/fuzz-json.c +index 648a6d441d..995a0265ba 100644 +--- a/src/fuzz/fuzz-json.c ++++ b/src/fuzz/fuzz-json.c +@@ -32,5 +32,80 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { + json_variant_dump(v, 0, g ?: stdout, NULL); + json_variant_dump(v, JSON_FORMAT_PRETTY|JSON_FORMAT_COLOR|JSON_FORMAT_SOURCE, g ?: stdout, NULL); + ++ bool sorted = json_variant_is_sorted(v); ++ log_debug("json_variant_is_sorted: %s", yes_no(sorted)); ++ ++ r = json_variant_sort(&v); ++ log_debug_errno(r, "json_variant_sort: %d/%m", r); ++ ++ sorted = json_variant_is_sorted(v); ++ log_debug("json_variant_is_sorted: %s", yes_no(sorted)); ++ assert_se(r < 0 || sorted); ++ ++ bool normalized = json_variant_is_normalized(v); ++ log_debug("json_variant_is_normalized: %s", yes_no(normalized)); ++ ++ r = json_variant_normalize(&v); ++ log_debug_errno(r, "json_variant_normalize: %d/%m", r); ++ ++ normalized = json_variant_is_normalized(v); ++ log_debug("json_variant_is_normalized: %s", yes_no(normalized)); ++ assert_se(r < 0 || normalized); ++ ++ double real = json_variant_real(v); ++ log_debug("json_variant_real: %lf", real); ++ ++ bool negative = json_variant_is_negative(v); ++ log_debug("json_variant_is_negative: %s", yes_no(negative)); ++ ++ bool blank = json_variant_is_blank_object(v); ++ log_debug("json_variant_is_blank_object: %s", yes_no(blank)); ++ ++ blank = json_variant_is_blank_array(v); ++ log_debug("json_variant_is_blank_array: %s", yes_no(blank)); ++ ++ size_t elements = json_variant_elements(v); ++ log_debug("json_variant_elements: %zu", elements); ++ ++ for (size_t i = 0; i <= elements + 2; i++) ++ (void) json_variant_by_index(v, i); ++ ++ assert_se(json_variant_equal(v, v)); ++ assert_se(!json_variant_equal(v, NULL)); ++ assert_se(!json_variant_equal(NULL, v)); ++ ++ bool sensitive = json_variant_is_sensitive(v); ++ log_debug("json_variant_is_sensitive: %s", yes_no(sensitive)); ++ ++ json_variant_sensitive(v); ++ ++ sensitive = json_variant_is_sensitive(v); ++ log_debug("json_variant_is_sensitive: %s", yes_no(sensitive)); ++ ++ const char *source; ++ unsigned line, column; ++ assert_se(json_variant_get_source(v, &source, &line, &column) == 0); ++ log_debug("json_variant_get_source: %s:%u:%u", source ?: "-", line, column); ++ ++ r = json_variant_set_field_string(&v, "a", "string-a"); ++ log_debug_errno(r, "json_set_field_string: %d/%m", r); ++ ++ r = json_variant_set_field_integer(&v, "b", -12345); ++ log_debug_errno(r, "json_set_field_integer: %d/%m", r); ++ ++ r = json_variant_set_field_unsigned(&v, "c", 12345); ++ log_debug_errno(r, "json_set_field_unsigned: %d/%m", r); ++ ++ r = json_variant_set_field_boolean(&v, "d", false); ++ log_debug_errno(r, "json_set_field_boolean: %d/%m", r); ++ ++ r = json_variant_set_field_strv(&v, "e", STRV_MAKE("e-1", "e-2", "e-3")); ++ log_debug_errno(r, "json_set_field_strv: %d/%m", r); ++ ++ r = json_variant_filter(&v, STRV_MAKE("a", "b", "c", "d", "e")); ++ log_debug_errno(r, "json_variant_filter: %d/%m", r); ++ ++ // TODO: json_variant_merge(&v, …); ++ // TODO: json_variant_append_array(&v, …); + return 0; + } diff --git a/0108-shared-json-wrap-long-comments.patch b/0108-shared-json-wrap-long-comments.patch new file mode 100644 index 0000000..7e1a8d0 --- /dev/null +++ b/0108-shared-json-wrap-long-comments.patch @@ -0,0 +1,106 @@ +From eb01fd30cb625e90d5620b3ca31ca6474e1b0ac0 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Mon, 9 May 2022 13:37:35 +0200 +Subject: [PATCH] shared/json: wrap long comments + +(cherry picked from commit bac06497feda9eb8c485243f2e05a7f7c112616c) +Related: #2087652 +--- + src/shared/json.c | 35 +++++++++++++++++------------------ + 1 file changed, 17 insertions(+), 18 deletions(-) + +diff --git a/src/shared/json.c b/src/shared/json.c +index d35874f8e3..ea1291e21b 100644 +--- a/src/shared/json.c ++++ b/src/shared/json.c +@@ -273,8 +273,8 @@ static JsonVariant *json_variant_formalize(JsonVariant *v) { + + static JsonVariant *json_variant_conservative_formalize(JsonVariant *v) { + +- /* Much like json_variant_formalize(), but won't simplify if the variant has a source/line location attached to +- * it, in order not to lose context */ ++ /* Much like json_variant_formalize(), but won't simplify if the variant has a source/line location ++ * attached to it, in order not to lose context */ + + if (!v) + return NULL; +@@ -546,7 +546,7 @@ int json_variant_new_array(JsonVariant **ret, JsonVariant **array, size_t n) { + + for (v->n_elements = 0; v->n_elements < n; v->n_elements++) { + JsonVariant *w = v + 1 + v->n_elements, +- *c = array[v->n_elements]; ++ *c = array[v->n_elements]; + uint16_t d; + + d = json_variant_depth(c); +@@ -690,7 +690,7 @@ int json_variant_new_object(JsonVariant **ret, JsonVariant **array, size_t n) { + + for (v->n_elements = 0; v->n_elements < n; v->n_elements++) { + JsonVariant *w = v + 1 + v->n_elements, +- *c = array[v->n_elements]; ++ *c = array[v->n_elements]; + uint16_t d; + + if ((v->n_elements & 1) == 0) { +@@ -731,7 +731,6 @@ int json_variant_new_object(JsonVariant **ret, JsonVariant **array, size_t n) { + } + + static size_t json_variant_size(JsonVariant* v) { +- + if (!json_variant_is_regular(v)) + return 0; + +@@ -2253,8 +2252,9 @@ static int json_variant_set_source(JsonVariant **v, JsonSource *source, unsigned + + assert(v); + +- /* Patch in source and line/column number. Tries to do this in-place if the caller is the sole referencer of +- * the object. If not, allocates a new object, possibly a surrogate for the original one */ ++ /* Patch in source and line/column number. Tries to do this in-place if the caller is the sole ++ * referencer of the object. If not, allocates a new object, possibly a surrogate for the original ++ * one */ + + if (!*v) + return 0; +@@ -3731,10 +3731,10 @@ int json_buildv(JsonVariant **ret, va_list ap) { + + stack[n_stack++] = (JsonStack) { + .expect = EXPECT_OBJECT_KEY, +- .n_suppress = current->n_suppress != 0 ? SIZE_MAX : 0, /* if we shall suppress the +- * new object, then we should +- * also suppress all object +- * members */ ++ .n_suppress = current->n_suppress != 0 ? SIZE_MAX : 0, /* If we shall suppress the ++ * new object, then we should ++ * also suppress all object ++ * members. */ + }; + + break; +@@ -4102,9 +4102,9 @@ int json_buildv(JsonVariant **ret, va_list ap) { + current->elements[current->n_elements++] = TAKE_PTR(add_more); + } + +- /* If we are supposed to suppress items, let's subtract how many items where generated from that +- * counter. Except if the counter is SIZE_MAX, i.e. we shall suppress an infinite number of elements +- * on this stack level */ ++ /* If we are supposed to suppress items, let's subtract how many items where generated from ++ * that counter. Except if the counter is SIZE_MAX, i.e. we shall suppress an infinite number ++ * of elements on this stack level */ + if (current->n_suppress != SIZE_MAX) { + if (current->n_suppress <= n_subtract) /* Saturated */ + current->n_suppress = 0; +@@ -4696,10 +4696,9 @@ finish: + } + + bool json_variant_is_normalized(JsonVariant *v) { +- +- /* For now, let's consider anything containing numbers not expressible as integers as +- * non-normalized. That's because we cannot sensibly compare them due to accuracy issues, nor even +- * store them if they are too large. */ ++ /* For now, let's consider anything containing numbers not expressible as integers as non-normalized. ++ * That's because we cannot sensibly compare them due to accuracy issues, nor even store them if they ++ * are too large. */ + if (json_variant_is_real(v) && !json_variant_is_integer(v) && !json_variant_is_unsigned(v)) + return false; + diff --git a/0109-shared-json-fix-memory-leak-on-failed-normalization.patch b/0109-shared-json-fix-memory-leak-on-failed-normalization.patch new file mode 100644 index 0000000..a1caeab --- /dev/null +++ b/0109-shared-json-fix-memory-leak-on-failed-normalization.patch @@ -0,0 +1,42 @@ +From 0c5992cdb85ac6d9d14b95e77f03797600e87667 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Mon, 9 May 2022 14:28:36 +0200 +Subject: [PATCH] shared/json: fix memory leak on failed normalization + +We need to increase the counter immediately after taking the ref, +otherwise we may not unref it properly if we fail before incrementing. + +(cherry picked from commit 7e4be6a5845f983a299932d4ccb2c4349cf8dd52) +Related: #2087652 +--- + src/shared/json.c | 5 +++-- + test/fuzz/fuzz-json/leak-normalize-fail | 1 + + 2 files changed, 4 insertions(+), 2 deletions(-) + create mode 100644 test/fuzz/fuzz-json/leak-normalize-fail + +diff --git a/src/shared/json.c b/src/shared/json.c +index ea1291e21b..fe05657dad 100644 +--- a/src/shared/json.c ++++ b/src/shared/json.c +@@ -4655,10 +4655,11 @@ int json_variant_normalize(JsonVariant **v) { + if (!a) + return -ENOMEM; + +- for (i = 0; i < m; i++) { ++ for (i = 0; i < m; ) { + a[i] = json_variant_ref(json_variant_by_index(*v, i)); ++ i++; + +- r = json_variant_normalize(a + i); ++ r = json_variant_normalize(&a[i-1]); + if (r < 0) + goto finish; + } +diff --git a/test/fuzz/fuzz-json/leak-normalize-fail b/test/fuzz/fuzz-json/leak-normalize-fail +new file mode 100644 +index 0000000000..b247ccd199 +--- /dev/null ++++ b/test/fuzz/fuzz-json/leak-normalize-fail +@@ -0,0 +1 @@ ++[7E73] +\ No newline at end of file diff --git a/0110-shared-json-add-helper-to-ref-first-unref-second.patch b/0110-shared-json-add-helper-to-ref-first-unref-second.patch new file mode 100644 index 0000000..843a505 --- /dev/null +++ b/0110-shared-json-add-helper-to-ref-first-unref-second.patch @@ -0,0 +1,141 @@ +From fb195ccc27d1643d4152ee874144c36c0104c56d Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Mon, 9 May 2022 15:10:36 +0200 +Subject: [PATCH] shared/json: add helper to ref first, unref second + +This normally wouldn't happen, but if some of those places were called +with lhs and rhs being the same object, we could unref the last ref first, +and then try to take the ref again. It's easier to be safe, and with the +helper we save some lines too. + +(cherry picked from commit ce913e0ec4c97651c7c1509b72fb81ee61d80c6a) +Related: #2087652 +--- + src/shared/json.c | 36 ++++++++++-------------------------- + src/shared/json.h | 8 ++++++++ + 2 files changed, 18 insertions(+), 26 deletions(-) + +diff --git a/src/shared/json.c b/src/shared/json.c +index fe05657dad..bb2363fd98 100644 +--- a/src/shared/json.c ++++ b/src/shared/json.c +@@ -1847,9 +1847,7 @@ int json_variant_filter(JsonVariant **v, char **to_remove) { + return r; + + json_variant_propagate_sensitive(*v, w); +- +- json_variant_unref(*v); +- *v = TAKE_PTR(w); ++ JSON_VARIANT_REPLACE(*v, TAKE_PTR(w)); + + return (int) n; + } +@@ -1918,9 +1916,7 @@ int json_variant_set_field(JsonVariant **v, const char *field, JsonVariant *valu + return r; + + json_variant_propagate_sensitive(*v, w); +- +- json_variant_unref(*v); +- *v = TAKE_PTR(w); ++ JSON_VARIANT_REPLACE(*v, TAKE_PTR(w)); + + return 1; + } +@@ -2001,8 +1997,7 @@ int json_variant_merge(JsonVariant **v, JsonVariant *m) { + return 0; /* nothing to do */ + + if (v_blank) { +- json_variant_unref(*v); +- *v = json_variant_ref(m); ++ JSON_VARIANT_REPLACE(*v, json_variant_ref(m)); + return 1; + } + +@@ -2039,9 +2034,7 @@ int json_variant_merge(JsonVariant **v, JsonVariant *m) { + + json_variant_propagate_sensitive(*v, w); + json_variant_propagate_sensitive(m, w); +- +- json_variant_unref(*v); +- *v = TAKE_PTR(w); ++ JSON_VARIANT_REPLACE(*v, TAKE_PTR(w)); + + return 1; + } +@@ -2081,9 +2074,7 @@ int json_variant_append_array(JsonVariant **v, JsonVariant *element) { + return r; + + json_variant_propagate_sensitive(*v, nv); +- +- json_variant_unref(*v); +- *v = TAKE_PTR(nv); ++ JSON_VARIANT_REPLACE(*v, TAKE_PTR(nv)); + + return 0; + } +@@ -2297,8 +2288,7 @@ static int json_variant_set_source(JsonVariant **v, JsonSource *source, unsigned + w->line = line; + w->column = column; + +- json_variant_unref(*v); +- *v = w; ++ JSON_VARIANT_REPLACE(*v, w); + + return 1; + } +@@ -4499,14 +4489,10 @@ int json_dispatch_strv(const char *name, JsonVariant *variant, JsonDispatchFlags + } + + int json_dispatch_variant(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata) { +- JsonVariant **p = userdata; +- ++ JsonVariant **p = ASSERT_PTR(userdata); + assert(variant); +- assert(p); +- +- json_variant_unref(*p); +- *p = json_variant_ref(variant); + ++ JSON_VARIANT_REPLACE(*p, json_variant_ref(variant)); + return 0; + } + +@@ -4628,8 +4614,7 @@ int json_variant_sort(JsonVariant **v) { + if (!n->sorted) /* Check if this worked. This will fail if there are multiple identical keys used. */ + return -ENOTUNIQ; + +- json_variant_unref(*v); +- *v = n; ++ JSON_VARIANT_REPLACE(*v, n); + + return 1; + } +@@ -4684,8 +4669,7 @@ int json_variant_normalize(JsonVariant **v) { + goto finish; + } + +- json_variant_unref(*v); +- *v = n; ++ JSON_VARIANT_REPLACE(*v, n); + + r = 1; + +diff --git a/src/shared/json.h b/src/shared/json.h +index 8760354b66..dd73c1e497 100644 +--- a/src/shared/json.h ++++ b/src/shared/json.h +@@ -82,6 +82,14 @@ JsonVariant *json_variant_ref(JsonVariant *v); + JsonVariant *json_variant_unref(JsonVariant *v); + void json_variant_unref_many(JsonVariant **array, size_t n); + ++#define JSON_VARIANT_REPLACE(v, q) \ ++ do { \ ++ typeof(v)* _v = &(v); \ ++ typeof(q) _q = (q); \ ++ json_variant_unref(*_v); \ ++ *_v = _q; \ ++ } while(0) ++ + DEFINE_TRIVIAL_CLEANUP_FUNC(JsonVariant *, json_variant_unref); + + const char *json_variant_string(JsonVariant *v); diff --git a/0111-basic-alloc-util-remove-unnecessary-parens.patch b/0111-basic-alloc-util-remove-unnecessary-parens.patch new file mode 100644 index 0000000..4abdc43 --- /dev/null +++ b/0111-basic-alloc-util-remove-unnecessary-parens.patch @@ -0,0 +1,28 @@ +From 965a99f34a185bb3b3aa5ac0e9e5d5eb05d0fac0 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Mon, 9 May 2022 15:11:20 +0200 +Subject: [PATCH] basic/alloc-util: remove unnecessary parens + +Those symbols are not macros anymore, so we can drop parens. + +(cherry picked from commit 96d651a22bf62e63080e489cb45e82bead11aa5d) +Related: #2087652 +--- + src/basic/alloc-util.h | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/src/basic/alloc-util.h b/src/basic/alloc-util.h +index 65d5175619..f57bcbdbcd 100644 +--- a/src/basic/alloc-util.h ++++ b/src/basic/alloc-util.h +@@ -54,8 +54,8 @@ typedef void (*free_func_t)(void *p); + typeof(a)* _a = &(a); \ + typeof(b)* _b = &(b); \ + free(*_a); \ +- (*_a) = (*_b); \ +- (*_b) = NULL; \ ++ *_a = *_b; \ ++ *_b = NULL; \ + 0; \ + }) + diff --git a/0112-fuzz-json-also-try-self-merge-operations.patch b/0112-fuzz-json-also-try-self-merge-operations.patch new file mode 100644 index 0000000..7f8627e --- /dev/null +++ b/0112-fuzz-json-also-try-self-merge-operations.patch @@ -0,0 +1,32 @@ +From 03795a6ae06088bc434906f3ef7222acfbdbe8cb Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Mon, 9 May 2022 15:14:33 +0200 +Subject: [PATCH] fuzz-json: also try self-merge operations + +This might even work ;) + +(cherry picked from commit dbd27c6d2830aeb7173933d1f4a9a07457e4092d) +Related: #2087652 +--- + src/fuzz/fuzz-json.c | 9 +++++++-- + 1 file changed, 7 insertions(+), 2 deletions(-) + +diff --git a/src/fuzz/fuzz-json.c b/src/fuzz/fuzz-json.c +index 995a0265ba..c393fcf394 100644 +--- a/src/fuzz/fuzz-json.c ++++ b/src/fuzz/fuzz-json.c +@@ -105,7 +105,12 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { + r = json_variant_filter(&v, STRV_MAKE("a", "b", "c", "d", "e")); + log_debug_errno(r, "json_variant_filter: %d/%m", r); + +- // TODO: json_variant_merge(&v, …); +- // TODO: json_variant_append_array(&v, …); ++ /* I assume we can merge v with itself… */ ++ r = json_variant_merge(&v, v); ++ log_debug_errno(r, "json_variant_merge: %d/%m", r); ++ ++ r = json_variant_append_array(&v, v); ++ log_debug_errno(r, "json_variant_append_array: %d/%m", r); ++ + return 0; + } diff --git a/0113-shared-json-fix-another-memleak-in-normalization.patch b/0113-shared-json-fix-another-memleak-in-normalization.patch new file mode 100644 index 0000000..df1a30e --- /dev/null +++ b/0113-shared-json-fix-another-memleak-in-normalization.patch @@ -0,0 +1,43 @@ +From 6e0d847273e6ef6ee1011fb1c8b6689e64a94276 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Tue, 10 May 2022 09:05:43 +0200 +Subject: [PATCH] shared/json: fix another memleak in normalization + +(cherry picked from commit 3b6ce05537cd3544a15073f920347cabd7a39450) +Related: #2087652 +--- + src/shared/json.c | 4 ++-- + test/fuzz/fuzz-json/leak-normalize-object | 1 + + 2 files changed, 3 insertions(+), 2 deletions(-) + create mode 100644 test/fuzz/fuzz-json/leak-normalize-object + +diff --git a/src/shared/json.c b/src/shared/json.c +index bb2363fd98..06ef556233 100644 +--- a/src/shared/json.c ++++ b/src/shared/json.c +@@ -4621,7 +4621,7 @@ int json_variant_sort(JsonVariant **v) { + + int json_variant_normalize(JsonVariant **v) { + _cleanup_free_ JsonVariant **a = NULL; +- JsonVariant *n = NULL; ++ _cleanup_(json_variant_unrefp) JsonVariant *n = NULL; + size_t i, m; + int r; + +@@ -4669,7 +4669,7 @@ int json_variant_normalize(JsonVariant **v) { + goto finish; + } + +- JSON_VARIANT_REPLACE(*v, n); ++ JSON_VARIANT_REPLACE(*v, TAKE_PTR(n)); + + r = 1; + +diff --git a/test/fuzz/fuzz-json/leak-normalize-object b/test/fuzz/fuzz-json/leak-normalize-object +new file mode 100644 +index 0000000000..0a8caa426c +--- /dev/null ++++ b/test/fuzz/fuzz-json/leak-normalize-object +@@ -0,0 +1 @@ ++[7,7,7,7,{"":7,"":7,"^t":7,"-":7},2777,7,7,7,3] +\ No newline at end of file diff --git a/0114-shared-json-fix-memleak-in-sort.patch b/0114-shared-json-fix-memleak-in-sort.patch new file mode 100644 index 0000000..e8f0602 --- /dev/null +++ b/0114-shared-json-fix-memleak-in-sort.patch @@ -0,0 +1,43 @@ +From 51bbb027e93637f5821215ebb067454ad6620190 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Tue, 10 May 2022 10:51:43 +0200 +Subject: [PATCH] shared/json: fix memleak in sort + +(cherry picked from commit 99b1145aae682ddd7554c7e3ac5ebf778e88f87d) +Related: #2087652 +--- + src/shared/json.c | 4 ++-- + test/fuzz/fuzz-json/leak-sort | 1 + + 2 files changed, 3 insertions(+), 2 deletions(-) + create mode 100644 test/fuzz/fuzz-json/leak-sort + +diff --git a/src/shared/json.c b/src/shared/json.c +index 06ef556233..6d23bdf4f9 100644 +--- a/src/shared/json.c ++++ b/src/shared/json.c +@@ -4581,7 +4581,7 @@ static int json_cmp_strings(const void *x, const void *y) { + + int json_variant_sort(JsonVariant **v) { + _cleanup_free_ JsonVariant **a = NULL; +- JsonVariant *n = NULL; ++ _cleanup_(json_variant_unrefp) JsonVariant *n = NULL; + size_t m; + int r; + +@@ -4614,7 +4614,7 @@ int json_variant_sort(JsonVariant **v) { + if (!n->sorted) /* Check if this worked. This will fail if there are multiple identical keys used. */ + return -ENOTUNIQ; + +- JSON_VARIANT_REPLACE(*v, n); ++ JSON_VARIANT_REPLACE(*v, TAKE_PTR(n)); + + return 1; + } +diff --git a/test/fuzz/fuzz-json/leak-sort b/test/fuzz/fuzz-json/leak-sort +new file mode 100644 +index 0000000000..f8446dbdc7 +--- /dev/null ++++ b/test/fuzz/fuzz-json/leak-sort +@@ -0,0 +1 @@ ++{"":2,"":6,"-":7} +\ No newline at end of file diff --git a/0115-execute-fix-resource-leak.patch b/0115-execute-fix-resource-leak.patch new file mode 100644 index 0000000..194c836 --- /dev/null +++ b/0115-execute-fix-resource-leak.patch @@ -0,0 +1,26 @@ +From 08b6aa9dfbe9476ad71b48edd0f4454511d9ac19 Mon Sep 17 00:00:00 2001 +From: Shreenidhi Shedi +Date: Sat, 4 Jun 2022 15:24:08 +0530 +Subject: [PATCH] execute: fix resource leak + +CID#1431998 + +(cherry picked from commit 41abd7f6dfe09ccc78cdbdcdec3bdcc10be40faf) +Related: #2087652 +--- + src/core/execute.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/core/execute.c b/src/core/execute.c +index 2ab65e9cfe..8a1d070e26 100644 +--- a/src/core/execute.c ++++ b/src/core/execute.c +@@ -3331,7 +3331,7 @@ static int apply_mount_namespace( + /* Symlinks for exec dirs are set up after other mounts, before they are made read-only. */ + r = compile_symlinks(context, params, &symlinks); + if (r < 0) +- return r; ++ goto finalize; + + needs_sandboxing = (params->flags & EXEC_APPLY_SANDBOXING) && !(command_flags & EXEC_COMMAND_FULLY_PRIVILEGED); + if (needs_sandboxing) { diff --git a/0116-tests-ignore-dbus-broker-launcher.patch b/0116-tests-ignore-dbus-broker-launcher.patch new file mode 100644 index 0000000..e97f951 --- /dev/null +++ b/0116-tests-ignore-dbus-broker-launcher.patch @@ -0,0 +1,31 @@ +From ae27d5b4be42cd98b3db299d161a2e3ea77eb604 Mon Sep 17 00:00:00 2001 +From: Evgeny Vereshchagin +Date: Wed, 11 May 2022 22:32:32 +0000 +Subject: [PATCH] tests: ignore dbus-broker-launcher + +There are memory leaks there https://github.com/bus1/dbus-broker/issues/289 +and it crashes from time to time +https://github.com/matusmarhefka/dfuzzer/issues/20#issuecomment-1114097840 +so let's just skip it by analogy with dbus-daemon to avoid +reports that have nothing to do with systemd itself. + +It's kind of a part of https://github.com/systemd/systemd/pull/22547 + +(cherry picked from commit d0880faa5dda495c7c77425697b82a94b4e68bf6) +Related: #2087652 +--- + test/test-functions | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/test/test-functions b/test/test-functions +index a299f5ff1f..7c37d05610 100644 +--- a/test/test-functions ++++ b/test/test-functions +@@ -1328,6 +1328,7 @@ check_asan_reports() { + BEGIN { + %services_to_ignore = ( + "dbus-daemon" => undef, ++ "dbus-broker-launch" => undef, + ); + } + print $2 if /\s(\S*)\[(\d+)\]:\s*SUMMARY:\s+\w+Sanitizer/ && !exists $services_to_ignore{$1}' diff --git a/0117-core-timer-fix-memleak.patch b/0117-core-timer-fix-memleak.patch new file mode 100644 index 0000000..3e58e63 --- /dev/null +++ b/0117-core-timer-fix-memleak.patch @@ -0,0 +1,59 @@ +From d35c27e44abcde252abddf369762dee8da309903 Mon Sep 17 00:00:00 2001 +From: Yu Watanabe +Date: Tue, 10 May 2022 14:09:24 +0900 +Subject: [PATCH] core/timer: fix memleak + +Fixes #23326. + +(cherry picked from commit d3ab7b8078944db28bc621f43dd942a3c878fffb) +Related: #2087652 +--- + src/core/timer.c | 11 ++++++----- + 1 file changed, 6 insertions(+), 5 deletions(-) + +diff --git a/src/core/timer.c b/src/core/timer.c +index a13b864741..0dc49dd46b 100644 +--- a/src/core/timer.c ++++ b/src/core/timer.c +@@ -135,6 +135,7 @@ static int timer_add_trigger_dependencies(Timer *t) { + } + + static int timer_setup_persistent(Timer *t) { ++ _cleanup_free_ char *stamp_path = NULL; + int r; + + assert(t); +@@ -148,13 +149,13 @@ static int timer_setup_persistent(Timer *t) { + if (r < 0) + return r; + +- t->stamp_path = strjoin("/var/lib/systemd/timers/stamp-", UNIT(t)->id); ++ stamp_path = strjoin("/var/lib/systemd/timers/stamp-", UNIT(t)->id); + } else { + const char *e; + + e = getenv("XDG_DATA_HOME"); + if (e) +- t->stamp_path = strjoin(e, "/systemd/timers/stamp-", UNIT(t)->id); ++ stamp_path = strjoin(e, "/systemd/timers/stamp-", UNIT(t)->id); + else { + + _cleanup_free_ char *h = NULL; +@@ -163,14 +164,14 @@ static int timer_setup_persistent(Timer *t) { + if (r < 0) + return log_unit_error_errno(UNIT(t), r, "Failed to determine home directory: %m"); + +- t->stamp_path = strjoin(h, "/.local/share/systemd/timers/stamp-", UNIT(t)->id); ++ stamp_path = strjoin(h, "/.local/share/systemd/timers/stamp-", UNIT(t)->id); + } + } + +- if (!t->stamp_path) ++ if (!stamp_path) + return log_oom(); + +- return 0; ++ return free_and_replace(t->stamp_path, stamp_path); + } + + static uint64_t timer_get_fixed_delay_hash(Timer *t) { diff --git a/0118-timedatectl-fix-a-memory-leak.patch b/0118-timedatectl-fix-a-memory-leak.patch new file mode 100644 index 0000000..68e40de --- /dev/null +++ b/0118-timedatectl-fix-a-memory-leak.patch @@ -0,0 +1,44 @@ +From 9c166afe17888b08d1e269cfd83a31838d601534 Mon Sep 17 00:00:00 2001 +From: Evgeny Vereshchagin +Date: Wed, 4 May 2022 11:35:19 +0000 +Subject: [PATCH] timedatectl: fix a memory leak + +``` +timedatectl list-timezones --no-pager +... +==164329==ERROR: LeakSanitizer: detected memory leaks + +Direct leak of 8192 byte(s) in 1 object(s) allocated from: + #0 0x7fe8a74b6f8c in reallocarray (/lib64/libasan.so.6+0xaef8c) + #1 0x7fe8a63485dc in strv_push ../src/basic/strv.c:419 + #2 0x7fe8a6349419 in strv_consume ../src/basic/strv.c:490 + #3 0x7fe8a634958d in strv_extend ../src/basic/strv.c:542 + #4 0x7fe8a643d787 in bus_message_read_strv_extend ../src/libsystemd/sd-bus/bus-message.c:5606 + #5 0x7fe8a643db9d in sd_bus_message_read_strv ../src/libsystemd/sd-bus/bus-message.c:5628 + #6 0x4085fb in list_timezones ../src/timedate/timedatectl.c:314 + #7 0x7fe8a61ef3e1 in dispatch_verb ../src/shared/verbs.c:103 + #8 0x410f91 in timedatectl_main ../src/timedate/timedatectl.c:1025 + #9 0x41111c in run ../src/timedate/timedatectl.c:1043 + #10 0x411242 in main ../src/timedate/timedatectl.c:1046 + #11 0x7fe8a489df1f in __libc_start_call_main (/lib64/libc.so.6+0x40f1f) +``` + +(cherry picked from commit a2e37d52312806b1847800df2358e61276cda052) +Related: #2087652 +--- + src/timedate/timedatectl.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/timedate/timedatectl.c b/src/timedate/timedatectl.c +index 75ca6195da..31909064cf 100644 +--- a/src/timedate/timedatectl.c ++++ b/src/timedate/timedatectl.c +@@ -304,7 +304,7 @@ static int list_timezones(int argc, char **argv, void *userdata) { + sd_bus *bus = userdata; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; + int r; +- char** zones; ++ _cleanup_strv_free_ char **zones = NULL; + + r = bus_call_method(bus, bus_timedate, "ListTimezones", &error, &reply, NULL); + if (r < 0) diff --git a/0119-test-fix-file-descriptor-leak-in-test-psi-util.patch b/0119-test-fix-file-descriptor-leak-in-test-psi-util.patch new file mode 100644 index 0000000..bd57db6 --- /dev/null +++ b/0119-test-fix-file-descriptor-leak-in-test-psi-util.patch @@ -0,0 +1,42 @@ +From 12274971840068b3effb7a933d62f1b5fe8009e1 Mon Sep 17 00:00:00 2001 +From: Yu Watanabe +Date: Tue, 22 Feb 2022 21:46:41 +0900 +Subject: [PATCH] test: fix file descriptor leak in test-psi-util + +Fixes an issue reported in #22576. + +(cherry picked from commit be99883e131ef422f8278ec1d099520996a78bb0) +Related: #2087652 +--- + src/test/test-psi-util.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/src/test/test-psi-util.c b/src/test/test-psi-util.c +index ed465b807e..111671c5a9 100644 +--- a/src/test/test-psi-util.c ++++ b/src/test/test-psi-util.c +@@ -1,20 +1,23 @@ + /* SPDX-License-Identifier: LGPL-2.1-or-later */ + + #include "alloc-util.h" ++#include "fd-util.h" + #include "fileio.h" + #include "fs-util.h" + #include "parse-util.h" + #include "psi-util.h" + #include "tests.h" ++#include "tmpfile-util.h" + + TEST(read_mem_pressure) { + _cleanup_(unlink_tempfilep) char path[] = "/tmp/pressurereadtestXXXXXX"; ++ _cleanup_close_ int fd = -1; + ResourcePressure rp; + + if (geteuid() != 0) + return (void) log_tests_skipped("not root"); + +- assert_se(mkstemp(path)); ++ assert_se((fd = mkostemp_safe(path)) >= 0); + + assert_se(read_resource_pressure("/verylikelynonexistentpath", PRESSURE_TYPE_SOME, &rp) < 0); + assert_se(read_resource_pressure(path, PRESSURE_TYPE_SOME, &rp) < 0); diff --git a/0120-test-fix-file-descriptor-leak-in-test-tmpfiles.c.patch b/0120-test-fix-file-descriptor-leak-in-test-tmpfiles.c.patch new file mode 100644 index 0000000..d670657 --- /dev/null +++ b/0120-test-fix-file-descriptor-leak-in-test-tmpfiles.c.patch @@ -0,0 +1,36 @@ +From 936e8cd5aff044832c98e5a6a97c9f057f44b476 Mon Sep 17 00:00:00 2001 +From: Yu Watanabe +Date: Tue, 22 Feb 2022 21:44:58 +0900 +Subject: [PATCH] test: fix file descriptor leak in test-tmpfiles.c + +Also fixes a typo in assertion. + +Fixes an issure reported in #22576. + +(cherry picked from commit 1da5325d19dee654326e5fa2f61262e5e0a40fff) +Related: #2087652 +--- + src/test/test-tmpfiles.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/src/test/test-tmpfiles.c b/src/test/test-tmpfiles.c +index 99243eb77a..f26701767f 100644 +--- a/src/test/test-tmpfiles.c ++++ b/src/test/test-tmpfiles.c +@@ -35,7 +35,7 @@ TEST(tmpfiles) { + assert_se(endswith(ans, " (deleted)")); + + fd2 = mkostemp_safe(pattern); +- assert_se(fd >= 0); ++ assert_se(fd2 >= 0); + assert_se(unlink(pattern) == 0); + + assert_se(asprintf(&cmd2, "ls -l /proc/"PID_FMT"/fd/%d", getpid_cached(), fd2) > 0); +@@ -47,6 +47,7 @@ TEST(tmpfiles) { + pattern = strjoina(p, "/tmpfiles-test"); + assert_se(tempfn_random(pattern, NULL, &d) >= 0); + ++ fd = safe_close(fd); + fd = open_tmpfile_linkable(d, O_RDWR|O_CLOEXEC, &tmp); + assert_se(fd >= 0); + assert_se(write(fd, "foobar\n", 7) == 7); diff --git a/0121-test-fix-file-descriptor-leak-in-test-fs-util.patch b/0121-test-fix-file-descriptor-leak-in-test-fs-util.patch new file mode 100644 index 0000000..8f2a2be --- /dev/null +++ b/0121-test-fix-file-descriptor-leak-in-test-fs-util.patch @@ -0,0 +1,46 @@ +From 3ca37c58cb3ff022e029b28539fd2e3b208802fd Mon Sep 17 00:00:00 2001 +From: Yu Watanabe +Date: Tue, 22 Feb 2022 21:42:22 +0900 +Subject: [PATCH] test: fix file descriptor leak in test-fs-util + +Fixes an issue reported in #22576. + +(cherry picked from commit 19962747ca86a25e7102c536380bb2e9d7cfee9a) +Related: #2087652 +--- + src/test/test-fs-util.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/src/test/test-fs-util.c b/src/test/test-fs-util.c +index 602ce75f98..f53a3ebf59 100644 +--- a/src/test/test-fs-util.c ++++ b/src/test/test-fs-util.c +@@ -29,10 +29,11 @@ static const char *arg_test_dir = NULL; + + TEST(chase_symlinks) { + _cleanup_free_ char *result = NULL; ++ _cleanup_close_ int pfd = -1; + char *temp; + const char *top, *p, *pslash, *q, *qslash; + struct stat st; +- int r, pfd; ++ int r; + + temp = strjoina(arg_test_dir ?: "/tmp", "/test-chase.XXXXXX"); + assert_se(mkdtemp(temp)); +@@ -318,6 +319,7 @@ TEST(chase_symlinks) { + assert_se(fstat(pfd, &st) >= 0); + assert_se(S_ISLNK(st.st_mode)); + result = mfree(result); ++ pfd = safe_close(pfd); + + /* s1 -> s2 -> nonexistent */ + q = strjoina(temp, "/s1"); +@@ -331,6 +333,7 @@ TEST(chase_symlinks) { + assert_se(fstat(pfd, &st) >= 0); + assert_se(S_ISLNK(st.st_mode)); + result = mfree(result); ++ pfd = safe_close(pfd); + + /* Test CHASE_STEP */ + diff --git a/0122-test-fix-file-descriptor-leak-in-test-oomd-util.patch b/0122-test-fix-file-descriptor-leak-in-test-oomd-util.patch new file mode 100644 index 0000000..7b8ce4a --- /dev/null +++ b/0122-test-fix-file-descriptor-leak-in-test-oomd-util.patch @@ -0,0 +1,48 @@ +From 9e37cb1855c8fc1667f7e404376070952c015788 Mon Sep 17 00:00:00 2001 +From: Yu Watanabe +Date: Tue, 22 Feb 2022 21:38:15 +0900 +Subject: [PATCH] test: fix file descriptor leak in test-oomd-util + +Fixes an issue reported in #22576. + +(cherry picked from commit 282696ce52471f5e3c963b9d98dbc89fba3a1fba) +Related: #2087652 +--- + src/oom/test-oomd-util.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/src/oom/test-oomd-util.c b/src/oom/test-oomd-util.c +index 265e77c0a2..0252ceecd7 100644 +--- a/src/oom/test-oomd-util.c ++++ b/src/oom/test-oomd-util.c +@@ -5,6 +5,7 @@ + #include "alloc-util.h" + #include "cgroup-setup.h" + #include "cgroup-util.h" ++#include "fd-util.h" + #include "fileio.h" + #include "fs-util.h" + #include "oomd-util.h" +@@ -13,6 +14,7 @@ + #include "string-util.h" + #include "strv.h" + #include "tests.h" ++#include "tmpfile-util.h" + + static int fork_and_sleep(unsigned sleep_min) { + usec_t n, timeout, ts; +@@ -244,12 +246,13 @@ static void test_oomd_update_cgroup_contexts_between_hashmaps(void) { + + static void test_oomd_system_context_acquire(void) { + _cleanup_(unlink_tempfilep) char path[] = "/oomdgetsysctxtestXXXXXX"; ++ _cleanup_close_ int fd = -1; + OomdSystemContext ctx; + + if (geteuid() != 0) + return (void) log_tests_skipped("not root"); + +- assert_se(mkstemp(path)); ++ assert_se((fd = mkostemp_safe(path)) >= 0); + + assert_se(oomd_system_context_acquire("/verylikelynonexistentpath", &ctx) == -ENOENT); + diff --git a/0123-test-fix-file-descriptor-leak-in-test-catalog.patch b/0123-test-fix-file-descriptor-leak-in-test-catalog.patch new file mode 100644 index 0000000..58b7423 --- /dev/null +++ b/0123-test-fix-file-descriptor-leak-in-test-catalog.patch @@ -0,0 +1,34 @@ +From d947339b49eb7935ce282e808a7e75a6098d088a Mon Sep 17 00:00:00 2001 +From: Yu Watanabe +Date: Tue, 22 Feb 2022 21:11:51 +0900 +Subject: [PATCH] test: fix file descriptor leak in test-catalog + +Fixes an issue reported in #22576. + +(cherry picked from commit 62d4b3b36e9aba9e605ba042a75c374155b6e18b) +Related: #2087652 +--- + src/libsystemd/sd-journal/test-catalog.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/src/libsystemd/sd-journal/test-catalog.c b/src/libsystemd/sd-journal/test-catalog.c +index 316c3b1634..ad06221175 100644 +--- a/src/libsystemd/sd-journal/test-catalog.c ++++ b/src/libsystemd/sd-journal/test-catalog.c +@@ -196,6 +196,7 @@ static void test_catalog_file_lang(void) { + + int main(int argc, char *argv[]) { + _cleanup_(unlink_tempfilep) char database[] = "/tmp/test-catalog.XXXXXX"; ++ _cleanup_close_ int fd = -1; + _cleanup_free_ char *text = NULL; + int r; + +@@ -218,7 +219,7 @@ int main(int argc, char *argv[]) { + test_catalog_import_merge(); + test_catalog_import_merge_no_body(); + +- assert_se(mkostemp_safe(database) >= 0); ++ assert_se((fd = mkostemp_safe(database)) >= 0); + + test_catalog_update(database); + diff --git a/0124-test-make-masking-of-supplementary-services-configur.patch b/0124-test-make-masking-of-supplementary-services-configur.patch new file mode 100644 index 0000000..8464645 --- /dev/null +++ b/0124-test-make-masking-of-supplementary-services-configur.patch @@ -0,0 +1,49 @@ +From 4197469aa26e8e3e61c859341002e37bde751ada Mon Sep 17 00:00:00 2001 +From: Frantisek Sumsal +Date: Wed, 16 Feb 2022 20:29:14 +0100 +Subject: [PATCH] test: make masking of supplementary services configurable + +(cherry picked from commit 508a7f04b345878dcd8365ff0ded5f87b18d75fa) + +Related: #2087652 +--- + test/TEST-01-BASIC/test.sh | 1 + + test/test-functions | 6 +++--- + 2 files changed, 4 insertions(+), 3 deletions(-) + +diff --git a/test/TEST-01-BASIC/test.sh b/test/TEST-01-BASIC/test.sh +index a790cd78ac..cc6d0651c1 100755 +--- a/test/TEST-01-BASIC/test.sh ++++ b/test/TEST-01-BASIC/test.sh +@@ -6,6 +6,7 @@ TEST_DESCRIPTION="Basic systemd setup" + IMAGE_NAME="basic" + RUN_IN_UNPRIVILEGED_CONTAINER=${RUN_IN_UNPRIVILEGED_CONTAINER:-yes} + TEST_REQUIRE_INSTALL_TESTS=0 ++TEST_SUPPORTING_SERVICES_SHOULD_BE_MASKED=0 + + # shellcheck source=test/test-functions + . "${TEST_BASE_DIR:?}/test-functions" +diff --git a/test/test-functions b/test/test-functions +index 7c37d05610..44f465c914 100644 +--- a/test/test-functions ++++ b/test/test-functions +@@ -40,6 +40,7 @@ IMAGE_NAME=${IMAGE_NAME:-default} + STRIP_BINARIES="${STRIP_BINARIES:-yes}" + TEST_REQUIRE_INSTALL_TESTS="${TEST_REQUIRE_INSTALL_TESTS:-1}" + TEST_PARALLELIZE="${TEST_PARALLELIZE:-0}" ++TEST_SUPPORTING_SERVICES_SHOULD_BE_MASKED="${TEST_SUPPORTING_SERVICES_SHOULD_BE_MASKED:-1}" + LOOPDEV= + + # Simple wrapper to unify boolean checks. +@@ -2787,9 +2788,8 @@ test_setup() { + fi + + mount_initdir +- # We want to test all services in TEST-01-BASIC, but mask them in +- # all other tests +- if [[ "${TESTID:?}" != "01" ]]; then ++ ++ if get_bool "${TEST_SUPPORTING_SERVICES_SHOULD_BE_MASKED}"; then + dinfo "Masking supporting services" + mask_supporting_services + fi diff --git a/0125-test-fuzz-our-dbus-interfaces-with-dfuzzer.patch b/0125-test-fuzz-our-dbus-interfaces-with-dfuzzer.patch new file mode 100644 index 0000000..1c63c5a --- /dev/null +++ b/0125-test-fuzz-our-dbus-interfaces-with-dfuzzer.patch @@ -0,0 +1,186 @@ +From 25338c37915521876c84bca196de50d73c3c17ea Mon Sep 17 00:00:00 2001 +From: Frantisek Sumsal +Date: Mon, 13 Dec 2021 20:50:28 +0100 +Subject: [PATCH] test: fuzz our dbus interfaces with dfuzzer + +(cherry picked from commit 354b3364aa63620a0f732bb8a6fe9332a4f550e4) + +Related: #2087652 +--- + test/TEST-21-DFUZZER/Makefile | 1 + + test/TEST-21-DFUZZER/test.sh | 24 +++++++++ + test/test-functions | 1 + + test/units/testsuite-21.service | 10 ++++ + test/units/testsuite-21.sh | 94 +++++++++++++++++++++++++++++++++ + 5 files changed, 130 insertions(+) + create mode 120000 test/TEST-21-DFUZZER/Makefile + create mode 100755 test/TEST-21-DFUZZER/test.sh + create mode 100644 test/units/testsuite-21.service + create mode 100755 test/units/testsuite-21.sh + +diff --git a/test/TEST-21-DFUZZER/Makefile b/test/TEST-21-DFUZZER/Makefile +new file mode 120000 +index 0000000000..e9f93b1104 +--- /dev/null ++++ b/test/TEST-21-DFUZZER/Makefile +@@ -0,0 +1 @@ ++../TEST-01-BASIC/Makefile +\ No newline at end of file +diff --git a/test/TEST-21-DFUZZER/test.sh b/test/TEST-21-DFUZZER/test.sh +new file mode 100755 +index 0000000000..ecc04e368c +--- /dev/null ++++ b/test/TEST-21-DFUZZER/test.sh +@@ -0,0 +1,24 @@ ++#!/usr/bin/env bash ++# SPDX-License-Identifier: LGPL-2.1-or-later ++set -e ++ ++TEST_DESCRIPTION="Fuzz our D-Bus interfaces with dfuzzer" ++TEST_NO_NSPAWN=1 ++TEST_SUPPORTING_SERVICES_SHOULD_BE_MASKED=0 ++QEMU_TIMEOUT="${QEMU_TIMEOUT:-1800}" ++ ++# shellcheck source=test/test-functions ++. "${TEST_BASE_DIR:?}/test-functions" ++ ++command -v dfuzzer >/dev/null || exit 0 ++ ++test_append_files() { ++ local workspace="${1:?}" ++ ++ image_install dfuzzer /etc/dfuzzer.conf ++ ++ # Enable all systemd-related services, including the D-Bus ones ++ "$SYSTEMCTL" --root="${workspace:?}" preset-all ++} ++ ++do_test "$@" +diff --git a/test/test-functions b/test/test-functions +index 44f465c914..079a7249e4 100644 +--- a/test/test-functions ++++ b/test/test-functions +@@ -99,6 +99,7 @@ SYSTEMD_JOURNAL_REMOTE="${SYSTEMD_JOURNAL_REMOTE:-$(command -v "$BUILD_DIR/syste + SYSTEMD="${SYSTEMD:-$(command -v "$BUILD_DIR/systemd" || command -v "$ROOTLIBDIR/systemd")}" + SYSTEMD_NSPAWN="${SYSTEMD_NSPAWN:-$(command -v "$BUILD_DIR/systemd-nspawn" || command -v systemd-nspawn)}" + JOURNALCTL="${JOURNALCTL:-$(command -v "$BUILD_DIR/journalctl" || command -v journalctl)}" ++SYSTEMCTL="${SYSTEMCTL:-$(command -v "$BUILD_DIR/systemctl" || command -v systemctl)}" + + TESTFILE="${BASH_SOURCE[1]}" + if [ -z "$TESTFILE" ]; then +diff --git a/test/units/testsuite-21.service b/test/units/testsuite-21.service +new file mode 100644 +index 0000000000..a5f77d07b4 +--- /dev/null ++++ b/test/units/testsuite-21.service +@@ -0,0 +1,10 @@ ++# SPDX-License-Identifier: LGPL-2.1-or-later ++[Unit] ++Description=Fuzz our D-Bus interfaces with dfuzzer ++After=dbus.service multi-user.target ++Wants=dbus.service multi-user.target ++ ++[Service] ++ExecStartPre=rm -f /failed /skipped /testok ++ExecStart=/usr/lib/systemd/tests/testdata/units/%N.sh ++Type=oneshot +diff --git a/test/units/testsuite-21.sh b/test/units/testsuite-21.sh +new file mode 100755 +index 0000000000..43b5fb6f22 +--- /dev/null ++++ b/test/units/testsuite-21.sh +@@ -0,0 +1,94 @@ ++#!/usr/bin/env bash ++# SPDX-License-Identifier: LGPL-2.1-or-later ++set -eux ++set -o pipefail ++ ++# Save the end.service state before we start fuzzing, as it might get changed ++# on the fly by one of the fuzzers ++systemctl list-jobs | grep -F 'end.service' && SHUTDOWN_AT_EXIT=1 || SHUTDOWN_AT_EXIT=0 ++ ++at_exit() { ++ # "Safety net" - check for any coredumps which might have not caused dfuzzer ++ # to stop & return an error (we need to do this now before truncating the ++ # journal) ++ # TODO: check fo ASan/UBSan errors ++ local found_cd=0 ++ while read -r exe; do ++ coredumctl info "$exe" ++ found_cd=1 ++ done < <(coredumpctl -F COREDUMP_EXE | sort -u) ++ [[ $found_cd -eq 0 ]] || exit 1 ++ ++ # We have to call the end.service explicitly even if it's specified on ++ # the kernel cmdline via systemd.wants=end.service, since dfuzzer calls ++ # org.freedesktop.systemd1.Manager.ClearJobs() which drops the service ++ # from the queue ++ [[ $SHUTDOWN_AT_EXIT -ne 0 ]] && systemctl start --job-mode=flush end.service ++} ++ ++trap at_exit EXIT ++ ++systemctl log-level info ++ ++# TODO ++# * check for possibly newly introduced buses? ++BUS_LIST=( ++ org.freedesktop.home1 ++ org.freedesktop.hostname1 ++ org.freedesktop.import1 ++ org.freedesktop.locale1 ++ org.freedesktop.login1 ++ org.freedesktop.machine1 ++ org.freedesktop.network1 ++ org.freedesktop.portable1 ++ org.freedesktop.resolve1 ++ org.freedesktop.systemd1 ++ org.freedesktop.timedate1 ++ org.freedesktop.timesync1 ++) ++ ++# systemd-oomd requires PSI ++if tail -n +1 /proc/pressure/{cpu,io,memory}; then ++ BUS_LIST+=(org.freedesktop.oom1) ++fi ++ ++SESSION_BUS_LIST=( ++ org.freedesktop.systemd1 ++) ++ ++# Maximum payload size generated by dfuzzer (in bytes) - default: 50K ++PAYLOAD_MAX=50000 ++# Tweak the maximum payload size if we're running under sanitizers, since ++# with larger payloads we start hitting reply timeouts ++if [[ -v ASAN_OPTIONS || -v UBSAN_OPTIONS ]]; then ++ PAYLOAD_MAX=10000 # 10K ++fi ++ ++# Overmount /var/lib/machines with a size-limited tmpfs, as fuzzing ++# the org.freedesktop.machine1 stuff makes quite a mess ++mount -t tmpfs -o size=50M tmpfs /var/lib/machines ++ ++# Fuzz both the system and the session buses (where applicable) ++for bus in "${BUS_LIST[@]}"; do ++ echo "Bus: $bus (system)" ++ systemd-run --pipe --wait \ ++ -- dfuzzer -v -b "$PAYLOAD_MAX" -n "$bus" ++ ++ # Let's reload the systemd daemon to test (de)serialization as well ++ systemctl daemon-reload ++done ++ ++umount /var/lib/machines ++ ++for bus in "${SESSION_BUS_LIST[@]}"; do ++ echo "Bus: $bus (session)" ++ systemd-run --machine 'testuser@.host' --user --pipe --wait \ ++ -- dfuzzer -v -b "$PAYLOAD_MAX" -n "$bus" ++ ++ # Let's reload the systemd user daemon to test (de)serialization as well ++ systemctl --machine 'testuser@.host' --user daemon-reload ++done ++ ++echo OK >/testok ++ ++exit 0 diff --git a/0126-test-skip-TEST-21-DFUZZER-without-ASan.patch b/0126-test-skip-TEST-21-DFUZZER-without-ASan.patch new file mode 100644 index 0000000..90ee4f4 --- /dev/null +++ b/0126-test-skip-TEST-21-DFUZZER-without-ASan.patch @@ -0,0 +1,31 @@ +From 8f848593293b69f293734e07ec975ee76a3e6df5 Mon Sep 17 00:00:00 2001 +From: Frantisek Sumsal +Date: Sun, 19 Jun 2022 10:39:12 +0200 +Subject: [PATCH] test: skip TEST-21-DFUZZER without ASan + +as the test is quite time consuming and it yields more useful reports +when the target app is built with sanitizers. + +(cherry picked from commit d768243a95c33e73afe9a7e487acf329884e03c1) + +Related: #2087652 +--- + test/TEST-21-DFUZZER/test.sh | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/test/TEST-21-DFUZZER/test.sh b/test/TEST-21-DFUZZER/test.sh +index ecc04e368c..42e37c8a9c 100755 +--- a/test/TEST-21-DFUZZER/test.sh ++++ b/test/TEST-21-DFUZZER/test.sh +@@ -12,6 +12,11 @@ QEMU_TIMEOUT="${QEMU_TIMEOUT:-1800}" + + command -v dfuzzer >/dev/null || exit 0 + ++if ! get_bool "$IS_BUILT_WITH_ASAN"; then ++ echo "systemd is built without ASan, skipping..." ++ exit 0 ++fi ++ + test_append_files() { + local workspace="${1:?}" + diff --git a/0127-core-annotate-Reexecute-as-NoReply.patch b/0127-core-annotate-Reexecute-as-NoReply.patch new file mode 100644 index 0000000..eaebcb5 --- /dev/null +++ b/0127-core-annotate-Reexecute-as-NoReply.patch @@ -0,0 +1,41 @@ +From fc6e005962167c26b9ef6cdd9e3476abeeb47313 Mon Sep 17 00:00:00 2001 +From: Frantisek Sumsal +Date: Mon, 9 May 2022 23:43:40 +0200 +Subject: [PATCH] core: annotate Reexecute() as NoReply + +So we're able to tell from the introspection data that the method +doesn't reply. + +(cherry picked from commit 624f685fe8ff1a90370e02faf60d0292a8e01f26) + +Related: #2087652 +--- + man/org.freedesktop.systemd1.xml | 1 + + src/core/dbus-manager.c | 2 +- + 2 files changed, 2 insertions(+), 1 deletion(-) + +diff --git a/man/org.freedesktop.systemd1.xml b/man/org.freedesktop.systemd1.xml +index bd69a00b57..e1abb7f389 100644 +--- a/man/org.freedesktop.systemd1.xml ++++ b/man/org.freedesktop.systemd1.xml +@@ -169,6 +169,7 @@ node /org/freedesktop/systemd1 { + Dump(out s output); + DumpByFileDescriptor(out h fd); + Reload(); ++ @org.freedesktop.DBus.Method.NoReply("true") + Reexecute(); + @org.freedesktop.systemd1.Privileged("true") + Exit(); +diff --git a/src/core/dbus-manager.c b/src/core/dbus-manager.c +index 9b64a8074d..1a3098ceb1 100644 +--- a/src/core/dbus-manager.c ++++ b/src/core/dbus-manager.c +@@ -3105,7 +3105,7 @@ const sd_bus_vtable bus_manager_vtable[] = { + NULL, + NULL, + method_reexecute, +- SD_BUS_VTABLE_UNPRIVILEGED), ++ SD_BUS_VTABLE_UNPRIVILEGED|SD_BUS_VTABLE_METHOD_NO_REPLY), + SD_BUS_METHOD("Exit", + NULL, + NULL, diff --git a/0128-test-always-force-a-new-image-for-dfuzzer.patch b/0128-test-always-force-a-new-image-for-dfuzzer.patch new file mode 100644 index 0000000..60da622 --- /dev/null +++ b/0128-test-always-force-a-new-image-for-dfuzzer.patch @@ -0,0 +1,28 @@ +From e162696827d97449e6395fc017fe6865aa6f1ad1 Mon Sep 17 00:00:00 2001 +From: Frantisek Sumsal +Date: Tue, 21 Jun 2022 10:01:30 +0200 +Subject: [PATCH] test: always force a new image for dfuzzer + +Otherwise we might end up with an image containing broken service +symlinks and other things, which break certain parts of the test. + +(cherry picked from commit 5dffa6b032168305213e4fb0d72fb02363acfd65) + +Related: #2087652 +--- + test/TEST-21-DFUZZER/test.sh | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/test/TEST-21-DFUZZER/test.sh b/test/TEST-21-DFUZZER/test.sh +index 42e37c8a9c..7669e4e0ad 100755 +--- a/test/TEST-21-DFUZZER/test.sh ++++ b/test/TEST-21-DFUZZER/test.sh +@@ -6,6 +6,8 @@ TEST_DESCRIPTION="Fuzz our D-Bus interfaces with dfuzzer" + TEST_NO_NSPAWN=1 + TEST_SUPPORTING_SERVICES_SHOULD_BE_MASKED=0 + QEMU_TIMEOUT="${QEMU_TIMEOUT:-1800}" ++IMAGE_NAME=dfuzzer ++TEST_FORCE_NEWIMAGE=1 + + # shellcheck source=test/test-functions + . "${TEST_BASE_DIR:?}/test-functions" diff --git a/0129-test-make-dfuzzer-less-verbose.patch b/0129-test-make-dfuzzer-less-verbose.patch new file mode 100644 index 0000000..be24139 --- /dev/null +++ b/0129-test-make-dfuzzer-less-verbose.patch @@ -0,0 +1,38 @@ +From 0e72d8a8bbed61ffa3cbf2637f1b29ade7af45be Mon Sep 17 00:00:00 2001 +From: Frantisek Sumsal +Date: Tue, 21 Jun 2022 10:04:03 +0200 +Subject: [PATCH] test: make dfuzzer less verbose + +Otherwise it oversaturates the journal, which in some cases can't keep +up with the load of messages (due to the performance penalty caused by +sanitizers), and gets killed by a watchdog. + +(cherry picked from commit d3eb4159c9577f0a9ee776d34fcec7ad913d88a5) + +Related: #2087652 +--- + test/units/testsuite-21.sh | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/test/units/testsuite-21.sh b/test/units/testsuite-21.sh +index 43b5fb6f22..604bf145ca 100755 +--- a/test/units/testsuite-21.sh ++++ b/test/units/testsuite-21.sh +@@ -72,7 +72,7 @@ mount -t tmpfs -o size=50M tmpfs /var/lib/machines + for bus in "${BUS_LIST[@]}"; do + echo "Bus: $bus (system)" + systemd-run --pipe --wait \ +- -- dfuzzer -v -b "$PAYLOAD_MAX" -n "$bus" ++ -- dfuzzer -b "$PAYLOAD_MAX" -n "$bus" + + # Let's reload the systemd daemon to test (de)serialization as well + systemctl daemon-reload +@@ -83,7 +83,7 @@ umount /var/lib/machines + for bus in "${SESSION_BUS_LIST[@]}"; do + echo "Bus: $bus (session)" + systemd-run --machine 'testuser@.host' --user --pipe --wait \ +- -- dfuzzer -v -b "$PAYLOAD_MAX" -n "$bus" ++ -- dfuzzer -b "$PAYLOAD_MAX" -n "$bus" + + # Let's reload the systemd user daemon to test (de)serialization as well + systemctl --machine 'testuser@.host' --user daemon-reload diff --git a/0130-test-drop-the-at_exit-coredump-check.patch b/0130-test-drop-the-at_exit-coredump-check.patch new file mode 100644 index 0000000..013bbff --- /dev/null +++ b/0130-test-drop-the-at_exit-coredump-check.patch @@ -0,0 +1,37 @@ +From e5291b4fb0d9adfc9da510f4acc7330d57e3e415 Mon Sep 17 00:00:00 2001 +From: Frantisek Sumsal +Date: Tue, 21 Jun 2022 10:13:48 +0200 +Subject: [PATCH] test: drop the at_exit() coredump check + +since we don't truncate the journal anymore. + +(cherry picked from commit 5309b56505dfccf9111cb5fe6461047725429e79) + +Related: #2087652 +--- + test/units/testsuite-21.sh | 12 +----------- + 1 file changed, 1 insertion(+), 11 deletions(-) + +diff --git a/test/units/testsuite-21.sh b/test/units/testsuite-21.sh +index 604bf145ca..053d571a90 100755 +--- a/test/units/testsuite-21.sh ++++ b/test/units/testsuite-21.sh +@@ -8,17 +8,7 @@ set -o pipefail + systemctl list-jobs | grep -F 'end.service' && SHUTDOWN_AT_EXIT=1 || SHUTDOWN_AT_EXIT=0 + + at_exit() { +- # "Safety net" - check for any coredumps which might have not caused dfuzzer +- # to stop & return an error (we need to do this now before truncating the +- # journal) +- # TODO: check fo ASan/UBSan errors +- local found_cd=0 +- while read -r exe; do +- coredumctl info "$exe" +- found_cd=1 +- done < <(coredumpctl -F COREDUMP_EXE | sort -u) +- [[ $found_cd -eq 0 ]] || exit 1 +- ++ set +e + # We have to call the end.service explicitly even if it's specified on + # the kernel cmdline via systemd.wants=end.service, since dfuzzer calls + # org.freedesktop.systemd1.Manager.ClearJobs() which drops the service diff --git a/0131-test-make-the-shutdown-routine-a-bit-more-robust.patch b/0131-test-make-the-shutdown-routine-a-bit-more-robust.patch new file mode 100644 index 0000000..f4ec02a --- /dev/null +++ b/0131-test-make-the-shutdown-routine-a-bit-more-robust.patch @@ -0,0 +1,54 @@ +From a0464b064c46f9a63fd3f8d6f2d8560c7e5d32d3 Mon Sep 17 00:00:00 2001 +From: Frantisek Sumsal +Date: Tue, 21 Jun 2022 10:20:12 +0200 +Subject: [PATCH] test: make the shutdown routine a bit more "robust" + +Replace the call to the `end.service` with `systemctl poweroff`, since +it seems to cause issues no matter what `--job-mode=` is used: + +``` +[ 129.070993] testsuite-21.sh[380]: ++ systemctl start --job-mode=flush end.service +[ 129.154985] testsuite-21.sh[912]: Failed to start end.service: Transaction for end.service/start is destructive (sysinit.target has 'stop' job queued, but 'start' is included in transaction). +[ 129.159636] testsuite-21.sh[912]: See system logs and 'systemctl status end.service' for details. +``` + +Also, add a "safety net" which bypasses the manager and does the +poweroff directly, since sometimes the D-Bus call performed by +`systemctl` might timeout (as the manager might be still processing data +from the fuzzing): + +``` +[ 115.776778] sh[894]: + systemctl poweroff --no-block +[ 166.164242] testsuite-21.sh[893]: Failed to start transient service unit: Connection timed out +[ 166.269289] sh[894]: Call to PowerOff failed: Connection timed out +``` + +(cherry picked from commit 56e8ee55d58e38d47992ca6b5b6466fdb5be4781) + +Related: #2087652 +--- + test/units/testsuite-21.sh | 8 ++++++-- + 1 file changed, 6 insertions(+), 2 deletions(-) + +diff --git a/test/units/testsuite-21.sh b/test/units/testsuite-21.sh +index 053d571a90..e9bf18603a 100755 +--- a/test/units/testsuite-21.sh ++++ b/test/units/testsuite-21.sh +@@ -9,11 +9,15 @@ systemctl list-jobs | grep -F 'end.service' && SHUTDOWN_AT_EXIT=1 || SHUTDOWN_AT + + at_exit() { + set +e +- # We have to call the end.service explicitly even if it's specified on ++ # We have to call the end.service/poweroff explicitly even if it's specified on + # the kernel cmdline via systemd.wants=end.service, since dfuzzer calls + # org.freedesktop.systemd1.Manager.ClearJobs() which drops the service + # from the queue +- [[ $SHUTDOWN_AT_EXIT -ne 0 ]] && systemctl start --job-mode=flush end.service ++ if [[ $SHUTDOWN_AT_EXIT -ne 0 ]] && ! systemctl poweroff; then ++ # PID1 is down let's try to save the journal ++ journalctl --sync || : # journal can be down as well so let's ignore exit codes here ++ systemctl -ff poweroff # sync() and reboot(RB_POWER_OFF) ++ fi + } + + trap at_exit EXIT diff --git a/0132-tree-wide-drop-manually-crafted-message-for-missing-.patch b/0132-tree-wide-drop-manually-crafted-message-for-missing-.patch new file mode 100644 index 0000000..868ae1e --- /dev/null +++ b/0132-tree-wide-drop-manually-crafted-message-for-missing-.patch @@ -0,0 +1,167 @@ +From 910711b21c5fe4f26ad20a4d86e1acfb2a0afbdb Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Wed, 4 May 2022 08:24:06 +0200 +Subject: [PATCH] tree-wide: drop manually-crafted message for missing + variables + +Bash will generate a very nice message for us: +/tmp/ff.sh: line 1: SOMEVAR: parameter null or not set + +Let's save some keystrokes by not replacing this with our own inferior +messages. + +(cherry picked from commit d7ff52403902900b61f644f87b5222822fd4a69b) + +Related: #2087652 +--- + test/TEST-36-NUMAPOLICY/test.sh | 2 +- + test/hwdb-test.sh | 2 +- + test/test-rpm-macros.sh | 2 +- + test/units/testsuite-15.sh | 4 ++-- + test/units/testsuite-36.sh | 14 +++++++------- + test/units/testsuite-46.sh | 2 +- + tools/check-directives.sh | 4 ++-- + 7 files changed, 15 insertions(+), 15 deletions(-) + +diff --git a/test/TEST-36-NUMAPOLICY/test.sh b/test/TEST-36-NUMAPOLICY/test.sh +index 0eaaee9608..5f38bf1009 100755 +--- a/test/TEST-36-NUMAPOLICY/test.sh ++++ b/test/TEST-36-NUMAPOLICY/test.sh +@@ -9,7 +9,7 @@ TEST_NO_NSPAWN=1 + . "${TEST_BASE_DIR:?}/test-functions" + + if qemu_min_version "5.2.0"; then +- QEMU_OPTIONS="-object memory-backend-ram,id=mem0,size=${QEMU_MEM:?QEMU_MEM is unset} -numa node,memdev=mem0,nodeid=0" ++ QEMU_OPTIONS="-object memory-backend-ram,id=mem0,size=${QEMU_MEM:?} -numa node,memdev=mem0,nodeid=0" + else + QEMU_OPTIONS="-numa node,nodeid=0" + fi +diff --git a/test/hwdb-test.sh b/test/hwdb-test.sh +index 0551f26a2d..29183e6829 100755 +--- a/test/hwdb-test.sh ++++ b/test/hwdb-test.sh +@@ -11,7 +11,7 @@ set -e + + export SYSTEMD_LOG_LEVEL=info + ROOTDIR="$(dirname "$(dirname "$(readlink -f "$0")")")" +-SYSTEMD_HWDB="${1:?missing argument}" ++SYSTEMD_HWDB="${1:?}" + + if [ ! -x "$SYSTEMD_HWDB" ]; then + echo "$SYSTEMD_HWDB is not executable" >&2 +diff --git a/test/test-rpm-macros.sh b/test/test-rpm-macros.sh +index 5843b72346..c7107dec3e 100755 +--- a/test/test-rpm-macros.sh ++++ b/test/test-rpm-macros.sh +@@ -6,7 +6,7 @@ + # rpmspec utility is required (so this test will work with RPM 4 but won't work with RPM 5). + set -eu + +-BUILD_DIR="${1:?Missing argument: build directory}" ++BUILD_DIR="${1:?}" + RPM_MACROS_FILE="${BUILD_DIR:?}/src/rpm/macros.systemd" + + if ! command -v rpm >/dev/null || ! command -v rpmspec >/dev/null; then +diff --git a/test/units/testsuite-15.sh b/test/units/testsuite-15.sh +index 0446e71c38..f847adac74 100755 +--- a/test/units/testsuite-15.sh ++++ b/test/units/testsuite-15.sh +@@ -4,7 +4,7 @@ set -eux + set -o pipefail + + _clear_service () { +- local SERVICE_NAME="${1:?_clear_service: missing argument}" ++ local SERVICE_NAME="${1:?}" + systemctl stop "$SERVICE_NAME.service" 2>/dev/null || : + rm -f /{etc,run,usr/lib}/systemd/system/"$SERVICE_NAME".service + rm -fr /{etc,run,usr/lib}/systemd/system/"$SERVICE_NAME".service.d +@@ -25,7 +25,7 @@ clear_services () { + } + + create_service () { +- local SERVICE_NAME="${1:?create_service: missing argument}" ++ local SERVICE_NAME="${1:?}" + clear_services "$SERVICE_NAME" + + cat >/etc/systemd/system/"$SERVICE_NAME".service <"$confDir/numa.conf" <"$testUnitNUMAConf" </dev/null || exit 77 + diff --git a/0133-test-allow-overriding-QEMU_MEM-when-running-w-ASan.patch b/0133-test-allow-overriding-QEMU_MEM-when-running-w-ASan.patch new file mode 100644 index 0000000..8f4ab69 --- /dev/null +++ b/0133-test-allow-overriding-QEMU_MEM-when-running-w-ASan.patch @@ -0,0 +1,56 @@ +From 3e31fc66a206c272e7f73581c5ca752b4439fec3 Mon Sep 17 00:00:00 2001 +From: Frantisek Sumsal +Date: Tue, 21 Jun 2022 12:09:35 +0200 +Subject: [PATCH] test: allow overriding $QEMU_MEM when running w/ ASan + +(cherry picked from commit dc350e78fe66ae8698574202b2e30e5d650219ec) + +Related: #2087652 +--- + test/TEST-36-NUMAPOLICY/test.sh | 2 +- + test/test-functions | 5 ++--- + 2 files changed, 3 insertions(+), 4 deletions(-) + +diff --git a/test/TEST-36-NUMAPOLICY/test.sh b/test/TEST-36-NUMAPOLICY/test.sh +index 5f38bf1009..7909b1dce3 100755 +--- a/test/TEST-36-NUMAPOLICY/test.sh ++++ b/test/TEST-36-NUMAPOLICY/test.sh +@@ -9,7 +9,7 @@ TEST_NO_NSPAWN=1 + . "${TEST_BASE_DIR:?}/test-functions" + + if qemu_min_version "5.2.0"; then +- QEMU_OPTIONS="-object memory-backend-ram,id=mem0,size=${QEMU_MEM:?} -numa node,memdev=mem0,nodeid=0" ++ QEMU_OPTIONS="-object memory-backend-ram,id=mem0,size=${QEMU_MEM:-512M} -numa node,memdev=mem0,nodeid=0" + else + QEMU_OPTIONS="-numa node,nodeid=0" + fi +diff --git a/test/test-functions b/test/test-functions +index 079a7249e4..98efd047d7 100644 +--- a/test/test-functions ++++ b/test/test-functions +@@ -30,7 +30,6 @@ TIMED_OUT= # will be 1 after run_* if *_TIMEOUT is set and test timed out + [[ "$LOOKS_LIKE_SUSE" ]] && FSTYPE="${FSTYPE:-btrfs}" || FSTYPE="${FSTYPE:-ext4}" + UNIFIED_CGROUP_HIERARCHY="${UNIFIED_CGROUP_HIERARCHY:-default}" + EFI_MOUNT="${EFI_MOUNT:-$(bootctl -x 2>/dev/null || echo /boot)}" +-QEMU_MEM="${QEMU_MEM:-512M}" + # Note that defining a different IMAGE_NAME in a test setup script will only result + # in default.img being copied and renamed. It can then be extended by defining + # a test_append_files() function. The $1 parameter will be the root directory. +@@ -255,7 +254,7 @@ if get_bool "$IS_BUILT_WITH_ASAN"; then + STRIP_BINARIES=no + SKIP_INITRD="${SKIP_INITRD:-yes}" + PATH_TO_INIT=$ROOTLIBDIR/systemd-under-asan +- QEMU_MEM="2048M" ++ QEMU_MEM="${QEMU_MEM:-2G}" + QEMU_SMP="${QEMU_SMP:-4}" + + # We need to correctly distinguish between gcc's and clang's ASan DSOs. +@@ -444,7 +443,7 @@ run_qemu() { + qemu_options+=( + -smp "$QEMU_SMP" + -net none +- -m "$QEMU_MEM" ++ -m "${QEMU_MEM:-512M}" + -nographic + -kernel "$KERNEL_BIN" + -drive "format=raw,cache=unsafe,file=$image" diff --git a/0134-test-don-t-test-buses-we-don-t-ship.patch b/0134-test-don-t-test-buses-we-don-t-ship.patch new file mode 100644 index 0000000..fbe3762 --- /dev/null +++ b/0134-test-don-t-test-buses-we-don-t-ship.patch @@ -0,0 +1,39 @@ +From a2c46d33809334614f93964b1707b01cbe2e05a5 Mon Sep 17 00:00:00 2001 +From: Frantisek Sumsal +Date: Wed, 22 Jun 2022 11:09:58 +0200 +Subject: [PATCH] test: don't test buses we don't ship + +rhel-only + +Related: #2087652 +--- + test/units/testsuite-21.sh | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/test/units/testsuite-21.sh b/test/units/testsuite-21.sh +index e9bf18603a..bb2b754f35 100755 +--- a/test/units/testsuite-21.sh ++++ b/test/units/testsuite-21.sh +@@ -27,18 +27,18 @@ systemctl log-level info + # TODO + # * check for possibly newly introduced buses? + BUS_LIST=( +- org.freedesktop.home1 ++# org.freedesktop.home1 + org.freedesktop.hostname1 + org.freedesktop.import1 + org.freedesktop.locale1 + org.freedesktop.login1 + org.freedesktop.machine1 +- org.freedesktop.network1 +- org.freedesktop.portable1 ++# org.freedesktop.network1 ++# org.freedesktop.portable1 + org.freedesktop.resolve1 + org.freedesktop.systemd1 + org.freedesktop.timedate1 +- org.freedesktop.timesync1 ++# org.freedesktop.timesync1 + ) + + # systemd-oomd requires PSI diff --git a/0135-shutdown-get-only-active-md-arrays.patch b/0135-shutdown-get-only-active-md-arrays.patch new file mode 100644 index 0000000..93e24b5 --- /dev/null +++ b/0135-shutdown-get-only-active-md-arrays.patch @@ -0,0 +1,68 @@ +From 00ee9938c9c2333dc445b44e475974a3d3e37c10 Mon Sep 17 00:00:00 2001 +From: Mariusz Tkaczyk +Date: Tue, 29 Mar 2022 12:49:54 +0200 +Subject: [PATCH] shutdown: get only active md arrays. + +Current md_list_get() implementation filters all block devices, started from +"md*". This is ambiguous because list could contain: +- partitions created upon md device (mdXpY) +- external metadata container- specific type of md array. + +For partitions there is no issue, because they aren't handle STOP_ARRAY +ioctl sent later. It generates misleading errors only. + +Second case is more problematic because containers are not locked in kernel. +They are stopped even if container member array is active. For that reason +reboot or shutdown flow could be blocked because metadata manager cannot be +restarted after switch root on shutdown. + +Add filters to remove partitions and containers from md_list. Partitions +can be excluded by DEVTYPE. Containers are determined by MD_LEVEL +property, we are excluding all with "container" value. + +Signed-off-by: Mariusz Tkaczyk +(cherry picked from commit 3a3b022d2cc112803ea7b9beea98bbcad110368a) + +Resolves: #2047682 +--- + src/shutdown/umount.c | 18 +++++++++++++++++- + 1 file changed, 17 insertions(+), 1 deletion(-) + +diff --git a/src/shutdown/umount.c b/src/shutdown/umount.c +index f5a2cb20c1..6b08d9de74 100644 +--- a/src/shutdown/umount.c ++++ b/src/shutdown/umount.c +@@ -352,9 +352,14 @@ static int md_list_get(MountPoint **head) { + if (r < 0) + return r; + ++ /* Filter out partitions. */ ++ r = sd_device_enumerator_add_match_property(e, "DEVTYPE", "disk"); ++ if (r < 0) ++ return r; ++ + FOREACH_DEVICE(e, d) { + _cleanup_free_ char *p = NULL; +- const char *dn; ++ const char *dn, *md_level; + MountPoint *m; + dev_t devnum; + +@@ -362,6 +367,17 @@ static int md_list_get(MountPoint **head) { + sd_device_get_devname(d, &dn) < 0) + continue; + ++ r = sd_device_get_property_value(d, "MD_LEVEL", &md_level); ++ if (r < 0) { ++ log_warning_errno(r, "Failed to get MD_LEVEL property for %s, ignoring: %m", dn); ++ continue; ++ } ++ ++ /* MD "containers" are a special type of MD devices, used for external metadata. ++ * Since it doesn't provide RAID functionality in itself we don't need to stop it. */ ++ if (streq(md_level, "container")) ++ continue; ++ + p = strdup(dn); + if (!p) + return -ENOMEM; diff --git a/0136-bus-Use-OrderedSet-for-introspection.patch b/0136-bus-Use-OrderedSet-for-introspection.patch new file mode 100644 index 0000000..8625af6 --- /dev/null +++ b/0136-bus-Use-OrderedSet-for-introspection.patch @@ -0,0 +1,276 @@ +From 52af91cfd0eece566cb2b6877e622b16289525a4 Mon Sep 17 00:00:00 2001 +From: Jan Janssen +Date: Wed, 19 Jan 2022 10:15:36 +0100 +Subject: [PATCH] bus: Use OrderedSet for introspection + +Otherwise, the generated xml files are not reproducible. + +(cherry picked from commit acac88340ace3cd631126eebb6d0390cd54e8231) + +Resolves: #2068131 +--- + src/libsystemd/sd-bus/bus-introspect.c | 4 +-- + src/libsystemd/sd-bus/bus-introspect.h | 4 +-- + src/libsystemd/sd-bus/bus-objects.c | 45 +++++++++++++------------- + src/shared/bus-object.c | 4 +-- + 4 files changed, 28 insertions(+), 29 deletions(-) + +diff --git a/src/libsystemd/sd-bus/bus-introspect.c b/src/libsystemd/sd-bus/bus-introspect.c +index b9ef6af631..eed0dae82f 100644 +--- a/src/libsystemd/sd-bus/bus-introspect.c ++++ b/src/libsystemd/sd-bus/bus-introspect.c +@@ -110,7 +110,7 @@ static int set_interface_name(struct introspect *intro, const char *interface_na + return free_and_strdup(&intro->interface_name, interface_name); + } + +-int introspect_write_child_nodes(struct introspect *i, Set *s, const char *prefix) { ++int introspect_write_child_nodes(struct introspect *i, OrderedSet *s, const char *prefix) { + char *node; + + assert(i); +@@ -118,7 +118,7 @@ int introspect_write_child_nodes(struct introspect *i, Set *s, const char *prefi + + assert_se(set_interface_name(i, NULL) >= 0); + +- while ((node = set_steal_first(s))) { ++ while ((node = ordered_set_steal_first(s))) { + const char *e; + + e = object_path_startswith(node, prefix); +diff --git a/src/libsystemd/sd-bus/bus-introspect.h b/src/libsystemd/sd-bus/bus-introspect.h +index 34f32a4cf9..19e3ef09e2 100644 +--- a/src/libsystemd/sd-bus/bus-introspect.h ++++ b/src/libsystemd/sd-bus/bus-introspect.h +@@ -5,7 +5,7 @@ + + #include "sd-bus.h" + +-#include "set.h" ++#include "ordered-set.h" + + struct introspect { + FILE *f; +@@ -17,7 +17,7 @@ struct introspect { + + int introspect_begin(struct introspect *i, bool trusted); + int introspect_write_default_interfaces(struct introspect *i, bool object_manager); +-int introspect_write_child_nodes(struct introspect *i, Set *s, const char *prefix); ++int introspect_write_child_nodes(struct introspect *i, OrderedSet *s, const char *prefix); + int introspect_write_interface( + struct introspect *i, + const char *interface_name, +diff --git a/src/libsystemd/sd-bus/bus-objects.c b/src/libsystemd/sd-bus/bus-objects.c +index bf69539062..40158a7326 100644 +--- a/src/libsystemd/sd-bus/bus-objects.c ++++ b/src/libsystemd/sd-bus/bus-objects.c +@@ -9,7 +9,6 @@ + #include "bus-slot.h" + #include "bus-type.h" + #include "missing_capability.h" +-#include "set.h" + #include "string-util.h" + #include "strv.h" + +@@ -99,7 +98,7 @@ static int add_enumerated_to_set( + sd_bus *bus, + const char *prefix, + struct node_enumerator *first, +- Set *s, ++ OrderedSet *s, + sd_bus_error *error) { + + struct node_enumerator *c; +@@ -146,7 +145,7 @@ static int add_enumerated_to_set( + continue; + } + +- r = set_consume(s, *k); ++ r = ordered_set_consume(s, *k); + if (r == -EEXIST) + r = 0; + } +@@ -171,7 +170,7 @@ static int add_subtree_to_set( + const char *prefix, + struct node *n, + unsigned flags, +- Set *s, ++ OrderedSet *s, + sd_bus_error *error) { + + struct node *i; +@@ -198,7 +197,7 @@ static int add_subtree_to_set( + if (!t) + return -ENOMEM; + +- r = set_consume(s, t); ++ r = ordered_set_consume(s, t); + if (r < 0 && r != -EEXIST) + return r; + +@@ -220,10 +219,10 @@ static int get_child_nodes( + const char *prefix, + struct node *n, + unsigned flags, +- Set **_s, ++ OrderedSet **_s, + sd_bus_error *error) { + +- Set *s = NULL; ++ OrderedSet *s = NULL; + int r; + + assert(bus); +@@ -231,13 +230,13 @@ static int get_child_nodes( + assert(n); + assert(_s); + +- s = set_new(&string_hash_ops); ++ s = ordered_set_new(&string_hash_ops); + if (!s) + return -ENOMEM; + + r = add_subtree_to_set(bus, prefix, n, flags, s, error); + if (r < 0) { +- set_free_free(s); ++ ordered_set_free_free(s); + return r; + } + +@@ -937,7 +936,7 @@ int introspect_path( + char **ret, + sd_bus_error *error) { + +- _cleanup_set_free_free_ Set *s = NULL; ++ _cleanup_ordered_set_free_ OrderedSet *s = NULL; + _cleanup_(introspect_free) struct introspect intro = {}; + struct node_vtable *c; + bool empty; +@@ -963,7 +962,7 @@ int introspect_path( + if (r < 0) + return r; + +- empty = set_isempty(s); ++ empty = ordered_set_isempty(s); + + LIST_FOREACH(vtables, c, n->vtables) { + if (require_fallback && !c->is_fallback) +@@ -1233,7 +1232,7 @@ static int process_get_managed_objects( + + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; +- _cleanup_set_free_free_ Set *s = NULL; ++ _cleanup_ordered_set_free_free_ OrderedSet *s = NULL; + char *path; + int r; + +@@ -1263,7 +1262,7 @@ static int process_get_managed_objects( + if (r < 0) + return r; + +- SET_FOREACH(path, s) { ++ ORDERED_SET_FOREACH(path, s) { + r = object_manager_serialize_path_and_fallbacks(bus, reply, path, &error); + if (r < 0) + return bus_maybe_reply_error(m, r, &error); +@@ -2352,7 +2351,7 @@ _public_ int sd_bus_emit_properties_changed( + static int object_added_append_all_prefix( + sd_bus *bus, + sd_bus_message *m, +- Set *s, ++ OrderedSet *s, + const char *prefix, + const char *path, + bool require_fallback) { +@@ -2392,10 +2391,10 @@ static int object_added_append_all_prefix( + * skip it on any of its parents. The child vtables + * always fully override any conflicting vtables of + * any parent node. */ +- if (set_get(s, c->interface)) ++ if (ordered_set_get(s, c->interface)) + continue; + +- r = set_put(s, c->interface); ++ r = ordered_set_put(s, c->interface); + if (r < 0) + return r; + +@@ -2441,7 +2440,7 @@ static int object_added_append_all_prefix( + } + + static int object_added_append_all(sd_bus *bus, sd_bus_message *m, const char *path) { +- _cleanup_set_free_ Set *s = NULL; ++ _cleanup_ordered_set_free_ OrderedSet *s = NULL; + _cleanup_free_ char *prefix = NULL; + size_t pl; + int r; +@@ -2465,7 +2464,7 @@ static int object_added_append_all(sd_bus *bus, sd_bus_message *m, const char *p + * a parent that were overwritten by a child. + */ + +- s = set_new(&string_hash_ops); ++ s = ordered_set_new(&string_hash_ops); + if (!s) + return -ENOMEM; + +@@ -2572,7 +2571,7 @@ _public_ int sd_bus_emit_object_added(sd_bus *bus, const char *path) { + static int object_removed_append_all_prefix( + sd_bus *bus, + sd_bus_message *m, +- Set *s, ++ OrderedSet *s, + const char *prefix, + const char *path, + bool require_fallback) { +@@ -2605,7 +2604,7 @@ static int object_removed_append_all_prefix( + * skip it on any of its parents. The child vtables + * always fully override any conflicting vtables of + * any parent node. */ +- if (set_get(s, c->interface)) ++ if (ordered_set_get(s, c->interface)) + continue; + + r = node_vtable_get_userdata(bus, path, c, &u, &error); +@@ -2616,7 +2615,7 @@ static int object_removed_append_all_prefix( + if (r == 0) + continue; + +- r = set_put(s, c->interface); ++ r = ordered_set_put(s, c->interface); + if (r < 0) + return r; + +@@ -2631,7 +2630,7 @@ static int object_removed_append_all_prefix( + } + + static int object_removed_append_all(sd_bus *bus, sd_bus_message *m, const char *path) { +- _cleanup_set_free_ Set *s = NULL; ++ _cleanup_ordered_set_free_ OrderedSet *s = NULL; + _cleanup_free_ char *prefix = NULL; + size_t pl; + int r; +@@ -2642,7 +2641,7 @@ static int object_removed_append_all(sd_bus *bus, sd_bus_message *m, const char + + /* see sd_bus_emit_object_added() for details */ + +- s = set_new(&string_hash_ops); ++ s = ordered_set_new(&string_hash_ops); + if (!s) + return -ENOMEM; + +diff --git a/src/shared/bus-object.c b/src/shared/bus-object.c +index f2e53913fb..4ed5215e3d 100644 +--- a/src/shared/bus-object.c ++++ b/src/shared/bus-object.c +@@ -156,10 +156,10 @@ int bus_introspect_implementations( + if (impl != main_impl) + bus_introspect_implementation(&intro, impl); + +- _cleanup_set_free_ Set *nodes = NULL; ++ _cleanup_ordered_set_free_ OrderedSet *nodes = NULL; + + for (size_t i = 0; impl->children && impl->children[i]; i++) { +- r = set_put_strdup(&nodes, impl->children[i]->path); ++ r = ordered_set_put_strdup(&nodes, impl->children[i]->path); + if (r < 0) + return log_oom(); + } diff --git a/0137-logind-session-dbus-allow-to-set-display-name-via-db.patch b/0137-logind-session-dbus-allow-to-set-display-name-via-db.patch new file mode 100644 index 0000000..97de43e --- /dev/null +++ b/0137-logind-session-dbus-allow-to-set-display-name-via-db.patch @@ -0,0 +1,160 @@ +From 5cfd162864213c5247d97ea31cfacce98b1caefc Mon Sep 17 00:00:00 2001 +From: David Tardon +Date: Fri, 10 Jun 2022 15:07:01 +0200 +Subject: [PATCH] logind-session-dbus: allow to set display name via dbus + +Currently, the only way to set display name of a graphical session is to +pass it to CreateSession(). But modern display managers like gdm start +the display server as part of the user session, which means that the +display name isn't known yet when the session is being created. Hence, +let's make it possible to set it later. + +(cherry picked from commit 4885d7490b23e08d8444e5a68927ce9ce8727e5a) + +Resolves: #2100340 +--- + man/org.freedesktop.login1.xml | 8 ++++++++ + src/login/logind-session-dbus.c | 29 +++++++++++++++++++++++++++ + src/login/logind-session.c | 20 ++++++++++++++++++ + src/login/logind-session.h | 1 + + src/login/org.freedesktop.login1.conf | 4 ++++ + 5 files changed, 62 insertions(+) + +diff --git a/man/org.freedesktop.login1.xml b/man/org.freedesktop.login1.xml +index d25287b18b..c11324ee3b 100644 +--- a/man/org.freedesktop.login1.xml ++++ b/man/org.freedesktop.login1.xml +@@ -1045,6 +1045,7 @@ node /org/freedesktop/login1/session/1 { + TakeControl(in b force); + ReleaseControl(); + SetType(in s type); ++ SetDisplay(in s display); + TakeDevice(in u major, + in u minor, + out h fd, +@@ -1142,6 +1143,8 @@ node /org/freedesktop/login1/session/1 { + + + ++ ++ + + + +@@ -1238,6 +1241,11 @@ node /org/freedesktop/login1/session/1 { + connection. This should help prevent a session from entering an inconsistent state, for example if the + controller crashes. The only argument type is the new session type. + ++ SetDisplay() allows the display name of the graphical session to be changed. This is ++ useful if the display server is started as part of the session. It can only be called by session's current ++ controller. If TakeControl() has not been called, this method will fail. The only argument ++ display is the new display name. ++ + TakeDevice() allows a session controller to get a file descriptor for a + specific device. Pass in the major and minor numbers of the character device and + systemd-logind will return a file descriptor for the device. Only a limited set of +diff --git a/src/login/logind-session-dbus.c b/src/login/logind-session-dbus.c +index ff4cd0a631..5480d7b2f4 100644 +--- a/src/login/logind-session-dbus.c ++++ b/src/login/logind-session-dbus.c +@@ -413,6 +413,30 @@ static int method_set_type(sd_bus_message *message, void *userdata, sd_bus_error + return sd_bus_reply_method_return(message, NULL); + } + ++static int method_set_display(sd_bus_message *message, void *userdata, sd_bus_error *error) { ++ Session *s = ASSERT_PTR(userdata); ++ const char *display; ++ int r; ++ ++ assert(message); ++ ++ r = sd_bus_message_read(message, "s", &display); ++ if (r < 0) ++ return r; ++ ++ if (!session_is_controller(s, sd_bus_message_get_sender(message))) ++ return sd_bus_error_set(error, BUS_ERROR_NOT_IN_CONTROL, "You must be in control of this session to set display"); ++ ++ if (!SESSION_TYPE_IS_GRAPHICAL(s->type)) ++ return sd_bus_error_set(error, SD_BUS_ERROR_NOT_SUPPORTED, "Setting display is only supported for graphical sessions"); ++ ++ r = session_set_display(s, display); ++ if (r < 0) ++ return r; ++ ++ return sd_bus_reply_method_return(message, NULL); ++} ++ + static int method_take_device(sd_bus_message *message, void *userdata, sd_bus_error *error) { + Session *s = userdata; + uint32_t major, minor; +@@ -901,6 +925,11 @@ static const sd_bus_vtable session_vtable[] = { + SD_BUS_NO_RESULT, + method_set_type, + SD_BUS_VTABLE_UNPRIVILEGED), ++ SD_BUS_METHOD_WITH_ARGS("SetDisplay", ++ SD_BUS_ARGS("s", display), ++ SD_BUS_NO_RESULT, ++ method_set_display, ++ SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD_WITH_ARGS("TakeDevice", + SD_BUS_ARGS("u", major, "u", minor), + SD_BUS_RESULT("h", fd, "b", inactive), +diff --git a/src/login/logind-session.c b/src/login/logind-session.c +index ab98a5055d..a052596e57 100644 +--- a/src/login/logind-session.c ++++ b/src/login/logind-session.c +@@ -1044,6 +1044,26 @@ void session_set_type(Session *s, SessionType t) { + session_send_changed(s, "Type", NULL); + } + ++int session_set_display(Session *s, const char *display) { ++ int r; ++ ++ assert(s); ++ assert(display); ++ ++ if (streq(s->display, display)) ++ return 0; ++ ++ r = free_and_strdup(&s->display, display); ++ if (r < 0) ++ return r; ++ ++ session_save(s); ++ ++ session_send_changed(s, "Display", NULL); ++ ++ return 1; ++} ++ + static int session_dispatch_fifo(sd_event_source *es, int fd, uint32_t revents, void *userdata) { + Session *s = userdata; + +diff --git a/src/login/logind-session.h b/src/login/logind-session.h +index 5c35071dc5..6b6ac2d573 100644 +--- a/src/login/logind-session.h ++++ b/src/login/logind-session.h +@@ -137,6 +137,7 @@ int session_set_idle_hint(Session *s, bool b); + int session_get_locked_hint(Session *s); + void session_set_locked_hint(Session *s, bool b); + void session_set_type(Session *s, SessionType t); ++int session_set_display(Session *s, const char *display); + int session_create_fifo(Session *s); + int session_start(Session *s, sd_bus_message *properties, sd_bus_error *error); + int session_stop(Session *s, bool force); +diff --git a/src/login/org.freedesktop.login1.conf b/src/login/org.freedesktop.login1.conf +index 95d2ef0f06..6113b64aa7 100644 +--- a/src/login/org.freedesktop.login1.conf ++++ b/src/login/org.freedesktop.login1.conf +@@ -346,6 +346,10 @@ + send_interface="org.freedesktop.login1.User" + send_member="Kill"/> + ++ ++ + + + diff --git a/0138-ci-limit-which-env-variables-we-pass-through-sudo.patch b/0138-ci-limit-which-env-variables-we-pass-through-sudo.patch new file mode 100644 index 0000000..3d1f9cd --- /dev/null +++ b/0138-ci-limit-which-env-variables-we-pass-through-sudo.patch @@ -0,0 +1,35 @@ +From 433d2036ecf211e9a7c85d57e4c91d8723f80cbb Mon Sep 17 00:00:00 2001 +From: Frantisek Sumsal +Date: Wed, 13 Jul 2022 11:12:36 +0200 +Subject: [PATCH] ci: limit which env variables we pass through `sudo` + +to work around #23987. + +(cherry picked from commit d46e7c7cfd6c286a38298c067f16ac784c2a26f0) + +Related: #2087652 +--- + .github/workflows/unit_tests.yml | 10 ++++++++-- + 1 file changed, 8 insertions(+), 2 deletions(-) + +diff --git a/.github/workflows/unit_tests.yml b/.github/workflows/unit_tests.yml +index 2afde5d59d..58b7b7cdb2 100644 +--- a/.github/workflows/unit_tests.yml ++++ b/.github/workflows/unit_tests.yml +@@ -28,8 +28,14 @@ jobs: + - name: Repository checkout + uses: actions/checkout@ec3a7ce113134d7a93b817d10a8272cb61118579 + - name: Install build dependencies +- run: sudo -E .github/workflows/unit_tests.sh SETUP ++ run: | ++ # Drop XDG_* stuff from /etc/environment, so we don't get the user ++ # XDG_* variables when running under sudo ++ sudo sed -i '/^XDG_/d' /etc/environment ++ # Pass only specific env variables through sudo, to avoid having ++ # the already existing XDG_* stuff on the "other side" ++ sudo --preserve-env=CRYPTOLIB,GITHUB_ACTIONS,CI .github/workflows/unit_tests.sh SETUP + - name: Build & test (${{ matrix.run_phase }}-${{ matrix.cryptolib }}) +- run: sudo -E .github/workflows/unit_tests.sh RUN_${{ matrix.run_phase }} ++ run: sudo --preserve-env=CRYPTOLIB,GITHUB_ACTIONS,CI .github/workflows/unit_tests.sh RUN_${{ matrix.run_phase }} + env: + CRYPTOLIB: ${{ matrix.cryptolib }} diff --git a/0139-ci-Mergify-Add-ci-waived-logic.patch b/0139-ci-Mergify-Add-ci-waived-logic.patch new file mode 100644 index 0000000..246526b --- /dev/null +++ b/0139-ci-Mergify-Add-ci-waived-logic.patch @@ -0,0 +1,104 @@ +From 09eeda8d25f0f45d2c545c05fd8ae84404c83d83 Mon Sep 17 00:00:00 2001 +From: Jan Macku +Date: Tue, 19 Jul 2022 12:29:28 +0200 +Subject: [PATCH] ci(Mergify): Add `ci-waived` logic + +RHEL-only + +Related: #2087652 +--- + .mergify.yml | 66 ++++++++++++++++++++++++++++------------------------ + 1 file changed, 35 insertions(+), 31 deletions(-) + +diff --git a/.mergify.yml b/.mergify.yml +index b7852b201c..be25e52c76 100644 +--- a/.mergify.yml ++++ b/.mergify.yml +@@ -4,6 +4,7 @@ + pull_request_rules: + - name: Add `needs-ci` label on CI fail + conditions: ++ - label!=ci-waived + - or: + # Build test + - -check-success=build (gcc, 10, bfd) +@@ -31,9 +32,9 @@ pull_request_rules: + - and: + - "-check-success=LGTM analysis: C/C++" + - "-check-neutral=LGTM analysis: C/C++" +- # Packit +- - -check-success=rpm-build:centos-stream-9-aarch64 +- - -check-success=rpm-build:centos-stream-9-x86_64 ++ # Packit ++ - -check-success=rpm-build:centos-stream-9-aarch64 ++ - -check-success=rpm-build:centos-stream-9-x86_64 + actions: + label: + add: +@@ -41,35 +42,38 @@ pull_request_rules: + + - name: Remove `needs-ci` label on CI success + conditions: +- # Build test +- - check-success=build (gcc, 10, bfd) +- - check-success=build (gcc, 11, gold) +- - check-success=build (clang, 11, bfd) +- - check-success=build (clang, 12, gold) +- - check-success=build (clang, 13, lld) +- # Unit tests +- - check-success=build (GCC, auto) +- - check-success=build (GCC_ASAN_UBSAN, auto) +- - check-success=build (CLANG, auto) +- - check-success=build (CLANG_ASAN_UBSAN, auto) +- - check-success=build (GCC, openssl) +- - check-success=build (CLANG, gcrypt) +- # CentOS CI +- - check-success=CentOS CI (CentOS Stream 9) +- - check-success=CentOS CI (CentOS Stream 9 + sanitizers) +- # LGTM + - or: +- - "check-success=LGTM analysis: JavaScript" +- - "check-neutral=LGTM analysis: JavaScript" +- - or: +- - "check-success=LGTM analysis: Python" +- - "check-neutral=LGTM analysis: Python" +- - or: +- - "check-success=LGTM analysis: C/C++" +- - "check-neutral=LGTM analysis: C/C++" +- # Packit +- - check-success=rpm-build:centos-stream-9-aarch64 +- - check-success=rpm-build:centos-stream-9-x86_64 ++ - label=ci-waived ++ - and: ++ # Build test ++ - check-success=build (gcc, 10, bfd) ++ - check-success=build (gcc, 11, gold) ++ - check-success=build (clang, 11, bfd) ++ - check-success=build (clang, 12, gold) ++ - check-success=build (clang, 13, lld) ++ # Unit tests ++ - check-success=build (GCC, auto) ++ - check-success=build (GCC_ASAN_UBSAN, auto) ++ - check-success=build (CLANG, auto) ++ - check-success=build (CLANG_ASAN_UBSAN, auto) ++ - check-success=build (GCC, openssl) ++ - check-success=build (CLANG, gcrypt) ++ # CentOS CI ++ - check-success=CentOS CI (CentOS Stream 9) ++ - check-success=CentOS CI (CentOS Stream 9 + sanitizers) ++ # LGTM ++ - or: ++ - "check-success=LGTM analysis: JavaScript" ++ - "check-neutral=LGTM analysis: JavaScript" ++ - or: ++ - "check-success=LGTM analysis: Python" ++ - "check-neutral=LGTM analysis: Python" ++ - or: ++ - "check-success=LGTM analysis: C/C++" ++ - "check-neutral=LGTM analysis: C/C++" ++ # Packit ++ - check-success=rpm-build:centos-stream-9-aarch64 ++ - check-success=rpm-build:centos-stream-9-x86_64 + actions: + label: + remove: diff --git a/0140-json-use-unsigned-for-refernce-counter.patch b/0140-json-use-unsigned-for-refernce-counter.patch new file mode 100644 index 0000000..8f3042a --- /dev/null +++ b/0140-json-use-unsigned-for-refernce-counter.patch @@ -0,0 +1,36 @@ +From 46118fd04a49b25bc0c686b07d1b26309ab4e395 Mon Sep 17 00:00:00 2001 +From: Yu Watanabe +Date: Sun, 17 Apr 2022 06:46:25 +0900 +Subject: [PATCH] json: use unsigned for refernce counter + +For other places, we use unsigned for reference counter. + +(cherry picked from commit 6dd18b34cf53ab663140f43f8814904c71cc29f7) + +Related: #2087652 +--- + src/shared/json.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/src/shared/json.c b/src/shared/json.c +index 6d23bdf4f9..bcc109abc2 100644 +--- a/src/shared/json.c ++++ b/src/shared/json.c +@@ -41,7 +41,7 @@ assert_cc(DEPTH_MAX <= UINT16_MAX); + + typedef struct JsonSource { + /* When we parse from a file or similar, encodes the filename, to indicate the source of a json variant */ +- size_t n_ref; ++ unsigned n_ref; + unsigned max_line; + unsigned max_column; + char name[]; +@@ -53,7 +53,7 @@ struct JsonVariant { + /* We either maintain a reference counter for this variant itself, or we are embedded into an + * array/object, in which case only that surrounding object is ref-counted. (If 'embedded' is false, + * see below.) */ +- size_t n_ref; ++ unsigned n_ref; + + /* If this JsonVariant is part of an array/object, then this field points to the surrounding + * JSON_VARIANT_ARRAY/JSON_VARIANT_OBJECT object. (If 'embedded' is true, see below.) */ diff --git a/0141-macro-check-over-flow-in-reference-counter.patch b/0141-macro-check-over-flow-in-reference-counter.patch new file mode 100644 index 0000000..4c7e15f --- /dev/null +++ b/0141-macro-check-over-flow-in-reference-counter.patch @@ -0,0 +1,31 @@ +From eb7eca006b5f290481720dc4d7fcdba88d8613cb Mon Sep 17 00:00:00 2001 +From: Yu Watanabe +Date: Sun, 17 Apr 2022 06:54:50 +0900 +Subject: [PATCH] macro: check over flow in reference counter + +(cherry picked from commit c8431e9e35a904673cf659fd238cb63b3c3896fc) + +Related: #2087652 +--- + src/basic/macro.h | 8 ++++++-- + 1 file changed, 6 insertions(+), 2 deletions(-) + +diff --git a/src/basic/macro.h b/src/basic/macro.h +index aa04039e80..e7dc83ddc5 100644 +--- a/src/basic/macro.h ++++ b/src/basic/macro.h +@@ -387,8 +387,12 @@ static inline int __coverity_check_and_return__(int condition) { + if (!p) \ + return NULL; \ + \ +- assert(p->n_ref > 0); \ +- p->n_ref++; \ ++ /* For type check. */ \ ++ unsigned *q = &p->n_ref; \ ++ assert(*q > 0); \ ++ assert(*q < UINT_MAX); \ ++ \ ++ (*q)++; \ + return p; \ + } + diff --git a/0142-sd-bus-fix-reference-counter-to-be-incremented.patch b/0142-sd-bus-fix-reference-counter-to-be-incremented.patch new file mode 100644 index 0000000..13b37c1 --- /dev/null +++ b/0142-sd-bus-fix-reference-counter-to-be-incremented.patch @@ -0,0 +1,34 @@ +From 4dcd6089addae3ef6b6c82e36b30b178a4261249 Mon Sep 17 00:00:00 2001 +From: Yu Watanabe +Date: Sun, 17 Apr 2022 07:05:07 +0900 +Subject: [PATCH] sd-bus: fix reference counter to be incremented + +Fixes #23097. + +(cherry picked from commit b21f237d996c8c18991a68e1204f060d07dc4745) + +Related: #2087652 +--- + src/libsystemd/sd-bus/bus-track.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/src/libsystemd/sd-bus/bus-track.c b/src/libsystemd/sd-bus/bus-track.c +index bc36673b83..891fd0c899 100644 +--- a/src/libsystemd/sd-bus/bus-track.c ++++ b/src/libsystemd/sd-bus/bus-track.c +@@ -191,12 +191,12 @@ _public_ int sd_bus_track_add_name(sd_bus_track *track, const char *name) { + i = hashmap_get(track->names, name); + if (i) { + if (track->recursive) { +- unsigned k = track->n_ref + 1; ++ unsigned k = i->n_ref + 1; + +- if (k < track->n_ref) /* Check for overflow */ ++ if (k < i->n_ref) /* Check for overflow */ + return -EOVERFLOW; + +- track->n_ref = k; ++ i->n_ref = k; + } + + bus_track_remove_from_queue(track); diff --git a/0143-sd-bus-introduce-ref-unref-function-for-track_item.patch b/0143-sd-bus-introduce-ref-unref-function-for-track_item.patch new file mode 100644 index 0000000..53f7b4b --- /dev/null +++ b/0143-sd-bus-introduce-ref-unref-function-for-track_item.patch @@ -0,0 +1,105 @@ +From 6fcc3befd0ca9897071af071287e8758a30046f0 Mon Sep 17 00:00:00 2001 +From: Yu Watanabe +Date: Sun, 17 Apr 2022 07:20:16 +0900 +Subject: [PATCH] sd-bus: introduce ref/unref function for track_item + +(cherry picked from commit c2d7dd35d2a8cda439384a385b0c1bec804b9b79) + +Related: #2087652 +--- + src/libsystemd/sd-bus/bus-track.c | 35 ++++++++++++++----------------- + 1 file changed, 16 insertions(+), 19 deletions(-) + +diff --git a/src/libsystemd/sd-bus/bus-track.c b/src/libsystemd/sd-bus/bus-track.c +index 891fd0c899..135dfddc5f 100644 +--- a/src/libsystemd/sd-bus/bus-track.c ++++ b/src/libsystemd/sd-bus/bus-track.c +@@ -40,7 +40,6 @@ struct sd_bus_track { + "arg0='", name, "'") + + static struct track_item* track_item_free(struct track_item *i) { +- + if (!i) + return NULL; + +@@ -49,7 +48,8 @@ static struct track_item* track_item_free(struct track_item *i) { + return mfree(i); + } + +-DEFINE_TRIVIAL_CLEANUP_FUNC(struct track_item*, track_item_free); ++DEFINE_PRIVATE_TRIVIAL_REF_UNREF_FUNC(struct track_item, track_item, track_item_free); ++DEFINE_TRIVIAL_CLEANUP_FUNC(struct track_item*, track_item_unref); + DEFINE_PRIVATE_HASH_OPS_WITH_VALUE_DESTRUCTOR(track_item_hash_ops, char, string_hash_func, string_compare_func, + struct track_item, track_item_free); + +@@ -180,7 +180,7 @@ static int on_name_owner_changed(sd_bus_message *message, void *userdata, sd_bus + } + + _public_ int sd_bus_track_add_name(sd_bus_track *track, const char *name) { +- _cleanup_(track_item_freep) struct track_item *n = NULL; ++ _cleanup_(track_item_unrefp) struct track_item *n = NULL; + struct track_item *i; + const char *match; + int r; +@@ -190,14 +190,8 @@ _public_ int sd_bus_track_add_name(sd_bus_track *track, const char *name) { + + i = hashmap_get(track->names, name); + if (i) { +- if (track->recursive) { +- unsigned k = i->n_ref + 1; +- +- if (k < i->n_ref) /* Check for overflow */ +- return -EOVERFLOW; +- +- i->n_ref = k; +- } ++ if (track->recursive) ++ track_item_ref(i); + + bus_track_remove_from_queue(track); + return 0; +@@ -207,9 +201,14 @@ _public_ int sd_bus_track_add_name(sd_bus_track *track, const char *name) { + if (r < 0) + return r; + +- n = new0(struct track_item, 1); ++ n = new(struct track_item, 1); + if (!n) + return -ENOMEM; ++ ++ *n = (struct track_item) { ++ .n_ref = 1, ++ }; ++ + n->name = strdup(name); + if (!n->name) + return -ENOMEM; +@@ -241,8 +240,7 @@ _public_ int sd_bus_track_add_name(sd_bus_track *track, const char *name) { + return r; + } + +- n->n_ref = 1; +- n = NULL; ++ TAKE_PTR(n); + + bus_track_remove_from_queue(track); + track->modified = true; +@@ -264,14 +262,13 @@ _public_ int sd_bus_track_remove_name(sd_bus_track *track, const char *name) { + i = hashmap_get(track->names, name); + if (!i) + return -EUNATCH; +- if (i->n_ref <= 0) +- return -EUNATCH; + +- i->n_ref--; +- +- if (i->n_ref <= 0) ++ assert(i->n_ref >= 1); ++ if (i->n_ref <= 1) + return bus_track_remove_name_fully(track, name); + ++ track_item_unref(i); ++ + return 1; + } + diff --git a/0144-sd-bus-do-not-read-unused-value.patch b/0144-sd-bus-do-not-read-unused-value.patch new file mode 100644 index 0000000..c3387a5 --- /dev/null +++ b/0144-sd-bus-do-not-read-unused-value.patch @@ -0,0 +1,32 @@ +From 5f241b4af41402be5357d6ab10b4c54378363c89 Mon Sep 17 00:00:00 2001 +From: Yu Watanabe +Date: Sun, 17 Apr 2022 07:25:09 +0900 +Subject: [PATCH] sd-bus: do not read unused value + +(cherry picked from commit 6a7ca27740be4229b4c9f540cd610b205ca5752c) + +Related: #2087652 +--- + src/libsystemd/sd-bus/bus-track.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/src/libsystemd/sd-bus/bus-track.c b/src/libsystemd/sd-bus/bus-track.c +index 135dfddc5f..1cbdb46f4c 100644 +--- a/src/libsystemd/sd-bus/bus-track.c ++++ b/src/libsystemd/sd-bus/bus-track.c +@@ -165,13 +165,13 @@ DEFINE_PUBLIC_TRIVIAL_REF_UNREF_FUNC(sd_bus_track, sd_bus_track, track_free); + + static int on_name_owner_changed(sd_bus_message *message, void *userdata, sd_bus_error *error) { + sd_bus_track *track = userdata; +- const char *name, *old, *new; ++ const char *name; + int r; + + assert(message); + assert(track); + +- r = sd_bus_message_read(message, "sss", &name, &old, &new); ++ r = sd_bus_message_read(message, "sss", &name, NULL, NULL); + if (r < 0) + return 0; + diff --git a/0145-sd-bus-do-not-return-negative-errno-when-unknown-nam.patch b/0145-sd-bus-do-not-return-negative-errno-when-unknown-nam.patch new file mode 100644 index 0000000..6826818 --- /dev/null +++ b/0145-sd-bus-do-not-return-negative-errno-when-unknown-nam.patch @@ -0,0 +1,35 @@ +From f2ca27c7fa3e98cbb412871d7ea18b51e7f5f048 Mon Sep 17 00:00:00 2001 +From: Yu Watanabe +Date: Sun, 17 Apr 2022 07:29:24 +0900 +Subject: [PATCH] sd-bus: do not return negative errno when unknown name is + specified + +When 'recursive' is false, then sd_bus_track_remove_name() does not +return negative errno when unknown name is specified. Let's follow the +same pattern for the case that 'recursive' is true. + +(cherry picked from commit 55bfacc6c33eaf3475762e71172b2ef504be5af8) + +Related: #2087652 +--- + src/libsystemd/sd-bus/bus-track.c | 5 +---- + 1 file changed, 1 insertion(+), 4 deletions(-) + +diff --git a/src/libsystemd/sd-bus/bus-track.c b/src/libsystemd/sd-bus/bus-track.c +index 1cbdb46f4c..c56bd03fc6 100644 +--- a/src/libsystemd/sd-bus/bus-track.c ++++ b/src/libsystemd/sd-bus/bus-track.c +@@ -256,12 +256,9 @@ _public_ int sd_bus_track_remove_name(sd_bus_track *track, const char *name) { + if (!track) /* Treat a NULL track object as an empty track object */ + return 0; + +- if (!track->recursive) +- return bus_track_remove_name_fully(track, name); +- + i = hashmap_get(track->names, name); + if (!i) +- return -EUNATCH; ++ return 0; + + assert(i->n_ref >= 1); + if (i->n_ref <= 1) diff --git a/0146-sd-bus-use-hashmap_contains-and-drop-unnecessary-cas.patch b/0146-sd-bus-use-hashmap_contains-and-drop-unnecessary-cas.patch new file mode 100644 index 0000000..80691c7 --- /dev/null +++ b/0146-sd-bus-use-hashmap_contains-and-drop-unnecessary-cas.patch @@ -0,0 +1,25 @@ +From 73c3e230dd66bedc82fa6dbf020c8d24592a32be Mon Sep 17 00:00:00 2001 +From: Yu Watanabe +Date: Sun, 17 Apr 2022 08:00:20 +0900 +Subject: [PATCH] sd-bus: use hashmap_contains() and drop unnecessary cast + +(cherry picked from commit c399ed923d6fa4bf731455d485cac5f00e060806) + +Related: #2087652 +--- + src/libsystemd/sd-bus/bus-track.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/libsystemd/sd-bus/bus-track.c b/src/libsystemd/sd-bus/bus-track.c +index c56bd03fc6..4c44162108 100644 +--- a/src/libsystemd/sd-bus/bus-track.c ++++ b/src/libsystemd/sd-bus/bus-track.c +@@ -287,7 +287,7 @@ _public_ const char* sd_bus_track_contains(sd_bus_track *track, const char *name + if (!track) /* Let's consider a NULL object equivalent to an empty object */ + return NULL; + +- return hashmap_get(track->names, (void*) name) ? name : NULL; ++ return hashmap_contains(track->names, name) ? name : NULL; + } + + _public_ const char* sd_bus_track_first(sd_bus_track *track) { diff --git a/0147-test-shorten-code-a-bit.patch b/0147-test-shorten-code-a-bit.patch new file mode 100644 index 0000000..e640be2 --- /dev/null +++ b/0147-test-shorten-code-a-bit.patch @@ -0,0 +1,99 @@ +From 6ddb7fc35d7051627fa2772226e07296c28b316f Mon Sep 17 00:00:00 2001 +From: Yu Watanabe +Date: Sun, 17 Apr 2022 07:35:05 +0900 +Subject: [PATCH] test: shorten code a bit + +(cherry picked from commit 63ec7a849039fab830961fd7fee0c1e266735fc8) + +Related: #2087652 +--- + src/libsystemd/sd-bus/test-bus-track.c | 39 +++++++++----------------- + 1 file changed, 13 insertions(+), 26 deletions(-) + +diff --git a/src/libsystemd/sd-bus/test-bus-track.c b/src/libsystemd/sd-bus/test-bus-track.c +index 64aa88bb4f..238934a880 100644 +--- a/src/libsystemd/sd-bus/test-bus-track.c ++++ b/src/libsystemd/sd-bus/test-bus-track.c +@@ -26,7 +26,6 @@ static int track_cb_x(sd_bus_track *t, void *userdata) { + } + + static int track_cb_y(sd_bus_track *t, void *userdata) { +- int r; + + log_error("TRACK CB Y"); + +@@ -35,8 +34,7 @@ static int track_cb_y(sd_bus_track *t, void *userdata) { + + /* We got disconnected, let's close everything */ + +- r = sd_event_exit(sd_bus_get_event(sd_bus_track_get_bus(t)), EXIT_SUCCESS); +- assert_se(r >= 0); ++ assert_se(sd_event_exit(sd_bus_get_event(sd_bus_track_get_bus(t)), EXIT_SUCCESS) >= 0); + + return 0; + } +@@ -51,8 +49,7 @@ int main(int argc, char *argv[]) { + + test_setup_logging(LOG_INFO); + +- r = sd_event_default(&event); +- assert_se(r >= 0); ++ assert_se(sd_event_default(&event) >= 0); + + r = sd_bus_open_user(&a); + if (IN_SET(r, -ECONNREFUSED, -ENOENT, -ENOMEDIUM)) { +@@ -63,43 +60,33 @@ int main(int argc, char *argv[]) { + } + assert_se(r >= 0); + +- r = sd_bus_attach_event(a, event, SD_EVENT_PRIORITY_NORMAL); +- assert_se(r >= 0); ++ assert_se(sd_bus_attach_event(a, event, SD_EVENT_PRIORITY_NORMAL) >= 0); + + if (use_system_bus) +- r = sd_bus_open_system(&b); ++ assert_se(sd_bus_open_system(&b) >= 0); + else +- r = sd_bus_open_user(&b); +- assert_se(r >= 0); ++ assert_se(sd_bus_open_user(&b) >= 0); + +- r = sd_bus_attach_event(b, event, SD_EVENT_PRIORITY_NORMAL); +- assert_se(r >= 0); ++ assert_se(sd_bus_attach_event(b, event, SD_EVENT_PRIORITY_NORMAL) >= 0); + + /* Watch b's name from a */ +- r = sd_bus_track_new(a, &x, track_cb_x, NULL); +- assert_se(r >= 0); ++ assert_se(sd_bus_track_new(a, &x, track_cb_x, NULL) >= 0); + +- r = sd_bus_get_unique_name(b, &unique); +- assert_se(r >= 0); ++ assert_se(sd_bus_get_unique_name(b, &unique) >= 0); + +- r = sd_bus_track_add_name(x, unique); +- assert_se(r >= 0); ++ assert_se(sd_bus_track_add_name(x, unique) >= 0); + + /* Watch's a's own name from a */ +- r = sd_bus_track_new(a, &y, track_cb_y, NULL); +- assert_se(r >= 0); ++ assert_se(sd_bus_track_new(a, &y, track_cb_y, NULL) >= 0); + +- r = sd_bus_get_unique_name(a, &unique); +- assert_se(r >= 0); ++ assert_se(sd_bus_get_unique_name(a, &unique) >= 0); + +- r = sd_bus_track_add_name(y, unique); +- assert_se(r >= 0); ++ assert_se(sd_bus_track_add_name(y, unique) >= 0); + + /* Now make b's name disappear */ + sd_bus_close(b); + +- r = sd_event_loop(event); +- assert_se(r >= 0); ++ assert_se(sd_event_loop(event) >= 0); + + assert_se(track_cb_called_x); + assert_se(track_cb_called_y); diff --git a/0148-test-add-several-tests-for-track-item.patch b/0148-test-add-several-tests-for-track-item.patch new file mode 100644 index 0000000..da0c5e3 --- /dev/null +++ b/0148-test-add-several-tests-for-track-item.patch @@ -0,0 +1,97 @@ +From 4895d281d18e244d8238c1f77e597ce43310531c Mon Sep 17 00:00:00 2001 +From: Yu Watanabe +Date: Sun, 17 Apr 2022 07:58:45 +0900 +Subject: [PATCH] test: add several tests for track item + +(cherry picked from commit 056a18e465bedb1bd35ce0bf78831be168c636cb) + +Related: #2087652 +--- + src/libsystemd/sd-bus/test-bus-track.c | 58 +++++++++++++++++++++++++- + 1 file changed, 57 insertions(+), 1 deletion(-) + +diff --git a/src/libsystemd/sd-bus/test-bus-track.c b/src/libsystemd/sd-bus/test-bus-track.c +index 238934a880..5604e84f52 100644 +--- a/src/libsystemd/sd-bus/test-bus-track.c ++++ b/src/libsystemd/sd-bus/test-bus-track.c +@@ -10,6 +10,7 @@ + + static bool track_cb_called_x = false; + static bool track_cb_called_y = false; ++static bool track_destroy_called_z = false; + + static int track_cb_x(sd_bus_track *t, void *userdata) { + +@@ -39,9 +40,17 @@ static int track_cb_y(sd_bus_track *t, void *userdata) { + return 0; + } + ++static int track_cb_z(sd_bus_track *t, void *userdata) { ++ assert_not_reached(); ++} ++ ++static void track_destroy_z(void *userdata) { ++ track_destroy_called_z = true; ++} ++ + int main(int argc, char *argv[]) { + _cleanup_(sd_event_unrefp) sd_event *event = NULL; +- _cleanup_(sd_bus_track_unrefp) sd_bus_track *x = NULL, *y = NULL; ++ _cleanup_(sd_bus_track_unrefp) sd_bus_track *x = NULL, *y = NULL, *z = NULL; + _cleanup_(sd_bus_unrefp) sd_bus *a = NULL, *b = NULL; + bool use_system_bus = false; + const char *unique; +@@ -83,6 +92,53 @@ int main(int argc, char *argv[]) { + + assert_se(sd_bus_track_add_name(y, unique) >= 0); + ++ /* Basic tests. */ ++ assert_se(sd_bus_track_new(a, &z, track_cb_z, NULL) >= 0); ++ ++ /* non-recursive case */ ++ assert_se(sd_bus_track_set_recursive(z, false) >= 0); ++ assert_se(sd_bus_track_get_recursive(z) == 0); ++ assert_se(!sd_bus_track_contains(z, unique)); ++ assert_se(sd_bus_track_count_name(z, unique) == 0); ++ assert_se(sd_bus_track_remove_name(z, unique) == 0); ++ assert_se(sd_bus_track_add_name(z, unique) >= 0); ++ assert_se(sd_bus_track_add_name(z, unique) >= 0); ++ assert_se(sd_bus_track_add_name(z, unique) >= 0); ++ assert_se(sd_bus_track_set_recursive(z, true) == -EBUSY); ++ assert_se(sd_bus_track_contains(z, unique)); ++ assert_se(sd_bus_track_count_name(z, unique) == 1); ++ assert_se(sd_bus_track_remove_name(z, unique) == 1); ++ assert_se(!sd_bus_track_contains(z, unique)); ++ assert_se(sd_bus_track_count_name(z, unique) == 0); ++ assert_se(sd_bus_track_remove_name(z, unique) == 0); ++ ++ /* recursive case */ ++ assert_se(sd_bus_track_set_recursive(z, true) >= 0); ++ assert_se(sd_bus_track_get_recursive(z) == 1); ++ assert_se(!sd_bus_track_contains(z, unique)); ++ assert_se(sd_bus_track_count_name(z, unique) == 0); ++ assert_se(sd_bus_track_remove_name(z, unique) == 0); ++ assert_se(sd_bus_track_add_name(z, unique) >= 0); ++ assert_se(sd_bus_track_add_name(z, unique) >= 0); ++ assert_se(sd_bus_track_add_name(z, unique) >= 0); ++ assert_se(sd_bus_track_set_recursive(z, false) == -EBUSY); ++ assert_se(sd_bus_track_contains(z, unique)); ++ assert_se(sd_bus_track_count_name(z, unique) == 3); ++ assert_se(sd_bus_track_remove_name(z, unique) == 1); ++ assert_se(sd_bus_track_contains(z, unique)); ++ assert_se(sd_bus_track_count_name(z, unique) == 2); ++ assert_se(sd_bus_track_remove_name(z, unique) == 1); ++ assert_se(sd_bus_track_contains(z, unique)); ++ assert_se(sd_bus_track_count_name(z, unique) == 1); ++ assert_se(sd_bus_track_remove_name(z, unique) == 1); ++ assert_se(!sd_bus_track_contains(z, unique)); ++ assert_se(sd_bus_track_count_name(z, unique) == 0); ++ assert_se(sd_bus_track_remove_name(z, unique) == 0); ++ ++ assert_se(sd_bus_track_set_destroy_callback(z, track_destroy_z) >= 0); ++ z = sd_bus_track_unref(z); ++ assert_se(track_destroy_called_z); ++ + /* Now make b's name disappear */ + sd_bus_close(b); + diff --git a/0149-core-slice-make-slice_freezer_action-return-0-if-fre.patch b/0149-core-slice-make-slice_freezer_action-return-0-if-fre.patch new file mode 100644 index 0000000..edf5faa --- /dev/null +++ b/0149-core-slice-make-slice_freezer_action-return-0-if-fre.patch @@ -0,0 +1,46 @@ +From 776aab7656db605a856d2d3e9225f23779da5483 Mon Sep 17 00:00:00 2001 +From: Yu Watanabe +Date: Fri, 6 May 2022 14:01:22 +0900 +Subject: [PATCH] core/slice: make slice_freezer_action() return 0 if freezing + state is unchanged + +Fixes #23278. + +(cherry picked from commit d171e72e7afa11b238ba20758384d223b0c76e39) + +Related: #2087652 +--- + src/core/slice.c | 6 +----- + src/core/unit.c | 2 ++ + 2 files changed, 3 insertions(+), 5 deletions(-) + +diff --git a/src/core/slice.c b/src/core/slice.c +index 2e43c00119..c453aa033e 100644 +--- a/src/core/slice.c ++++ b/src/core/slice.c +@@ -389,11 +389,7 @@ static int slice_freezer_action(Unit *s, FreezerAction action) { + return r; + } + +- r = unit_cgroup_freezer_action(s, action); +- if (r < 0) +- return r; +- +- return 1; ++ return unit_cgroup_freezer_action(s, action); + } + + static int slice_freeze(Unit *s) { +diff --git a/src/core/unit.c b/src/core/unit.c +index 9cbed08987..aac87dcc7a 100644 +--- a/src/core/unit.c ++++ b/src/core/unit.c +@@ -5822,6 +5822,8 @@ static int unit_freezer_action(Unit *u, FreezerAction action) { + if (r <= 0) + return r; + ++ assert(IN_SET(u->freezer_state, FREEZER_FREEZING, FREEZER_THAWING)); ++ + return 1; + } + diff --git a/0150-core-unit-fix-use-after-free.patch b/0150-core-unit-fix-use-after-free.patch new file mode 100644 index 0000000..e308d5f --- /dev/null +++ b/0150-core-unit-fix-use-after-free.patch @@ -0,0 +1,29 @@ +From b8ccf30c4654ed5697562842a8a608e627425370 Mon Sep 17 00:00:00 2001 +From: Yu Watanabe +Date: Mon, 9 May 2022 00:56:05 +0900 +Subject: [PATCH] core/unit: fix use-after-free + +Fixes #23312. + +(cherry picked from commit 734582830b58e000a26e18807ea277c18778573c) + +Related: #2087652 +--- + src/core/unit.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/src/core/unit.c b/src/core/unit.c +index aac87dcc7a..0eade13ee9 100644 +--- a/src/core/unit.c ++++ b/src/core/unit.c +@@ -671,8 +671,8 @@ Unit* unit_free(Unit *u) { + + unit_dequeue_rewatch_pids(u); + +- sd_bus_slot_unref(u->match_bus_slot); +- sd_bus_track_unref(u->bus_track); ++ u->match_bus_slot = sd_bus_slot_unref(u->match_bus_slot); ++ u->bus_track = sd_bus_track_unref(u->bus_track); + u->deserialized_refs = strv_free(u->deserialized_refs); + u->pending_freezer_message = sd_bus_message_unref(u->pending_freezer_message); + diff --git a/0151-core-timer-fix-potential-use-after-free.patch b/0151-core-timer-fix-potential-use-after-free.patch new file mode 100644 index 0000000..c83f10b --- /dev/null +++ b/0151-core-timer-fix-potential-use-after-free.patch @@ -0,0 +1,25 @@ +From e9acfceb104c8f9ccec8b468b5d111844285f43a Mon Sep 17 00:00:00 2001 +From: Yu Watanabe +Date: Tue, 10 May 2022 14:10:17 +0900 +Subject: [PATCH] core/timer: fix potential use-after-free + +(cherry picked from commit 756491af392a99c4286d876b0041535e50df80ad) + +Related: #2087652 +--- + src/core/timer.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/core/timer.c b/src/core/timer.c +index 0dc49dd46b..b439802bc2 100644 +--- a/src/core/timer.c ++++ b/src/core/timer.c +@@ -68,7 +68,7 @@ static void timer_done(Unit *u) { + t->monotonic_event_source = sd_event_source_disable_unref(t->monotonic_event_source); + t->realtime_event_source = sd_event_source_disable_unref(t->realtime_event_source); + +- free(t->stamp_path); ++ t->stamp_path = mfree(t->stamp_path); + } + + static int timer_verify(Timer *t) { diff --git a/0152-core-command-argument-can-be-longer-than-PATH_MAX.patch b/0152-core-command-argument-can-be-longer-than-PATH_MAX.patch new file mode 100644 index 0000000..c9880b5 --- /dev/null +++ b/0152-core-command-argument-can-be-longer-than-PATH_MAX.patch @@ -0,0 +1,64 @@ +From fdc436432f1ca2dd9df2f24728916ab1201015c1 Mon Sep 17 00:00:00 2001 +From: Yu Watanabe +Date: Tue, 5 Apr 2022 21:47:46 +0900 +Subject: [PATCH] core: command argument can be longer than PATH_MAX + +Fixes a bug introduced by 065364920281e1cf59cab989e17aff21790505c4. + +Fixes #22957. + +(cherry picked from commit 58dd4999dcc81a0ed92fbd78bce3592c3e3afe9e) + +Resolves: #2073994 +--- + src/core/load-fragment.c | 2 +- + src/test/test-load-fragment.c | 16 ++++++++++++++++ + 2 files changed, 17 insertions(+), 1 deletion(-) + +diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c +index ad5a0912fc..461e073269 100644 +--- a/src/core/load-fragment.c ++++ b/src/core/load-fragment.c +@@ -1000,7 +1000,7 @@ int config_parse_exec( + if (r < 0) + return ignore ? 0 : -ENOEXEC; + +- r = unit_path_printf(u, word, &resolved); ++ r = unit_full_printf(u, word, &resolved); + if (r < 0) { + log_syntax(unit, ignore ? LOG_WARNING : LOG_ERR, filename, line, r, + "Failed to resolve unit specifiers in %s%s: %m", +diff --git a/src/test/test-load-fragment.c b/src/test/test-load-fragment.c +index fbe4744333..c579be4150 100644 +--- a/src/test/test-load-fragment.c ++++ b/src/test/test-load-fragment.c +@@ -10,6 +10,7 @@ + #include "capability-util.h" + #include "conf-parser.h" + #include "fd-util.h" ++#include "fileio.h" + #include "format-util.h" + #include "fs-util.h" + #include "hashmap.h" +@@ -416,6 +417,21 @@ TEST(config_parse_exec) { + assert_se(r == 0); + assert_se(c1->command_next == NULL); + ++ log_info("/* long arg */"); /* See issue #22957. */ ++ ++ char x[LONG_LINE_MAX-100], *y; ++ y = mempcpy(x, "/bin/echo ", STRLEN("/bin/echo ")); ++ memset(y, 'x', sizeof(x) - STRLEN("/bin/echo ") - 1); ++ x[sizeof(x) - 1] = '\0'; ++ ++ r = config_parse_exec(NULL, "fake", 5, "section", 1, ++ "LValue", 0, x, ++ &c, u); ++ assert_se(r >= 0); ++ c1 = c1->command_next; ++ check_execcommand(c1, ++ "/bin/echo", NULL, y, NULL, false); ++ + log_info("/* empty argument, reset */"); + r = config_parse_exec(NULL, "fake", 4, "section", 1, + "LValue", 0, "", diff --git a/0153-shared-install-consistently-use-lp-as-the-name-for-t.patch b/0153-shared-install-consistently-use-lp-as-the-name-for-t.patch new file mode 100644 index 0000000..fa69c99 --- /dev/null +++ b/0153-shared-install-consistently-use-lp-as-the-name-for-t.patch @@ -0,0 +1,1534 @@ +From a2632eca864670f7a88e1a81947a9e726282e531 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Wed, 2 Mar 2022 17:17:39 +0100 +Subject: [PATCH] shared/install: consistently use 'lp' as the name for the + LookupPaths instance + +Most of the codebase does this. Here we were using 'p' or 'paths' +instead. Those names are very generic and not good for a "global-like" +object like the LookupPaths instance. And we also have 'path' variable, +and it's confusing to have 'path' and 'paths' in the same function that +are unrelated. + +Also pass down LookupPaths* lower in the call stack, in preparation for +future changes. + +(cherry picked from commit c3e7fba07c19f232f5945c07e7cc730986615adf) + +Related: #2082131 +--- + src/shared/install.c | 427 +++++++++++++++++++++---------------------- + 1 file changed, 212 insertions(+), 215 deletions(-) + +diff --git a/src/shared/install.c b/src/shared/install.c +index 8f1af755fa..c6cbe96fdb 100644 +--- a/src/shared/install.c ++++ b/src/shared/install.c +@@ -98,7 +98,7 @@ static const char *const unit_file_type_table[_UNIT_FILE_TYPE_MAX] = { + + DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(unit_file_type, UnitFileType); + +-static int in_search_path(const LookupPaths *p, const char *path) { ++static int in_search_path(const LookupPaths *lp, const char *path) { + _cleanup_free_ char *parent = NULL; + + assert(path); +@@ -107,19 +107,16 @@ static int in_search_path(const LookupPaths *p, const char *path) { + if (!parent) + return -ENOMEM; + +- return path_strv_contains(p->search_path, parent); ++ return path_strv_contains(lp->search_path, parent); + } + +-static const char* skip_root(const LookupPaths *p, const char *path) { +- char *e; +- +- assert(p); ++static const char* skip_root(const char *root_dir, const char *path) { + assert(path); + +- if (!p->root_dir) ++ if (!root_dir) + return path; + +- e = path_startswith(path, p->root_dir); ++ const char *e = path_startswith(path, root_dir); + if (!e) + return NULL; + +@@ -134,52 +131,52 @@ static const char* skip_root(const LookupPaths *p, const char *path) { + return e; + } + +-static int path_is_generator(const LookupPaths *p, const char *path) { ++static int path_is_generator(const LookupPaths *lp, const char *path) { + _cleanup_free_ char *parent = NULL; + +- assert(p); ++ assert(lp); + assert(path); + + parent = dirname_malloc(path); + if (!parent) + return -ENOMEM; + +- return path_equal_ptr(parent, p->generator) || +- path_equal_ptr(parent, p->generator_early) || +- path_equal_ptr(parent, p->generator_late); ++ return path_equal_ptr(parent, lp->generator) || ++ path_equal_ptr(parent, lp->generator_early) || ++ path_equal_ptr(parent, lp->generator_late); + } + +-static int path_is_transient(const LookupPaths *p, const char *path) { ++static int path_is_transient(const LookupPaths *lp, const char *path) { + _cleanup_free_ char *parent = NULL; + +- assert(p); ++ assert(lp); + assert(path); + + parent = dirname_malloc(path); + if (!parent) + return -ENOMEM; + +- return path_equal_ptr(parent, p->transient); ++ return path_equal_ptr(parent, lp->transient); + } + +-static int path_is_control(const LookupPaths *p, const char *path) { ++static int path_is_control(const LookupPaths *lp, const char *path) { + _cleanup_free_ char *parent = NULL; + +- assert(p); ++ assert(lp); + assert(path); + + parent = dirname_malloc(path); + if (!parent) + return -ENOMEM; + +- return path_equal_ptr(parent, p->persistent_control) || +- path_equal_ptr(parent, p->runtime_control); ++ return path_equal_ptr(parent, lp->persistent_control) || ++ path_equal_ptr(parent, lp->runtime_control); + } + +-static int path_is_config(const LookupPaths *p, const char *path, bool check_parent) { ++static int path_is_config(const LookupPaths *lp, const char *path, bool check_parent) { + _cleanup_free_ char *parent = NULL; + +- assert(p); ++ assert(lp); + assert(path); + + /* Note that we do *not* have generic checks for /etc or /run in place, since with +@@ -193,21 +190,21 @@ static int path_is_config(const LookupPaths *p, const char *path, bool check_par + path = parent; + } + +- return path_equal_ptr(path, p->persistent_config) || +- path_equal_ptr(path, p->runtime_config); ++ return path_equal_ptr(path, lp->persistent_config) || ++ path_equal_ptr(path, lp->runtime_config); + } + +-static int path_is_runtime(const LookupPaths *p, const char *path, bool check_parent) { ++static int path_is_runtime(const LookupPaths *lp, const char *path, bool check_parent) { + _cleanup_free_ char *parent = NULL; + const char *rpath; + +- assert(p); ++ assert(lp); + assert(path); + + /* Everything in /run is considered runtime. On top of that we also add + * explicit checks for the various runtime directories, as safety net. */ + +- rpath = skip_root(p, path); ++ rpath = skip_root(lp->root_dir, path); + if (rpath && path_startswith(rpath, "/run")) + return true; + +@@ -219,21 +216,21 @@ static int path_is_runtime(const LookupPaths *p, const char *path, bool check_pa + path = parent; + } + +- return path_equal_ptr(path, p->runtime_config) || +- path_equal_ptr(path, p->generator) || +- path_equal_ptr(path, p->generator_early) || +- path_equal_ptr(path, p->generator_late) || +- path_equal_ptr(path, p->transient) || +- path_equal_ptr(path, p->runtime_control); ++ return path_equal_ptr(path, lp->runtime_config) || ++ path_equal_ptr(path, lp->generator) || ++ path_equal_ptr(path, lp->generator_early) || ++ path_equal_ptr(path, lp->generator_late) || ++ path_equal_ptr(path, lp->transient) || ++ path_equal_ptr(path, lp->runtime_control); + } + +-static int path_is_vendor_or_generator(const LookupPaths *p, const char *path) { ++static int path_is_vendor_or_generator(const LookupPaths *lp, const char *path) { + const char *rpath; + +- assert(p); ++ assert(lp); + assert(path); + +- rpath = skip_root(p, path); ++ rpath = skip_root(lp->root_dir, path); + if (!rpath) + return 0; + +@@ -245,19 +242,19 @@ static int path_is_vendor_or_generator(const LookupPaths *p, const char *path) { + return true; + #endif + +- if (path_is_generator(p, rpath)) ++ if (path_is_generator(lp, rpath)) + return true; + + return path_equal(rpath, SYSTEM_DATA_UNIT_DIR); + } + +-static const char* config_path_from_flags(const LookupPaths *paths, UnitFileFlags flags) { +- assert(paths); ++static const char* config_path_from_flags(const LookupPaths *lp, UnitFileFlags flags) { ++ assert(lp); + + if (FLAGS_SET(flags, UNIT_FILE_PORTABLE)) +- return FLAGS_SET(flags, UNIT_FILE_RUNTIME) ? paths->runtime_attached : paths->persistent_attached; ++ return FLAGS_SET(flags, UNIT_FILE_RUNTIME) ? lp->runtime_attached : lp->persistent_attached; + else +- return FLAGS_SET(flags, UNIT_FILE_RUNTIME) ? paths->runtime_config : paths->persistent_config; ++ return FLAGS_SET(flags, UNIT_FILE_RUNTIME) ? lp->runtime_config : lp->persistent_config; + } + + int unit_file_changes_add( +@@ -435,7 +432,7 @@ static bool chroot_symlinks_same(const char *root, const char *wd, const char *a + } + + static int create_symlink( +- const LookupPaths *paths, ++ const LookupPaths *lp, + const char *old_path, + const char *new_path, + bool force, +@@ -449,7 +446,7 @@ static int create_symlink( + assert(old_path); + assert(new_path); + +- rp = skip_root(paths, old_path); ++ rp = skip_root(lp->root_dir, old_path); + if (rp) + old_path = rp; + +@@ -487,7 +484,7 @@ static int create_symlink( + if (!dirname) + return -ENOMEM; + +- if (chroot_symlinks_same(paths->root_dir, dirname, dest, old_path)) { ++ if (chroot_symlinks_same(lp->root_dir, dirname, dest, old_path)) { + log_debug("Symlink %s → %s already exists", new_path, dest); + return 1; + } +@@ -642,7 +639,7 @@ static int remove_marked_symlinks_fd( + /* Now, remember the full path (but with the root prefix removed) of + * the symlink we just removed, and remove any symlinks to it, too. */ + +- rp = skip_root(lp, p); ++ rp = skip_root(lp->root_dir, p); + q = mark_symlink_for_removal(&remove_symlinks_to, rp ?: p); + if (q < 0) + return q; +@@ -861,7 +858,7 @@ static int find_symlinks( + + static int find_symlinks_in_scope( + UnitFileScope scope, +- const LookupPaths *paths, ++ const LookupPaths *lp, + const UnitFileInstallInfo *i, + bool match_name, + UnitFileState *state) { +@@ -872,23 +869,23 @@ static int find_symlinks_in_scope( + char **p; + int r; + +- assert(paths); ++ assert(lp); + assert(i); + +- /* As we iterate over the list of search paths in paths->search_path, we may encounter "same name" ++ /* As we iterate over the list of search paths in lp->search_path, we may encounter "same name" + * symlinks. The ones which are "below" (i.e. have lower priority) than the unit file itself are + * effectively masked, so we should ignore them. */ + +- STRV_FOREACH(p, paths->search_path) { ++ STRV_FOREACH(p, lp->search_path) { + bool same_name_link = false; + +- r = find_symlinks(paths->root_dir, i, match_name, ignore_same_name, *p, &same_name_link); ++ r = find_symlinks(lp->root_dir, i, match_name, ignore_same_name, *p, &same_name_link); + if (r < 0) + return r; + if (r > 0) { + /* We found symlinks in this dir? Yay! Let's see where precisely it is enabled. */ + +- if (path_equal_ptr(*p, paths->persistent_config)) { ++ if (path_equal_ptr(*p, lp->persistent_config)) { + /* This is the best outcome, let's return it immediately. */ + *state = UNIT_FILE_ENABLED; + return 1; +@@ -900,7 +897,7 @@ static int find_symlinks_in_scope( + return 1; + } + +- r = path_is_runtime(paths, *p, false); ++ r = path_is_runtime(lp, *p, false); + if (r < 0) + return r; + if (r > 0) +@@ -909,10 +906,10 @@ static int find_symlinks_in_scope( + enabled_at_all = true; + + } else if (same_name_link) { +- if (path_equal_ptr(*p, paths->persistent_config)) ++ if (path_equal_ptr(*p, lp->persistent_config)) + same_name_link_config = true; + else { +- r = path_is_runtime(paths, *p, false); ++ r = path_is_runtime(lp, *p, false); + if (r < 0) + return r; + if (r > 0) +@@ -990,11 +987,11 @@ static UnitFileInstallInfo *install_info_find(InstallContext *c, const char *nam + + static int install_info_may_process( + const UnitFileInstallInfo *i, +- const LookupPaths *paths, ++ const LookupPaths *lp, + UnitFileChange **changes, + size_t *n_changes) { + assert(i); +- assert(paths); ++ assert(lp); + + /* Checks whether the loaded unit file is one we should process, or is masked, + * transient or generated and thus not subject to enable/disable operations. */ +@@ -1003,8 +1000,8 @@ static int install_info_may_process( + unit_file_changes_add(changes, n_changes, -ERFKILL, i->path, NULL); + return -ERFKILL; + } +- if (path_is_generator(paths, i->path) || +- path_is_transient(paths, i->path)) { ++ if (path_is_generator(lp, i->path) || ++ path_is_transient(lp, i->path)) { + unit_file_changes_add(changes, n_changes, -EADDRNOTAVAIL, i->path, NULL); + return -EADDRNOTAVAIL; + } +@@ -1339,20 +1336,20 @@ static int unit_file_load_or_readlink( + InstallContext *c, + UnitFileInstallInfo *info, + const char *path, +- const char *root_dir, ++ const LookupPaths *lp, + SearchFlags flags) { + + _cleanup_free_ char *resolved = NULL; + int r; + +- r = unit_file_load(c, info, path, root_dir, flags); ++ r = unit_file_load(c, info, path, lp->root_dir, flags); + if (r != -ELOOP || (flags & SEARCH_DROPIN)) + return r; + +- r = chase_symlinks(path, root_dir, CHASE_WARN | CHASE_NONEXISTENT, &resolved, NULL); ++ r = chase_symlinks(path, lp->root_dir, CHASE_WARN | CHASE_NONEXISTENT, &resolved, NULL); + if (r >= 0 && +- root_dir && +- path_equal_ptr(path_startswith(resolved, root_dir), "dev/null")) ++ lp->root_dir && ++ path_equal_ptr(path_startswith(resolved, lp->root_dir), "dev/null")) + /* When looking under root_dir, we can't expect /dev/ to be mounted, + * so let's see if the path is a (possibly dangling) symlink to /dev/null. */ + info->type = UNIT_FILE_TYPE_MASKED; +@@ -1402,7 +1399,7 @@ static int unit_file_load_or_readlink( + + if (path_is_absolute(target)) + /* This is an absolute path, prefix the root so that we always deal with fully qualified paths */ +- info->symlink_target = path_join(root_dir, target); ++ info->symlink_target = path_join(lp->root_dir, target); + else + /* This is a relative path, take it relative to the dir the symlink is located in. */ + info->symlink_target = file_in_same_dir(path, target); +@@ -1418,7 +1415,7 @@ static int unit_file_load_or_readlink( + static int unit_file_search( + InstallContext *c, + UnitFileInstallInfo *info, +- const LookupPaths *paths, ++ const LookupPaths *lp, + SearchFlags flags) { + + const char *dropin_dir_name = NULL, *dropin_template_dir_name = NULL; +@@ -1429,14 +1426,14 @@ static int unit_file_search( + char **p; + + assert(info); +- assert(paths); ++ assert(lp); + + /* Was this unit already loaded? */ + if (info->type != _UNIT_FILE_TYPE_INVALID) + return 0; + + if (info->path) +- return unit_file_load_or_readlink(c, info, info->path, paths->root_dir, flags); ++ return unit_file_load_or_readlink(c, info, info->path, lp, flags); + + assert(info->name); + +@@ -1446,14 +1443,14 @@ static int unit_file_search( + return r; + } + +- STRV_FOREACH(p, paths->search_path) { ++ STRV_FOREACH(p, lp->search_path) { + _cleanup_free_ char *path = NULL; + + path = path_join(*p, info->name); + if (!path) + return -ENOMEM; + +- r = unit_file_load_or_readlink(c, info, path, paths->root_dir, flags); ++ r = unit_file_load_or_readlink(c, info, path, lp, flags); + if (r >= 0) { + info->path = TAKE_PTR(path); + result = r; +@@ -1469,14 +1466,14 @@ static int unit_file_search( + * enablement was requested. We will check if it is + * possible to load template unit file. */ + +- STRV_FOREACH(p, paths->search_path) { ++ STRV_FOREACH(p, lp->search_path) { + _cleanup_free_ char *path = NULL; + + path = path_join(*p, template); + if (!path) + return -ENOMEM; + +- r = unit_file_load_or_readlink(c, info, path, paths->root_dir, flags); ++ r = unit_file_load_or_readlink(c, info, path, lp, flags); + if (r >= 0) { + info->path = TAKE_PTR(path); + result = r; +@@ -1498,7 +1495,7 @@ static int unit_file_search( + /* Search for drop-in directories */ + + dropin_dir_name = strjoina(info->name, ".d"); +- STRV_FOREACH(p, paths->search_path) { ++ STRV_FOREACH(p, lp->search_path) { + char *path; + + path = path_join(*p, dropin_dir_name); +@@ -1512,7 +1509,7 @@ static int unit_file_search( + + if (template) { + dropin_template_dir_name = strjoina(template, ".d"); +- STRV_FOREACH(p, paths->search_path) { ++ STRV_FOREACH(p, lp->search_path) { + char *path; + + path = path_join(*p, dropin_template_dir_name); +@@ -1532,7 +1529,7 @@ static int unit_file_search( + return log_debug_errno(r, "Failed to get list of conf files: %m"); + + STRV_FOREACH(p, files) { +- r = unit_file_load_or_readlink(c, info, *p, paths->root_dir, flags | SEARCH_DROPIN); ++ r = unit_file_load_or_readlink(c, info, *p, lp, flags | SEARCH_DROPIN); + if (r < 0) + return log_debug_errno(r, "Failed to load conf file %s: %m", *p); + } +@@ -1543,7 +1540,7 @@ static int unit_file_search( + static int install_info_follow( + InstallContext *c, + UnitFileInstallInfo *i, +- const char *root_dir, ++ const LookupPaths *lp, + SearchFlags flags, + bool ignore_different_name) { + +@@ -1564,7 +1561,7 @@ static int install_info_follow( + free_and_replace(i->path, i->symlink_target); + i->type = _UNIT_FILE_TYPE_INVALID; + +- return unit_file_load_or_readlink(c, i, i->path, root_dir, flags); ++ return unit_file_load_or_readlink(c, i, i->path, lp, flags); + } + + /** +@@ -1574,7 +1571,7 @@ static int install_info_follow( + static int install_info_traverse( + UnitFileScope scope, + InstallContext *c, +- const LookupPaths *paths, ++ const LookupPaths *lp, + UnitFileInstallInfo *start, + SearchFlags flags, + UnitFileInstallInfo **ret) { +@@ -1583,11 +1580,11 @@ static int install_info_traverse( + unsigned k = 0; + int r; + +- assert(paths); ++ assert(lp); + assert(start); + assert(c); + +- r = unit_file_search(c, start, paths, flags); ++ r = unit_file_search(c, start, lp, flags); + if (r < 0) + return r; + +@@ -1599,14 +1596,14 @@ static int install_info_traverse( + return -ELOOP; + + if (!(flags & SEARCH_FOLLOW_CONFIG_SYMLINKS)) { +- r = path_is_config(paths, i->path, true); ++ r = path_is_config(lp, i->path, true); + if (r < 0) + return r; + if (r > 0) + return -ELOOP; + } + +- r = install_info_follow(c, i, paths->root_dir, flags, false); ++ r = install_info_follow(c, i, lp, flags, false); + if (r == -EXDEV) { + _cleanup_free_ char *buffer = NULL; + const char *bn; +@@ -1635,7 +1632,7 @@ static int install_info_traverse( + /* We filled in the instance, and the target stayed the same? If so, then let's + * honour the link as it is. */ + +- r = install_info_follow(c, i, paths->root_dir, flags, true); ++ r = install_info_follow(c, i, lp, flags, true); + if (r < 0) + return r; + +@@ -1645,12 +1642,12 @@ static int install_info_traverse( + bn = buffer; + } + +- r = install_info_add(c, bn, NULL, paths->root_dir, /* auxiliary= */ false, &i); ++ r = install_info_add(c, bn, NULL, lp->root_dir, /* auxiliary= */ false, &i); + if (r < 0) + return r; + + /* Try again, with the new target we found. */ +- r = unit_file_search(c, i, paths, flags); ++ r = unit_file_search(c, i, lp, flags); + if (r == -ENOENT) + /* Translate error code to highlight this specific case */ + return -ENOLINK; +@@ -1672,7 +1669,7 @@ static int install_info_traverse( + */ + static int install_info_add_auto( + InstallContext *c, +- const LookupPaths *paths, ++ const LookupPaths *lp, + const char *name_or_path, + UnitFileInstallInfo **ret) { + +@@ -1682,17 +1679,17 @@ static int install_info_add_auto( + if (path_is_absolute(name_or_path)) { + const char *pp; + +- pp = prefix_roota(paths->root_dir, name_or_path); ++ pp = prefix_roota(lp->root_dir, name_or_path); + +- return install_info_add(c, NULL, pp, paths->root_dir, /* auxiliary= */ false, ret); ++ return install_info_add(c, NULL, pp, lp->root_dir, /* auxiliary= */ false, ret); + } else +- return install_info_add(c, name_or_path, NULL, paths->root_dir, /* auxiliary= */ false, ret); ++ return install_info_add(c, name_or_path, NULL, lp->root_dir, /* auxiliary= */ false, ret); + } + + static int install_info_discover( + UnitFileScope scope, + InstallContext *c, +- const LookupPaths *paths, ++ const LookupPaths *lp, + const char *name, + SearchFlags flags, + UnitFileInstallInfo **ret, +@@ -1703,12 +1700,12 @@ static int install_info_discover( + int r; + + assert(c); +- assert(paths); ++ assert(lp); + assert(name); + +- r = install_info_add_auto(c, paths, name, &i); ++ r = install_info_add_auto(c, lp, name, &i); + if (r >= 0) +- r = install_info_traverse(scope, c, paths, i, flags, ret); ++ r = install_info_traverse(scope, c, lp, i, flags, ret); + + if (r < 0) + unit_file_changes_add(changes, n_changes, r, name, NULL); +@@ -1718,7 +1715,7 @@ static int install_info_discover( + static int install_info_discover_and_check( + UnitFileScope scope, + InstallContext *c, +- const LookupPaths *paths, ++ const LookupPaths *lp, + const char *name, + SearchFlags flags, + UnitFileInstallInfo **ret, +@@ -1727,11 +1724,11 @@ static int install_info_discover_and_check( + + int r; + +- r = install_info_discover(scope, c, paths, name, flags, ret, changes, n_changes); ++ r = install_info_discover(scope, c, lp, name, flags, ret, changes, n_changes); + if (r < 0) + return r; + +- return install_info_may_process(ret ? *ret : NULL, paths, changes, n_changes); ++ return install_info_may_process(ret ? *ret : NULL, lp, changes, n_changes); + } + + int unit_file_verify_alias(const UnitFileInstallInfo *i, const char *dst, char **ret_dst) { +@@ -1812,7 +1809,7 @@ int unit_file_verify_alias(const UnitFileInstallInfo *i, const char *dst, char * + + static int install_info_symlink_alias( + UnitFileInstallInfo *i, +- const LookupPaths *paths, ++ const LookupPaths *lp, + const char *config_path, + bool force, + UnitFileChange **changes, +@@ -1822,7 +1819,7 @@ static int install_info_symlink_alias( + int r = 0, q; + + assert(i); +- assert(paths); ++ assert(lp); + assert(config_path); + + STRV_FOREACH(s, i->aliases) { +@@ -1840,7 +1837,7 @@ static int install_info_symlink_alias( + if (!alias_path) + return -ENOMEM; + +- q = create_symlink(paths, i->path, alias_path, force, changes, n_changes); ++ q = create_symlink(lp, i->path, alias_path, force, changes, n_changes); + if (r == 0) + r = q; + } +@@ -1852,7 +1849,7 @@ static int install_info_symlink_wants( + UnitFileScope scope, + UnitFileFlags file_flags, + UnitFileInstallInfo *i, +- const LookupPaths *paths, ++ const LookupPaths *lp, + const char *config_path, + char **list, + const char *suffix, +@@ -1866,7 +1863,7 @@ static int install_info_symlink_wants( + int r = 0, q; + + assert(i); +- assert(paths); ++ assert(lp); + assert(config_path); + + if (strv_isempty(list)) +@@ -1889,7 +1886,7 @@ static int install_info_symlink_wants( + return r; + + instance.name = buf; +- r = unit_file_search(NULL, &instance, paths, SEARCH_FOLLOW_CONFIG_SYMLINKS); ++ r = unit_file_search(NULL, &instance, lp, SEARCH_FOLLOW_CONFIG_SYMLINKS); + if (r < 0) + return r; + +@@ -1943,11 +1940,11 @@ static int install_info_symlink_wants( + if (!path) + return -ENOMEM; + +- q = create_symlink(paths, i->path, path, true, changes, n_changes); ++ q = create_symlink(lp, i->path, path, true, changes, n_changes); + if (r == 0) + r = q; + +- if (unit_file_exists(scope, paths, dst) == 0) ++ if (unit_file_exists(scope, lp, dst) == 0) + unit_file_changes_add(changes, n_changes, UNIT_FILE_DESTINATION_NOT_PRESENT, dst, i->path); + } + +@@ -1956,7 +1953,7 @@ static int install_info_symlink_wants( + + static int install_info_symlink_link( + UnitFileInstallInfo *i, +- const LookupPaths *paths, ++ const LookupPaths *lp, + const char *config_path, + bool force, + UnitFileChange **changes, +@@ -1966,11 +1963,11 @@ static int install_info_symlink_link( + int r; + + assert(i); +- assert(paths); ++ assert(lp); + assert(config_path); + assert(i->path); + +- r = in_search_path(paths, i->path); ++ r = in_search_path(lp, i->path); + if (r < 0) + return r; + if (r > 0) +@@ -1980,14 +1977,14 @@ static int install_info_symlink_link( + if (!path) + return -ENOMEM; + +- return create_symlink(paths, i->path, path, force, changes, n_changes); ++ return create_symlink(lp, i->path, path, force, changes, n_changes); + } + + static int install_info_apply( + UnitFileScope scope, + UnitFileFlags file_flags, + UnitFileInstallInfo *i, +- const LookupPaths *paths, ++ const LookupPaths *lp, + const char *config_path, + UnitFileChange **changes, + size_t *n_changes) { +@@ -1995,7 +1992,7 @@ static int install_info_apply( + int r, q; + + assert(i); +- assert(paths); ++ assert(lp); + assert(config_path); + + if (i->type != UNIT_FILE_TYPE_REGULAR) +@@ -2003,17 +2000,17 @@ static int install_info_apply( + + bool force = file_flags & UNIT_FILE_FORCE; + +- r = install_info_symlink_alias(i, paths, config_path, force, changes, n_changes); ++ r = install_info_symlink_alias(i, lp, config_path, force, changes, n_changes); + +- q = install_info_symlink_wants(scope, file_flags, i, paths, config_path, i->wanted_by, ".wants/", changes, n_changes); ++ q = install_info_symlink_wants(scope, file_flags, i, lp, config_path, i->wanted_by, ".wants/", changes, n_changes); + if (r == 0) + r = q; + +- q = install_info_symlink_wants(scope, file_flags, i, paths, config_path, i->required_by, ".requires/", changes, n_changes); ++ q = install_info_symlink_wants(scope, file_flags, i, lp, config_path, i->required_by, ".requires/", changes, n_changes); + if (r == 0) + r = q; + +- q = install_info_symlink_link(i, paths, config_path, force, changes, n_changes); ++ q = install_info_symlink_link(i, lp, config_path, force, changes, n_changes); + /* Do not count links to the unit file towards the "carries_install_info" count */ + if (r == 0 && q < 0) + r = q; +@@ -2025,7 +2022,7 @@ static int install_context_apply( + UnitFileScope scope, + UnitFileFlags file_flags, + InstallContext *c, +- const LookupPaths *paths, ++ const LookupPaths *lp, + const char *config_path, + SearchFlags flags, + UnitFileChange **changes, +@@ -2035,7 +2032,7 @@ static int install_context_apply( + int r; + + assert(c); +- assert(paths); ++ assert(lp); + assert(config_path); + + if (ordered_hashmap_isempty(c->will_process)) +@@ -2053,7 +2050,7 @@ static int install_context_apply( + if (q < 0) + return q; + +- q = install_info_traverse(scope, c, paths, i, flags, NULL); ++ q = install_info_traverse(scope, c, lp, i, flags, NULL); + if (q < 0) { + if (i->auxiliary) { + q = unit_file_changes_add(changes, n_changes, UNIT_FILE_AUXILIARY_FAILED, NULL, i->name); +@@ -2080,7 +2077,7 @@ static int install_context_apply( + if (i->type != UNIT_FILE_TYPE_REGULAR) + continue; + +- q = install_info_apply(scope, file_flags, i, paths, config_path, changes, n_changes); ++ q = install_info_apply(scope, file_flags, i, lp, config_path, changes, n_changes); + if (r >= 0) { + if (q < 0) + r = q; +@@ -2095,7 +2092,7 @@ static int install_context_apply( + static int install_context_mark_for_removal( + UnitFileScope scope, + InstallContext *c, +- const LookupPaths *paths, ++ const LookupPaths *lp, + Set **remove_symlinks_to, + const char *config_path, + UnitFileChange **changes, +@@ -2105,7 +2102,7 @@ static int install_context_mark_for_removal( + int r; + + assert(c); +- assert(paths); ++ assert(lp); + assert(config_path); + + /* Marks all items for removal */ +@@ -2123,7 +2120,7 @@ static int install_context_mark_for_removal( + if (r < 0) + return r; + +- r = install_info_traverse(scope, c, paths, i, SEARCH_LOAD|SEARCH_FOLLOW_CONFIG_SYMLINKS, NULL); ++ r = install_info_traverse(scope, c, lp, i, SEARCH_LOAD|SEARCH_FOLLOW_CONFIG_SYMLINKS, NULL); + if (r == -ENOLINK) { + log_debug_errno(r, "Name %s leads to a dangling symlink, removing name.", i->name); + unit_file_changes_add(changes, n_changes, UNIT_FILE_IS_DANGLING, i->path ?: i->name, NULL); +@@ -2164,7 +2161,7 @@ int unit_file_mask( + UnitFileChange **changes, + size_t *n_changes) { + +- _cleanup_(lookup_paths_free) LookupPaths paths = {}; ++ _cleanup_(lookup_paths_free) LookupPaths lp = {}; + const char *config_path; + char **i; + int r; +@@ -2172,11 +2169,11 @@ int unit_file_mask( + assert(scope >= 0); + assert(scope < _UNIT_FILE_SCOPE_MAX); + +- r = lookup_paths_init(&paths, scope, 0, root_dir); ++ r = lookup_paths_init(&lp, scope, 0, root_dir); + if (r < 0) + return r; + +- config_path = (flags & UNIT_FILE_RUNTIME) ? paths.runtime_config : paths.persistent_config; ++ config_path = (flags & UNIT_FILE_RUNTIME) ? lp.runtime_config : lp.persistent_config; + if (!config_path) + return -ENXIO; + +@@ -2194,7 +2191,7 @@ int unit_file_mask( + if (!path) + return -ENOMEM; + +- q = create_symlink(&paths, "/dev/null", path, !!(flags & UNIT_FILE_FORCE), changes, n_changes); ++ q = create_symlink(&lp, "/dev/null", path, !!(flags & UNIT_FILE_FORCE), changes, n_changes); + if (q < 0 && r >= 0) + r = q; + } +@@ -2210,7 +2207,7 @@ int unit_file_unmask( + UnitFileChange **changes, + size_t *n_changes) { + +- _cleanup_(lookup_paths_free) LookupPaths paths = {}; ++ _cleanup_(lookup_paths_free) LookupPaths lp = {}; + _cleanup_set_free_free_ Set *remove_symlinks_to = NULL; + _cleanup_strv_free_ char **todo = NULL; + const char *config_path; +@@ -2222,11 +2219,11 @@ int unit_file_unmask( + assert(scope >= 0); + assert(scope < _UNIT_FILE_SCOPE_MAX); + +- r = lookup_paths_init(&paths, scope, 0, root_dir); ++ r = lookup_paths_init(&lp, scope, 0, root_dir); + if (r < 0) + return r; + +- config_path = (flags & UNIT_FILE_RUNTIME) ? paths.runtime_config : paths.persistent_config; ++ config_path = (flags & UNIT_FILE_RUNTIME) ? lp.runtime_config : lp.persistent_config; + if (!config_path) + return -ENXIO; + +@@ -2283,13 +2280,13 @@ int unit_file_unmask( + + unit_file_changes_add(changes, n_changes, UNIT_FILE_UNLINK, path, NULL); + +- rp = skip_root(&paths, path); ++ rp = skip_root(lp.root_dir, path); + q = mark_symlink_for_removal(&remove_symlinks_to, rp ?: path); + if (q < 0) + return q; + } + +- q = remove_marked_symlinks(remove_symlinks_to, config_path, &paths, dry_run, changes, n_changes); ++ q = remove_marked_symlinks(remove_symlinks_to, config_path, &lp, dry_run, changes, n_changes); + if (r >= 0) + r = q; + +@@ -2304,7 +2301,7 @@ int unit_file_link( + UnitFileChange **changes, + size_t *n_changes) { + +- _cleanup_(lookup_paths_free) LookupPaths paths = {}; ++ _cleanup_(lookup_paths_free) LookupPaths lp = {}; + _cleanup_strv_free_ char **todo = NULL; + const char *config_path; + size_t n_todo = 0; +@@ -2314,11 +2311,11 @@ int unit_file_link( + assert(scope >= 0); + assert(scope < _UNIT_FILE_SCOPE_MAX); + +- r = lookup_paths_init(&paths, scope, 0, root_dir); ++ r = lookup_paths_init(&lp, scope, 0, root_dir); + if (r < 0) + return r; + +- config_path = (flags & UNIT_FILE_RUNTIME) ? paths.runtime_config : paths.persistent_config; ++ config_path = (flags & UNIT_FILE_RUNTIME) ? lp.runtime_config : lp.persistent_config; + if (!config_path) + return -ENXIO; + +@@ -2334,7 +2331,7 @@ int unit_file_link( + if (!unit_name_is_valid(fn, UNIT_NAME_ANY)) + return -EINVAL; + +- full = path_join(paths.root_dir, *i); ++ full = path_join(lp.root_dir, *i); + if (!full) + return -ENOMEM; + +@@ -2344,7 +2341,7 @@ int unit_file_link( + if (r < 0) + return r; + +- q = in_search_path(&paths, *i); ++ q = in_search_path(&lp, *i); + if (q < 0) + return q; + if (q > 0) +@@ -2370,7 +2367,7 @@ int unit_file_link( + if (!new_path) + return -ENOMEM; + +- q = create_symlink(&paths, *i, new_path, !!(flags & UNIT_FILE_FORCE), changes, n_changes); ++ q = create_symlink(&lp, *i, new_path, !!(flags & UNIT_FILE_FORCE), changes, n_changes); + if (q < 0 && r >= 0) + r = q; + } +@@ -2378,23 +2375,23 @@ int unit_file_link( + return r; + } + +-static int path_shall_revert(const LookupPaths *paths, const char *path) { ++static int path_shall_revert(const LookupPaths *lp, const char *path) { + int r; + +- assert(paths); ++ assert(lp); + assert(path); + + /* Checks whether the path is one where the drop-in directories shall be removed. */ + +- r = path_is_config(paths, path, true); ++ r = path_is_config(lp, path, true); + if (r != 0) + return r; + +- r = path_is_control(paths, path); ++ r = path_is_control(lp, path); + if (r != 0) + return r; + +- return path_is_transient(paths, path); ++ return path_is_transient(lp, path); + } + + int unit_file_revert( +@@ -2405,7 +2402,7 @@ int unit_file_revert( + size_t *n_changes) { + + _cleanup_set_free_free_ Set *remove_symlinks_to = NULL; +- _cleanup_(lookup_paths_free) LookupPaths paths = {}; ++ _cleanup_(lookup_paths_free) LookupPaths lp = {}; + _cleanup_strv_free_ char **todo = NULL; + size_t n_todo = 0; + char **i; +@@ -2422,7 +2419,7 @@ int unit_file_revert( + * We remove all that in both the runtime and the persistent directories, if that applies. + */ + +- r = lookup_paths_init(&paths, scope, 0, root_dir); ++ r = lookup_paths_init(&lp, scope, 0, root_dir); + if (r < 0) + return r; + +@@ -2433,7 +2430,7 @@ int unit_file_revert( + if (!unit_name_is_valid(*i, UNIT_NAME_ANY)) + return -EINVAL; + +- STRV_FOREACH(p, paths.search_path) { ++ STRV_FOREACH(p, lp.search_path) { + _cleanup_free_ char *path = NULL, *dropin = NULL; + struct stat st; + +@@ -2447,7 +2444,7 @@ int unit_file_revert( + return -errno; + } else if (S_ISREG(st.st_mode)) { + /* Check if there's a vendor version */ +- r = path_is_vendor_or_generator(&paths, path); ++ r = path_is_vendor_or_generator(&lp, path); + if (r < 0) + return r; + if (r > 0) +@@ -2464,7 +2461,7 @@ int unit_file_revert( + return -errno; + } else if (S_ISDIR(st.st_mode)) { + /* Remove the drop-ins */ +- r = path_shall_revert(&paths, dropin); ++ r = path_shall_revert(&lp, dropin); + if (r < 0) + return r; + if (r > 0) { +@@ -2480,7 +2477,7 @@ int unit_file_revert( + continue; + + /* OK, there's a vendor version, hence drop all configuration versions */ +- STRV_FOREACH(p, paths.search_path) { ++ STRV_FOREACH(p, lp.search_path) { + _cleanup_free_ char *path = NULL; + struct stat st; + +@@ -2493,7 +2490,7 @@ int unit_file_revert( + if (errno != ENOENT) + return -errno; + } else if (S_ISREG(st.st_mode) || S_ISLNK(st.st_mode)) { +- r = path_is_config(&paths, path, true); ++ r = path_is_config(&lp, path, true); + if (r < 0) + return r; + if (r > 0) { +@@ -2534,17 +2531,17 @@ int unit_file_revert( + + unit_file_changes_add(changes, n_changes, UNIT_FILE_UNLINK, *i, NULL); + +- rp = skip_root(&paths, *i); ++ rp = skip_root(lp.root_dir, *i); + q = mark_symlink_for_removal(&remove_symlinks_to, rp ?: *i); + if (q < 0) + return q; + } + +- q = remove_marked_symlinks(remove_symlinks_to, paths.runtime_config, &paths, false, changes, n_changes); ++ q = remove_marked_symlinks(remove_symlinks_to, lp.runtime_config, &lp, false, changes, n_changes); + if (r >= 0) + r = q; + +- q = remove_marked_symlinks(remove_symlinks_to, paths.persistent_config, &paths, false, changes, n_changes); ++ q = remove_marked_symlinks(remove_symlinks_to, lp.persistent_config, &lp, false, changes, n_changes); + if (r >= 0) + r = q; + +@@ -2561,7 +2558,7 @@ int unit_file_add_dependency( + UnitFileChange **changes, + size_t *n_changes) { + +- _cleanup_(lookup_paths_free) LookupPaths paths = {}; ++ _cleanup_(lookup_paths_free) LookupPaths lp = {}; + _cleanup_(install_context_done) InstallContext c = {}; + UnitFileInstallInfo *i, *target_info; + const char *config_path; +@@ -2578,15 +2575,15 @@ int unit_file_add_dependency( + if (!unit_name_is_valid(target, UNIT_NAME_ANY)) + return -EINVAL; + +- r = lookup_paths_init(&paths, scope, 0, root_dir); ++ r = lookup_paths_init(&lp, scope, 0, root_dir); + if (r < 0) + return r; + +- config_path = (file_flags & UNIT_FILE_RUNTIME) ? paths.runtime_config : paths.persistent_config; ++ config_path = (file_flags & UNIT_FILE_RUNTIME) ? lp.runtime_config : lp.persistent_config; + if (!config_path) + return -ENXIO; + +- r = install_info_discover_and_check(scope, &c, &paths, target, SEARCH_FOLLOW_CONFIG_SYMLINKS, ++ r = install_info_discover_and_check(scope, &c, &lp, target, SEARCH_FOLLOW_CONFIG_SYMLINKS, + &target_info, changes, n_changes); + if (r < 0) + return r; +@@ -2596,7 +2593,7 @@ int unit_file_add_dependency( + STRV_FOREACH(f, files) { + char ***l; + +- r = install_info_discover_and_check(scope, &c, &paths, *f, SEARCH_FOLLOW_CONFIG_SYMLINKS, ++ r = install_info_discover_and_check(scope, &c, &lp, *f, SEARCH_FOLLOW_CONFIG_SYMLINKS, + &i, changes, n_changes); + if (r < 0) + return r; +@@ -2618,7 +2615,7 @@ int unit_file_add_dependency( + return -ENOMEM; + } + +- return install_context_apply(scope, file_flags, &c, &paths, config_path, ++ return install_context_apply(scope, file_flags, &c, &lp, config_path, + SEARCH_FOLLOW_CONFIG_SYMLINKS, changes, n_changes); + } + +@@ -2630,7 +2627,7 @@ int unit_file_enable( + UnitFileChange **changes, + size_t *n_changes) { + +- _cleanup_(lookup_paths_free) LookupPaths paths = {}; ++ _cleanup_(lookup_paths_free) LookupPaths lp = {}; + _cleanup_(install_context_done) InstallContext c = {}; + const char *config_path; + UnitFileInstallInfo *i; +@@ -2640,16 +2637,16 @@ int unit_file_enable( + assert(scope >= 0); + assert(scope < _UNIT_FILE_SCOPE_MAX); + +- r = lookup_paths_init(&paths, scope, 0, root_dir); ++ r = lookup_paths_init(&lp, scope, 0, root_dir); + if (r < 0) + return r; + +- config_path = config_path_from_flags(&paths, file_flags); ++ config_path = config_path_from_flags(&lp, file_flags); + if (!config_path) + return -ENXIO; + + STRV_FOREACH(f, files) { +- r = install_info_discover_and_check(scope, &c, &paths, *f, SEARCH_LOAD|SEARCH_FOLLOW_CONFIG_SYMLINKS, ++ r = install_info_discover_and_check(scope, &c, &lp, *f, SEARCH_LOAD|SEARCH_FOLLOW_CONFIG_SYMLINKS, + &i, changes, n_changes); + if (r < 0) + return r; +@@ -2662,7 +2659,7 @@ int unit_file_enable( + is useful to determine whether the passed files had any + installation data at all. */ + +- return install_context_apply(scope, file_flags, &c, &paths, config_path, SEARCH_LOAD, changes, n_changes); ++ return install_context_apply(scope, file_flags, &c, &lp, config_path, SEARCH_LOAD, changes, n_changes); + } + + int unit_file_disable( +@@ -2673,7 +2670,7 @@ int unit_file_disable( + UnitFileChange **changes, + size_t *n_changes) { + +- _cleanup_(lookup_paths_free) LookupPaths paths = {}; ++ _cleanup_(lookup_paths_free) LookupPaths lp = {}; + _cleanup_(install_context_done) InstallContext c = {}; + _cleanup_set_free_free_ Set *remove_symlinks_to = NULL; + const char *config_path; +@@ -2683,11 +2680,11 @@ int unit_file_disable( + assert(scope >= 0); + assert(scope < _UNIT_FILE_SCOPE_MAX); + +- r = lookup_paths_init(&paths, scope, 0, root_dir); ++ r = lookup_paths_init(&lp, scope, 0, root_dir); + if (r < 0) + return r; + +- config_path = config_path_from_flags(&paths, flags); ++ config_path = config_path_from_flags(&lp, flags); + if (!config_path) + return -ENXIO; + +@@ -2695,16 +2692,16 @@ int unit_file_disable( + if (!unit_name_is_valid(*i, UNIT_NAME_ANY)) + return -EINVAL; + +- r = install_info_add(&c, *i, NULL, paths.root_dir, /* auxiliary= */ false, NULL); ++ r = install_info_add(&c, *i, NULL, lp.root_dir, /* auxiliary= */ false, NULL); + if (r < 0) + return r; + } + +- r = install_context_mark_for_removal(scope, &c, &paths, &remove_symlinks_to, config_path, changes, n_changes); ++ r = install_context_mark_for_removal(scope, &c, &lp, &remove_symlinks_to, config_path, changes, n_changes); + if (r < 0) + return r; + +- return remove_marked_symlinks(remove_symlinks_to, config_path, &paths, !!(flags & UNIT_FILE_DRY_RUN), changes, n_changes); ++ return remove_marked_symlinks(remove_symlinks_to, config_path, &lp, !!(flags & UNIT_FILE_DRY_RUN), changes, n_changes); + } + + int unit_file_reenable( +@@ -2742,7 +2739,7 @@ int unit_file_set_default( + UnitFileChange **changes, + size_t *n_changes) { + +- _cleanup_(lookup_paths_free) LookupPaths paths = {}; ++ _cleanup_(lookup_paths_free) LookupPaths lp = {}; + _cleanup_(install_context_done) InstallContext c = {}; + UnitFileInstallInfo *i; + const char *new_path; +@@ -2757,16 +2754,16 @@ int unit_file_set_default( + if (streq(name, SPECIAL_DEFAULT_TARGET)) + return -EINVAL; + +- r = lookup_paths_init(&paths, scope, 0, root_dir); ++ r = lookup_paths_init(&lp, scope, 0, root_dir); + if (r < 0) + return r; + +- r = install_info_discover_and_check(scope, &c, &paths, name, 0, &i, changes, n_changes); ++ r = install_info_discover_and_check(scope, &c, &lp, name, 0, &i, changes, n_changes); + if (r < 0) + return r; + +- new_path = strjoina(paths.persistent_config, "/" SPECIAL_DEFAULT_TARGET); +- return create_symlink(&paths, i->path, new_path, !!(flags & UNIT_FILE_FORCE), changes, n_changes); ++ new_path = strjoina(lp.persistent_config, "/" SPECIAL_DEFAULT_TARGET); ++ return create_symlink(&lp, i->path, new_path, !!(flags & UNIT_FILE_FORCE), changes, n_changes); + } + + int unit_file_get_default( +@@ -2774,7 +2771,7 @@ int unit_file_get_default( + const char *root_dir, + char **name) { + +- _cleanup_(lookup_paths_free) LookupPaths paths = {}; ++ _cleanup_(lookup_paths_free) LookupPaths lp = {}; + _cleanup_(install_context_done) InstallContext c = {}; + UnitFileInstallInfo *i; + char *n; +@@ -2784,15 +2781,15 @@ int unit_file_get_default( + assert(scope < _UNIT_FILE_SCOPE_MAX); + assert(name); + +- r = lookup_paths_init(&paths, scope, 0, root_dir); ++ r = lookup_paths_init(&lp, scope, 0, root_dir); + if (r < 0) + return r; + +- r = install_info_discover(scope, &c, &paths, SPECIAL_DEFAULT_TARGET, SEARCH_FOLLOW_CONFIG_SYMLINKS, ++ r = install_info_discover(scope, &c, &lp, SPECIAL_DEFAULT_TARGET, SEARCH_FOLLOW_CONFIG_SYMLINKS, + &i, NULL, NULL); + if (r < 0) + return r; +- r = install_info_may_process(i, &paths, NULL, 0); ++ r = install_info_may_process(i, &lp, NULL, 0); + if (r < 0) + return r; + +@@ -2806,7 +2803,7 @@ int unit_file_get_default( + + int unit_file_lookup_state( + UnitFileScope scope, +- const LookupPaths *paths, ++ const LookupPaths *lp, + const char *name, + UnitFileState *ret) { + +@@ -2815,13 +2812,13 @@ int unit_file_lookup_state( + UnitFileState state; + int r; + +- assert(paths); ++ assert(lp); + assert(name); + + if (!unit_name_is_valid(name, UNIT_NAME_ANY)) + return -EINVAL; + +- r = install_info_discover(scope, &c, paths, name, SEARCH_LOAD|SEARCH_FOLLOW_CONFIG_SYMLINKS, ++ r = install_info_discover(scope, &c, lp, name, SEARCH_LOAD|SEARCH_FOLLOW_CONFIG_SYMLINKS, + &i, NULL, NULL); + if (r < 0) + return log_debug_errno(r, "Failed to discover unit %s: %m", name); +@@ -2837,7 +2834,7 @@ int unit_file_lookup_state( + switch (i->type) { + + case UNIT_FILE_TYPE_MASKED: +- r = path_is_runtime(paths, i->path, true); ++ r = path_is_runtime(lp, i->path, true); + if (r < 0) + return r; + +@@ -2851,7 +2848,7 @@ int unit_file_lookup_state( + break; + } + +- r = path_is_generator(paths, i->path); ++ r = path_is_generator(lp, i->path); + if (r < 0) + return r; + if (r > 0) { +@@ -2859,7 +2856,7 @@ int unit_file_lookup_state( + break; + } + +- r = path_is_transient(paths, i->path); ++ r = path_is_transient(lp, i->path); + if (r < 0) + return r; + if (r > 0) { +@@ -2870,7 +2867,7 @@ int unit_file_lookup_state( + /* Check if any of the Alias= symlinks have been created. + * We ignore other aliases, and only check those that would + * be created by systemctl enable for this unit. */ +- r = find_symlinks_in_scope(scope, paths, i, true, &state); ++ r = find_symlinks_in_scope(scope, lp, i, true, &state); + if (r < 0) + return r; + if (r > 0) +@@ -2878,7 +2875,7 @@ int unit_file_lookup_state( + + /* Check if the file is known under other names. If it is, + * it might be in use. Report that as UNIT_FILE_INDIRECT. */ +- r = find_symlinks_in_scope(scope, paths, i, false, &state); ++ r = find_symlinks_in_scope(scope, lp, i, false, &state); + if (r < 0) + return r; + if (r > 0) +@@ -2908,31 +2905,31 @@ int unit_file_get_state( + const char *name, + UnitFileState *ret) { + +- _cleanup_(lookup_paths_free) LookupPaths paths = {}; ++ _cleanup_(lookup_paths_free) LookupPaths lp = {}; + int r; + + assert(scope >= 0); + assert(scope < _UNIT_FILE_SCOPE_MAX); + assert(name); + +- r = lookup_paths_init(&paths, scope, 0, root_dir); ++ r = lookup_paths_init(&lp, scope, 0, root_dir); + if (r < 0) + return r; + +- return unit_file_lookup_state(scope, &paths, name, ret); ++ return unit_file_lookup_state(scope, &lp, name, ret); + } + +-int unit_file_exists(UnitFileScope scope, const LookupPaths *paths, const char *name) { ++int unit_file_exists(UnitFileScope scope, const LookupPaths *lp, const char *name) { + _cleanup_(install_context_done) InstallContext c = {}; + int r; + +- assert(paths); ++ assert(lp); + assert(name); + + if (!unit_name_is_valid(name, UNIT_NAME_ANY)) + return -EINVAL; + +- r = install_info_discover(scope, &c, paths, name, 0, NULL, NULL, NULL); ++ r = install_info_discover(scope, &c, lp, name, 0, NULL, NULL, NULL); + if (r == -ENOENT) + return 0; + if (r < 0) +@@ -3195,7 +3192,7 @@ static int execute_preset( + UnitFileFlags file_flags, + InstallContext *plus, + InstallContext *minus, +- const LookupPaths *paths, ++ const LookupPaths *lp, + const char *config_path, + char **files, + UnitFilePresetMode mode, +@@ -3206,17 +3203,17 @@ static int execute_preset( + + assert(plus); + assert(minus); +- assert(paths); ++ assert(lp); + assert(config_path); + + if (mode != UNIT_FILE_PRESET_ENABLE_ONLY) { + _cleanup_set_free_free_ Set *remove_symlinks_to = NULL; + +- r = install_context_mark_for_removal(scope, minus, paths, &remove_symlinks_to, config_path, changes, n_changes); ++ r = install_context_mark_for_removal(scope, minus, lp, &remove_symlinks_to, config_path, changes, n_changes); + if (r < 0) + return r; + +- r = remove_marked_symlinks(remove_symlinks_to, config_path, paths, false, changes, n_changes); ++ r = remove_marked_symlinks(remove_symlinks_to, config_path, lp, false, changes, n_changes); + } else + r = 0; + +@@ -3226,7 +3223,7 @@ static int execute_preset( + /* Returns number of symlinks that where supposed to be installed. */ + q = install_context_apply(scope, + file_flags | UNIT_FILE_IGNORE_AUXILIARY_FAILURE, +- plus, paths, config_path, SEARCH_LOAD, changes, n_changes); ++ plus, lp, config_path, SEARCH_LOAD, changes, n_changes); + if (r >= 0) { + if (q < 0) + r = q; +@@ -3242,7 +3239,7 @@ static int preset_prepare_one( + UnitFileScope scope, + InstallContext *plus, + InstallContext *minus, +- LookupPaths *paths, ++ LookupPaths *lp, + const char *name, + const UnitFilePresets *presets, + UnitFileChange **changes, +@@ -3256,7 +3253,7 @@ static int preset_prepare_one( + if (install_info_find(plus, name) || install_info_find(minus, name)) + return 0; + +- r = install_info_discover(scope, &tmp, paths, name, SEARCH_FOLLOW_CONFIG_SYMLINKS, ++ r = install_info_discover(scope, &tmp, lp, name, SEARCH_FOLLOW_CONFIG_SYMLINKS, + &i, changes, n_changes); + if (r < 0) + return r; +@@ -3273,20 +3270,20 @@ static int preset_prepare_one( + if (instance_name_list) { + char **s; + STRV_FOREACH(s, instance_name_list) { +- r = install_info_discover_and_check(scope, plus, paths, *s, SEARCH_LOAD|SEARCH_FOLLOW_CONFIG_SYMLINKS, ++ r = install_info_discover_and_check(scope, plus, lp, *s, SEARCH_LOAD|SEARCH_FOLLOW_CONFIG_SYMLINKS, + &i, changes, n_changes); + if (r < 0) + return r; + } + } else { +- r = install_info_discover_and_check(scope, plus, paths, name, SEARCH_LOAD|SEARCH_FOLLOW_CONFIG_SYMLINKS, ++ r = install_info_discover_and_check(scope, plus, lp, name, SEARCH_LOAD|SEARCH_FOLLOW_CONFIG_SYMLINKS, + &i, changes, n_changes); + if (r < 0) + return r; + } + + } else +- r = install_info_discover(scope, minus, paths, name, SEARCH_FOLLOW_CONFIG_SYMLINKS, ++ r = install_info_discover(scope, minus, lp, name, SEARCH_FOLLOW_CONFIG_SYMLINKS, + &i, changes, n_changes); + + return r; +@@ -3302,7 +3299,7 @@ int unit_file_preset( + size_t *n_changes) { + + _cleanup_(install_context_done) InstallContext plus = {}, minus = {}; +- _cleanup_(lookup_paths_free) LookupPaths paths = {}; ++ _cleanup_(lookup_paths_free) LookupPaths lp = {}; + _cleanup_(unit_file_presets_freep) UnitFilePresets presets = {}; + const char *config_path; + char **i; +@@ -3312,11 +3309,11 @@ int unit_file_preset( + assert(scope < _UNIT_FILE_SCOPE_MAX); + assert(mode < _UNIT_FILE_PRESET_MAX); + +- r = lookup_paths_init(&paths, scope, 0, root_dir); ++ r = lookup_paths_init(&lp, scope, 0, root_dir); + if (r < 0) + return r; + +- config_path = (file_flags & UNIT_FILE_RUNTIME) ? paths.runtime_config : paths.persistent_config; ++ config_path = (file_flags & UNIT_FILE_RUNTIME) ? lp.runtime_config : lp.persistent_config; + if (!config_path) + return -ENXIO; + +@@ -3325,12 +3322,12 @@ int unit_file_preset( + return r; + + STRV_FOREACH(i, files) { +- r = preset_prepare_one(scope, &plus, &minus, &paths, *i, &presets, changes, n_changes); ++ r = preset_prepare_one(scope, &plus, &minus, &lp, *i, &presets, changes, n_changes); + if (r < 0) + return r; + } + +- return execute_preset(scope, file_flags, &plus, &minus, &paths, config_path, files, mode, changes, n_changes); ++ return execute_preset(scope, file_flags, &plus, &minus, &lp, config_path, files, mode, changes, n_changes); + } + + int unit_file_preset_all( +@@ -3342,7 +3339,7 @@ int unit_file_preset_all( + size_t *n_changes) { + + _cleanup_(install_context_done) InstallContext plus = {}, minus = {}; +- _cleanup_(lookup_paths_free) LookupPaths paths = {}; ++ _cleanup_(lookup_paths_free) LookupPaths lp = {}; + _cleanup_(unit_file_presets_freep) UnitFilePresets presets = {}; + const char *config_path = NULL; + char **i; +@@ -3352,11 +3349,11 @@ int unit_file_preset_all( + assert(scope < _UNIT_FILE_SCOPE_MAX); + assert(mode < _UNIT_FILE_PRESET_MAX); + +- r = lookup_paths_init(&paths, scope, 0, root_dir); ++ r = lookup_paths_init(&lp, scope, 0, root_dir); + if (r < 0) + return r; + +- config_path = (file_flags & UNIT_FILE_RUNTIME) ? paths.runtime_config : paths.persistent_config; ++ config_path = (file_flags & UNIT_FILE_RUNTIME) ? lp.runtime_config : lp.persistent_config; + if (!config_path) + return -ENXIO; + +@@ -3364,7 +3361,7 @@ int unit_file_preset_all( + if (r < 0) + return r; + +- STRV_FOREACH(i, paths.search_path) { ++ STRV_FOREACH(i, lp.search_path) { + _cleanup_closedir_ DIR *d = NULL; + + d = opendir(*i); +@@ -3383,7 +3380,7 @@ int unit_file_preset_all( + if (!IN_SET(de->d_type, DT_LNK, DT_REG)) + continue; + +- r = preset_prepare_one(scope, &plus, &minus, &paths, de->d_name, &presets, changes, n_changes); ++ r = preset_prepare_one(scope, &plus, &minus, &lp, de->d_name, &presets, changes, n_changes); + if (r < 0 && + !IN_SET(r, -EEXIST, -ERFKILL, -EADDRNOTAVAIL, -EIDRM, -EUCLEAN, -ELOOP, -ENOENT)) + /* Ignore generated/transient/missing/invalid units when applying preset, propagate other errors. +@@ -3392,7 +3389,7 @@ int unit_file_preset_all( + } + } + +- return execute_preset(scope, file_flags, &plus, &minus, &paths, config_path, NULL, mode, changes, n_changes); ++ return execute_preset(scope, file_flags, &plus, &minus, &lp, config_path, NULL, mode, changes, n_changes); + } + + static UnitFileList* unit_file_list_free_one(UnitFileList *f) { +@@ -3416,7 +3413,7 @@ int unit_file_get_list( + char **states, + char **patterns) { + +- _cleanup_(lookup_paths_free) LookupPaths paths = {}; ++ _cleanup_(lookup_paths_free) LookupPaths lp = {}; + char **dirname; + int r; + +@@ -3424,11 +3421,11 @@ int unit_file_get_list( + assert(scope < _UNIT_FILE_SCOPE_MAX); + assert(h); + +- r = lookup_paths_init(&paths, scope, 0, root_dir); ++ r = lookup_paths_init(&lp, scope, 0, root_dir); + if (r < 0) + return r; + +- STRV_FOREACH(dirname, paths.search_path) { ++ STRV_FOREACH(dirname, lp.search_path) { + _cleanup_closedir_ DIR *d = NULL; + + d = opendir(*dirname); +@@ -3466,7 +3463,7 @@ int unit_file_get_list( + if (!f->path) + return -ENOMEM; + +- r = unit_file_lookup_state(scope, &paths, de->d_name, &f->state); ++ r = unit_file_lookup_state(scope, &lp, de->d_name, &f->state); + if (r < 0) + f->state = UNIT_FILE_BAD; + diff --git a/0154-shared-specifier-treat-NULL-the-same-as.patch b/0154-shared-specifier-treat-NULL-the-same-as.patch new file mode 100644 index 0000000..26cd8b6 --- /dev/null +++ b/0154-shared-specifier-treat-NULL-the-same-as.patch @@ -0,0 +1,191 @@ +From c36354b26c757e526e9f3d8c5bc78aa36f095f61 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Thu, 20 Jan 2022 15:47:22 +0100 +Subject: [PATCH] shared/specifier: treat NULL the same as "" + +We would busily allocate an empty string to concatenate all of it's +zero characters to the output. Let's make things a bit simpler by letting +the specifier functions return NULL to mean "nothing to append". + +(cherry picked from commit 01c69460811f64e416c3e4a545ef84787bb6700b) + +Related: #2082131 +--- + src/shared/specifier.c | 56 ++++++++++++++------------------------- + src/test/test-specifier.c | 9 ++++--- + 2 files changed, 25 insertions(+), 40 deletions(-) + +diff --git a/src/shared/specifier.c b/src/shared/specifier.c +index 1fd76b1d15..f8ab98541f 100644 +--- a/src/shared/specifier.c ++++ b/src/shared/specifier.c +@@ -35,7 +35,6 @@ + int specifier_printf(const char *text, size_t max_length, const Specifier table[], const char *root, const void *userdata, char **ret) { + _cleanup_free_ char *result = NULL; + bool percent = false; +- const char *f; + size_t l; + char *t; + int r; +@@ -48,8 +47,10 @@ int specifier_printf(const char *text, size_t max_length, const Specifier table[ + return -ENOMEM; + t = result; + +- for (f = text; *f != '\0'; f++, l--) { ++ for (const char *f = text; *f != '\0'; f++, l--) { + if (percent) { ++ percent = false; ++ + if (*f == '%') + *(t++) = '%'; + else { +@@ -66,6 +67,8 @@ int specifier_printf(const char *text, size_t max_length, const Specifier table[ + r = i->lookup(i->specifier, i->data, root, userdata, &w); + if (r < 0) + return r; ++ if (isempty(w)) ++ continue; + + j = t - result; + k = strlen(w); +@@ -82,8 +85,6 @@ int specifier_printf(const char *text, size_t max_length, const Specifier table[ + *(t++) = *f; + } + } +- +- percent = false; + } else if (*f == '%') + percent = true; + else +@@ -108,11 +109,13 @@ int specifier_printf(const char *text, size_t max_length, const Specifier table[ + /* Generic handler for simple string replacements */ + + int specifier_string(char specifier, const void *data, const char *root, const void *userdata, char **ret) { +- char *n; ++ char *n = NULL; + +- n = strdup(strempty(data)); +- if (!n) +- return -ENOMEM; ++ if (!isempty(data)) { ++ n = strdup(data); ++ if (!n) ++ return -ENOMEM; ++ } + + *ret = n; + return 0; +@@ -186,10 +189,8 @@ int specifier_short_host_name(char specifier, const void *data, const char *root + int specifier_kernel_release(char specifier, const void *data, const char *root, const void *userdata, char **ret) { + struct utsname uts; + char *n; +- int r; + +- r = uname(&uts); +- if (r < 0) ++ if (uname(&uts) < 0) + return -errno; + + n = strdup(uts.release); +@@ -211,47 +212,31 @@ int specifier_architecture(char specifier, const void *data, const char *root, c + return 0; + } + +-static int specifier_os_release_common(const char *field, const char *root, char **ret) { +- char *t = NULL; +- int r; +- +- r = parse_os_release(root, field, &t); +- if (r < 0) +- return r; +- if (!t) { +- /* fields in /etc/os-release might quite possibly be missing, even if everything is entirely +- * valid otherwise. Let's hence return "" in that case. */ +- t = strdup(""); +- if (!t) +- return -ENOMEM; +- } +- +- *ret = t; +- return 0; +-} ++/* Note: fields in /etc/os-release might quite possibly be missing, even if everything is entirely valid ++ * otherwise. We'll return an empty value or NULL in that case from the functions below. */ + + int specifier_os_id(char specifier, const void *data, const char *root, const void *userdata, char **ret) { +- return specifier_os_release_common("ID", root, ret); ++ return parse_os_release(root, "ID", ret); + } + + int specifier_os_version_id(char specifier, const void *data, const char *root, const void *userdata, char **ret) { +- return specifier_os_release_common("VERSION_ID", root, ret); ++ return parse_os_release(root, "VERSION_ID", ret); + } + + int specifier_os_build_id(char specifier, const void *data, const char *root, const void *userdata, char **ret) { +- return specifier_os_release_common("BUILD_ID", root, ret); ++ return parse_os_release(root, "BUILD_ID", ret); + } + + int specifier_os_variant_id(char specifier, const void *data, const char *root, const void *userdata, char **ret) { +- return specifier_os_release_common("VARIANT_ID", root, ret); ++ return parse_os_release(root, "VARIANT_ID", ret); + } + + int specifier_os_image_id(char specifier, const void *data, const char *root, const void *userdata, char **ret) { +- return specifier_os_release_common("IMAGE_ID", root, ret); ++ return parse_os_release(root, "IMAGE_ID", ret); + } + + int specifier_os_image_version(char specifier, const void *data, const char *root, const void *userdata, char **ret) { +- return specifier_os_release_common("IMAGE_VERSION", root, ret); ++ return parse_os_release(root, "IMAGE_VERSION", ret); + } + + int specifier_group_name(char specifier, const void *data, const char *root, const void *userdata, char **ret) { +@@ -291,7 +276,6 @@ int specifier_user_name(char specifier, const void *data, const char *root, cons + } + + int specifier_user_id(char specifier, const void *data, const char *root, const void *userdata, char **ret) { +- + if (asprintf(ret, UID_FMT, getuid()) < 0) + return -ENOMEM; + +diff --git a/src/test/test-specifier.c b/src/test/test-specifier.c +index 40957eeb59..dda993ce9d 100644 +--- a/src/test/test-specifier.c ++++ b/src/test/test-specifier.c +@@ -56,6 +56,7 @@ TEST(specifier_printf) { + static const Specifier table[] = { + { 'X', specifier_string, (char*) "AAAA" }, + { 'Y', specifier_string, (char*) "BBBB" }, ++ { 'e', specifier_string, NULL }, + COMMON_SYSTEM_SPECIFIERS, + {} + }; +@@ -63,21 +64,21 @@ TEST(specifier_printf) { + _cleanup_free_ char *w = NULL; + int r; + +- r = specifier_printf("xxx a=%X b=%Y yyy", SIZE_MAX, table, NULL, NULL, &w); ++ r = specifier_printf("xxx a=%X b=%Y e=%e yyy", SIZE_MAX, table, NULL, NULL, &w); + assert_se(r >= 0); + assert_se(w); + + puts(w); +- assert_se(streq(w, "xxx a=AAAA b=BBBB yyy")); ++ assert_se(streq(w, "xxx a=AAAA b=BBBB e= yyy")); + + free(w); +- r = specifier_printf("machine=%m, boot=%b, host=%H, version=%v, arch=%a", SIZE_MAX, table, NULL, NULL, &w); ++ r = specifier_printf("machine=%m, boot=%b, host=%H, version=%v, arch=%a, empty=%e", SIZE_MAX, table, NULL, NULL, &w); + assert_se(r >= 0); + assert_se(w); + puts(w); + + w = mfree(w); +- specifier_printf("os=%o, os-version=%w, build=%B, variant=%W", SIZE_MAX, table, NULL, NULL, &w); ++ specifier_printf("os=%o, os-version=%w, build=%B, variant=%W, empty=%e%e%e", SIZE_MAX, table, NULL, NULL, &w); + if (w) + puts(w); + } diff --git a/0155-shared-install-do-not-print-aliases-longer-than-UNIT.patch b/0155-shared-install-do-not-print-aliases-longer-than-UNIT.patch new file mode 100644 index 0000000..c49163f --- /dev/null +++ b/0155-shared-install-do-not-print-aliases-longer-than-UNIT.patch @@ -0,0 +1,30 @@ +From 5f66b67ac6594a3dee6e463a5f31c2d1051503cc Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Tue, 8 Mar 2022 11:47:23 +0100 +Subject: [PATCH] shared/install: do not print aliases longer than + UNIT_NAME_MAX + +065364920281e1cf59cab989e17aff21790505c4 did the conversion to install_path_printf(). +But IIUC, here we are just looking at a unit file name, not the full +path. + +(cherry picked from commit 46801e7647d98ccac8fca4cc91ef9c3513151943) + +Related: #2082131 +--- + src/shared/install.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/shared/install.c b/src/shared/install.c +index c6cbe96fdb..79e5109ce1 100644 +--- a/src/shared/install.c ++++ b/src/shared/install.c +@@ -1825,7 +1825,7 @@ static int install_info_symlink_alias( + STRV_FOREACH(s, i->aliases) { + _cleanup_free_ char *alias_path = NULL, *dst = NULL, *dst_updated = NULL; + +- q = install_path_printf(i, *s, i->root, &dst); ++ q = install_name_printf(i, *s, i->root, &dst); + if (q < 0) + return q; + diff --git a/0156-shared-install-printf-drop-now-unused-install_path_p.patch b/0156-shared-install-printf-drop-now-unused-install_path_p.patch new file mode 100644 index 0000000..361fa69 --- /dev/null +++ b/0156-shared-install-printf-drop-now-unused-install_path_p.patch @@ -0,0 +1,50 @@ +From b635f03ba218df6c184da4d53648b13241b6b07d Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Tue, 8 Mar 2022 11:49:19 +0100 +Subject: [PATCH] shared/install-printf: drop now-unused install_path_printf() + +(cherry picked from commit 2cdd6bef9c940774d40046db9be41ea73cdb5d8e) + +Related: #2082131 +--- + src/shared/install-printf.c | 4 ++-- + src/shared/install-printf.h | 9 +-------- + 2 files changed, 3 insertions(+), 10 deletions(-) + +diff --git a/src/shared/install-printf.c b/src/shared/install-printf.c +index 403d6013c1..6ff4198ac9 100644 +--- a/src/shared/install-printf.c ++++ b/src/shared/install-printf.c +@@ -103,7 +103,7 @@ static int specifier_last_component(char specifier, const void *data, const char + return 0; + } + +-int install_full_printf_internal(const UnitFileInstallInfo *i, const char *format, size_t max_length, const char *root, char **ret) { ++int install_name_printf(const UnitFileInstallInfo *i, const char *format, const char *root, char **ret) { + /* This is similar to unit_name_printf() */ + + const Specifier table[] = { +@@ -123,5 +123,5 @@ int install_full_printf_internal(const UnitFileInstallInfo *i, const char *forma + assert(format); + assert(ret); + +- return specifier_printf(format, max_length, table, root, i, ret); ++ return specifier_printf(format, UNIT_NAME_MAX, table, root, i, ret); + } +diff --git a/src/shared/install-printf.h b/src/shared/install-printf.h +index af32acc2ca..5ca9406797 100644 +--- a/src/shared/install-printf.h ++++ b/src/shared/install-printf.h +@@ -4,11 +4,4 @@ + #include "install.h" + #include "unit-name.h" + +-int install_full_printf_internal(const UnitFileInstallInfo *i, const char *format, size_t max_length, const char *root, char **ret); +- +-static inline int install_name_printf(const UnitFileInstallInfo *i, const char *format, const char *root, char **ret) { +- return install_full_printf_internal(i, format, UNIT_NAME_MAX, root, ret); +-} +-static inline int install_path_printf(const UnitFileInstallInfo *i, const char *format, const char *root, char **ret) { +- return install_full_printf_internal(i, format, PATH_MAX-1, root, ret); +-} ++int install_name_printf(const UnitFileInstallInfo *i, const char *format, const char *root, char **ret); diff --git a/0157-strv-declare-iterator-of-FOREACH_STRING-in-the-loop.patch b/0157-strv-declare-iterator-of-FOREACH_STRING-in-the-loop.patch new file mode 100644 index 0000000..8ce9253 --- /dev/null +++ b/0157-strv-declare-iterator-of-FOREACH_STRING-in-the-loop.patch @@ -0,0 +1,1088 @@ +From f7660c55adcf3e6a7eec251c474edc0cbb19e26d Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Wed, 23 Mar 2022 10:48:13 +0100 +Subject: [PATCH] strv: declare iterator of FOREACH_STRING() in the loop + +Same idea as 03677889f0ef42cdc534bf3b31265a054b20a354. + +No functional change intended. The type of the iterator is generally changed to +be 'const char*' instead of 'char*'. Despite the type commonly used, modifying +the string was not allowed. + +I adjusted the naming of some short variables for clarity and reduced the scope +of some variable declarations in code that was being touched anyway. + +(cherry picked from commit 5980d463048f25411c55da2f6387cdc8eaeef4c8) + +Related: #2082131 +--- + src/activate/activate.c | 1 - + src/basic/fs-util.c | 1 - + src/basic/os-util.c | 2 -- + src/basic/strv.h | 2 +- + src/basic/unit-file.c | 1 - + src/boot/bootctl.c | 9 ++++----- + src/cgtop/cgtop.c | 1 - + src/core/apparmor-setup.c | 1 - + src/core/efi-random.c | 11 +++++------ + src/core/execute.c | 1 - + src/core/timer.c | 2 -- + src/core/unit.c | 1 - + src/getty-generator/getty-generator.c | 4 +--- + src/home/homectl.c | 17 +++-------------- + src/home/homed-manager.c | 1 - + src/libsystemd/sd-device/sd-device.c | 6 +----- + src/locale/localed.c | 2 +- + src/login/logind-user.c | 1 - + src/nspawn/nspawn-cgroup.c | 1 - + src/nspawn/nspawn-mount.c | 4 ++-- + src/nspawn/nspawn.c | 5 ++--- + src/partition/repart.c | 3 +-- + src/portable/portable.c | 1 - + src/resolve/resolved-resolv-conf.c | 2 -- + src/resolve/test-resolved-etc-hosts.c | 1 - + src/run/run.c | 2 -- + src/shared/bootspec.c | 3 ++- + src/shared/chown-recursive.c | 1 - + src/shared/discover-image.c | 2 +- + src/shared/dissect-image.c | 1 - + src/shared/machine-id-setup.c | 2 +- + src/shared/mount-setup.c | 4 ---- + src/shared/netif-util.c | 7 ++++--- + src/shared/pager.c | 2 +- + src/shared/psi-util.c | 2 -- + src/shared/switch-root.c | 11 +++++------ + src/shared/tests.c | 11 +++++------ + src/systemctl/systemctl-edit.c | 8 ++++---- + src/systemctl/systemctl-sysv-compat.c | 25 ++++++++++++------------- + src/test/test-bpf-devices.c | 1 - + src/test/test-ellipsize.c | 8 ++------ + src/test/test-env-file.c | 2 -- + src/test/test-execute.c | 16 ++++++---------- + src/test/test-fileio.c | 1 - + src/test/test-gpt.c | 6 +----- + src/test/test-libcrypt-util.c | 2 -- + src/test/test-loop-block.c | 1 - + src/test/test-mount-util.c | 1 - + src/test/test-stat-util.c | 2 -- + src/test/test-strv.c | 4 +--- + src/test/test-utf8.c | 3 --- + src/tmpfiles/offline-passwd.c | 2 -- + 52 files changed, 66 insertions(+), 145 deletions(-) + +diff --git a/src/activate/activate.c b/src/activate/activate.c +index 0c32152671..b625d97f2e 100644 +--- a/src/activate/activate.c ++++ b/src/activate/activate.c +@@ -124,7 +124,6 @@ static int open_sockets(int *epoll_fd, bool accept) { + + static int exec_process(const char *name, char **argv, int start_fd, size_t n_fds) { + _cleanup_strv_free_ char **envp = NULL; +- const char *var; + char **s; + int r; + +diff --git a/src/basic/fs-util.c b/src/basic/fs-util.c +index 552986f546..2ee7c23f68 100644 +--- a/src/basic/fs-util.c ++++ b/src/basic/fs-util.c +@@ -570,7 +570,6 @@ int get_files_in_directory(const char *path, char ***list) { + } + + static int getenv_tmp_dir(const char **ret_path) { +- const char *n; + int r, ret = 0; + + assert(ret_path); +diff --git a/src/basic/os-util.c b/src/basic/os-util.c +index 75c8500e51..a6e4d09473 100644 +--- a/src/basic/os-util.c ++++ b/src/basic/os-util.c +@@ -170,8 +170,6 @@ int open_extension_release(const char *root, const char *extension, char **ret_p + } + } + } else { +- const char *p; +- + FOREACH_STRING(p, "/etc/os-release", "/usr/lib/os-release") { + r = chase_symlinks(p, root, CHASE_PREFIX_ROOT, + ret_path ? &q : NULL, +diff --git a/src/basic/strv.h b/src/basic/strv.h +index 092d40c84b..27d4450468 100644 +--- a/src/basic/strv.h ++++ b/src/basic/strv.h +@@ -207,7 +207,7 @@ void strv_print(char * const *l); + }) + + #define _FOREACH_STRING(uniq, x, y, ...) \ +- for (char **UNIQ_T(l, uniq) = STRV_MAKE(({ x = y; }), ##__VA_ARGS__); \ ++ for (const char *x, * const*UNIQ_T(l, uniq) = STRV_MAKE_CONST(({ x = y; }), ##__VA_ARGS__); \ + x; \ + x = *(++UNIQ_T(l, uniq))) + +diff --git a/src/basic/unit-file.c b/src/basic/unit-file.c +index faea92f66d..96826e2940 100644 +--- a/src/basic/unit-file.c ++++ b/src/basic/unit-file.c +@@ -237,7 +237,6 @@ bool lookup_paths_timestamp_hash_same(const LookupPaths *lp, uint64_t timestamp_ + } + + static int directory_name_is_valid(const char *name) { +- const char *suffix; + + /* Accept a directory whose name is a valid unit file name ending in .wants/, .requires/ or .d/ */ + +diff --git a/src/boot/bootctl.c b/src/boot/bootctl.c +index 1bcb4d1689..9427a0e4ce 100644 +--- a/src/boot/bootctl.c ++++ b/src/boot/bootctl.c +@@ -1044,12 +1044,11 @@ static int remove_variables(sd_id128_t uuid, const char *path, bool in_order) { + } + + static int remove_loader_variables(void) { +- const char *variable; + int r = 0; + + /* Remove all persistent loader variables we define */ + +- FOREACH_STRING(variable, ++ FOREACH_STRING(var, + EFI_LOADER_VARIABLE(LoaderConfigTimeout), + EFI_LOADER_VARIABLE(LoaderConfigTimeoutOneShot), + EFI_LOADER_VARIABLE(LoaderEntryDefault), +@@ -1058,15 +1057,15 @@ static int remove_loader_variables(void) { + + int q; + +- q = efi_set_variable(variable, NULL, 0); ++ q = efi_set_variable(var, NULL, 0); + if (q == -ENOENT) + continue; + if (q < 0) { +- log_warning_errno(q, "Failed to remove EFI variable %s: %m", variable); ++ log_warning_errno(q, "Failed to remove EFI variable %s: %m", var); + if (r >= 0) + r = q; + } else +- log_info("Removed EFI variable %s.", variable); ++ log_info("Removed EFI variable %s.", var); + } + + return r; +diff --git a/src/cgtop/cgtop.c b/src/cgtop/cgtop.c +index e5ab904c4f..b023e71757 100644 +--- a/src/cgtop/cgtop.c ++++ b/src/cgtop/cgtop.c +@@ -510,7 +510,6 @@ static int refresh_one( + } + + static int refresh(const char *root, Hashmap *a, Hashmap *b, unsigned iteration) { +- const char *c; + int r; + + FOREACH_STRING(c, SYSTEMD_CGROUP_CONTROLLER, "cpu", "cpuacct", "memory", "io", "blkio", "pids") { +diff --git a/src/core/apparmor-setup.c b/src/core/apparmor-setup.c +index 304a3e6aac..3426a10358 100644 +--- a/src/core/apparmor-setup.c ++++ b/src/core/apparmor-setup.c +@@ -24,7 +24,6 @@ int mac_apparmor_setup(void) { + #if HAVE_APPARMOR + _cleanup_(aa_policy_cache_unrefp) aa_policy_cache *policy_cache = NULL; + _cleanup_(aa_features_unrefp) aa_features *features = NULL; +- const char *current_file; + _cleanup_free_ char *current_profile = NULL, *cache_dir_path = NULL; + int r; + +diff --git a/src/core/efi-random.c b/src/core/efi-random.c +index a0b89d1379..e8d8ccd117 100644 +--- a/src/core/efi-random.c ++++ b/src/core/efi-random.c +@@ -20,24 +20,23 @@ + * is suitably validated. */ + + static void lock_down_efi_variables(void) { +- const char *p; + int r; + + /* Paranoia: let's restrict access modes of these a bit, so that unprivileged users can't use them to + * identify the system or gain too much insight into what we might have credited to the entropy + * pool. */ +- FOREACH_STRING(p, ++ FOREACH_STRING(path, + EFIVAR_PATH(EFI_LOADER_VARIABLE(LoaderRandomSeed)), + EFIVAR_PATH(EFI_LOADER_VARIABLE(LoaderSystemToken))) { + +- r = chattr_path(p, 0, FS_IMMUTABLE_FL, NULL); ++ r = chattr_path(path, 0, FS_IMMUTABLE_FL, NULL); + if (r == -ENOENT) + continue; + if (r < 0) +- log_warning_errno(r, "Failed to drop FS_IMMUTABLE_FL from %s, ignoring: %m", p); ++ log_warning_errno(r, "Failed to drop FS_IMMUTABLE_FL from %s, ignoring: %m", path); + +- if (chmod(p, 0600) < 0) +- log_warning_errno(errno, "Failed to reduce access mode of %s, ignoring: %m", p); ++ if (chmod(path, 0600) < 0) ++ log_warning_errno(errno, "Failed to reduce access mode of %s, ignoring: %m", path); + } + } + +diff --git a/src/core/execute.c b/src/core/execute.c +index 8a1d070e26..3cafd0f17d 100644 +--- a/src/core/execute.c ++++ b/src/core/execute.c +@@ -2917,7 +2917,6 @@ static int setup_credentials( + uid_t uid) { + + _cleanup_free_ char *p = NULL, *q = NULL; +- const char *i; + int r; + + assert(context); +diff --git a/src/core/timer.c b/src/core/timer.c +index b439802bc2..23f466c630 100644 +--- a/src/core/timer.c ++++ b/src/core/timer.c +@@ -100,8 +100,6 @@ static int timer_add_default_dependencies(Timer *t) { + return r; + + LIST_FOREACH(value, v, t->values) { +- const char *target; +- + if (v->base != TIMER_CALENDAR) + continue; + +diff --git a/src/core/unit.c b/src/core/unit.c +index 0eade13ee9..3d30f3807c 100644 +--- a/src/core/unit.c ++++ b/src/core/unit.c +@@ -4104,7 +4104,6 @@ int unit_patch_contexts(Unit *u) { + + if ((ec->root_image || !LIST_IS_EMPTY(ec->mount_images)) && + (cc->device_policy != CGROUP_DEVICE_POLICY_AUTO || cc->device_allow)) { +- const char *p; + + /* When RootImage= or MountImages= is specified, the following devices are touched. */ + FOREACH_STRING(p, "/dev/loop-control", "/dev/mapper/control") { +diff --git a/src/getty-generator/getty-generator.c b/src/getty-generator/getty-generator.c +index 59bdfc496b..4e8162a319 100644 +--- a/src/getty-generator/getty-generator.c ++++ b/src/getty-generator/getty-generator.c +@@ -215,9 +215,7 @@ static int run(const char *dest, const char *dest_early, const char *dest_late) + return r; + } + +- /* Automatically add in a serial getty on the first +- * virtualizer console */ +- const char *j; ++ /* Automatically add in a serial getty on the first virtualizer console */ + FOREACH_STRING(j, + "hvc0", + "xvc0", +diff --git a/src/home/homectl.c b/src/home/homectl.c +index 1e3c96f5ad..ac7b00889d 100644 +--- a/src/home/homectl.c ++++ b/src/home/homectl.c +@@ -2961,8 +2961,6 @@ static int parse_argv(int argc, char *argv[]) { + + case ARG_DISK_SIZE: + if (isempty(optarg)) { +- const char *prop; +- + FOREACH_STRING(prop, "diskSize", "diskSizeRelative", "rebalanceWeight") { + r = drop_from_identity(prop); + if (r < 0) +@@ -3464,9 +3462,7 @@ static int parse_argv(int argc, char *argv[]) { + break; + } + +- case ARG_PKCS11_TOKEN_URI: { +- const char *p; +- ++ case ARG_PKCS11_TOKEN_URI: + if (streq(optarg, "list")) + return pkcs11_list_tokens(); + +@@ -3500,11 +3496,8 @@ static int parse_argv(int argc, char *argv[]) { + + strv_uniq(arg_pkcs11_token_uri); + break; +- } +- +- case ARG_FIDO2_DEVICE: { +- const char *p; + ++ case ARG_FIDO2_DEVICE: + if (streq(optarg, "list")) + return fido2_list_devices(); + +@@ -3534,7 +3527,6 @@ static int parse_argv(int argc, char *argv[]) { + + strv_uniq(arg_fido2_device); + break; +- } + + case ARG_FIDO2_WITH_PIN: { + bool lock_with_pin; +@@ -3569,9 +3561,7 @@ static int parse_argv(int argc, char *argv[]) { + break; + } + +- case ARG_RECOVERY_KEY: { +- const char *p; +- ++ case ARG_RECOVERY_KEY: + r = parse_boolean(optarg); + if (r < 0) + return log_error_errno(r, "Failed to parse --recovery-key= argument: %s", optarg); +@@ -3585,7 +3575,6 @@ static int parse_argv(int argc, char *argv[]) { + } + + break; +- } + + case ARG_AUTO_RESIZE_MODE: + if (isempty(optarg)) { +diff --git a/src/home/homed-manager.c b/src/home/homed-manager.c +index c1ec555cac..a02248a6de 100644 +--- a/src/home/homed-manager.c ++++ b/src/home/homed-manager.c +@@ -482,7 +482,6 @@ static int manager_enumerate_records(Manager *m) { + static int search_quota(uid_t uid, const char *exclude_quota_path) { + struct stat exclude_st = {}; + dev_t previous_devno = 0; +- const char *where; + int r; + + /* Checks whether the specified UID owns any files on the files system, but ignore any file system +diff --git a/src/libsystemd/sd-device/sd-device.c b/src/libsystemd/sd-device/sd-device.c +index b163a0fb6b..af11730f33 100644 +--- a/src/libsystemd/sd-device/sd-device.c ++++ b/src/libsystemd/sd-device/sd-device.c +@@ -322,7 +322,6 @@ _public_ int sd_device_new_from_subsystem_sysname( + const char *subsystem, + const char *sysname) { + +- const char *s; + char *name; + int r; + +@@ -331,7 +330,6 @@ _public_ int sd_device_new_from_subsystem_sysname( + assert_return(path_is_normalized(sysname), -EINVAL); + + if (streq(subsystem, "subsystem")) { +- + FOREACH_STRING(s, "/sys/subsystem/", "/sys/bus/", "/sys/class/") { + r = device_strjoin_new(s, sysname, NULL, NULL, ret); + if (r < 0) +@@ -341,7 +339,6 @@ _public_ int sd_device_new_from_subsystem_sysname( + } + + } else if (streq(subsystem, "module")) { +- + r = device_strjoin_new("/sys/module/", sysname, NULL, NULL, ret); + if (r < 0) + return r; +@@ -353,9 +350,8 @@ _public_ int sd_device_new_from_subsystem_sysname( + + sep = strchr(sysname, ':'); + if (sep && sep[1] != '\0') { /* Require ":" and something non-empty after that. */ +- const char *subsys; + +- subsys = memdupa_suffix0(sysname, sep - sysname); ++ const char *subsys = memdupa_suffix0(sysname, sep - sysname); + sep++; + + FOREACH_STRING(s, "/sys/subsystem/", "/sys/bus/") { +diff --git a/src/locale/localed.c b/src/locale/localed.c +index c228385d0e..f3e6ef2db1 100644 +--- a/src/locale/localed.c ++++ b/src/locale/localed.c +@@ -475,7 +475,7 @@ static int method_set_locale(sd_bus_message *m, void *userdata, sd_bus_error *er + + static int method_set_vc_keyboard(sd_bus_message *m, void *userdata, sd_bus_error *error) { + Context *c = userdata; +- const char *name, *keymap, *keymap_toggle; ++ const char *keymap, *keymap_toggle; + int convert, interactive, r; + + assert(m); +diff --git a/src/login/logind-user.c b/src/login/logind-user.c +index 6d250be321..74739b4242 100644 +--- a/src/login/logind-user.c ++++ b/src/login/logind-user.c +@@ -626,7 +626,6 @@ int user_check_linger_file(User *u) { + } + + static bool user_unit_active(User *u) { +- const char *i; + int r; + + assert(u->service); +diff --git a/src/nspawn/nspawn-cgroup.c b/src/nspawn/nspawn-cgroup.c +index d472e80c03..d8e1fe0907 100644 +--- a/src/nspawn/nspawn-cgroup.c ++++ b/src/nspawn/nspawn-cgroup.c +@@ -22,7 +22,6 @@ + + static int chown_cgroup_path(const char *path, uid_t uid_shift) { + _cleanup_close_ int fd = -1; +- const char *fn; + + fd = open(path, O_RDONLY|O_CLOEXEC|O_DIRECTORY); + if (fd < 0) +diff --git a/src/nspawn/nspawn-mount.c b/src/nspawn/nspawn-mount.c +index 40773d90c1..678fde3669 100644 +--- a/src/nspawn/nspawn-mount.c ++++ b/src/nspawn/nspawn-mount.c +@@ -408,7 +408,7 @@ int tmpfs_patch_options( + } + + int mount_sysfs(const char *dest, MountSettingsMask mount_settings) { +- const char *full, *top, *x; ++ const char *full, *top; + int r; + unsigned long extra_flags = 0; + +@@ -468,7 +468,7 @@ int mount_sysfs(const char *dest, MountSettingsMask mount_settings) { + /* Create mountpoint for cgroups. Otherwise we are not allowed since we + * remount /sys read-only. + */ +- x = prefix_roota(top, "/fs/cgroup"); ++ const char *x = prefix_roota(top, "/fs/cgroup"); + (void) mkdir_p(x, 0755); + + return mount_nofollow_verbose(LOG_ERR, NULL, top, NULL, +diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c +index 9225c8f162..1333a8702a 100644 +--- a/src/nspawn/nspawn.c ++++ b/src/nspawn/nspawn.c +@@ -2564,7 +2564,7 @@ static int setup_hostname(void) { + + static int setup_journal(const char *directory) { + _cleanup_free_ char *d = NULL; +- const char *dirname, *p, *q; ++ const char *p, *q; + sd_id128_t this_id; + bool try; + int r; +@@ -3513,7 +3513,6 @@ static int inner_child( + (void) fdset_close_others(fds); + + if (arg_start_mode == START_BOOT) { +- const char *init; + char **a; + size_t m; + +@@ -4604,7 +4603,7 @@ static int load_settings(void) { + _cleanup_(settings_freep) Settings *settings = NULL; + _cleanup_fclose_ FILE *f = NULL; + _cleanup_free_ char *p = NULL; +- const char *fn, *i; ++ const char *fn; + int r; + + if (arg_oci_bundle) +diff --git a/src/partition/repart.c b/src/partition/repart.c +index 0862a37a8d..509cf69b5d 100644 +--- a/src/partition/repart.c ++++ b/src/partition/repart.c +@@ -4561,9 +4561,8 @@ static int acquire_root_devno( + } + + static int find_root(char **ret, int *ret_fd) { +- const char *p; +- int r; + _cleanup_free_ char *device = NULL; ++ int r; + + assert(ret); + assert(ret_fd); +diff --git a/src/portable/portable.c b/src/portable/portable.c +index be311f94c4..bdc10da36f 100644 +--- a/src/portable/portable.c ++++ b/src/portable/portable.c +@@ -1568,7 +1568,6 @@ int portable_detach( + + SET_FOREACH(item, unit_files) { + _cleanup_free_ char *md = NULL; +- const char *suffix; + + if (unlinkat(dirfd(d), item, 0) < 0) { + log_debug_errno(errno, "Can't remove unit file %s/%s: %m", where, item); +diff --git a/src/resolve/resolved-resolv-conf.c b/src/resolve/resolved-resolv-conf.c +index e9785ab964..ee86cf75a0 100644 +--- a/src/resolve/resolved-resolv-conf.c ++++ b/src/resolve/resolved-resolv-conf.c +@@ -51,8 +51,6 @@ int manager_check_resolv_conf(const Manager *m) { + } + + static bool file_is_our_own(const struct stat *st) { +- const char *path; +- + assert(st); + + FOREACH_STRING(path, +diff --git a/src/resolve/test-resolved-etc-hosts.c b/src/resolve/test-resolved-etc-hosts.c +index cc55a980ad..f15e025b7b 100644 +--- a/src/resolve/test-resolved-etc-hosts.c ++++ b/src/resolve/test-resolved-etc-hosts.c +@@ -45,7 +45,6 @@ static void test_parse_etc_hosts(void) { + + int fd; + _cleanup_fclose_ FILE *f; +- const char *s; + + fd = mkostemp_safe(t); + assert_se(fd >= 0); +diff --git a/src/run/run.c b/src/run/run.c +index e75b027542..2ae629f595 100644 +--- a/src/run/run.c ++++ b/src/run/run.c +@@ -1702,8 +1702,6 @@ static int start_transient_trigger( + } + + static bool shall_make_executable_absolute(void) { +- const char *f; +- + if (strv_isempty(arg_cmdline)) + return false; + if (arg_transport != BUS_TRANSPORT_LOCAL) +diff --git a/src/shared/bootspec.c b/src/shared/bootspec.c +index 0076092c2a..a17375eb4c 100644 +--- a/src/shared/bootspec.c ++++ b/src/shared/bootspec.c +@@ -1207,7 +1207,8 @@ int find_esp_and_warn( + goto found; + } + +- FOREACH_STRING(path, "/efi", "/boot", "/boot/efi") { ++ FOREACH_STRING(_path, "/efi", "/boot", "/boot/efi") { ++ path = _path; + + r = verify_esp(path, true, unprivileged_mode, ret_part, ret_pstart, ret_psize, ret_uuid); + if (r >= 0) +diff --git a/src/shared/chown-recursive.c b/src/shared/chown-recursive.c +index 7c9a3050b4..05a7a10ce4 100644 +--- a/src/shared/chown-recursive.c ++++ b/src/shared/chown-recursive.c +@@ -21,7 +21,6 @@ static int chown_one( + gid_t gid, + mode_t mask) { + +- const char *n; + int r; + + assert(fd >= 0); +diff --git a/src/shared/discover-image.c b/src/shared/discover-image.c +index 268d910214..1d432328e7 100644 +--- a/src/shared/discover-image.c ++++ b/src/shared/discover-image.c +@@ -85,7 +85,7 @@ DEFINE_HASH_OPS_WITH_VALUE_DESTRUCTOR(image_hash_ops, char, string_hash_func, st + + static char **image_settings_path(Image *image) { + _cleanup_strv_free_ char **l = NULL; +- const char *fn, *s; ++ const char *fn; + unsigned i = 0; + + assert(image); +diff --git a/src/shared/dissect-image.c b/src/shared/dissect-image.c +index 39a7f4c3f2..b38f16c37a 100644 +--- a/src/shared/dissect-image.c ++++ b/src/shared/dissect-image.c +@@ -3042,7 +3042,6 @@ int dissected_image_acquire_metadata(DissectedImage *m, DissectImageFlags extra_ + + case META_HAS_INIT_SYSTEM: { + bool found = false; +- const char *init; + + FOREACH_STRING(init, + "/usr/lib/systemd/systemd", /* systemd on /usr merged system */ +diff --git a/src/shared/machine-id-setup.c b/src/shared/machine-id-setup.c +index e483675a75..df4ac419cb 100644 +--- a/src/shared/machine-id-setup.c ++++ b/src/shared/machine-id-setup.c +@@ -197,7 +197,7 @@ finish: + + int machine_id_commit(const char *root) { + _cleanup_close_ int fd = -1, initial_mntns_fd = -1; +- const char *etc_machine_id, *sync_path; ++ const char *etc_machine_id; + sd_id128_t id; + int r; + +diff --git a/src/shared/mount-setup.c b/src/shared/mount-setup.c +index 7917968497..7eadff3ace 100644 +--- a/src/shared/mount-setup.c ++++ b/src/shared/mount-setup.c +@@ -126,9 +126,6 @@ bool mount_point_is_api(const char *path) { + } + + bool mount_point_ignore(const char *path) { +- +- const char *i; +- + /* These are API file systems that might be mounted by other software, we just list them here so that + * we know that we should ignore them. */ + FOREACH_STRING(i, +@@ -518,7 +515,6 @@ int mount_setup(bool loaded_policy, bool leave_propagation) { + * use the same label for all their files. */ + if (loaded_policy) { + usec_t before_relabel, after_relabel; +- const char *i; + int n_extra; + + before_relabel = now(CLOCK_MONOTONIC); +diff --git a/src/shared/netif-util.c b/src/shared/netif-util.c +index 603d4de109..7605427052 100644 +--- a/src/shared/netif-util.c ++++ b/src/shared/netif-util.c +@@ -39,14 +39,15 @@ int net_get_type_string(sd_device *device, uint16_t iftype, char **ret) { + } + + const char *net_get_persistent_name(sd_device *device) { +- const char *name, *field; +- + assert(device); + + /* fetch some persistent data unique (on this machine) to this device */ +- FOREACH_STRING(field, "ID_NET_NAME_ONBOARD", "ID_NET_NAME_SLOT", "ID_NET_NAME_PATH", "ID_NET_NAME_MAC") ++ FOREACH_STRING(field, "ID_NET_NAME_ONBOARD", "ID_NET_NAME_SLOT", "ID_NET_NAME_PATH", "ID_NET_NAME_MAC") { ++ const char *name; ++ + if (sd_device_get_property_value(device, field, &name) >= 0) + return name; ++ } + + return NULL; + } +diff --git a/src/shared/pager.c b/src/shared/pager.c +index 9426d3ef98..1a93deb628 100644 +--- a/src/shared/pager.c ++++ b/src/shared/pager.c +@@ -144,7 +144,7 @@ void pager_open(PagerFlags flags) { + if (r < 0) + return; + if (r == 0) { +- const char *less_charset, *exe; ++ const char *less_charset; + + /* In the child start the pager */ + +diff --git a/src/shared/psi-util.c b/src/shared/psi-util.c +index 009095e8c3..8bdd0d4a85 100644 +--- a/src/shared/psi-util.c ++++ b/src/shared/psi-util.c +@@ -106,8 +106,6 @@ int read_resource_pressure(const char *path, PressureType type, ResourcePressure + } + + int is_pressure_supported(void) { +- const char *p; +- + /* The pressure files, both under /proc and in cgroups, will exist + * even if the kernel has PSI support disabled; we have to read + * the file to make sure it doesn't return -EOPNOTSUPP */ +diff --git a/src/shared/switch-root.c b/src/shared/switch-root.c +index 99cd574197..1a444841fa 100644 +--- a/src/shared/switch-root.c ++++ b/src/shared/switch-root.c +@@ -33,7 +33,6 @@ int switch_root(const char *new_root, + _cleanup_free_ char *resolved_old_root_after = NULL; + _cleanup_close_ int old_root_fd = -1; + bool old_root_remove; +- const char *i; + int r; + + assert(new_root); +@@ -64,12 +63,12 @@ int switch_root(const char *new_root, + if (mount(NULL, "/", NULL, MS_REC|MS_PRIVATE, NULL) < 0) + return log_error_errno(errno, "Failed to set \"/\" mount propagation to private: %m"); + +- FOREACH_STRING(i, "/sys", "/dev", "/run", "/proc") { ++ FOREACH_STRING(path, "/sys", "/dev", "/run", "/proc") { + _cleanup_free_ char *chased = NULL; + +- r = chase_symlinks(i, new_root, CHASE_PREFIX_ROOT|CHASE_NONEXISTENT, &chased, NULL); ++ r = chase_symlinks(path, new_root, CHASE_PREFIX_ROOT|CHASE_NONEXISTENT, &chased, NULL); + if (r < 0) +- return log_error_errno(r, "Failed to resolve %s/%s: %m", new_root, i); ++ return log_error_errno(r, "Failed to resolve %s/%s: %m", new_root, path); + if (r > 0) { + /* Already exists. Let's see if it is a mount point already. */ + r = path_is_mount_point(chased, NULL, 0); +@@ -81,8 +80,8 @@ int switch_root(const char *new_root, + /* Doesn't exist yet? */ + (void) mkdir_p_label(chased, 0755); + +- if (mount(i, chased, NULL, mount_flags, NULL) < 0) +- return log_error_errno(errno, "Failed to mount %s to %s: %m", i, chased); ++ if (mount(path, chased, NULL, mount_flags, NULL) < 0) ++ return log_error_errno(errno, "Failed to mount %s to %s: %m", path, chased); + } + + /* Do not fail if base_filesystem_create() fails. Not all switch roots are like base_filesystem_create() wants +diff --git a/src/shared/tests.c b/src/shared/tests.c +index b00006b41a..f5d9536411 100644 +--- a/src/shared/tests.c ++++ b/src/shared/tests.c +@@ -307,16 +307,15 @@ const char *ci_environment(void) { + * just the general CI environment type, but also whether we're sanitizing or not, etc. The caller is + * expected to use strstr on the returned value. */ + static const char *ans = POINTER_MAX; +- const char *p; + int r; + + if (ans != POINTER_MAX) + return ans; + + /* We allow specifying the environment with $CITYPE. Nobody uses this so far, but we are ready. */ +- p = getenv("CITYPE"); +- if (!isempty(p)) +- return (ans = p); ++ const char *citype = getenv("CITYPE"); ++ if (!isempty(citype)) ++ return (ans = citype); + + if (getenv_bool("TRAVIS") > 0) + return (ans = "travis"); +@@ -327,12 +326,12 @@ const char *ci_environment(void) { + if (getenv("AUTOPKGTEST_ARTIFACTS") || getenv("AUTOPKGTEST_TMP")) + return (ans = "autopkgtest"); + +- FOREACH_STRING(p, "CI", "CONTINOUS_INTEGRATION") { ++ FOREACH_STRING(var, "CI", "CONTINOUS_INTEGRATION") { + /* Those vars are booleans according to Semaphore and Travis docs: + * https://docs.travis-ci.com/user/environment-variables/#default-environment-variables + * https://docs.semaphoreci.com/ci-cd-environment/environment-variables/#ci + */ +- r = getenv_bool(p); ++ r = getenv_bool(var); + if (r > 0) + return (ans = "unknown"); /* Some other unknown thing */ + if (r == 0) +diff --git a/src/systemctl/systemctl-edit.c b/src/systemctl/systemctl-edit.c +index b59a67ac22..a97aa7be4c 100644 +--- a/src/systemctl/systemctl-edit.c ++++ b/src/systemctl/systemctl-edit.c +@@ -320,7 +320,7 @@ static int run_editor(char **paths) { + if (r == 0) { + char **editor_args = NULL, **tmp_path, **original_path; + size_t n_editor_args = 0, i = 1, argc; +- const char **args, *editor, *p; ++ const char **args, *editor; + + argc = strv_length(paths)/2 + 1; + +@@ -358,9 +358,9 @@ static int run_editor(char **paths) { + if (n_editor_args > 0) + execvp(args[0], (char* const*) args); + +- FOREACH_STRING(p, "editor", "nano", "vim", "vi") { +- args[0] = p; +- execvp(p, (char* const*) args); ++ FOREACH_STRING(name, "editor", "nano", "vim", "vi") { ++ args[0] = name; ++ execvp(name, (char* const*) args); + /* We do not fail if the editor doesn't exist because we want to try each one of them + * before failing. */ + if (errno != ENOENT) { +diff --git a/src/systemctl/systemctl-sysv-compat.c b/src/systemctl/systemctl-sysv-compat.c +index a78fa1e04c..017dba2034 100644 +--- a/src/systemctl/systemctl-sysv-compat.c ++++ b/src/systemctl/systemctl-sysv-compat.c +@@ -18,9 +18,8 @@ + + int talk_initctl(char rl) { + #if HAVE_SYSV_COMPAT +- struct init_request request; + _cleanup_close_ int fd = -1; +- const char *p; ++ const char *path; + int r; + + /* Try to switch to the specified SysV runlevel. Returns == 0 if the operation does not apply on this +@@ -29,19 +28,19 @@ int talk_initctl(char rl) { + if (rl == 0) + return 0; + +- FOREACH_STRING(p, "/run/initctl", "/dev/initctl") { +- fd = open(p, O_WRONLY|O_NONBLOCK|O_CLOEXEC|O_NOCTTY); +- if (fd >= 0 || errno != ENOENT) +- break; +- } +- if (fd < 0) { +- if (errno == ENOENT) +- return 0; ++ FOREACH_STRING(_path, "/run/initctl", "/dev/initctl") { ++ path = _path; + +- return log_error_errno(errno, "Failed to open initctl fifo: %m"); ++ fd = open(path, O_WRONLY|O_NONBLOCK|O_CLOEXEC|O_NOCTTY); ++ if (fd < 0 && errno != ENOENT) ++ return log_error_errno(errno, "Failed to open %s: %m", path); ++ if (fd >= 0) ++ break; + } ++ if (fd < 0) ++ return 0; + +- request = (struct init_request) { ++ struct init_request request = { + .magic = INIT_MAGIC, + .sleeptime = 0, + .cmd = INIT_CMD_RUNLVL, +@@ -50,7 +49,7 @@ int talk_initctl(char rl) { + + r = loop_write(fd, &request, sizeof(request), false); + if (r < 0) +- return log_error_errno(r, "Failed to write to %s: %m", p); ++ return log_error_errno(r, "Failed to write to %s: %m", path); + + return 1; + #else +diff --git a/src/test/test-bpf-devices.c b/src/test/test-bpf-devices.c +index bbaa7b3605..587591cf04 100644 +--- a/src/test/test-bpf-devices.c ++++ b/src/test/test-bpf-devices.c +@@ -30,7 +30,6 @@ static void test_policy_closed(const char *cgroup_path, BPFProgram **installed_p + r = bpf_devices_apply_policy(&prog, CGROUP_DEVICE_POLICY_CLOSED, true, cgroup_path, installed_prog); + assert_se(r >= 0); + +- const char *s; + FOREACH_STRING(s, "/dev/null", + "/dev/zero", + "/dev/full", +diff --git a/src/test/test-ellipsize.c b/src/test/test-ellipsize.c +index b840355f5e..7317193363 100644 +--- a/src/test/test-ellipsize.c ++++ b/src/test/test-ellipsize.c +@@ -64,18 +64,14 @@ static void test_ellipsize_mem_one(const char *s, size_t old_length, size_t new_ + } + + TEST(ellipsize_mem) { +- const char *s; +- ssize_t l, k; +- + FOREACH_STRING(s, + "_XXXXXXXXXXX_", /* ASCII */ + "_aąęółśćńżźć_", /* two-byte utf-8 */ + "გამარჯობა", /* multi-byte utf-8 */ + "你好世界", /* wide characters */ + "你გą世óoó界") /* a mix */ +- +- for (l = strlen(s); l >= 0; l--) +- for (k = strlen(s) + 1; k >= 0; k--) ++ for (ssize_t l = strlen(s); l >= 0; l--) ++ for (ssize_t k = strlen(s) + 1; k >= 0; k--) + test_ellipsize_mem_one(s, l, k); + } + +diff --git a/src/test/test-env-file.c b/src/test/test-env-file.c +index 7b132447bf..f97206b4d6 100644 +--- a/src/test/test-env-file.c ++++ b/src/test/test-env-file.c +@@ -166,8 +166,6 @@ TEST(load_env_file_6) { + } + + TEST(write_and_load_env_file) { +- const char *v; +- + /* Make sure that our writer, parser and the shell agree on what our env var files mean */ + + FOREACH_STRING(v, +diff --git a/src/test/test-execute.c b/src/test/test-execute.c +index 49629c6bc2..0760df6603 100644 +--- a/src/test/test-execute.c ++++ b/src/test/test-execute.c +@@ -190,19 +190,15 @@ static bool check_user_has_group_with_same_name(const char *name) { + } + + static bool is_inaccessible_available(void) { +- const char *p; +- + FOREACH_STRING(p, +- "/run/systemd/inaccessible/reg", +- "/run/systemd/inaccessible/dir", +- "/run/systemd/inaccessible/chr", +- "/run/systemd/inaccessible/blk", +- "/run/systemd/inaccessible/fifo", +- "/run/systemd/inaccessible/sock" +- ) { ++ "/run/systemd/inaccessible/reg", ++ "/run/systemd/inaccessible/dir", ++ "/run/systemd/inaccessible/chr", ++ "/run/systemd/inaccessible/blk", ++ "/run/systemd/inaccessible/fifo", ++ "/run/systemd/inaccessible/sock") + if (access(p, F_OK) < 0) + return false; +- } + + return true; + } +diff --git a/src/test/test-fileio.c b/src/test/test-fileio.c +index 087d76f760..4f91d94709 100644 +--- a/src/test/test-fileio.c ++++ b/src/test/test-fileio.c +@@ -1003,7 +1003,6 @@ TEST(read_full_file_offset_size) { + } + + static void test_read_virtual_file_one(size_t max_size) { +- const char *filename; + int r; + + log_info("/* %s (max_size=%zu) */", __func__, max_size); +diff --git a/src/test/test-gpt.c b/src/test/test-gpt.c +index ab26d5d096..05da7a9e48 100644 +--- a/src/test/test-gpt.c ++++ b/src/test/test-gpt.c +@@ -11,16 +11,13 @@ + #include "util.h" + + TEST(gpt_types_against_architectures) { +- const char *prefix; + int r; + + /* Dumps a table indicating for which architectures we know we have matching GPT partition + * types. Also validates whether we can properly categorize the entries. */ + + FOREACH_STRING(prefix, "root-", "usr-") +- for (int a = 0; a < _ARCHITECTURE_MAX; a++) { +- const char *suffix; +- ++ for (int a = 0; a < _ARCHITECTURE_MAX; a++) + FOREACH_STRING(suffix, "", "-verity", "-verity-sig") { + _cleanup_free_ char *joined = NULL; + sd_id128_t id; +@@ -48,7 +45,6 @@ TEST(gpt_types_against_architectures) { + + assert_se(gpt_partition_type_uuid_to_arch(id) == a); + } +- } + } + + DEFINE_TEST_MAIN(LOG_INFO); +diff --git a/src/test/test-libcrypt-util.c b/src/test/test-libcrypt-util.c +index ebd520f7ba..f88a9f9b24 100644 +--- a/src/test/test-libcrypt-util.c ++++ b/src/test/test-libcrypt-util.c +@@ -39,7 +39,6 @@ static int test_hash_password(void) { + /* As a warm-up exercise, check if we can hash passwords. */ + + bool have_sane_hash = false; +- const char *hash; + + FOREACH_STRING(hash, + "ew3bU1.hoKk4o", +@@ -68,7 +67,6 @@ static void test_hash_password_full(void) { + log_info("/* %s */", __func__); + + _cleanup_free_ void *cd_data = NULL; +- const char *i; + int cd_size = 0; + + log_info("sizeof(struct crypt_data): %zu bytes", sizeof(struct crypt_data)); +diff --git a/src/test/test-loop-block.c b/src/test/test-loop-block.c +index 1642f82e40..9c8c55bca2 100644 +--- a/src/test/test-loop-block.c ++++ b/src/test/test-loop-block.c +@@ -114,7 +114,6 @@ int main(int argc, char *argv[]) { + _cleanup_(dissected_image_unrefp) DissectedImage *dissected = NULL; + _cleanup_(umount_and_rmdir_and_freep) char *mounted = NULL; + pthread_t threads[N_THREADS]; +- const char *fs; + sd_id128_t id; + int r; + +diff --git a/src/test/test-mount-util.c b/src/test/test-mount-util.c +index 74d352268e..7e06fc419c 100644 +--- a/src/test/test-mount-util.c ++++ b/src/test/test-mount-util.c +@@ -128,7 +128,6 @@ TEST(mount_flags_to_string) { + TEST(bind_remount_recursive) { + _cleanup_(rm_rf_physical_and_freep) char *tmp = NULL; + _cleanup_free_ char *subdir = NULL; +- const char *p; + + if (geteuid() != 0 || have_effective_cap(CAP_SYS_ADMIN) <= 0) { + (void) log_tests_skipped("not running privileged"); +diff --git a/src/test/test-stat-util.c b/src/test/test-stat-util.c +index 7f633ab259..5f744b0288 100644 +--- a/src/test/test-stat-util.c ++++ b/src/test/test-stat-util.c +@@ -67,7 +67,6 @@ TEST(path_is_fs_type) { + } + + TEST(path_is_temporary_fs) { +- const char *s; + int r; + + FOREACH_STRING(s, "/", "/run", "/sys", "/sys/", "/proc", "/i-dont-exist", "/var", "/var/lib") { +@@ -85,7 +84,6 @@ TEST(path_is_temporary_fs) { + } + + TEST(path_is_read_only_fs) { +- const char *s; + int r; + + FOREACH_STRING(s, "/", "/run", "/sys", "/sys/", "/proc", "/i-dont-exist", "/var", "/var/lib") { +diff --git a/src/test/test-strv.c b/src/test/test-strv.c +index 94581fc832..0ece342521 100644 +--- a/src/test/test-strv.c ++++ b/src/test/test-strv.c +@@ -924,12 +924,10 @@ TEST(foreach_string) { + "waldo", + NULL + }; +- const char *x; +- unsigned i = 0; + ++ unsigned i = 0; + FOREACH_STRING(x, "foo", "bar", "waldo") + assert_se(streq_ptr(t[i++], x)); +- + assert_se(i == 3); + + FOREACH_STRING(x, "zzz") +diff --git a/src/test/test-utf8.c b/src/test/test-utf8.c +index 7337b81227..f070c171fe 100644 +--- a/src/test/test-utf8.c ++++ b/src/test/test-utf8.c +@@ -144,7 +144,6 @@ TEST(utf8_escape_non_printable) { + } + + TEST(utf8_escape_non_printable_full) { +- const char *s; + FOREACH_STRING(s, + "goo goo goo", /* ASCII */ + "\001 \019\20\a", /* control characters */ +@@ -210,8 +209,6 @@ TEST(utf8_console_width) { + } + + TEST(utf8_to_utf16) { +- const char *p; +- + FOREACH_STRING(p, + "abc", + "zażółcić gęślą jaźń", +diff --git a/src/tmpfiles/offline-passwd.c b/src/tmpfiles/offline-passwd.c +index 8ba3fea984..c847266ed4 100644 +--- a/src/tmpfiles/offline-passwd.c ++++ b/src/tmpfiles/offline-passwd.c +@@ -39,7 +39,6 @@ static int populate_uid_cache(const char *root, Hashmap **ret) { + /* The directory list is hardcoded here: /etc is the standard, and rpm-ostree uses /usr/lib. This + * could be made configurable, but I don't see the point right now. */ + +- const char *fname; + FOREACH_STRING(fname, "/etc/passwd", "/usr/lib/passwd") { + _cleanup_fclose_ FILE *f = NULL; + +@@ -78,7 +77,6 @@ static int populate_gid_cache(const char *root, Hashmap **ret) { + if (!cache) + return -ENOMEM; + +- const char *fname; + FOREACH_STRING(fname, "/etc/group", "/usr/lib/group") { + _cleanup_fclose_ FILE *f = NULL; + diff --git a/0158-basic-unit-file-split-out-the-subroutine-for-symlink.patch b/0158-basic-unit-file-split-out-the-subroutine-for-symlink.patch new file mode 100644 index 0000000..43c2405 --- /dev/null +++ b/0158-basic-unit-file-split-out-the-subroutine-for-symlink.patch @@ -0,0 +1,213 @@ +From d49d646d00078b201cdde2978b7941d20acb1d4b Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Wed, 2 Mar 2022 16:53:54 +0100 +Subject: [PATCH] basic/unit-file: split out the subroutine for symlink + verification + +The old logs used __func__, but this doesn't make sense now, because the +low-level function will be used in other places. So those are adjusted to be +more generic. + +(cherry picked from commit 9825181143530af7003fc50567b814dbbee39046) + +Related: #2082131 +--- + src/basic/unit-file.c | 159 +++++++++++++++++++++++++----------------- + 1 file changed, 96 insertions(+), 63 deletions(-) + +diff --git a/src/basic/unit-file.c b/src/basic/unit-file.c +index 96826e2940..25abce932a 100644 +--- a/src/basic/unit-file.c ++++ b/src/basic/unit-file.c +@@ -260,6 +260,83 @@ static int directory_name_is_valid(const char *name) { + return false; + } + ++static int unit_file_resolve_symlink( ++ const char *root_dir, ++ char **search_path, ++ const char *dir, ++ int dirfd, ++ const char *filename, ++ char **ret_destination) { ++ ++ _cleanup_free_ char *target = NULL, *simplified = NULL, *dst = NULL; ++ int r; ++ ++ assert(dir); ++ assert(dirfd >= 0); ++ assert(filename); ++ assert(ret_destination); ++ ++ r = readlinkat_malloc(dirfd, filename, &target); ++ if (r < 0) ++ return log_warning_errno(r, "Failed to read symlink %s%s%s: %m", ++ dir, dir ? "/" : "", filename); ++ ++ bool is_abs = path_is_absolute(target); ++ if (root_dir || !is_abs) { ++ char *target_abs = path_join(is_abs ? root_dir : dir, target); ++ if (!target_abs) ++ return log_oom(); ++ ++ free_and_replace(target, target_abs); ++ } ++ ++ /* Get rid of "." and ".." components in target path */ ++ r = chase_symlinks(target, root_dir, CHASE_NOFOLLOW | CHASE_NONEXISTENT, &simplified, NULL); ++ if (r < 0) ++ return log_warning_errno(r, "Failed to resolve symlink %s/%s pointing to %s: %m", ++ dir, filename, target); ++ ++ /* Check if the symlink goes outside of our search path. ++ * If yes, it's a linked unit file or mask, and we don't care about the target name. ++ * Let's just store the link source directly. ++ * If not, let's verify that it's a good symlink. */ ++ const char *tail = path_startswith_strv(simplified, search_path); ++ if (!tail) { ++ log_debug("Linked unit file: %s/%s → %s", dir, filename, simplified); ++ ++ dst = path_join(dir, filename); ++ if (!dst) ++ return log_oom(); ++ ++ } else { ++ r = path_extract_filename(simplified, &dst); ++ if (r < 0) ++ return r; ++ ++ bool self_alias = streq(dst, filename); ++ ++ if (is_path(tail)) ++ log_full(self_alias ? LOG_DEBUG : LOG_WARNING, ++ "Suspicious symlink %s/%s→%s, treating as alias.", ++ dir, filename, simplified); ++ ++ r = unit_validate_alias_symlink_and_warn(filename, simplified); ++ if (r < 0) ++ return r; ++ ++ if (self_alias) ++ /* A self-alias that has no effect */ ++ return log_debug_errno(SYNTHETIC_ERRNO(ELOOP), ++ "Unit file self-alias: %s/%s → %s, ignoring.", ++ dir, filename, dst); ++ ++ log_debug("Unit file alias: %s/%s → %s", dir, filename, dst); ++ } ++ ++ *ret_destination = TAKE_PTR(dst); ++ return 0; ++} ++ + int unit_file_build_name_map( + const LookupPaths *lp, + uint64_t *cache_timestamp_hash, +@@ -310,10 +387,9 @@ int unit_file_build_name_map( + + FOREACH_DIRENT_ALL(de, d, log_warning_errno(errno, "Failed to read \"%s\", ignoring: %m", *dir)) { + _unused_ _cleanup_free_ char *_filename_free = NULL; +- _cleanup_free_ char *simplified = NULL; +- bool symlink_to_dir = false; +- const char *dst = NULL; + char *filename; ++ _cleanup_free_ char *dst = NULL; ++ bool symlink_to_dir = false; + + /* We only care about valid units and dirs with certain suffixes, let's ignore the + * rest. */ +@@ -397,77 +473,34 @@ int unit_file_build_name_map( + /* We don't explicitly check for alias loops here. unit_ids_map_get() which + * limits the number of hops should be used to access the map. */ + +- _cleanup_free_ char *target = NULL; +- +- r = readlinkat_malloc(dirfd(d), de->d_name, &target); +- if (r < 0) { +- log_warning_errno(r, "Failed to read symlink %s/%s, ignoring: %m", +- *dir, de->d_name); ++ r = unit_file_resolve_symlink(lp->root_dir, lp->search_path, ++ *dir, dirfd(d), de->d_name, ++ &dst); ++ if (r == -ENOMEM) ++ return r; ++ if (r < 0) /* we ignore other errors here */ + continue; +- } + +- const bool is_abs = path_is_absolute(target); +- if (lp->root_dir || !is_abs) { +- char *target_abs = path_join(is_abs ? lp->root_dir : *dir, target); +- if (!target_abs) ++ } else { ++ dst = TAKE_PTR(_filename_free); /* Grab the copy we made previously, if available. */ ++ if (!dst) { ++ dst = strdup(filename); ++ if (!dst) + return log_oom(); +- +- free_and_replace(target, target_abs); + } + +- /* Get rid of "." and ".." components in target path */ +- r = chase_symlinks(target, lp->root_dir, CHASE_NOFOLLOW | CHASE_NONEXISTENT, &simplified, NULL); +- if (r < 0) { +- log_warning_errno(r, "Failed to resolve symlink %s pointing to %s, ignoring: %m", +- filename, target); +- continue; +- } +- +- /* Check if the symlink goes outside of our search path. +- * If yes, it's a linked unit file or mask, and we don't care about the target name. +- * Let's just store the link source directly. +- * If not, let's verify that it's a good symlink. */ +- char *tail = path_startswith_strv(simplified, lp->search_path); +- if (!tail) { +- log_debug("%s: linked unit file: %s → %s", +- __func__, filename, simplified); +- +- dst = filename; +- } else { +- +- bool self_alias; +- +- dst = basename(simplified); +- self_alias = streq(dst, de->d_name); +- +- if (is_path(tail)) +- log_full(self_alias ? LOG_DEBUG : LOG_WARNING, +- "Suspicious symlink %s→%s, treating as alias.", +- filename, simplified); +- +- r = unit_validate_alias_symlink_and_warn(filename, simplified); +- if (r < 0) +- continue; +- +- if (self_alias) { +- /* A self-alias that has no effect */ +- log_debug("%s: self-alias: %s/%s → %s, ignoring.", +- __func__, *dir, de->d_name, dst); +- continue; +- } +- +- log_debug("%s: alias: %s/%s → %s", __func__, *dir, de->d_name, dst); +- } +- +- } else { +- dst = filename; + log_debug("%s: normal unit file: %s", __func__, dst); + } + +- r = hashmap_put_strdup(&ids, de->d_name, dst); ++ _cleanup_free_ char *key = strdup(de->d_name); ++ if (!key) ++ return log_oom(); ++ ++ r = hashmap_ensure_put(&ids, &string_hash_ops_free_free, key, dst); + if (r < 0) + return log_warning_errno(r, "Failed to add entry to hashmap (%s→%s): %m", + de->d_name, dst); ++ key = dst = NULL; + } + } + diff --git a/0159-basic-stat-util-add-null_or_empty_path_with_root.patch b/0159-basic-stat-util-add-null_or_empty_path_with_root.patch new file mode 100644 index 0000000..64f0c2e --- /dev/null +++ b/0159-basic-stat-util-add-null_or_empty_path_with_root.patch @@ -0,0 +1,100 @@ +From fae45af368a90cdce95680d82b66d8e460ab939f Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Wed, 23 Mar 2022 17:47:33 +0100 +Subject: [PATCH] basic/stat-util: add null_or_empty_path_with_root() + +(cherry picked from commit 48542eac39999f58f6c331b4b3cdf2d78bf15979) + +Related: #2082131 +--- + src/basic/stat-util.c | 15 ++++++++++----- + src/basic/stat-util.h | 6 +++++- + src/test/test-stat-util.c | 24 ++++++++++++++++++++++++ + 3 files changed, 39 insertions(+), 6 deletions(-) + +diff --git a/src/basic/stat-util.c b/src/basic/stat-util.c +index efac7b002e..21e71794b4 100644 +--- a/src/basic/stat-util.c ++++ b/src/basic/stat-util.c +@@ -127,17 +127,22 @@ bool null_or_empty(struct stat *st) { + return false; + } + +-int null_or_empty_path(const char *fn) { ++int null_or_empty_path_with_root(const char *fn, const char *root) { + struct stat st; ++ int r; + + assert(fn); + +- /* If we have the path, let's do an easy text comparison first. */ +- if (path_equal(fn, "/dev/null")) ++ /* A symlink to /dev/null or an empty file? ++ * When looking under root_dir, we can't expect /dev/ to be mounted, ++ * so let's see if the path is a (possibly dangling) symlink to /dev/null. */ ++ ++ if (path_equal_ptr(path_startswith(fn, root ?: "/"), "dev/null")) + return true; + +- if (stat(fn, &st) < 0) +- return -errno; ++ r = chase_symlinks_and_stat(fn, root, CHASE_PREFIX_ROOT, NULL, &st, NULL); ++ if (r < 0) ++ return r; + + return null_or_empty(&st); + } +diff --git a/src/basic/stat-util.h b/src/basic/stat-util.h +index a566114f7c..2c5edeb891 100644 +--- a/src/basic/stat-util.h ++++ b/src/basic/stat-util.h +@@ -31,9 +31,13 @@ static inline int dir_is_populated(const char *path) { + } + + bool null_or_empty(struct stat *st) _pure_; +-int null_or_empty_path(const char *fn); ++int null_or_empty_path_with_root(const char *fn, const char *root); + int null_or_empty_fd(int fd); + ++static inline int null_or_empty_path(const char *fn) { ++ return null_or_empty_path_with_root(fn, NULL); ++} ++ + int path_is_read_only_fs(const char *path); + + int files_same(const char *filea, const char *fileb, int flags); +diff --git a/src/test/test-stat-util.c b/src/test/test-stat-util.c +index 5f744b0288..9975a1848d 100644 +--- a/src/test/test-stat-util.c ++++ b/src/test/test-stat-util.c +@@ -18,6 +18,30 @@ + #include "tests.h" + #include "tmpfile-util.h" + ++TEST(null_or_empty_path) { ++ assert_se(null_or_empty_path("/dev/null") == 1); ++ assert_se(null_or_empty_path("/dev/tty") == 1); /* We assume that any character device is "empty", bleh. */ ++ assert_se(null_or_empty_path("../../../../../../../../../../../../../../../../../../../../dev/null") == 1); ++ assert_se(null_or_empty_path("/proc/self/exe") == 0); ++ assert_se(null_or_empty_path("/nosuchfileordir") == -ENOENT); ++} ++ ++TEST(null_or_empty_path_with_root) { ++ assert_se(null_or_empty_path_with_root("/dev/null", NULL) == 1); ++ assert_se(null_or_empty_path_with_root("/dev/null", "/") == 1); ++ assert_se(null_or_empty_path_with_root("/dev/null", "/.././../") == 1); ++ assert_se(null_or_empty_path_with_root("/dev/null", "/.././..") == 1); ++ assert_se(null_or_empty_path_with_root("../../../../../../../../../../../../../../../../../../../../dev/null", NULL) == 1); ++ assert_se(null_or_empty_path_with_root("../../../../../../../../../../../../../../../../../../../../dev/null", "/") == 1); ++ assert_se(null_or_empty_path_with_root("/proc/self/exe", NULL) == 0); ++ assert_se(null_or_empty_path_with_root("/proc/self/exe", "/") == 0); ++ assert_se(null_or_empty_path_with_root("/nosuchfileordir", NULL) == -ENOENT); ++ assert_se(null_or_empty_path_with_root("/nosuchfileordir", "/.././../") == -ENOENT); ++ assert_se(null_or_empty_path_with_root("/nosuchfileordir", "/.././..") == -ENOENT); ++ assert_se(null_or_empty_path_with_root("/foobar/barbar/dev/null", "/foobar/barbar") == 1); ++ assert_se(null_or_empty_path_with_root("/foobar/barbar/dev/null", "/foobar/barbar/") == 1); ++} ++ + TEST(files_same) { + _cleanup_close_ int fd = -1; + char name[] = "/tmp/test-files_same.XXXXXX"; diff --git a/0160-shared-install-reuse-the-standard-symlink-verificati.patch b/0160-shared-install-reuse-the-standard-symlink-verificati.patch new file mode 100644 index 0000000..3ba922e --- /dev/null +++ b/0160-shared-install-reuse-the-standard-symlink-verificati.patch @@ -0,0 +1,298 @@ +From 5ec751ab9a06dadc62b30dc07e9dd7a41f8da403 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Fri, 4 Mar 2022 18:47:31 +0100 +Subject: [PATCH] shared/install: reuse the standard symlink verification + subroutine +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +We save a few lines, but the important thing is that we don't have two +different implementations with slightly different rules used for enablement +and loading. Fixes #22000. + +Tested with: +- the report in #22000, it now says: +$ SYSTEMD_LOG_LEVEL=debug systemctl --root=/ enable test.service +Suspicious symlink /etc/systemd/system/test.service→/etc/systemd/system/myown.d/test.service, treating as alias. +unit_file_resolve_symlink: self-alias: /etc/systemd/system/test.service → test.service, ignoring. +running_in_chroot(): Permission denied +Suspicious symlink /etc/systemd/system/test.service→/etc/systemd/system/myown.d/test.service, treating as alias. +unit_file_resolve_symlink: self-alias: /etc/systemd/system/test.service → test.service, ignoring. +Failed to enable unit, refusing to operate on linked unit file test.service + +- a symlink to /dev/null: +... +unit_file_resolve_symlink: linked unit file: /etc/systemd/system/test3.service → /dev/null +Failed to enable unit, unit /etc/systemd/system/test3.service is masked. + +- the same from the host: +... +unit_file_resolve_symlink: linked unit file: /var/lib/machines/rawhide/etc/systemd/system/test3.service → /var/lib/machines/rawhide/dev/null +Failed to enable unit, unit /var/lib/machines/rawhide/etc/systemd/system/test3.service is masked. + +- through the manager: +$ sudo systemctl enable test.service +Failed to enable unit: Refusing to operate on alias name or linked unit file: test.service +$ sudo systemctl enable test3.service +Failed to enable unit: Unit file /etc/systemd/system/test3.service is masked. + +As seen in the first example, the warning is repeated. This is because we call +the lookup logic twice: first for sysv-compat, and then again for real. I think +that since this is only for broken setups, and when sysv-compat is enabled, and +in an infrequent manual operation, at debug level, this is OK. + +(cherry picked from commit 047d37dc3d376d912275c14d217f7a0dda9a5f0e) + +Related: #2082131 +--- + src/basic/unit-file.c | 70 +++++++++++++++++++++++++++++++---------- + src/basic/unit-file.h | 10 ++++++ + src/shared/install.c | 72 +++++++------------------------------------ + 3 files changed, 75 insertions(+), 77 deletions(-) + +diff --git a/src/basic/unit-file.c b/src/basic/unit-file.c +index 25abce932a..f7a10b22c6 100644 +--- a/src/basic/unit-file.c ++++ b/src/basic/unit-file.c +@@ -260,27 +260,50 @@ static int directory_name_is_valid(const char *name) { + return false; + } + +-static int unit_file_resolve_symlink( ++int unit_file_resolve_symlink( + const char *root_dir, + char **search_path, + const char *dir, + int dirfd, + const char *filename, ++ bool resolve_destination_target, + char **ret_destination) { + +- _cleanup_free_ char *target = NULL, *simplified = NULL, *dst = NULL; ++ _cleanup_free_ char *target = NULL, *simplified = NULL, *dst = NULL, *_dir = NULL, *_filename = NULL; + int r; + +- assert(dir); +- assert(dirfd >= 0); ++ /* This can be called with either dir+dirfd valid and filename just a name, ++ * or !dir && dirfd==AT_FDCWD, and filename being a full path. ++ * ++ * If resolve_destination_target is true, an absolute path will be returned. ++ * If not, an absolute path is returned for linked unit files, and a relative ++ * path otherwise. */ ++ + assert(filename); + assert(ret_destination); ++ assert(dir || path_is_absolute(filename)); ++ assert(dirfd >= 0 || dirfd == AT_FDCWD); + + r = readlinkat_malloc(dirfd, filename, &target); + if (r < 0) + return log_warning_errno(r, "Failed to read symlink %s%s%s: %m", + dir, dir ? "/" : "", filename); + ++ if (!dir) { ++ r = path_extract_directory(filename, &_dir); ++ if (r < 0) ++ return r; ++ dir = _dir; ++ ++ r = path_extract_filename(filename, &_filename); ++ if (r < 0) ++ return r; ++ if (r == O_DIRECTORY) ++ return log_warning_errno(SYNTHETIC_ERRNO(EISDIR), ++ "Unexpected path to a directory \"%s\", refusing.", filename); ++ filename = _filename; ++ } ++ + bool is_abs = path_is_absolute(target); + if (root_dir || !is_abs) { + char *target_abs = path_join(is_abs ? root_dir : dir, target); +@@ -296,24 +319,36 @@ static int unit_file_resolve_symlink( + return log_warning_errno(r, "Failed to resolve symlink %s/%s pointing to %s: %m", + dir, filename, target); + ++ assert(path_is_absolute(simplified)); ++ + /* Check if the symlink goes outside of our search path. +- * If yes, it's a linked unit file or mask, and we don't care about the target name. +- * Let's just store the link source directly. +- * If not, let's verify that it's a good symlink. */ ++ * If yes, it's a linked unit file or mask, and we don't care about the target name ++ * when loading units, and we return the link *source* (resolve_destination_target == false); ++ * When this is called for installation purposes, we want the final destination, ++ * so we return the *target*. ++ * ++ * Otherwise, let's verify that it's a good alias. ++ */ + const char *tail = path_startswith_strv(simplified, search_path); + if (!tail) { + log_debug("Linked unit file: %s/%s → %s", dir, filename, simplified); + +- dst = path_join(dir, filename); +- if (!dst) +- return log_oom(); ++ if (resolve_destination_target) ++ dst = TAKE_PTR(simplified); ++ else { ++ dst = path_join(dir, filename); ++ if (!dst) ++ return log_oom(); ++ } + + } else { +- r = path_extract_filename(simplified, &dst); ++ _cleanup_free_ char *target_name = NULL; ++ ++ r = path_extract_filename(simplified, &target_name); + if (r < 0) + return r; + +- bool self_alias = streq(dst, filename); ++ bool self_alias = streq(target_name, filename); + + if (is_path(tail)) + log_full(self_alias ? LOG_DEBUG : LOG_WARNING, +@@ -324,13 +359,15 @@ static int unit_file_resolve_symlink( + if (r < 0) + return r; + +- if (self_alias) +- /* A self-alias that has no effect */ ++ if (self_alias && !resolve_destination_target) ++ /* A self-alias that has no effect when loading, let's just ignore it. */ + return log_debug_errno(SYNTHETIC_ERRNO(ELOOP), + "Unit file self-alias: %s/%s → %s, ignoring.", +- dir, filename, dst); ++ dir, filename, target_name); ++ ++ log_debug("Unit file alias: %s/%s → %s", dir, filename, target_name); + +- log_debug("Unit file alias: %s/%s → %s", dir, filename, dst); ++ dst = resolve_destination_target ? TAKE_PTR(simplified) : TAKE_PTR(target_name); + } + + *ret_destination = TAKE_PTR(dst); +@@ -475,6 +512,7 @@ int unit_file_build_name_map( + + r = unit_file_resolve_symlink(lp->root_dir, lp->search_path, + *dir, dirfd(d), de->d_name, ++ /* resolve_destination_target= */ false, + &dst); + if (r == -ENOMEM) + return r; +diff --git a/src/basic/unit-file.h b/src/basic/unit-file.h +index cc731a9e06..e29e878cfd 100644 +--- a/src/basic/unit-file.h ++++ b/src/basic/unit-file.h +@@ -44,6 +44,16 @@ int unit_symlink_name_compatible(const char *symlink, const char *target, bool i + int unit_validate_alias_symlink_and_warn(const char *filename, const char *target); + + bool lookup_paths_timestamp_hash_same(const LookupPaths *lp, uint64_t timestamp_hash, uint64_t *ret_new); ++ ++int unit_file_resolve_symlink( ++ const char *root_dir, ++ char **search_path, ++ const char *dir, ++ int dirfd, ++ const char *filename, ++ bool resolve_destination_target, ++ char **ret_destination); ++ + int unit_file_build_name_map( + const LookupPaths *lp, + uint64_t *cache_timestamp_hash, +diff --git a/src/shared/install.c b/src/shared/install.c +index 79e5109ce1..e07ca31797 100644 +--- a/src/shared/install.c ++++ b/src/shared/install.c +@@ -1338,76 +1338,26 @@ static int unit_file_load_or_readlink( + const char *path, + const LookupPaths *lp, + SearchFlags flags) { +- +- _cleanup_free_ char *resolved = NULL; + int r; + + r = unit_file_load(c, info, path, lp->root_dir, flags); + if (r != -ELOOP || (flags & SEARCH_DROPIN)) + return r; + +- r = chase_symlinks(path, lp->root_dir, CHASE_WARN | CHASE_NONEXISTENT, &resolved, NULL); +- if (r >= 0 && +- lp->root_dir && +- path_equal_ptr(path_startswith(resolved, lp->root_dir), "dev/null")) +- /* When looking under root_dir, we can't expect /dev/ to be mounted, +- * so let's see if the path is a (possibly dangling) symlink to /dev/null. */ +- info->type = UNIT_FILE_TYPE_MASKED; +- +- else if (r > 0 && null_or_empty_path(resolved) > 0) ++ /* This is a symlink, let's read and verify it. */ ++ r = unit_file_resolve_symlink(lp->root_dir, lp->search_path, ++ NULL, AT_FDCWD, path, ++ true, &info->symlink_target); ++ if (r < 0) ++ return r; + ++ r = null_or_empty_path_with_root(info->symlink_target, lp->root_dir); ++ if (r < 0 && r != -ENOENT) ++ return log_debug_errno(r, "Failed to stat %s: %m", info->symlink_target); ++ if (r > 0) + info->type = UNIT_FILE_TYPE_MASKED; +- +- else { +- _cleanup_free_ char *target = NULL; +- const char *bn; +- UnitType a, b; +- +- /* This is a symlink, let's read it. We read the link again, because last time +- * we followed the link until resolution, and here we need to do one step. */ +- +- r = readlink_malloc(path, &target); +- if (r < 0) +- return r; +- +- bn = basename(target); +- +- if (unit_name_is_valid(info->name, UNIT_NAME_PLAIN)) { +- +- if (!unit_name_is_valid(bn, UNIT_NAME_PLAIN)) +- return -EINVAL; +- +- } else if (unit_name_is_valid(info->name, UNIT_NAME_INSTANCE)) { +- +- if (!unit_name_is_valid(bn, UNIT_NAME_INSTANCE|UNIT_NAME_TEMPLATE)) +- return -EINVAL; +- +- } else if (unit_name_is_valid(info->name, UNIT_NAME_TEMPLATE)) { +- +- if (!unit_name_is_valid(bn, UNIT_NAME_TEMPLATE)) +- return -EINVAL; +- } else +- return -EINVAL; +- +- /* Enforce that the symlink destination does not +- * change the unit file type. */ +- +- a = unit_name_to_type(info->name); +- b = unit_name_to_type(bn); +- if (a < 0 || b < 0 || a != b) +- return -EINVAL; +- +- if (path_is_absolute(target)) +- /* This is an absolute path, prefix the root so that we always deal with fully qualified paths */ +- info->symlink_target = path_join(lp->root_dir, target); +- else +- /* This is a relative path, take it relative to the dir the symlink is located in. */ +- info->symlink_target = file_in_same_dir(path, target); +- if (!info->symlink_target) +- return -ENOMEM; +- ++ else + info->type = UNIT_FILE_TYPE_SYMLINK; +- } + + return 0; + } diff --git a/0161-shared-install-add-a-bit-more-quoting.patch b/0161-shared-install-add-a-bit-more-quoting.patch new file mode 100644 index 0000000..290f6b1 --- /dev/null +++ b/0161-shared-install-add-a-bit-more-quoting.patch @@ -0,0 +1,118 @@ +From 348699605248eb30743c0aac4f2ecbff5dd986ad Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Thu, 3 Mar 2022 11:09:25 +0100 +Subject: [PATCH] shared/install: add a bit more quoting + +When we are printing a valid unit name, quoting isn't necessary, because +unit names cannot contain whitespace or other confusing characters. In particular +if the unit name is prefixed by " unit " or something else that clearly +identifies the string as a unit name, quoting would just add unnecessary +noise. But when we're printing paths or invalid names, it's better to add +quotes for clarity. + +(cherry picked from commit e75a26d0457d67a3146ff2d90af07db22213da3c) + +Related: #2082131 +--- + src/shared/install.c | 22 +++++++++++----------- + 1 file changed, 11 insertions(+), 11 deletions(-) + +diff --git a/src/shared/install.c b/src/shared/install.c +index e07ca31797..cbfe96b1e8 100644 +--- a/src/shared/install.c ++++ b/src/shared/install.c +@@ -338,7 +338,7 @@ void unit_file_dump_changes(int r, const char *verb, const UnitFileChange *chang + break; + case UNIT_FILE_UNLINK: + if (!quiet) +- log_info("Removed %s.", changes[i].path); ++ log_info("Removed \"%s\".", changes[i].path); + break; + case UNIT_FILE_IS_MASKED: + if (!quiet) +@@ -361,11 +361,11 @@ void unit_file_dump_changes(int r, const char *verb, const UnitFileChange *chang + case -EEXIST: + if (changes[i].source) + log_error_errno(changes[i].type_or_errno, +- "Failed to %s unit, file %s already exists and is a symlink to %s.", ++ "Failed to %s unit, file \"%s\" already exists and is a symlink to \"%s\".", + verb, changes[i].path, changes[i].source); + else + log_error_errno(changes[i].type_or_errno, +- "Failed to %s unit, file %s already exists.", ++ "Failed to %s unit, file \"%s\" already exists.", + verb, changes[i].path); + logged = true; + break; +@@ -391,7 +391,7 @@ void unit_file_dump_changes(int r, const char *verb, const UnitFileChange *chang + logged = true; + break; + case -ELOOP: +- log_error_errno(changes[i].type_or_errno, "Failed to %s unit, refusing to operate on linked unit file %s", ++ log_error_errno(changes[i].type_or_errno, "Failed to %s unit, refusing to operate on linked unit file %s.", + verb, changes[i].path); + logged = true; + break; +@@ -403,7 +403,7 @@ void unit_file_dump_changes(int r, const char *verb, const UnitFileChange *chang + + default: + assert(changes[i].type_or_errno < 0); +- log_error_errno(changes[i].type_or_errno, "Failed to %s unit, file %s: %m.", ++ log_error_errno(changes[i].type_or_errno, "Failed to %s unit, file \"%s\": %m", + verb, changes[i].path); + logged = true; + } +@@ -840,7 +840,7 @@ static int find_symlinks( + + d = opendir(path); + if (!d) { +- log_error_errno(errno, "Failed to open directory '%s' while scanning for symlinks, ignoring: %m", path); ++ log_error_errno(errno, "Failed to open directory \"%s\" while scanning for symlinks, ignoring: %m", path); + continue; + } + +@@ -848,7 +848,7 @@ static int find_symlinks( + if (r > 0) + return 1; + else if (r < 0) +- log_debug_errno(r, "Failed to lookup for symlinks in '%s': %m", path); ++ log_debug_errno(r, "Failed to look up symlinks in \"%s\": %m", path); + } + + /* We didn't find any suitable symlinks in .wants or .requires directories, let's look for linked unit files in this directory. */ +@@ -1321,7 +1321,7 @@ static int unit_file_load( + 0, info, + NULL); + if (r < 0) +- return log_debug_errno(r, "Failed to parse %s: %m", info->name); ++ return log_debug_errno(r, "Failed to parse \"%s\": %m", info->name); + + if ((flags & SEARCH_DROPIN) == 0) + info->type = UNIT_FILE_TYPE_REGULAR; +@@ -1481,7 +1481,7 @@ static int unit_file_search( + STRV_FOREACH(p, files) { + r = unit_file_load_or_readlink(c, info, *p, lp, flags | SEARCH_DROPIN); + if (r < 0) +- return log_debug_errno(r, "Failed to load conf file %s: %m", *p); ++ return log_debug_errno(r, "Failed to load conf file \"%s\": %m", *p); + } + + return result; +@@ -1726,7 +1726,7 @@ int unit_file_verify_alias(const UnitFileInstallInfo *i, const char *dst, char * + return log_error_errno(r, "Failed to verify alias validity: %m"); + if (r == 0) + return log_warning_errno(SYNTHETIC_ERRNO(EXDEV), +- "Invalid unit %s symlink %s.", ++ "Invalid unit \"%s\" symlink \"%s\".", + i->name, dst); + + } else { +@@ -1737,7 +1737,7 @@ int unit_file_verify_alias(const UnitFileInstallInfo *i, const char *dst, char * + + UnitNameFlags type = unit_name_to_instance(i->name, &inst); + if (type < 0) +- return log_error_errno(type, "Failed to extract instance name from %s: %m", i->name); ++ return log_error_errno(type, "Failed to extract instance name from \"%s\": %m", i->name); + + if (type == UNIT_NAME_INSTANCE) { + r = unit_name_replace_instance(dst, inst, &dst_updated); diff --git a/0162-test-add-test-for-systemctl-link-enable.patch b/0162-test-add-test-for-systemctl-link-enable.patch new file mode 100644 index 0000000..439eb7c --- /dev/null +++ b/0162-test-add-test-for-systemctl-link-enable.patch @@ -0,0 +1,587 @@ +From e7bd636e75a5435b80a1df478e9e637dd2f7b851 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Mon, 7 Mar 2022 12:15:42 +0100 +Subject: [PATCH] test: add test for systemctl link & enable + +This test has overlap with test-install-root, but it tests things at a +different level, so I think it's useful to add. It immediately shows various +bugs which will be fixed in later patches. + +(cherry picked from commit 50c5f5a3d907f819fa139e1853f660ad4fd82c55) + +Related: #2082131 +--- + meson.build | 9 +- + test/meson.build | 1 + + test/test-systemctl-enable.sh | 523 ++++++++++++++++++++++++++++++++++ + 3 files changed, 532 insertions(+), 1 deletion(-) + create mode 100644 test/test-systemctl-enable.sh + +diff --git a/meson.build b/meson.build +index fdf02b8110..005af872cf 100644 +--- a/meson.build ++++ b/meson.build +@@ -2371,7 +2371,7 @@ public_programs += executable( + install_rpath : rootlibexecdir, + install : true) + +-public_programs += executable( ++exe = executable( + 'systemctl', + systemctl_sources, + include_directories : includes, +@@ -2385,6 +2385,13 @@ public_programs += executable( + install_rpath : rootlibexecdir, + install : true, + install_dir : rootbindir) ++public_programs += exe ++if want_tests != 'false' ++ test('test-systemctl-enable', ++ test_systemctl_enable_sh, ++ # https://github.com/mesonbuild/meson/issues/2681 ++ args : exe.full_path()) ++endif + + if conf.get('ENABLE_PORTABLED') == 1 + dbus_programs += executable( +diff --git a/test/meson.build b/test/meson.build +index c5d8d6917b..c69d8a0204 100644 +--- a/test/meson.build ++++ b/test/meson.build +@@ -88,6 +88,7 @@ endif + + test_fstab_generator_sh = find_program('test-fstab-generator.sh') + test_network_generator_conversion_sh = find_program('test-network-generator-conversion.sh') ++test_systemctl_enable_sh = find_program('test-systemctl-enable.sh') + test_systemd_tmpfiles_py = find_program('test-systemd-tmpfiles.py') + hwdb_test_sh = find_program('hwdb-test.sh') + +diff --git a/test/test-systemctl-enable.sh b/test/test-systemctl-enable.sh +new file mode 100644 +index 0000000000..30ba6532e7 +--- /dev/null ++++ b/test/test-systemctl-enable.sh +@@ -0,0 +1,523 @@ ++#!/usr/bin/env bash ++# SPDX-License-Identifier: LGPL-2.1-or-later ++set -ex ++ ++# Silence warning from running_in_chroot_or_offline() ++export SYSTEMD_IGNORE_CHROOT=1 ++ ++systemctl=${1:-systemctl} ++ ++unset root ++cleanup() { ++ [ -n "$root" ] && rm -rf "$root" ++} ++trap cleanup exit ++root=$(mktemp -d --tmpdir systemctl-test.XXXXXX) ++ ++islink() { ++ test -h "$1" || return 1 ++ test "$(readlink "$1")" = "$2" || return 2 ++} ++ ++: ------enablement nonexistent-------------------------------- ++"$systemctl" --root="$root" enable test1.service && { echo "Expected failure" >&2; exit 1; } ++ ++: ------basic enablement-------------------------------------- ++mkdir -p "$root/etc/systemd/system" ++cat >"$root/etc/systemd/system/test1.service" <>"$root/etc/systemd/system/test1.service" <"$root/etc/systemd/system/test2.socket" <"$root/etc/systemd/system/test2.service" <&2; exit 1; } ++test ! -e "$root/etc/systemd/system/link1.path" ++ ++cat >"$root/link1.path" <&2; exit 1; } ++islink "$root/etc/systemd/system/link1.path" "/link1.path" ++ ++: -------link bad suffix-------------------------------------- ++cp "$root/link1.path" "$root/subdir/link1.suffix" ++"$systemctl" --root="$root" link '/subdir/link1.suffix' && { echo "Expected failure" >&2; exit 1; } ++test ! -e "$root/etc/systemd/system/link1.suffix" ++ ++: -------unlink by unit name---------------------------------- ++"$systemctl" --root="$root" disable 'link1.path' ++test ! -e "$root/etc/systemd/system/link1.path" ++ ++: -------unlink by path--------------------------------------- ++"$systemctl" --root="$root" link '/link1.path' ++test -h "$root/etc/systemd/system/link1.path" ++"$systemctl" --root="$root" disable '/link1.path' ++test ! -e "$root/etc/systemd/system/link1.path" ++ ++: -------unlink by wrong path--------------------------------- ++"$systemctl" --root="$root" link '/link1.path' ++test -h "$root/etc/systemd/system/link1.path" ++"$systemctl" --root="$root" disable '/subdir/link1.path' # we only care about the name ++test ! -e "$root/etc/systemd/system/link1.path" ++ ++ ++: -------link and enable-------------------------------------- ++"$systemctl" --root="$root" enable '/link1.path' ++islink "$root/etc/systemd/system/link1.path" "/link1.path" ++islink "$root/etc/systemd/system/paths.target.wants/link1.path" "/link1.path" ++ ++: -------enable already linked same path---------------------- ++"$systemctl" --root="$root" enable '/link1.path' ++islink "$root/etc/systemd/system/link1.path" "/link1.path" ++islink "$root/etc/systemd/system/paths.target.wants/link1.path" "/link1.path" ++ ++: -------enable already linked different path----------------- ++# FIXME ++# "$systemctl" --root="$root" enable '/subdir/link1.path' && { echo "Expected failure" >&2; exit 1; } ++# test -h "$root/etc/systemd/system/link1.path" ++# readlink "$root/etc/systemd/system/link1.path" ++# test -h "$root/etc/systemd/system/paths.target.wants/link1.path" ++# readlink "$root/etc/systemd/system/paths.target.wants/link1.path" ++ ++: -------enable bad suffix------------------------------------ ++cp "$root/link1.path" "$root/subdir/link1.suffix" ++"$systemctl" --root="$root" enable '/subdir/link1.suffix' && { echo "Expected failure" >&2; exit 1; } ++test ! -e "$root/etc/systemd/system/link1.suffix" ++test ! -e "$root/etc/systemd/system/paths.target.wants/link1.suffix" ++ ++: -------disable by unit name--------------------------------- ++"$systemctl" --root="$root" disable 'link1.path' ++test ! -e "$root/etc/systemd/system/link1.path" ++test ! -e "$root/etc/systemd/system/paths.target.wants/link1.path" ++ ++: -------disable by path-------------------------------------- ++"$systemctl" --root="$root" enable '/link1.path' ++test -h "$root/etc/systemd/system/link1.path" ++test -h "$root/etc/systemd/system/paths.target.wants/link1.path" ++"$systemctl" --root="$root" disable '/link1.path' ++test ! -e "$root/etc/systemd/system/link1.path" ++test ! -e "$root/etc/systemd/system/paths.target.wants/link1.path" ++ ++ ++: -------link then enable------------------------------------- ++"$systemctl" --root="$root" link '/link1.path' ++islink "$root/etc/systemd/system/link1.path" "/link1.path" ++test ! -h "$root/etc/systemd/system/paths.target.wants/link1.path" ++ ++"$systemctl" --root="$root" enable 'link1.path' ++islink "$root/etc/systemd/system/link1.path" "/link1.path" ++islink "$root/etc/systemd/system/paths.target.wants/link1.path" "/link1.path" ++ ++# FIXME ++# "$systemctl" --root="$root" reenable 'link1.path' ++# islink "$root/etc/systemd/system/link1.path" "/link1.path" ++# islink "$root/etc/systemd/system/paths.target.wants/link1.path" "/link1.path" ++ ++ ++: -------manual link------------------------------------------ ++cat >"$root/link3.suffix" <&2; exit 1; } ++"$systemctl" --root="$root" enable '/etc/systemd/system/masked.service' && { echo "Expected failure" >&2; exit 1; } ++ ++: -------enable on masked alias------------------------------- ++test -h "$root/etc/systemd/system/masked.service" ++ln -s "masked.service" "$root/etc/systemd/system/masked-alias.service" ++"$systemctl" --root="$root" enable 'masked-alias.service' && { echo "Expected failure" >&2; exit 1; } ++"$systemctl" --root="$root" enable '/etc/systemd/system/masked-alias.service' && { echo "Expected failure" >&2; exit 1; } ++ ++: -------issue 22000: link in subdirectory-------------------- ++mkdir -p "$root/etc/systemd/system/myown.d" ++cat >"$root/etc/systemd/system/link5-also.service" <"$root/etc/systemd/system/myown.d/link5.service" <&2; exit 1; } ++test ! -h "$root/etc/systemd/system/services.target.wants/link5.service" ++test ! -h "$root/etc/systemd/system/services.target.wants/link5-also.service" ++ ++"$systemctl" --root="$root" enable 'link5-also.service' ++test ! -h "$root/etc/systemd/system/services.target.wants/link5.service" ++islink "$root/etc/systemd/system/services.target.wants/link5-also.service" "/etc/systemd/system/link5-also.service" ++ ++: -------template enablement---------------------------------- ++cat >"$root/etc/systemd/system/templ1@.service" <&2; exit 1; } ++test ! -h "$root/etc/systemd/system/services.target.wants/templ1@.service" ++ ++"$systemctl" --root="$root" enable 'templ1@one.service' ++test ! -h "$root/etc/systemd/system/services.target.wants/templ1@.service" ++islink "$root/etc/systemd/system/services.target.wants/templ1@one.service" "/etc/systemd/system/templ1@.service" ++ ++"$systemctl" --root="$root" enable 'templ1@two.service' ++test ! -h "$root/etc/systemd/system/services.target.wants/templ1@.service" ++islink "$root/etc/systemd/system/services.target.wants/templ1@one.service" "/etc/systemd/system/templ1@.service" ++islink "$root/etc/systemd/system/services.target.wants/templ1@two.service" "/etc/systemd/system/templ1@.service" ++ ++"$systemctl" --root="$root" disable 'templ1@one.service' ++test ! -h "$root/etc/systemd/system/services.target.wants/templ1@.service" ++test ! -h "$root/etc/systemd/system/services.target.wants/templ1@one.service" ++islink "$root/etc/systemd/system/services.target.wants/templ1@two.service" "/etc/systemd/system/templ1@.service" ++ ++"$systemctl" --root="$root" disable 'templ1@two.service' ++test ! -h "$root/etc/systemd/system/services.target.wants/templ1@.service" ++test ! -h "$root/etc/systemd/system/services.target.wants/templ1@one.service" ++test ! -h "$root/etc/systemd/system/services.target.wants/templ1@two.service" ++ ++: -------template enablement w/ default instance-------------- ++cat >>"$root/etc/systemd/system/templ1@.service" <"$root/etc/systemd/system/link4.service" <"$root/etc/systemd/system/link5.service" <"$root/etc/systemd/system/link5@.path" <"$root/etc/systemd/system/multilink.mount" <"$root/etc/systemd/system/some-some-link6@.socket" <&2; exit 1; } ++ ++check_alias z 'z' && { echo "Expected failure because %z is not known" >&2; exit 1; } ++ ++# FIXME: if there's an invalid Alias=, we shouldn't preach about empty [Install] ++ ++exit 0 # yes, this is needed because the last test above fails ++ ++# TODO: repeat the tests above for presets diff --git a/0163-tests-add-helper-for-creating-tempfiles-with-content.patch b/0163-tests-add-helper-for-creating-tempfiles-with-content.patch new file mode 100644 index 0000000..50d813b --- /dev/null +++ b/0163-tests-add-helper-for-creating-tempfiles-with-content.patch @@ -0,0 +1,248 @@ +From ad50f15e51f4f2ffc4ebbfab10a3e1c5739c9ce6 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Mon, 7 Mar 2022 15:06:57 +0100 +Subject: [PATCH] tests: add helper for creating tempfiles with content + +I put it in tests because I think we're most likely to use it in tests. +If necessary, it can be moved somewhere else later. + +(cherry picked from commit 367c47c886af7d915e23de8d6aae0a1c135c0350) + +Related: #2082131 +--- + src/shared/tests.c | 19 +++++++++ + src/shared/tests.h | 2 + + src/test/test-env-file.c | 77 +++++++++---------------------------- + src/test/test-socket-util.c | 19 +++------ + 4 files changed, 44 insertions(+), 73 deletions(-) + +diff --git a/src/shared/tests.c b/src/shared/tests.c +index f5d9536411..307f796fe2 100644 +--- a/src/shared/tests.c ++++ b/src/shared/tests.c +@@ -25,6 +25,7 @@ + #include "cgroup-util.h" + #include "env-file.h" + #include "env-util.h" ++#include "fd-util.h" + #include "fs-util.h" + #include "log.h" + #include "namespace-util.h" +@@ -33,6 +34,7 @@ + #include "random-util.h" + #include "strv.h" + #include "tests.h" ++#include "tmpfile-util.h" + + char* setup_fake_runtime_dir(void) { + char t[] = "/tmp/fake-xdg-runtime-XXXXXX", *p; +@@ -133,6 +135,23 @@ int log_tests_skipped_errno(int r, const char *message) { + return EXIT_TEST_SKIP; + } + ++int write_tmpfile(char *pattern, const char *contents) { ++ _cleanup_close_ int fd = -1; ++ ++ assert(pattern); ++ assert(contents); ++ ++ fd = mkostemp_safe(pattern); ++ if (fd < 0) ++ return fd; ++ ++ ssize_t l = strlen(contents); ++ errno = 0; ++ if (write(fd, contents, l) != l) ++ return errno_or_else(EIO); ++ return 0; ++} ++ + bool have_namespaces(void) { + siginfo_t si = {}; + pid_t pid; +diff --git a/src/shared/tests.h b/src/shared/tests.h +index ef6acd368e..ade527590b 100644 +--- a/src/shared/tests.h ++++ b/src/shared/tests.h +@@ -30,6 +30,8 @@ void test_setup_logging(int level); + int log_tests_skipped(const char *message); + int log_tests_skipped_errno(int r, const char *message); + ++int write_tmpfile(char *pattern, const char *contents); ++ + bool have_namespaces(void); + + /* We use the small but non-trivial limit here */ +diff --git a/src/test/test-env-file.c b/src/test/test-env-file.c +index f97206b4d6..886a8e4bc8 100644 +--- a/src/test/test-env-file.c ++++ b/src/test/test-env-file.c +@@ -55,18 +55,11 @@ + + + TEST(load_env_file_1) { +- _cleanup_strv_free_ char **data = NULL; +- int r; +- + _cleanup_(unlink_tempfilep) char name[] = "/tmp/test-load-env-file.XXXXXX"; +- _cleanup_close_ int fd; +- +- fd = mkostemp_safe(name); +- assert_se(fd >= 0); +- assert_se(write(fd, env_file_1, strlen(env_file_1)) == strlen(env_file_1)); ++ assert_se(write_tmpfile(name, env_file_1) == 0); + +- r = load_env_file(NULL, name, &data); +- assert_se(r == 0); ++ _cleanup_strv_free_ char **data = NULL; ++ assert_se(load_env_file(NULL, name, &data) == 0); + assert_se(streq(data[0], "a=a")); + assert_se(streq(data[1], "b=bc")); + assert_se(streq(data[2], "d=de f")); +@@ -77,50 +70,30 @@ TEST(load_env_file_1) { + } + + TEST(load_env_file_2) { +- _cleanup_strv_free_ char **data = NULL; +- int r; +- + _cleanup_(unlink_tempfilep) char name[] = "/tmp/test-load-env-file.XXXXXX"; +- _cleanup_close_ int fd; ++ assert_se(write_tmpfile(name, env_file_2) == 0); + +- fd = mkostemp_safe(name); +- assert_se(fd >= 0); +- assert_se(write(fd, env_file_2, strlen(env_file_2)) == strlen(env_file_2)); +- +- r = load_env_file(NULL, name, &data); +- assert_se(r == 0); ++ _cleanup_strv_free_ char **data = NULL; ++ assert_se(load_env_file(NULL, name, &data) == 0); + assert_se(streq(data[0], "a=a")); + assert_se(data[1] == NULL); + } + + TEST(load_env_file_3) { +- _cleanup_strv_free_ char **data = NULL; +- int r; +- + _cleanup_(unlink_tempfilep) char name[] = "/tmp/test-load-env-file.XXXXXX"; +- _cleanup_close_ int fd; +- +- fd = mkostemp_safe(name); +- assert_se(fd >= 0); +- assert_se(write(fd, env_file_3, strlen(env_file_3)) == strlen(env_file_3)); ++ assert_se(write_tmpfile(name, env_file_3) == 0); + +- r = load_env_file(NULL, name, &data); +- assert_se(r == 0); ++ _cleanup_strv_free_ char **data = NULL; ++ assert_se(load_env_file(NULL, name, &data) == 0); + assert_se(data == NULL); + } + + TEST(load_env_file_4) { +- _cleanup_strv_free_ char **data = NULL; + _cleanup_(unlink_tempfilep) char name[] = "/tmp/test-load-env-file.XXXXXX"; +- _cleanup_close_ int fd; +- int r; +- +- fd = mkostemp_safe(name); +- assert_se(fd >= 0); +- assert_se(write(fd, env_file_4, strlen(env_file_4)) == strlen(env_file_4)); ++ assert_se(write_tmpfile(name, env_file_4) == 0); + +- r = load_env_file(NULL, name, &data); +- assert_se(r == 0); ++ _cleanup_strv_free_ char **data = NULL; ++ assert_se(load_env_file(NULL, name, &data) == 0); + assert_se(streq(data[0], "HWMON_MODULES=coretemp f71882fg")); + assert_se(streq(data[1], "MODULE_0=coretemp")); + assert_se(streq(data[2], "MODULE_1=f71882fg")); +@@ -128,36 +101,22 @@ TEST(load_env_file_4) { + } + + TEST(load_env_file_5) { +- _cleanup_strv_free_ char **data = NULL; +- int r; +- + _cleanup_(unlink_tempfilep) char name[] = "/tmp/test-load-env-file.XXXXXX"; +- _cleanup_close_ int fd; +- +- fd = mkostemp_safe(name); +- assert_se(fd >= 0); +- assert_se(write(fd, env_file_5, strlen(env_file_5)) == strlen(env_file_5)); ++ assert_se(write_tmpfile(name, env_file_5) == 0); + +- r = load_env_file(NULL, name, &data); +- assert_se(r == 0); ++ _cleanup_strv_free_ char **data = NULL; ++ assert_se(load_env_file(NULL, name, &data) == 0); + assert_se(streq(data[0], "a=")); + assert_se(streq(data[1], "b=")); + assert_se(data[2] == NULL); + } + + TEST(load_env_file_6) { +- _cleanup_strv_free_ char **data = NULL; +- int r; +- + _cleanup_(unlink_tempfilep) char name[] = "/tmp/test-load-env-file.XXXXXX"; +- _cleanup_close_ int fd; ++ assert_se(write_tmpfile(name, env_file_6) == 0); + +- fd = mkostemp_safe(name); +- assert_se(fd >= 0); +- assert_se(write(fd, env_file_6, strlen(env_file_6)) == strlen(env_file_6)); +- +- r = load_env_file(NULL, name, &data); +- assert_se(r == 0); ++ _cleanup_strv_free_ char **data = NULL; ++ assert_se(load_env_file(NULL, name, &data) == 0); + assert_se(streq(data[0], "a= n t x y '")); + assert_se(streq(data[1], "b=$'")); + assert_se(streq(data[2], "c= \\n\\t\\$\\`\\\\\n")); +diff --git a/src/test/test-socket-util.c b/src/test/test-socket-util.c +index 9ee651a5fa..3245516f9a 100644 +--- a/src/test/test-socket-util.c ++++ b/src/test/test-socket-util.c +@@ -228,17 +228,12 @@ TEST(passfd_read) { + + if (r == 0) { + /* Child */ +- char tmpfile[] = "/tmp/test-socket-util-passfd-read-XXXXXX"; +- _cleanup_close_ int tmpfd = -1; +- + pair[0] = safe_close(pair[0]); + +- tmpfd = mkostemp_safe(tmpfile); +- assert_se(tmpfd >= 0); +- assert_se(write(tmpfd, file_contents, strlen(file_contents)) == (ssize_t) strlen(file_contents)); +- tmpfd = safe_close(tmpfd); ++ char tmpfile[] = "/tmp/test-socket-util-passfd-read-XXXXXX"; ++ assert_se(write_tmpfile(tmpfile, file_contents) == 0); + +- tmpfd = open(tmpfile, O_RDONLY); ++ _cleanup_close_ int tmpfd = open(tmpfile, O_RDONLY); + assert_se(tmpfd >= 0); + assert_se(unlink(tmpfile) == 0); + +@@ -277,16 +272,12 @@ TEST(passfd_contents_read) { + /* Child */ + struct iovec iov = IOVEC_INIT_STRING(wire_contents); + char tmpfile[] = "/tmp/test-socket-util-passfd-contents-read-XXXXXX"; +- _cleanup_close_ int tmpfd = -1; + + pair[0] = safe_close(pair[0]); + +- tmpfd = mkostemp_safe(tmpfile); +- assert_se(tmpfd >= 0); +- assert_se(write(tmpfd, file_contents, strlen(file_contents)) == (ssize_t) strlen(file_contents)); +- tmpfd = safe_close(tmpfd); ++ assert_se(write_tmpfile(tmpfile, file_contents) == 0); + +- tmpfd = open(tmpfile, O_RDONLY); ++ _cleanup_close_ int tmpfd = open(tmpfile, O_RDONLY); + assert_se(tmpfd >= 0); + assert_se(unlink(tmpfile) == 0); + diff --git a/0164-man-clarify-the-descriptions-of-aliases-and-linked-u.patch b/0164-man-clarify-the-descriptions-of-aliases-and-linked-u.patch new file mode 100644 index 0000000..a47ca97 --- /dev/null +++ b/0164-man-clarify-the-descriptions-of-aliases-and-linked-u.patch @@ -0,0 +1,106 @@ +From 2c9079ca0eaa2a1df2a1775c28fa7a49785999df Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Mon, 28 Mar 2022 11:46:38 +0200 +Subject: [PATCH] man: clarify the descriptions of aliases and linked unit + files + +This just describes the rules that are implemented by the manager, and this +pull request does not change any of them. + +(cherry picked from commit ecd6c000d3a2e743a0f533d427250714c7593cf7) + +Related: #2082131 +--- + man/systemd.unit.xml | 58 ++++++++++++++++++++++++++++++++------------ + 1 file changed, 43 insertions(+), 15 deletions(-) + +diff --git a/man/systemd.unit.xml b/man/systemd.unit.xml +index 2a44b8cfd8..4ba602b5ad 100644 +--- a/man/systemd.unit.xml ++++ b/man/systemd.unit.xml +@@ -140,7 +140,7 @@ + a symlink, so when systemd is asked through D-Bus to load + dbus-org.freedesktop.network1.service, it'll load + systemd-networkd.service. As another example, default.target — +- the default system target started at boot — is commonly symlinked (aliased) to either ++ the default system target started at boot — is commonly aliased to either + multi-user.target or graphical.target to select what is started + by default. Alias names may be used in commands like disable, + start, stop, status, and similar, and in all +@@ -156,8 +156,12 @@ + template instance (e.g. alias@inst.service) may be a symlink to different template + (e.g. template@inst.service). In that case, just this specific instance is aliased, + while other instances of the template (e.g. alias@foo.service, +- alias@bar.service) are not aliased. Those rule preserve the requirement that the +- instance (if any) is always uniquely defined for a given unit and all its aliases. ++ alias@bar.service) are not aliased. Those rules preserve the requirement that the ++ instance (if any) is always uniquely defined for a given unit and all its aliases. The target of alias ++ symlink must point to a valid unit file location, i.e. the symlink target name must match the symlink ++ source name as described, and the destination path must be in one of the unit search paths, see UNIT FILE ++ LOAD PATH section below for more details. Note that the target file may not exist, i.e. the symlink may ++ be dangling. + + Unit files may specify aliases through the Alias= directive in the [Install] + section. When the unit is enabled, symlinks will be created for those names, and removed when the unit is +@@ -177,11 +181,18 @@ + exists for Requires= type dependencies as well, the directory suffix is + .requires/ in this case. This functionality is useful to hook units into the + start-up of other units, without having to modify their unit files. For details about the semantics of +- Wants=, see below. The preferred way to create symlinks in the +- .wants/ or .requires/ directory of a unit file is by embedding +- the dependency in [Install] section of the target unit, and creating the symlink in the file system with +- the enable or preset commands of +- systemctl1. ++ Wants= and Requires=, see below. The preferred way to create ++ symlinks in the .wants/ or .requires/ directories is by ++ specifying the dependency in [Install] section of the target unit, and creating the symlink in the file ++ system with the enable or preset commands of ++ systemctl1. The ++ target can be a normal unit (either plain or a specific instance of a template unit). In case when the ++ source unit is a template, the target can also be a template, in which case the instance will be ++ "propagated" to the target unit to form a valid unit instance. The target of symlinks in ++ .wants/ or .requires/ must thus point to a valid unit file ++ location, i.e. the symlink target name must satisfy the described requirements, and the destination path ++ must be in one of the unit search paths, see UNIT FILE LOAD PATH section below for more details. Note ++ that the target file may not exist, i.e. the symlink may be dangling. + + Along with a unit file foo.service, a "drop-in" directory + foo.service.d/ may exist. All files with the suffix +@@ -503,13 +514,30 @@ + systemd-analyze --user unit-paths + + +- Moreover, additional units might be loaded into systemd from +- directories not on the unit load path by creating a symlink pointing to a +- unit file in the directories. You can use systemctl link +- for this operation. See +- systemctl1 +- for its usage and precaution. +- ++ Moreover, additional units might be loaded into systemd from directories not on the unit load path ++ by creating a symlink pointing to a unit file in the directories. You can use systemctl ++ link for this; see ++ systemctl1. The file ++ system where the linked unit files are located must be accessible when systemd is started (e.g. anything ++ underneath /home/ or /var/ is not allowed, unless those ++ directories are located on the root file system). ++ ++ It is important to distinguish "linked unit files" from "unit file aliases": any symlink where the ++ symlink target is within the unit load path becomes an alias: the source name and ++ the target file name must satisfy specific constraints listed above in the discussion of aliases, but the ++ symlink target doesn't have to exist, and in fact the symlink target path is not used, except to check ++ whether the target is within the unit load path. In constrast, a symlink which goes outside of the unit ++ load path signifies a linked unit file. The symlink is followed when loading the file, but the ++ destination name is otherwise unused (and may even not be a valid unit file name). For example, symlinks ++ /etc/systemd/system/alias1.serviceservice1.service, ++ /etc/systemd/system/alias2.service/usr/lib/systemd/service1.service, ++ /etc/systemd/system/alias3.service/etc/systemd/system/service1.service ++ are all valid aliases and service1.service will have ++ four names, even if the unit file is located at ++ /run/systemd/system/service1.service. In contrast, ++ a symlink /etc/systemd/system/link1.service../link1_service_file ++ means that link1.service is a "linked unit" and the contents of ++ /etc/systemd/link1_service_file provide its configuration. + + + diff --git a/0165-basic-add-new-variable-SYSTEMD_OS_RELEASE-to-overrid.patch b/0165-basic-add-new-variable-SYSTEMD_OS_RELEASE-to-overrid.patch new file mode 100644 index 0000000..83b187f --- /dev/null +++ b/0165-basic-add-new-variable-SYSTEMD_OS_RELEASE-to-overrid.patch @@ -0,0 +1,85 @@ +From d424adce45d593d41e52294bd8f32fd33c625498 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Mon, 7 Mar 2022 18:54:50 +0100 +Subject: [PATCH] basic: add new variable $SYSTEMD_OS_RELEASE to override + location of os-release + +The test for the variable is added in test-systemctl-enable because there we +can do it almost for free, and the variable is most likely to be used with +'systemctl enable --root' anyway. + +(cherry picked from commit df78419d107662dd49892d76a745c294d7031d66) + +Related: #2082131 +--- + docs/ENVIRONMENT.md | 5 +++++ + src/basic/os-util.c | 16 +++++++++++----- + test/test-systemctl-enable.sh | 12 ++++++++++-- + 3 files changed, 26 insertions(+), 7 deletions(-) + +diff --git a/docs/ENVIRONMENT.md b/docs/ENVIRONMENT.md +index 71d6c55010..5e9548449c 100644 +--- a/docs/ENVIRONMENT.md ++++ b/docs/ENVIRONMENT.md +@@ -43,6 +43,11 @@ All tools: + debugging, in order to test generators and other code against specific kernel + command lines. + ++* `$SYSTEMD_OS_RELEASE` — if set, use this path instead of `/etc/os-release` or ++ `/usr/lib/os-release`. When operating under some root (e.g. `systemctl ++ --root=…`), the path is taken relative to the outside root. Only useful for ++ debugging. ++ + * `$SYSTEMD_FSTAB` — if set, use this path instead of `/etc/fstab`. Only useful + for debugging. + +diff --git a/src/basic/os-util.c b/src/basic/os-util.c +index a6e4d09473..38b2179e48 100644 +--- a/src/basic/os-util.c ++++ b/src/basic/os-util.c +@@ -170,13 +170,19 @@ int open_extension_release(const char *root, const char *extension, char **ret_p + } + } + } else { +- FOREACH_STRING(p, "/etc/os-release", "/usr/lib/os-release") { +- r = chase_symlinks(p, root, CHASE_PREFIX_ROOT, ++ const char *var = secure_getenv("SYSTEMD_OS_RELEASE"); ++ if (var) ++ r = chase_symlinks(var, root, 0, + ret_path ? &q : NULL, + ret_fd ? &fd : NULL); +- if (r != -ENOENT) +- break; +- } ++ else ++ FOREACH_STRING(path, "/etc/os-release", "/usr/lib/os-release") { ++ r = chase_symlinks(path, root, CHASE_PREFIX_ROOT, ++ ret_path ? &q : NULL, ++ ret_fd ? &fd : NULL); ++ if (r != -ENOENT) ++ break; ++ } + } + if (r < 0) + return r; +diff --git a/test/test-systemctl-enable.sh b/test/test-systemctl-enable.sh +index 30ba6532e7..769341129c 100644 +--- a/test/test-systemctl-enable.sh ++++ b/test/test-systemctl-enable.sh +@@ -518,6 +518,14 @@ check_alias z 'z' && { echo "Expected failure because %z is not known" >&2; exit + + # FIXME: if there's an invalid Alias=, we shouldn't preach about empty [Install] + +-exit 0 # yes, this is needed because the last test above fails +- + # TODO: repeat the tests above for presets ++ ++: -------SYSTEMD_OS_RELEASE relative to root------------------ ++# check that os-release overwriting works as expected with root ++test -e "$root/etc/os-release" ++ ++cat >"$root/etc/os-release2" < +Date: Mon, 7 Mar 2022 19:22:01 +0100 +Subject: [PATCH] test-os-util: add basic tests for os-release parsing + +(cherry picked from commit 80e72f80bc407753582b421421c13ca50b675027) + +Related: #2082131 +--- + src/test/test-os-util.c | 62 +++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 62 insertions(+) + +diff --git a/src/test/test-os-util.c b/src/test/test-os-util.c +index eb5466259a..5f82748783 100644 +--- a/src/test/test-os-util.c ++++ b/src/test/test-os-util.c +@@ -2,8 +2,11 @@ + + #include + ++#include "fs-util.h" + #include "log.h" + #include "os-util.h" ++#include "string-util.h" ++#include "strv.h" + #include "tests.h" + + TEST(path_is_os_tree) { +@@ -12,4 +15,63 @@ TEST(path_is_os_tree) { + assert_se(path_is_os_tree("/idontexist") == -ENOENT); + } + ++TEST(parse_os_release) { ++ /* Let's assume that we're running in a valid system, so os-release is available */ ++ _cleanup_free_ char *id = NULL, *id2 = NULL, *name = NULL, *foobar = NULL; ++ assert_se(parse_os_release(NULL, "ID", &id) == 1); ++ log_info("ID: %s", id); ++ ++ assert_se(setenv("SYSTEMD_OS_RELEASE", "/dev/null", 1) == 0); ++ assert_se(parse_os_release(NULL, "ID", &id2) == 0); ++ log_info("ID: %s", strnull(id2)); ++ ++ _cleanup_(unlink_tempfilep) char tmpfile[] = "/tmp/test-os-util.XXXXXX"; ++ assert_se(write_tmpfile(tmpfile, ++ "ID=the-id \n" ++ "NAME=the-name") == 0); ++ ++ assert_se(setenv("SYSTEMD_OS_RELEASE", tmpfile, 1) == 0); ++ assert_se(parse_os_release(NULL, "ID", &id, "NAME", &name) == 2); ++ log_info("ID: %s NAME: %s", id, name); ++ assert_se(streq(id, "the-id")); ++ assert_se(streq(name, "the-name")); ++ ++ _cleanup_(unlink_tempfilep) char tmpfile2[] = "/tmp/test-os-util.XXXXXX"; ++ assert_se(write_tmpfile(tmpfile2, ++ "ID=\"ignored\" \n" ++ "ID=\"the-id\" \n" ++ "NAME='the-name'") == 0); ++ ++ assert_se(setenv("SYSTEMD_OS_RELEASE", tmpfile2, 1) == 0); ++ // FIXME: we return 3, which means that the return value is useless in face of repeats ++ assert_se(parse_os_release(NULL, "ID", &id, "NAME", &name) == 3); ++ log_info("ID: %s NAME: %s", id, name); ++ assert_se(streq(id, "the-id")); ++ assert_se(streq(name, "the-name")); ++ ++ assert_se(parse_os_release(NULL, "FOOBAR", &foobar) == 0); ++ log_info("FOOBAR: %s", strnull(foobar)); ++ assert_se(foobar == NULL); ++ ++ assert_se(unsetenv("SYSTEMD_OS_RELEASE") == 0); ++} ++ ++TEST(load_os_release_pairs) { ++ _cleanup_(unlink_tempfilep) char tmpfile[] = "/tmp/test-os-util.XXXXXX"; ++ assert_se(write_tmpfile(tmpfile, ++ "ID=\"ignored\" \n" ++ "ID=\"the-id\" \n" ++ "NAME='the-name'") == 0); ++ ++ assert_se(setenv("SYSTEMD_OS_RELEASE", tmpfile, 1) == 0); ++ ++ _cleanup_strv_free_ char **pairs = NULL; ++ assert_se(load_os_release_pairs(NULL, &pairs) == 0); ++ assert_se(strv_equal(pairs, STRV_MAKE("ID", "ignored", // FIXME ++ "ID", "the-id", ++ "NAME", "the-name"))); ++ ++ assert_se(unsetenv("SYSTEMD_OS_RELEASE") == 0); ++} ++ + DEFINE_TEST_MAIN(LOG_DEBUG); diff --git a/0167-basic-env-file-make-load-env-file-deduplicate-entrie.patch b/0167-basic-env-file-make-load-env-file-deduplicate-entrie.patch new file mode 100644 index 0000000..3ba038c --- /dev/null +++ b/0167-basic-env-file-make-load-env-file-deduplicate-entrie.patch @@ -0,0 +1,104 @@ +From f990ee961a75791adfdea2f5efb35017a51a310e Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Tue, 8 Mar 2022 10:08:05 +0100 +Subject: [PATCH] basic/env-file: make load-env-file deduplicate entries with + the same key + +We generally assume parsing like the shell would do it, so the last value +should win when there are repeats. + +(cherry picked from commit 25407ad2a785d10b1aadff0c99829ea0cf51082b) + +Related: #2082131 +--- + src/basic/env-file.c | 31 ++++++++++++++++++++----------- + src/test/test-env-file.c | 5 +++++ + src/test/test-os-util.c | 3 +-- + 3 files changed, 26 insertions(+), 13 deletions(-) + +diff --git a/src/basic/env-file.c b/src/basic/env-file.c +index 599b73bc22..0353f3f2a0 100644 +--- a/src/basic/env-file.c ++++ b/src/basic/env-file.c +@@ -415,30 +415,39 @@ static int load_env_file_push_pairs( + const char *key, char *value, + void *userdata, + int *n_pushed) { +- char ***m = userdata; ++ char ***m = ASSERT_PTR(userdata); ++ bool added = false; + int r; + + r = check_utf8ness_and_warn(filename, line, key, value); + if (r < 0) + return r; + ++ /* Check if the key is present */ ++ for (char **t = *m; t && *t; t += 2) ++ if (streq(t[0], key)) { ++ if (value) ++ r = free_and_replace(t[1], value); ++ else ++ r = free_and_strdup(t+1, ""); ++ goto finish; ++ } ++ + r = strv_extend(m, key); + if (r < 0) + return -ENOMEM; + +- if (!value) { +- r = strv_extend(m, ""); +- if (r < 0) +- return -ENOMEM; +- } else { ++ if (value) + r = strv_push(m, value); +- if (r < 0) +- return r; +- } ++ else ++ r = strv_extend(m, ""); ++ added = true; ++ finish: ++ if (r < 0) ++ return r; + +- if (n_pushed) ++ if (n_pushed && added) + (*n_pushed)++; +- + return 0; + } + +diff --git a/src/test/test-env-file.c b/src/test/test-env-file.c +index 886a8e4bc8..461a0f0810 100644 +--- a/src/test/test-env-file.c ++++ b/src/test/test-env-file.c +@@ -9,7 +9,12 @@ + #include "tests.h" + #include "tmpfile-util.h" + ++/* In case of repeating keys, later entries win. */ ++ + #define env_file_1 \ ++ "a=a\n" \ ++ "a=b\n" \ ++ "a=b\n" \ + "a=a\n" \ + "b=b\\\n" \ + "c\n" \ +diff --git a/src/test/test-os-util.c b/src/test/test-os-util.c +index 5f82748783..d6336c53e9 100644 +--- a/src/test/test-os-util.c ++++ b/src/test/test-os-util.c +@@ -67,8 +67,7 @@ TEST(load_os_release_pairs) { + + _cleanup_strv_free_ char **pairs = NULL; + assert_se(load_os_release_pairs(NULL, &pairs) == 0); +- assert_se(strv_equal(pairs, STRV_MAKE("ID", "ignored", // FIXME +- "ID", "the-id", ++ assert_se(strv_equal(pairs, STRV_MAKE("ID", "the-id", + "NAME", "the-name"))); + + assert_se(unsetenv("SYSTEMD_OS_RELEASE") == 0); diff --git a/0168-man-os-release-add-a-note-about-repeating-entries.patch b/0168-man-os-release-add-a-note-about-repeating-entries.patch new file mode 100644 index 0000000..2fe5e02 --- /dev/null +++ b/0168-man-os-release-add-a-note-about-repeating-entries.patch @@ -0,0 +1,33 @@ +From b4087419bac3cd656a3f8ba82653750fd60c19b9 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Tue, 8 Mar 2022 10:10:12 +0100 +Subject: [PATCH] man/os-release: add a note about repeating entries + +We didn't actually say that keys should not be repeated. At least the +examples in docs (both python and shell) would do that, and any simple +parser that builds a dictionary would most likely behave the same way. +But let's document this expectation, but also say how to deal with malformed +files. + +(cherry picked from commit 3a84a3c9dfde5182398a6d0863a2b2fe90a936b1) + +Related: #2082131 +--- + man/os-release.xml | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/man/os-release.xml b/man/os-release.xml +index 1826a60d1a..baff088bc0 100644 +--- a/man/os-release.xml ++++ b/man/os-release.xml +@@ -75,6 +75,10 @@ + from earliest boot on, and hence must be located on the root file + system. + ++ os-release must not contain repeating keys. Nevertheless, readers should pick ++ the entries later in the file in case of repeats, similarly to how a shell sourcing the file would. A ++ reader may warn about repeating entries. ++ + For a longer rationale for os-release + please refer to the Announcement of /etc/os-release. diff --git a/0169-shared-specifier-clarify-and-add-test-for-missing-da.patch b/0169-shared-specifier-clarify-and-add-test-for-missing-da.patch new file mode 100644 index 0000000..9e778f6 --- /dev/null +++ b/0169-shared-specifier-clarify-and-add-test-for-missing-da.patch @@ -0,0 +1,55 @@ +From fb51d78042fec1a2df2a7da1f9a759875bd7e07e Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Tue, 8 Mar 2022 11:38:46 +0100 +Subject: [PATCH] shared/specifier: clarify and add test for missing data + +In systemd.unit we document that unset fields resolve to "". But we didn't +directly test this, so let's do that. Also, we return -ENOENT if the file +is missing, which we didn't document or test. + +(cherry picked from commit 7962116fc8a2572c5c89904ac50fe99c8101f28f) + +Related: #2082131 +--- + src/shared/specifier.c | 4 +++- + src/test/test-specifier.c | 14 ++++++++++++++ + 2 files changed, 17 insertions(+), 1 deletion(-) + +diff --git a/src/shared/specifier.c b/src/shared/specifier.c +index f8ab98541f..c26628975c 100644 +--- a/src/shared/specifier.c ++++ b/src/shared/specifier.c +@@ -213,7 +213,9 @@ int specifier_architecture(char specifier, const void *data, const char *root, c + } + + /* Note: fields in /etc/os-release might quite possibly be missing, even if everything is entirely valid +- * otherwise. We'll return an empty value or NULL in that case from the functions below. */ ++ * otherwise. We'll return an empty value or NULL in that case from the functions below. But if the ++ * os-release file is missing, we'll return -ENOENT. This means that something is seriously wrong with the ++ * installation. */ + + int specifier_os_id(char specifier, const void *data, const char *root, const void *userdata, char **ret) { + return parse_os_release(root, "ID", ret); +diff --git a/src/test/test-specifier.c b/src/test/test-specifier.c +index dda993ce9d..790f0252d7 100644 +--- a/src/test/test-specifier.c ++++ b/src/test/test-specifier.c +@@ -96,4 +96,18 @@ TEST(specifiers) { + } + } + ++TEST(specifiers_missing_data_ok) { ++ _cleanup_free_ char *resolved = NULL; ++ ++ assert_se(setenv("SYSTEMD_OS_RELEASE", "/dev/null", 1) == 0); ++ assert_se(specifier_printf("%A-%B-%M-%o-%w-%W", SIZE_MAX, specifier_table, NULL, NULL, &resolved) >= 0); ++ assert_se(streq(resolved, "-----")); ++ ++ assert_se(setenv("SYSTEMD_OS_RELEASE", "/nosuchfileordirectory", 1) == 0); ++ assert_se(specifier_printf("%A-%B-%M-%o-%w-%W", SIZE_MAX, specifier_table, NULL, NULL, &resolved) == -ENOENT); ++ assert_se(streq(resolved, "-----")); ++ ++ assert_se(unsetenv("SYSTEMD_OS_RELEASE") == 0); ++} ++ + DEFINE_TEST_MAIN(LOG_DEBUG); diff --git a/0170-shared-specifier-provide-proper-error-messages-when-.patch b/0170-shared-specifier-provide-proper-error-messages-when-.patch new file mode 100644 index 0000000..843675d --- /dev/null +++ b/0170-shared-specifier-provide-proper-error-messages-when-.patch @@ -0,0 +1,278 @@ +From b3b45ed9385341e72edfc1bae08819026d841d46 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Tue, 8 Mar 2022 12:08:00 +0100 +Subject: [PATCH] shared/specifier: provide proper error messages when + specifiers fail to read files + +ENOENT is easily confused with the file that we're working on not being +present, e.g. when the file contains %o or something else that requires +os-release to be present. Let's use -EUNATCH instead to reduce that chances of +confusion if the context of the error is lost. + +And once we have pinpointed the reason, let's provide a proper error message: + ++ build/systemctl --root=/tmp/systemctl-test.TO7Mcb enable some-some-link6@.socket +/tmp/systemctl-test.TO7Mcb/etc/systemd/system/some-some-link6@.socket: Failed to resolve alias "target@A:%A.socket": Protocol driver not attached +Failed to enable unit, cannot resolve specifiers in "target@A:%A.socket". + +(cherry picked from commit 6ec4c852c910b1aca649e87ba3143841334f01fa) + +Related: #2082131 +--- + src/shared/install.c | 31 +++++++++++++------- + src/shared/specifier.c | 27 ++++++++++++----- + src/test/test-specifier.c | 2 +- + test/test-systemctl-enable.sh | 55 ++++++++++++++++++++++++++--------- + 4 files changed, 82 insertions(+), 33 deletions(-) + +diff --git a/src/shared/install.c b/src/shared/install.c +index cbfe96b1e8..ea5bc36482 100644 +--- a/src/shared/install.c ++++ b/src/shared/install.c +@@ -374,6 +374,7 @@ void unit_file_dump_changes(int r, const char *verb, const UnitFileChange *chang + verb, changes[i].path); + logged = true; + break; ++ + case -EADDRNOTAVAIL: + log_error_errno(changes[i].type_or_errno, "Failed to %s unit, unit %s is transient or generated.", + verb, changes[i].path); +@@ -401,6 +402,12 @@ void unit_file_dump_changes(int r, const char *verb, const UnitFileChange *chang + logged = true; + break; + ++ case -EUNATCH: ++ log_error_errno(changes[i].type_or_errno, "Failed to %s unit, cannot resolve specifiers in \"%s\".", ++ verb, changes[i].path); ++ logged = true; ++ break; ++ + default: + assert(changes[i].type_or_errno < 0); + log_error_errno(changes[i].type_or_errno, "Failed to %s unit, file \"%s\": %m", +@@ -1154,7 +1161,8 @@ static int config_parse_also( + + r = install_name_printf(info, word, info->root, &printed); + if (r < 0) +- return r; ++ return log_syntax(unit, LOG_WARNING, filename, line, r, ++ "Failed to resolve unit name in Also=\"%s\": %m", word); + + r = install_info_add(c, printed, NULL, info->root, /* auxiliary= */ true, NULL); + if (r < 0) +@@ -1201,14 +1209,13 @@ static int config_parse_default_instance( + + r = install_name_printf(i, rvalue, i->root, &printed); + if (r < 0) +- return r; ++ return log_syntax(unit, LOG_WARNING, filename, line, r, ++ "Failed to resolve instance name in DefaultInstance=\"%s\": %m", rvalue); + +- if (isempty(printed)) { +- i->default_instance = mfree(i->default_instance); +- return 0; +- } ++ if (isempty(printed)) ++ printed = mfree(printed); + +- if (!unit_instance_is_valid(printed)) ++ if (printed && !unit_instance_is_valid(printed)) + return log_syntax(unit, LOG_WARNING, filename, line, SYNTHETIC_ERRNO(EINVAL), + "Invalid DefaultInstance= value \"%s\".", printed); + +@@ -1776,8 +1783,10 @@ static int install_info_symlink_alias( + _cleanup_free_ char *alias_path = NULL, *dst = NULL, *dst_updated = NULL; + + q = install_name_printf(i, *s, i->root, &dst); +- if (q < 0) ++ if (q < 0) { ++ unit_file_changes_add(changes, n_changes, q, *s, NULL); + return q; ++ } + + q = unit_file_verify_alias(i, dst, &dst_updated); + if (q < 0) +@@ -1861,8 +1870,10 @@ static int install_info_symlink_wants( + _cleanup_free_ char *path = NULL, *dst = NULL; + + q = install_name_printf(i, *s, i->root, &dst); +- if (q < 0) ++ if (q < 0) { ++ unit_file_changes_add(changes, n_changes, q, *s, NULL); + return q; ++ } + + if (!unit_name_is_valid(dst, valid_dst_type)) { + /* Generate a proper error here: EUCLEAN if the name is generally bad, EIDRM if the +@@ -3332,7 +3343,7 @@ int unit_file_preset_all( + + r = preset_prepare_one(scope, &plus, &minus, &lp, de->d_name, &presets, changes, n_changes); + if (r < 0 && +- !IN_SET(r, -EEXIST, -ERFKILL, -EADDRNOTAVAIL, -EIDRM, -EUCLEAN, -ELOOP, -ENOENT)) ++ !IN_SET(r, -EEXIST, -ERFKILL, -EADDRNOTAVAIL, -EIDRM, -EUCLEAN, -ELOOP, -ENOENT, -EUNATCH)) + /* Ignore generated/transient/missing/invalid units when applying preset, propagate other errors. + * Coordinate with unit_file_dump_changes() above. */ + return r; +diff --git a/src/shared/specifier.c b/src/shared/specifier.c +index c26628975c..a917378427 100644 +--- a/src/shared/specifier.c ++++ b/src/shared/specifier.c +@@ -131,7 +131,8 @@ int specifier_machine_id(char specifier, const void *data, const char *root, con + + fd = chase_symlinks_and_open("/etc/machine-id", root, CHASE_PREFIX_ROOT, O_RDONLY|O_CLOEXEC|O_NOCTTY, NULL); + if (fd < 0) +- return fd; ++ /* Translate error for missing os-release file to EUNATCH. */ ++ return fd == -ENOENT ? -EUNATCH : fd; + + r = id128_read_fd(fd, ID128_PLAIN, &id); + } else +@@ -214,31 +215,41 @@ int specifier_architecture(char specifier, const void *data, const char *root, c + + /* Note: fields in /etc/os-release might quite possibly be missing, even if everything is entirely valid + * otherwise. We'll return an empty value or NULL in that case from the functions below. But if the +- * os-release file is missing, we'll return -ENOENT. This means that something is seriously wrong with the ++ * os-release file is missing, we'll return -EUNATCH. This means that something is seriously wrong with the + * installation. */ + ++static int parse_os_release_specifier(const char *root, const char *id, char **ret) { ++ int r; ++ ++ assert(ret); ++ ++ /* Translate error for missing os-release file to EUNATCH. */ ++ r = parse_os_release(root, id, ret); ++ return r == -ENOENT ? -EUNATCH : r; ++} ++ + int specifier_os_id(char specifier, const void *data, const char *root, const void *userdata, char **ret) { +- return parse_os_release(root, "ID", ret); ++ return parse_os_release_specifier(root, "ID", ret); + } + + int specifier_os_version_id(char specifier, const void *data, const char *root, const void *userdata, char **ret) { +- return parse_os_release(root, "VERSION_ID", ret); ++ return parse_os_release_specifier(root, "VERSION_ID", ret); + } + + int specifier_os_build_id(char specifier, const void *data, const char *root, const void *userdata, char **ret) { +- return parse_os_release(root, "BUILD_ID", ret); ++ return parse_os_release_specifier(root, "BUILD_ID", ret); + } + + int specifier_os_variant_id(char specifier, const void *data, const char *root, const void *userdata, char **ret) { +- return parse_os_release(root, "VARIANT_ID", ret); ++ return parse_os_release_specifier(root, "VARIANT_ID", ret); + } + + int specifier_os_image_id(char specifier, const void *data, const char *root, const void *userdata, char **ret) { +- return parse_os_release(root, "IMAGE_ID", ret); ++ return parse_os_release_specifier(root, "IMAGE_ID", ret); + } + + int specifier_os_image_version(char specifier, const void *data, const char *root, const void *userdata, char **ret) { +- return parse_os_release(root, "IMAGE_VERSION", ret); ++ return parse_os_release_specifier(root, "IMAGE_VERSION", ret); + } + + int specifier_group_name(char specifier, const void *data, const char *root, const void *userdata, char **ret) { +diff --git a/src/test/test-specifier.c b/src/test/test-specifier.c +index 790f0252d7..a45d1bd0b9 100644 +--- a/src/test/test-specifier.c ++++ b/src/test/test-specifier.c +@@ -104,7 +104,7 @@ TEST(specifiers_missing_data_ok) { + assert_se(streq(resolved, "-----")); + + assert_se(setenv("SYSTEMD_OS_RELEASE", "/nosuchfileordirectory", 1) == 0); +- assert_se(specifier_printf("%A-%B-%M-%o-%w-%W", SIZE_MAX, specifier_table, NULL, NULL, &resolved) == -ENOENT); ++ assert_se(specifier_printf("%A-%B-%M-%o-%w-%W", SIZE_MAX, specifier_table, NULL, NULL, &resolved) == -EUNATCH); + assert_se(streq(resolved, "-----")); + + assert_se(unsetenv("SYSTEMD_OS_RELEASE") == 0); +diff --git a/test/test-systemctl-enable.sh b/test/test-systemctl-enable.sh +index 769341129c..43a2c0a0fb 100644 +--- a/test/test-systemctl-enable.sh ++++ b/test/test-systemctl-enable.sh +@@ -445,12 +445,45 @@ EOF + + check_alias a "$(uname -m | tr '_' '-')" + +-# FIXME: when os-release is not found, we fail we a cryptic error +-# Alias=target@%A.socket ++test ! -e "$root/etc/os-release" ++test ! -e "$root/usr/lib/os-release" ++ ++check_alias A '' && { echo "Expected failure" >&2; exit 1; } ++check_alias B '' && { echo "Expected failure" >&2; exit 1; } ++check_alias M '' && { echo "Expected failure" >&2; exit 1; } ++check_alias o '' && { echo "Expected failure" >&2; exit 1; } ++check_alias w '' && { echo "Expected failure" >&2; exit 1; } ++check_alias W '' && { echo "Expected failure" >&2; exit 1; } ++ ++cat >"$root/etc/os-release" <"$root/etc/os-release" <&2; exit 1; } + +-# FIXME: Failed to enable: No such file or directory. +-# Alias=target@%M.socket ++systemd-id128 new >"$root/etc/machine-id" ++check_alias m "$(cat "$root/etc/machine-id")" + + check_alias n 'some-some-link6@.socket' + check_alias N 'some-some-link6@' + +-# FIXME: Failed to enable: No such file or directory. +-# Alias=target@%o.socket +- + check_alias p 'some-some-link6' + + # FIXME: Failed to enable: Invalid slot. +@@ -509,9 +539,6 @@ check_alias v "$(uname -r)" + # FIXME: Failed to enable: Invalid slot. + # Alias=target@%V.socket + +-# Alias=target@%w.socket +-# Alias=target@%W.socket +- + check_alias % '%' && { echo "Expected failure because % is not legal in unit name" >&2; exit 1; } + + check_alias z 'z' && { echo "Expected failure because %z is not known" >&2; exit 1; } diff --git a/0171-shared-install-provide-proper-error-messages-when-in.patch b/0171-shared-install-provide-proper-error-messages-when-in.patch new file mode 100644 index 0000000..7b886a8 --- /dev/null +++ b/0171-shared-install-provide-proper-error-messages-when-in.patch @@ -0,0 +1,142 @@ +From 256e0d19abd531ab34ed28181ffdae5d5c0dcfed Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Wed, 9 Mar 2022 16:06:24 +0100 +Subject: [PATCH] shared/install: provide proper error messages when invalid + specifiers are used + +$ build/systemctl --root=/tmp/systemctl-test.KXY8fu enable some-some-link6@.socket +Failed to enable unit, invalid specifier in "target@C:%C.socket". + +(cherry picked from commit 19b9d5d0d14f2c9b8be8d0a026b0445168808b94) + +Related: #2082131 +--- + src/shared/install.c | 11 +++++----- + test/test-systemctl-enable.sh | 40 ++++++++++++----------------------- + 2 files changed, 20 insertions(+), 31 deletions(-) + +diff --git a/src/shared/install.c b/src/shared/install.c +index ea5bc36482..fd57488024 100644 +--- a/src/shared/install.c ++++ b/src/shared/install.c +@@ -374,12 +374,16 @@ void unit_file_dump_changes(int r, const char *verb, const UnitFileChange *chang + verb, changes[i].path); + logged = true; + break; +- + case -EADDRNOTAVAIL: + log_error_errno(changes[i].type_or_errno, "Failed to %s unit, unit %s is transient or generated.", + verb, changes[i].path); + logged = true; + break; ++ case -EBADSLT: ++ log_error_errno(changes[i].type_or_errno, "Failed to %s unit, invalid specifier in \"%s\".", ++ verb, changes[i].path); ++ logged = true; ++ break; + case -EIDRM: + log_error_errno(changes[i].type_or_errno, "Failed to %s %s, destination unit %s is a non-template unit.", + verb, changes[i].source, changes[i].path); +@@ -396,18 +400,15 @@ void unit_file_dump_changes(int r, const char *verb, const UnitFileChange *chang + verb, changes[i].path); + logged = true; + break; +- + case -ENOENT: + log_error_errno(changes[i].type_or_errno, "Failed to %s unit, unit %s does not exist.", verb, changes[i].path); + logged = true; + break; +- + case -EUNATCH: + log_error_errno(changes[i].type_or_errno, "Failed to %s unit, cannot resolve specifiers in \"%s\".", + verb, changes[i].path); + logged = true; + break; +- + default: + assert(changes[i].type_or_errno < 0); + log_error_errno(changes[i].type_or_errno, "Failed to %s unit, file \"%s\": %m", +@@ -3343,7 +3344,7 @@ int unit_file_preset_all( + + r = preset_prepare_one(scope, &plus, &minus, &lp, de->d_name, &presets, changes, n_changes); + if (r < 0 && +- !IN_SET(r, -EEXIST, -ERFKILL, -EADDRNOTAVAIL, -EIDRM, -EUCLEAN, -ELOOP, -ENOENT, -EUNATCH)) ++ !IN_SET(r, -EEXIST, -ERFKILL, -EADDRNOTAVAIL, -EBADSLT, -EIDRM, -EUCLEAN, -ELOOP, -ENOENT, -EUNATCH)) + /* Ignore generated/transient/missing/invalid units when applying preset, propagate other errors. + * Coordinate with unit_file_dump_changes() above. */ + return r; +diff --git a/test/test-systemctl-enable.sh b/test/test-systemctl-enable.sh +index 43a2c0a0fb..da1fffe944 100644 +--- a/test/test-systemctl-enable.sh ++++ b/test/test-systemctl-enable.sh +@@ -485,33 +485,31 @@ check_alias W 'right' + + check_alias b "$(systemd-id128 boot-id)" + +-# FIXME: Failed to enable: Invalid slot. +-# Alias=target@%C.socket +-# Alias=target@%E.socket +-# Alias=target@%f.socket ++# Specifiers not available for [Install] ++check_alias C '' && { echo "Expected failure" >&2; exit 1; } ++check_alias E '' && { echo "Expected failure" >&2; exit 1; } ++check_alias f '' && { echo "Expected failure" >&2; exit 1; } ++check_alias h '' && { echo "Expected failure" >&2; exit 1; } ++check_alias I '' && { echo "Expected failure" >&2; exit 1; } ++check_alias J '' && { echo "Expected failure" >&2; exit 1; } ++check_alias L '' && { echo "Expected failure" >&2; exit 1; } ++check_alias P '' && { echo "Expected failure" >&2; exit 1; } ++check_alias s '' && { echo "Expected failure" >&2; exit 1; } ++check_alias S '' && { echo "Expected failure" >&2; exit 1; } ++check_alias t '' && { echo "Expected failure" >&2; exit 1; } ++check_alias T '' && { echo "Expected failure" >&2; exit 1; } ++check_alias V '' && { echo "Expected failure" >&2; exit 1; } + + # FIXME: we use the calling user instead of root :( + check_alias g root || : + check_alias G 0 || : + +-# FIXME: Failed to enable: Invalid slot. +-# Alias=target@%h.socket +- + check_alias i "" + +-# FIXME: Failed to enable: Invalid slot. +-# Alias=target@%I.socket +- + check_alias j 'link6' + +-# FIXME: Failed to enable: Invalid slot. +-# Alias=target@%J.socket +- + check_alias l "$(uname -n | sed 's/\..*//')" + +-# FIXME: Failed to enable: Invalid slot. +-# Alias=target@%L.socket +- + test ! -e "$root/etc/machine-id" + check_alias m '' && { echo "Expected failure" >&2; exit 1; } + +@@ -523,22 +521,12 @@ check_alias N 'some-some-link6@' + + check_alias p 'some-some-link6' + +-# FIXME: Failed to enable: Invalid slot. +-# Alias=target@%P.socket +-# Alias=target@%s.socket +-# Alias=target@%S.socket +-# Alias=target@%t.socket +-# Alias=target@%T.socket +- + # FIXME: we use the calling user instead of root :( + check_alias u root || : + check_alias U 0 || : + + check_alias v "$(uname -r)" + +-# FIXME: Failed to enable: Invalid slot. +-# Alias=target@%V.socket +- + check_alias % '%' && { echo "Expected failure because % is not legal in unit name" >&2; exit 1; } + + check_alias z 'z' && { echo "Expected failure because %z is not known" >&2; exit 1; } diff --git a/0172-shared-install-move-scope-into-InstallContext.patch b/0172-shared-install-move-scope-into-InstallContext.patch new file mode 100644 index 0000000..ed0c624 --- /dev/null +++ b/0172-shared-install-move-scope-into-InstallContext.patch @@ -0,0 +1,1239 @@ +From b6088ce6c68e3f6e50f75ca3d1d60d2dae16dbb9 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Wed, 9 Mar 2022 17:51:36 +0100 +Subject: [PATCH] shared/install: move scope into InstallContext +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This makes it easier to pass it around in preparation for future changes. + +While at it, let's rename InstallContext c → ctx, and InstallInfo i → info. +'c' and 'i' are bad names for variables that are passed through multiple layers +of functions calls. It's easier to follow what is happening with a meaningful +variable names. + +(cherry picked from commit 4a84db4c0c2eef6f40da35347c95dfa6b6e3d139) + +Related: #2082131 +--- + src/shared/install.c | 386 +++++++++++++++++++++---------------------- + 1 file changed, 191 insertions(+), 195 deletions(-) + +diff --git a/src/shared/install.c b/src/shared/install.c +index fd57488024..bfdeee48bf 100644 +--- a/src/shared/install.c ++++ b/src/shared/install.c +@@ -47,6 +47,7 @@ typedef enum SearchFlags { + } SearchFlags; + + typedef struct { ++ UnitFileScope scope; + OrderedHashmap *will_process; + OrderedHashmap *have_processed; + } InstallContext; +@@ -727,7 +728,7 @@ static int find_symlinks_in_directory( + DIR *dir, + const char *dir_path, + const char *root_dir, +- const UnitFileInstallInfo *i, ++ const UnitFileInstallInfo *info, + bool match_aliases, + bool ignore_same_name, + const char *config_path, +@@ -764,17 +765,17 @@ static int find_symlinks_in_directory( + free_and_replace(dest, x); + } + +- assert(unit_name_is_valid(i->name, UNIT_NAME_ANY)); ++ assert(unit_name_is_valid(info->name, UNIT_NAME_ANY)); + if (!ignore_same_name) + /* Check if the symlink itself matches what we are looking for. + * + * If ignore_same_name is specified, we are in one of the directories which + * have lower priority than the unit file, and even if a file or symlink with + * this name was found, we should ignore it. */ +- found_path = streq(de->d_name, i->name); ++ found_path = streq(de->d_name, info->name); + + /* Check if what the symlink points to matches what we are looking for */ +- found_dest = streq(basename(dest), i->name); ++ found_dest = streq(basename(dest), info->name); + + if (found_path && found_dest) { + _cleanup_free_ char *p = NULL, *t = NULL; +@@ -782,7 +783,7 @@ static int find_symlinks_in_directory( + /* Filter out same name links in the main + * config path */ + p = path_make_absolute(de->d_name, dir_path); +- t = path_make_absolute(i->name, config_path); ++ t = path_make_absolute(info->name, config_path); + + if (!p || !t) + return -ENOMEM; +@@ -797,7 +798,7 @@ static int find_symlinks_in_directory( + return 1; + + /* Check if symlink name is in the set of names used by [Install] */ +- q = is_symlink_with_known_name(i, de->d_name); ++ q = is_symlink_with_known_name(info, de->d_name); + if (q < 0) + return q; + if (q > 0) +@@ -867,7 +868,7 @@ static int find_symlinks( + static int find_symlinks_in_scope( + UnitFileScope scope, + const LookupPaths *lp, +- const UnitFileInstallInfo *i, ++ const UnitFileInstallInfo *info, + bool match_name, + UnitFileState *state) { + +@@ -878,7 +879,7 @@ static int find_symlinks_in_scope( + int r; + + assert(lp); +- assert(i); ++ assert(info); + + /* As we iterate over the list of search paths in lp->search_path, we may encounter "same name" + * symlinks. The ones which are "below" (i.e. have lower priority) than the unit file itself are +@@ -887,7 +888,7 @@ static int find_symlinks_in_scope( + STRV_FOREACH(p, lp->search_path) { + bool same_name_link = false; + +- r = find_symlinks(lp->root_dir, i, match_name, ignore_same_name, *p, &same_name_link); ++ r = find_symlinks(lp->root_dir, info, match_name, ignore_same_name, *p, &same_name_link); + if (r < 0) + return r; + if (r > 0) { +@@ -927,7 +928,7 @@ static int find_symlinks_in_scope( + + /* Check if next iteration will be "below" the unit file (either a regular file + * or a symlink), and hence should be ignored */ +- if (!ignore_same_name && path_startswith(i->path, *p)) ++ if (!ignore_same_name && path_startswith(info->path, *p)) + ignore_same_name = true; + } + +@@ -940,7 +941,7 @@ static int find_symlinks_in_scope( + * outside of runtime and configuration directory, then we consider it statically enabled. Note we do that only + * for instance, not for regular names, as those are merely aliases, while instances explicitly instantiate + * something, and hence are a much stronger concept. */ +- if (enabled_at_all && unit_name_is_valid(i->name, UNIT_NAME_INSTANCE)) { ++ if (enabled_at_all && unit_name_is_valid(info->name, UNIT_NAME_INSTANCE)) { + *state = UNIT_FILE_STATIC; + return 1; + } +@@ -960,7 +961,6 @@ static int find_symlinks_in_scope( + } + + static void install_info_free(UnitFileInstallInfo *i) { +- + if (!i) + return; + +@@ -976,21 +976,21 @@ static void install_info_free(UnitFileInstallInfo *i) { + free(i); + } + +-static void install_context_done(InstallContext *c) { +- assert(c); ++static void install_context_done(InstallContext *ctx) { ++ assert(ctx); + +- c->will_process = ordered_hashmap_free_with_destructor(c->will_process, install_info_free); +- c->have_processed = ordered_hashmap_free_with_destructor(c->have_processed, install_info_free); ++ ctx->will_process = ordered_hashmap_free_with_destructor(ctx->will_process, install_info_free); ++ ctx->have_processed = ordered_hashmap_free_with_destructor(ctx->have_processed, install_info_free); + } + +-static UnitFileInstallInfo *install_info_find(InstallContext *c, const char *name) { ++static UnitFileInstallInfo *install_info_find(InstallContext *ctx, const char *name) { + UnitFileInstallInfo *i; + +- i = ordered_hashmap_get(c->have_processed, name); ++ i = ordered_hashmap_get(ctx->have_processed, name); + if (i) + return i; + +- return ordered_hashmap_get(c->will_process, name); ++ return ordered_hashmap_get(ctx->will_process, name); + } + + static int install_info_may_process( +@@ -1024,7 +1024,7 @@ static int install_info_may_process( + * Returns negative on error, 0 if the unit was already known, 1 otherwise. + */ + static int install_info_add( +- InstallContext *c, ++ InstallContext *ctx, + const char *name, + const char *path, + const char *root, +@@ -1034,7 +1034,7 @@ static int install_info_add( + UnitFileInstallInfo *i = NULL; + int r; + +- assert(c); ++ assert(ctx); + + if (!name) { + /* 'name' and 'path' must not both be null. Check here 'path' using assert_se() to +@@ -1047,7 +1047,7 @@ static int install_info_add( + if (!unit_name_is_valid(name, UNIT_NAME_ANY)) + return -EINVAL; + +- i = install_info_find(c, name); ++ i = install_info_find(ctx, name); + if (i) { + i->auxiliary = i->auxiliary && auxiliary; + +@@ -1087,7 +1087,7 @@ static int install_info_add( + } + } + +- r = ordered_hashmap_ensure_put(&c->will_process, &string_hash_ops, i->name, i); ++ r = ordered_hashmap_ensure_put(&ctx->will_process, &string_hash_ops, i->name, i); + if (r < 0) + goto fail; + +@@ -1142,8 +1142,8 @@ static int config_parse_also( + void *data, + void *userdata) { + +- UnitFileInstallInfo *info = userdata; +- InstallContext *c = data; ++ UnitFileInstallInfo *info = ASSERT_PTR(userdata); ++ InstallContext *ctx = ASSERT_PTR(data); + int r; + + assert(unit); +@@ -1165,7 +1165,7 @@ static int config_parse_also( + return log_syntax(unit, LOG_WARNING, filename, line, r, + "Failed to resolve unit name in Also=\"%s\": %m", word); + +- r = install_info_add(c, printed, NULL, info->root, /* auxiliary= */ true, NULL); ++ r = install_info_add(ctx, printed, NULL, info->root, /* auxiliary= */ true, NULL); + if (r < 0) + return r; + +@@ -1191,7 +1191,7 @@ static int config_parse_default_instance( + void *data, + void *userdata) { + +- UnitFileInstallInfo *i = data; ++ UnitFileInstallInfo *info = ASSERT_PTR(userdata); + _cleanup_free_ char *printed = NULL; + int r; + +@@ -1208,7 +1208,7 @@ static int config_parse_default_instance( + return log_syntax(unit, LOG_WARNING, filename, line, 0, + "DefaultInstance= only makes sense for template units, ignoring."); + +- r = install_name_printf(i, rvalue, i->root, &printed); ++ r = install_name_printf(info, rvalue, info->root, &printed); + if (r < 0) + return log_syntax(unit, LOG_WARNING, filename, line, r, + "Failed to resolve instance name in DefaultInstance=\"%s\": %m", rvalue); +@@ -1220,11 +1220,11 @@ static int config_parse_default_instance( + return log_syntax(unit, LOG_WARNING, filename, line, SYNTHETIC_ERRNO(EINVAL), + "Invalid DefaultInstance= value \"%s\".", printed); + +- return free_and_replace(i->default_instance, printed); ++ return free_and_replace(info->default_instance, printed); + } + + static int unit_file_load( +- InstallContext *c, ++ InstallContext *ctx, + UnitFileInstallInfo *info, + const char *path, + const char *root_dir, +@@ -1235,7 +1235,7 @@ static int unit_file_load( + { "Install", "WantedBy", config_parse_strv, 0, &info->wanted_by }, + { "Install", "RequiredBy", config_parse_strv, 0, &info->required_by }, + { "Install", "DefaultInstance", config_parse_default_instance, 0, info }, +- { "Install", "Also", config_parse_also, 0, c }, ++ { "Install", "Also", config_parse_also, 0, ctx }, + {} + }; + +@@ -1308,8 +1308,8 @@ static int unit_file_load( + if (!f) + return -errno; + +- /* c is only needed if we actually load the file (it's referenced from items[] btw, in case you wonder.) */ +- assert(c); ++ /* ctx is only needed if we actually load the file (it's referenced from items[] btw, in case you wonder.) */ ++ assert(ctx); + + r = config_parse(info->name, path, f, + "Install\0" +@@ -1341,14 +1341,14 @@ static int unit_file_load( + } + + static int unit_file_load_or_readlink( +- InstallContext *c, ++ InstallContext *ctx, + UnitFileInstallInfo *info, + const char *path, + const LookupPaths *lp, + SearchFlags flags) { + int r; + +- r = unit_file_load(c, info, path, lp->root_dir, flags); ++ r = unit_file_load(ctx, info, path, lp->root_dir, flags); + if (r != -ELOOP || (flags & SEARCH_DROPIN)) + return r; + +@@ -1371,7 +1371,7 @@ static int unit_file_load_or_readlink( + } + + static int unit_file_search( +- InstallContext *c, ++ InstallContext *ctx, + UnitFileInstallInfo *info, + const LookupPaths *lp, + SearchFlags flags) { +@@ -1391,7 +1391,7 @@ static int unit_file_search( + return 0; + + if (info->path) +- return unit_file_load_or_readlink(c, info, info->path, lp, flags); ++ return unit_file_load_or_readlink(ctx, info, info->path, lp, flags); + + assert(info->name); + +@@ -1408,7 +1408,7 @@ static int unit_file_search( + if (!path) + return -ENOMEM; + +- r = unit_file_load_or_readlink(c, info, path, lp, flags); ++ r = unit_file_load_or_readlink(ctx, info, path, lp, flags); + if (r >= 0) { + info->path = TAKE_PTR(path); + result = r; +@@ -1431,7 +1431,7 @@ static int unit_file_search( + if (!path) + return -ENOMEM; + +- r = unit_file_load_or_readlink(c, info, path, lp, flags); ++ r = unit_file_load_or_readlink(ctx, info, path, lp, flags); + if (r >= 0) { + info->path = TAKE_PTR(path); + result = r; +@@ -1487,7 +1487,7 @@ static int unit_file_search( + return log_debug_errno(r, "Failed to get list of conf files: %m"); + + STRV_FOREACH(p, files) { +- r = unit_file_load_or_readlink(c, info, *p, lp, flags | SEARCH_DROPIN); ++ r = unit_file_load_or_readlink(ctx, info, *p, lp, flags | SEARCH_DROPIN); + if (r < 0) + return log_debug_errno(r, "Failed to load conf file \"%s\": %m", *p); + } +@@ -1496,30 +1496,30 @@ static int unit_file_search( + } + + static int install_info_follow( +- InstallContext *c, +- UnitFileInstallInfo *i, ++ InstallContext *ctx, ++ UnitFileInstallInfo *info, + const LookupPaths *lp, + SearchFlags flags, + bool ignore_different_name) { + +- assert(c); +- assert(i); ++ assert(ctx); ++ assert(info); + +- if (i->type != UNIT_FILE_TYPE_SYMLINK) ++ if (info->type != UNIT_FILE_TYPE_SYMLINK) + return -EINVAL; +- if (!i->symlink_target) ++ if (!info->symlink_target) + return -EINVAL; + + /* If the basename doesn't match, the caller should add a + * complete new entry for this. */ + +- if (!ignore_different_name && !streq(basename(i->symlink_target), i->name)) ++ if (!ignore_different_name && !streq(basename(info->symlink_target), info->name)) + return -EXDEV; + +- free_and_replace(i->path, i->symlink_target); +- i->type = _UNIT_FILE_TYPE_INVALID; ++ free_and_replace(info->path, info->symlink_target); ++ info->type = _UNIT_FILE_TYPE_INVALID; + +- return unit_file_load_or_readlink(c, i, i->path, lp, flags); ++ return unit_file_load_or_readlink(ctx, info, info->path, lp, flags); + } + + /** +@@ -1527,8 +1527,7 @@ static int install_info_follow( + * target, maybe more than once. Propagate the instance name if present. + */ + static int install_info_traverse( +- UnitFileScope scope, +- InstallContext *c, ++ InstallContext *ctx, + const LookupPaths *lp, + UnitFileInstallInfo *start, + SearchFlags flags, +@@ -1540,9 +1539,9 @@ static int install_info_traverse( + + assert(lp); + assert(start); +- assert(c); ++ assert(ctx); + +- r = unit_file_search(c, start, lp, flags); ++ r = unit_file_search(ctx, start, lp, flags); + if (r < 0) + return r; + +@@ -1561,7 +1560,7 @@ static int install_info_traverse( + return -ELOOP; + } + +- r = install_info_follow(c, i, lp, flags, false); ++ r = install_info_follow(ctx, i, lp, flags, false); + if (r == -EXDEV) { + _cleanup_free_ char *buffer = NULL; + const char *bn; +@@ -1590,7 +1589,7 @@ static int install_info_traverse( + /* We filled in the instance, and the target stayed the same? If so, then let's + * honour the link as it is. */ + +- r = install_info_follow(c, i, lp, flags, true); ++ r = install_info_follow(ctx, i, lp, flags, true); + if (r < 0) + return r; + +@@ -1600,12 +1599,12 @@ static int install_info_traverse( + bn = buffer; + } + +- r = install_info_add(c, bn, NULL, lp->root_dir, /* auxiliary= */ false, &i); ++ r = install_info_add(ctx, bn, NULL, lp->root_dir, /* auxiliary= */ false, &i); + if (r < 0) + return r; + + /* Try again, with the new target we found. */ +- r = unit_file_search(c, i, lp, flags); ++ r = unit_file_search(ctx, i, lp, flags); + if (r == -ENOENT) + /* Translate error code to highlight this specific case */ + return -ENOLINK; +@@ -1626,12 +1625,12 @@ static int install_info_traverse( + * or the name (otherwise). root_dir is prepended to the path. + */ + static int install_info_add_auto( +- InstallContext *c, ++ InstallContext *ctx, + const LookupPaths *lp, + const char *name_or_path, + UnitFileInstallInfo **ret) { + +- assert(c); ++ assert(ctx); + assert(name_or_path); + + if (path_is_absolute(name_or_path)) { +@@ -1639,14 +1638,13 @@ static int install_info_add_auto( + + pp = prefix_roota(lp->root_dir, name_or_path); + +- return install_info_add(c, NULL, pp, lp->root_dir, /* auxiliary= */ false, ret); ++ return install_info_add(ctx, NULL, pp, lp->root_dir, /* auxiliary= */ false, ret); + } else +- return install_info_add(c, name_or_path, NULL, lp->root_dir, /* auxiliary= */ false, ret); ++ return install_info_add(ctx, name_or_path, NULL, lp->root_dir, /* auxiliary= */ false, ret); + } + + static int install_info_discover( +- UnitFileScope scope, +- InstallContext *c, ++ InstallContext *ctx, + const LookupPaths *lp, + const char *name, + SearchFlags flags, +@@ -1654,16 +1652,16 @@ static int install_info_discover( + UnitFileChange **changes, + size_t *n_changes) { + +- UnitFileInstallInfo *i; ++ UnitFileInstallInfo *info; + int r; + +- assert(c); ++ assert(ctx); + assert(lp); + assert(name); + +- r = install_info_add_auto(c, lp, name, &i); ++ r = install_info_add_auto(ctx, lp, name, &info); + if (r >= 0) +- r = install_info_traverse(scope, c, lp, i, flags, ret); ++ r = install_info_traverse(ctx, lp, info, flags, ret); + + if (r < 0) + unit_file_changes_add(changes, n_changes, r, name, NULL); +@@ -1671,25 +1669,24 @@ static int install_info_discover( + } + + static int install_info_discover_and_check( +- UnitFileScope scope, +- InstallContext *c, +- const LookupPaths *lp, +- const char *name, +- SearchFlags flags, +- UnitFileInstallInfo **ret, +- UnitFileChange **changes, +- size_t *n_changes) { ++ InstallContext *ctx, ++ const LookupPaths *lp, ++ const char *name, ++ SearchFlags flags, ++ UnitFileInstallInfo **ret, ++ UnitFileChange **changes, ++ size_t *n_changes) { + + int r; + +- r = install_info_discover(scope, c, lp, name, flags, ret, changes, n_changes); ++ r = install_info_discover(ctx, lp, name, flags, ret, changes, n_changes); + if (r < 0) + return r; + + return install_info_may_process(ret ? *ret : NULL, lp, changes, n_changes); + } + +-int unit_file_verify_alias(const UnitFileInstallInfo *i, const char *dst, char **ret_dst) { ++int unit_file_verify_alias(const UnitFileInstallInfo *info, const char *dst, char **ret_dst) { + _cleanup_free_ char *dst_updated = NULL; + int r; + +@@ -1729,13 +1726,13 @@ int unit_file_verify_alias(const UnitFileInstallInfo *i, const char *dst, char * + const bool instance_propagation = type == UNIT_NAME_TEMPLATE; + + /* That's the name we want to use for verification. */ +- r = unit_symlink_name_compatible(path_alias, i->name, instance_propagation); ++ r = unit_symlink_name_compatible(path_alias, info->name, instance_propagation); + if (r < 0) + return log_error_errno(r, "Failed to verify alias validity: %m"); + if (r == 0) + return log_warning_errno(SYNTHETIC_ERRNO(EXDEV), + "Invalid unit \"%s\" symlink \"%s\".", +- i->name, dst); ++ info->name, dst); + + } else { + /* If the symlink target has an instance set and the symlink source doesn't, we "propagate +@@ -1743,9 +1740,9 @@ int unit_file_verify_alias(const UnitFileInstallInfo *i, const char *dst, char * + if (unit_name_is_valid(dst, UNIT_NAME_TEMPLATE)) { + _cleanup_free_ char *inst = NULL; + +- UnitNameFlags type = unit_name_to_instance(i->name, &inst); ++ UnitNameFlags type = unit_name_to_instance(info->name, &inst); + if (type < 0) +- return log_error_errno(type, "Failed to extract instance name from \"%s\": %m", i->name); ++ return log_error_errno(type, "Failed to extract instance name from \"%s\": %m", info->name); + + if (type == UNIT_NAME_INSTANCE) { + r = unit_name_replace_instance(dst, inst, &dst_updated); +@@ -1755,10 +1752,9 @@ int unit_file_verify_alias(const UnitFileInstallInfo *i, const char *dst, char * + } + } + +- r = unit_validate_alias_symlink_and_warn(dst_updated ?: dst, i->name); ++ r = unit_validate_alias_symlink_and_warn(dst_updated ?: dst, info->name); + if (r < 0) + return r; +- + } + + *ret_dst = TAKE_PTR(dst_updated); +@@ -1766,7 +1762,8 @@ int unit_file_verify_alias(const UnitFileInstallInfo *i, const char *dst, char * + } + + static int install_info_symlink_alias( +- UnitFileInstallInfo *i, ++ UnitFileScope scope, ++ UnitFileInstallInfo *info, + const LookupPaths *lp, + const char *config_path, + bool force, +@@ -1776,20 +1773,20 @@ static int install_info_symlink_alias( + char **s; + int r = 0, q; + +- assert(i); ++ assert(info); + assert(lp); + assert(config_path); + +- STRV_FOREACH(s, i->aliases) { ++ STRV_FOREACH(s, info->aliases) { + _cleanup_free_ char *alias_path = NULL, *dst = NULL, *dst_updated = NULL; + +- q = install_name_printf(i, *s, i->root, &dst); ++ q = install_name_printf(info, *s, info->root, &dst); + if (q < 0) { + unit_file_changes_add(changes, n_changes, q, *s, NULL); + return q; + } + +- q = unit_file_verify_alias(i, dst, &dst_updated); ++ q = unit_file_verify_alias(info, dst, &dst_updated); + if (q < 0) + continue; + +@@ -1797,7 +1794,7 @@ static int install_info_symlink_alias( + if (!alias_path) + return -ENOMEM; + +- q = create_symlink(lp, i->path, alias_path, force, changes, n_changes); ++ q = create_symlink(lp, info->path, alias_path, force, changes, n_changes); + if (r == 0) + r = q; + } +@@ -1808,7 +1805,7 @@ static int install_info_symlink_alias( + static int install_info_symlink_wants( + UnitFileScope scope, + UnitFileFlags file_flags, +- UnitFileInstallInfo *i, ++ UnitFileInstallInfo *info, + const LookupPaths *lp, + const char *config_path, + char **list, +@@ -1822,18 +1819,18 @@ static int install_info_symlink_wants( + char **s; + int r = 0, q; + +- assert(i); ++ assert(info); + assert(lp); + assert(config_path); + + if (strv_isempty(list)) + return 0; + +- if (unit_name_is_valid(i->name, UNIT_NAME_PLAIN | UNIT_NAME_INSTANCE)) ++ if (unit_name_is_valid(info->name, UNIT_NAME_PLAIN | UNIT_NAME_INSTANCE)) + /* Not a template unit. Use the name directly. */ +- n = i->name; ++ n = info->name; + +- else if (i->default_instance) { ++ else if (info->default_instance) { + UnitFileInstallInfo instance = { + .type = _UNIT_FILE_TYPE_INVALID, + }; +@@ -1841,7 +1838,7 @@ static int install_info_symlink_wants( + + /* If this is a template, and we have a default instance, use it. */ + +- r = unit_name_replace_instance(i->name, i->default_instance, &buf); ++ r = unit_name_replace_instance(info->name, info->default_instance, &buf); + if (r < 0) + return r; + +@@ -1864,13 +1861,13 @@ static int install_info_symlink_wants( + * the instance from that unit. Cannot be used with non-instance units. */ + + valid_dst_type = UNIT_NAME_INSTANCE | UNIT_NAME_TEMPLATE; +- n = i->name; ++ n = info->name; + } + + STRV_FOREACH(s, list) { + _cleanup_free_ char *path = NULL, *dst = NULL; + +- q = install_name_printf(i, *s, i->root, &dst); ++ q = install_name_printf(info, *s, info->root, &dst); + if (q < 0) { + unit_file_changes_add(changes, n_changes, q, *s, NULL); + return q; +@@ -1902,19 +1899,19 @@ static int install_info_symlink_wants( + if (!path) + return -ENOMEM; + +- q = create_symlink(lp, i->path, path, true, changes, n_changes); ++ q = create_symlink(lp, info->path, path, true, changes, n_changes); + if (r == 0) + r = q; + + if (unit_file_exists(scope, lp, dst) == 0) +- unit_file_changes_add(changes, n_changes, UNIT_FILE_DESTINATION_NOT_PRESENT, dst, i->path); ++ unit_file_changes_add(changes, n_changes, UNIT_FILE_DESTINATION_NOT_PRESENT, dst, info->path); + } + + return r; + } + + static int install_info_symlink_link( +- UnitFileInstallInfo *i, ++ UnitFileInstallInfo *info, + const LookupPaths *lp, + const char *config_path, + bool force, +@@ -1924,28 +1921,28 @@ static int install_info_symlink_link( + _cleanup_free_ char *path = NULL; + int r; + +- assert(i); ++ assert(info); + assert(lp); + assert(config_path); +- assert(i->path); ++ assert(info->path); + +- r = in_search_path(lp, i->path); ++ r = in_search_path(lp, info->path); + if (r < 0) + return r; + if (r > 0) + return 0; + +- path = path_join(config_path, i->name); ++ path = path_join(config_path, info->name); + if (!path) + return -ENOMEM; + +- return create_symlink(lp, i->path, path, force, changes, n_changes); ++ return create_symlink(lp, info->path, path, force, changes, n_changes); + } + + static int install_info_apply( + UnitFileScope scope, + UnitFileFlags file_flags, +- UnitFileInstallInfo *i, ++ UnitFileInstallInfo *info, + const LookupPaths *lp, + const char *config_path, + UnitFileChange **changes, +@@ -1953,26 +1950,26 @@ static int install_info_apply( + + int r, q; + +- assert(i); ++ assert(info); + assert(lp); + assert(config_path); + +- if (i->type != UNIT_FILE_TYPE_REGULAR) ++ if (info->type != UNIT_FILE_TYPE_REGULAR) + return 0; + + bool force = file_flags & UNIT_FILE_FORCE; + +- r = install_info_symlink_alias(i, lp, config_path, force, changes, n_changes); ++ r = install_info_symlink_alias(scope, info, lp, config_path, force, changes, n_changes); + +- q = install_info_symlink_wants(scope, file_flags, i, lp, config_path, i->wanted_by, ".wants/", changes, n_changes); ++ q = install_info_symlink_wants(scope, file_flags, info, lp, config_path, info->wanted_by, ".wants/", changes, n_changes); + if (r == 0) + r = q; + +- q = install_info_symlink_wants(scope, file_flags, i, lp, config_path, i->required_by, ".requires/", changes, n_changes); ++ q = install_info_symlink_wants(scope, file_flags, info, lp, config_path, info->required_by, ".requires/", changes, n_changes); + if (r == 0) + r = q; + +- q = install_info_symlink_link(i, lp, config_path, force, changes, n_changes); ++ q = install_info_symlink_link(info, lp, config_path, force, changes, n_changes); + /* Do not count links to the unit file towards the "carries_install_info" count */ + if (r == 0 && q < 0) + r = q; +@@ -1981,10 +1978,9 @@ static int install_info_apply( + } + + static int install_context_apply( +- UnitFileScope scope, +- UnitFileFlags file_flags, +- InstallContext *c, ++ InstallContext *ctx, + const LookupPaths *lp, ++ UnitFileFlags file_flags, + const char *config_path, + SearchFlags flags, + UnitFileChange **changes, +@@ -1993,26 +1989,26 @@ static int install_context_apply( + UnitFileInstallInfo *i; + int r; + +- assert(c); ++ assert(ctx); + assert(lp); + assert(config_path); + +- if (ordered_hashmap_isempty(c->will_process)) ++ if (ordered_hashmap_isempty(ctx->will_process)) + return 0; + +- r = ordered_hashmap_ensure_allocated(&c->have_processed, &string_hash_ops); ++ r = ordered_hashmap_ensure_allocated(&ctx->have_processed, &string_hash_ops); + if (r < 0) + return r; + + r = 0; +- while ((i = ordered_hashmap_first(c->will_process))) { ++ while ((i = ordered_hashmap_first(ctx->will_process))) { + int q; + +- q = ordered_hashmap_move_one(c->have_processed, c->will_process, i->name); ++ q = ordered_hashmap_move_one(ctx->have_processed, ctx->will_process, i->name); + if (q < 0) + return q; + +- q = install_info_traverse(scope, c, lp, i, flags, NULL); ++ q = install_info_traverse(ctx, lp, i, flags, NULL); + if (q < 0) { + if (i->auxiliary) { + q = unit_file_changes_add(changes, n_changes, UNIT_FILE_AUXILIARY_FAILED, NULL, i->name); +@@ -2039,7 +2035,7 @@ static int install_context_apply( + if (i->type != UNIT_FILE_TYPE_REGULAR) + continue; + +- q = install_info_apply(scope, file_flags, i, lp, config_path, changes, n_changes); ++ q = install_info_apply(ctx->scope, file_flags, i, lp, config_path, changes, n_changes); + if (r >= 0) { + if (q < 0) + r = q; +@@ -2052,8 +2048,7 @@ static int install_context_apply( + } + + static int install_context_mark_for_removal( +- UnitFileScope scope, +- InstallContext *c, ++ InstallContext *ctx, + const LookupPaths *lp, + Set **remove_symlinks_to, + const char *config_path, +@@ -2063,26 +2058,26 @@ static int install_context_mark_for_removal( + UnitFileInstallInfo *i; + int r; + +- assert(c); ++ assert(ctx); + assert(lp); + assert(config_path); + + /* Marks all items for removal */ + +- if (ordered_hashmap_isempty(c->will_process)) ++ if (ordered_hashmap_isempty(ctx->will_process)) + return 0; + +- r = ordered_hashmap_ensure_allocated(&c->have_processed, &string_hash_ops); ++ r = ordered_hashmap_ensure_allocated(&ctx->have_processed, &string_hash_ops); + if (r < 0) + return r; + +- while ((i = ordered_hashmap_first(c->will_process))) { ++ while ((i = ordered_hashmap_first(ctx->will_process))) { + +- r = ordered_hashmap_move_one(c->have_processed, c->will_process, i->name); ++ r = ordered_hashmap_move_one(ctx->have_processed, ctx->will_process, i->name); + if (r < 0) + return r; + +- r = install_info_traverse(scope, c, lp, i, SEARCH_LOAD|SEARCH_FOLLOW_CONFIG_SYMLINKS, NULL); ++ r = install_info_traverse(ctx, lp, i, SEARCH_LOAD|SEARCH_FOLLOW_CONFIG_SYMLINKS, NULL); + if (r == -ENOLINK) { + log_debug_errno(r, "Name %s leads to a dangling symlink, removing name.", i->name); + unit_file_changes_add(changes, n_changes, UNIT_FILE_IS_DANGLING, i->path ?: i->name, NULL); +@@ -2521,8 +2516,8 @@ int unit_file_add_dependency( + size_t *n_changes) { + + _cleanup_(lookup_paths_free) LookupPaths lp = {}; +- _cleanup_(install_context_done) InstallContext c = {}; +- UnitFileInstallInfo *i, *target_info; ++ _cleanup_(install_context_done) InstallContext ctx = { .scope = scope }; ++ UnitFileInstallInfo *info, *target_info; + const char *config_path; + char **f; + int r; +@@ -2545,7 +2540,7 @@ int unit_file_add_dependency( + if (!config_path) + return -ENXIO; + +- r = install_info_discover_and_check(scope, &c, &lp, target, SEARCH_FOLLOW_CONFIG_SYMLINKS, ++ r = install_info_discover_and_check(&ctx, &lp, target, SEARCH_FOLLOW_CONFIG_SYMLINKS, + &target_info, changes, n_changes); + if (r < 0) + return r; +@@ -2555,21 +2550,21 @@ int unit_file_add_dependency( + STRV_FOREACH(f, files) { + char ***l; + +- r = install_info_discover_and_check(scope, &c, &lp, *f, SEARCH_FOLLOW_CONFIG_SYMLINKS, +- &i, changes, n_changes); ++ r = install_info_discover_and_check(&ctx, &lp, *f, SEARCH_FOLLOW_CONFIG_SYMLINKS, ++ &info, changes, n_changes); + if (r < 0) + return r; + +- assert(i->type == UNIT_FILE_TYPE_REGULAR); ++ assert(info->type == UNIT_FILE_TYPE_REGULAR); + + /* We didn't actually load anything from the unit + * file, but instead just add in our new symlink to + * create. */ + + if (dep == UNIT_WANTS) +- l = &i->wanted_by; ++ l = &info->wanted_by; + else +- l = &i->required_by; ++ l = &info->required_by; + + strv_free(*l); + *l = strv_new(target_info->name); +@@ -2577,7 +2572,7 @@ int unit_file_add_dependency( + return -ENOMEM; + } + +- return install_context_apply(scope, file_flags, &c, &lp, config_path, ++ return install_context_apply(&ctx, &lp, file_flags, config_path, + SEARCH_FOLLOW_CONFIG_SYMLINKS, changes, n_changes); + } + +@@ -2590,9 +2585,9 @@ int unit_file_enable( + size_t *n_changes) { + + _cleanup_(lookup_paths_free) LookupPaths lp = {}; +- _cleanup_(install_context_done) InstallContext c = {}; ++ _cleanup_(install_context_done) InstallContext ctx = { .scope = scope }; + const char *config_path; +- UnitFileInstallInfo *i; ++ UnitFileInstallInfo *info; + char **f; + int r; + +@@ -2608,12 +2603,12 @@ int unit_file_enable( + return -ENXIO; + + STRV_FOREACH(f, files) { +- r = install_info_discover_and_check(scope, &c, &lp, *f, SEARCH_LOAD|SEARCH_FOLLOW_CONFIG_SYMLINKS, +- &i, changes, n_changes); ++ r = install_info_discover_and_check(&ctx, &lp, *f, SEARCH_LOAD|SEARCH_FOLLOW_CONFIG_SYMLINKS, ++ &info, changes, n_changes); + if (r < 0) + return r; + +- assert(i->type == UNIT_FILE_TYPE_REGULAR); ++ assert(info->type == UNIT_FILE_TYPE_REGULAR); + } + + /* This will return the number of symlink rules that were +@@ -2621,7 +2616,8 @@ int unit_file_enable( + is useful to determine whether the passed files had any + installation data at all. */ + +- return install_context_apply(scope, file_flags, &c, &lp, config_path, SEARCH_LOAD, changes, n_changes); ++ return install_context_apply(&ctx, &lp, file_flags, config_path, ++ SEARCH_LOAD, changes, n_changes); + } + + int unit_file_disable( +@@ -2633,7 +2629,7 @@ int unit_file_disable( + size_t *n_changes) { + + _cleanup_(lookup_paths_free) LookupPaths lp = {}; +- _cleanup_(install_context_done) InstallContext c = {}; ++ _cleanup_(install_context_done) InstallContext ctx = { .scope = scope }; + _cleanup_set_free_free_ Set *remove_symlinks_to = NULL; + const char *config_path; + char **i; +@@ -2654,12 +2650,12 @@ int unit_file_disable( + if (!unit_name_is_valid(*i, UNIT_NAME_ANY)) + return -EINVAL; + +- r = install_info_add(&c, *i, NULL, lp.root_dir, /* auxiliary= */ false, NULL); ++ r = install_info_add(&ctx, *i, NULL, lp.root_dir, /* auxiliary= */ false, NULL); + if (r < 0) + return r; + } + +- r = install_context_mark_for_removal(scope, &c, &lp, &remove_symlinks_to, config_path, changes, n_changes); ++ r = install_context_mark_for_removal(&ctx, &lp, &remove_symlinks_to, config_path, changes, n_changes); + if (r < 0) + return r; + +@@ -2702,8 +2698,8 @@ int unit_file_set_default( + size_t *n_changes) { + + _cleanup_(lookup_paths_free) LookupPaths lp = {}; +- _cleanup_(install_context_done) InstallContext c = {}; +- UnitFileInstallInfo *i; ++ _cleanup_(install_context_done) InstallContext ctx = { .scope = scope }; ++ UnitFileInstallInfo *info; + const char *new_path; + int r; + +@@ -2720,12 +2716,12 @@ int unit_file_set_default( + if (r < 0) + return r; + +- r = install_info_discover_and_check(scope, &c, &lp, name, 0, &i, changes, n_changes); ++ r = install_info_discover_and_check(&ctx, &lp, name, 0, &info, changes, n_changes); + if (r < 0) + return r; + + new_path = strjoina(lp.persistent_config, "/" SPECIAL_DEFAULT_TARGET); +- return create_symlink(&lp, i->path, new_path, !!(flags & UNIT_FILE_FORCE), changes, n_changes); ++ return create_symlink(&lp, info->path, new_path, flags & UNIT_FILE_FORCE, changes, n_changes); + } + + int unit_file_get_default( +@@ -2734,8 +2730,8 @@ int unit_file_get_default( + char **name) { + + _cleanup_(lookup_paths_free) LookupPaths lp = {}; +- _cleanup_(install_context_done) InstallContext c = {}; +- UnitFileInstallInfo *i; ++ _cleanup_(install_context_done) InstallContext ctx = { .scope = scope }; ++ UnitFileInstallInfo *info; + char *n; + int r; + +@@ -2747,15 +2743,15 @@ int unit_file_get_default( + if (r < 0) + return r; + +- r = install_info_discover(scope, &c, &lp, SPECIAL_DEFAULT_TARGET, SEARCH_FOLLOW_CONFIG_SYMLINKS, +- &i, NULL, NULL); ++ r = install_info_discover(&ctx, &lp, SPECIAL_DEFAULT_TARGET, SEARCH_FOLLOW_CONFIG_SYMLINKS, ++ &info, NULL, NULL); + if (r < 0) + return r; +- r = install_info_may_process(i, &lp, NULL, 0); ++ r = install_info_may_process(info, &lp, NULL, 0); + if (r < 0) + return r; + +- n = strdup(i->name); ++ n = strdup(info->name); + if (!n) + return -ENOMEM; + +@@ -2769,8 +2765,8 @@ int unit_file_lookup_state( + const char *name, + UnitFileState *ret) { + +- _cleanup_(install_context_done) InstallContext c = {}; +- UnitFileInstallInfo *i; ++ _cleanup_(install_context_done) InstallContext ctx = { .scope = scope }; ++ UnitFileInstallInfo *info; + UnitFileState state; + int r; + +@@ -2780,23 +2776,23 @@ int unit_file_lookup_state( + if (!unit_name_is_valid(name, UNIT_NAME_ANY)) + return -EINVAL; + +- r = install_info_discover(scope, &c, lp, name, SEARCH_LOAD|SEARCH_FOLLOW_CONFIG_SYMLINKS, +- &i, NULL, NULL); ++ r = install_info_discover(&ctx, lp, name, SEARCH_LOAD|SEARCH_FOLLOW_CONFIG_SYMLINKS, ++ &info, NULL, NULL); + if (r < 0) + return log_debug_errno(r, "Failed to discover unit %s: %m", name); + +- assert(IN_SET(i->type, UNIT_FILE_TYPE_REGULAR, UNIT_FILE_TYPE_MASKED)); +- log_debug("Found unit %s at %s (%s)", name, strna(i->path), +- i->type == UNIT_FILE_TYPE_REGULAR ? "regular file" : "mask"); ++ assert(IN_SET(info->type, UNIT_FILE_TYPE_REGULAR, UNIT_FILE_TYPE_MASKED)); ++ log_debug("Found unit %s at %s (%s)", name, strna(info->path), ++ info->type == UNIT_FILE_TYPE_REGULAR ? "regular file" : "mask"); + + /* Shortcut things, if the caller just wants to know if this unit exists. */ + if (!ret) + return 0; + +- switch (i->type) { ++ switch (info->type) { + + case UNIT_FILE_TYPE_MASKED: +- r = path_is_runtime(lp, i->path, true); ++ r = path_is_runtime(lp, info->path, true); + if (r < 0) + return r; + +@@ -2805,12 +2801,12 @@ int unit_file_lookup_state( + + case UNIT_FILE_TYPE_REGULAR: + /* Check if the name we were querying is actually an alias */ +- if (!streq(name, basename(i->path)) && !unit_name_is_valid(i->name, UNIT_NAME_INSTANCE)) { ++ if (!streq(name, basename(info->path)) && !unit_name_is_valid(info->name, UNIT_NAME_INSTANCE)) { + state = UNIT_FILE_ALIAS; + break; + } + +- r = path_is_generator(lp, i->path); ++ r = path_is_generator(lp, info->path); + if (r < 0) + return r; + if (r > 0) { +@@ -2818,7 +2814,7 @@ int unit_file_lookup_state( + break; + } + +- r = path_is_transient(lp, i->path); ++ r = path_is_transient(lp, info->path); + if (r < 0) + return r; + if (r > 0) { +@@ -2829,7 +2825,7 @@ int unit_file_lookup_state( + /* Check if any of the Alias= symlinks have been created. + * We ignore other aliases, and only check those that would + * be created by systemctl enable for this unit. */ +- r = find_symlinks_in_scope(scope, lp, i, true, &state); ++ r = find_symlinks_in_scope(scope, lp, info, true, &state); + if (r < 0) + return r; + if (r > 0) +@@ -2837,15 +2833,15 @@ int unit_file_lookup_state( + + /* Check if the file is known under other names. If it is, + * it might be in use. Report that as UNIT_FILE_INDIRECT. */ +- r = find_symlinks_in_scope(scope, lp, i, false, &state); ++ r = find_symlinks_in_scope(scope, lp, info, false, &state); + if (r < 0) + return r; + if (r > 0) + state = UNIT_FILE_INDIRECT; + else { +- if (unit_file_install_info_has_rules(i)) ++ if (unit_file_install_info_has_rules(info)) + state = UNIT_FILE_DISABLED; +- else if (unit_file_install_info_has_also(i)) ++ else if (unit_file_install_info_has_also(info)) + state = UNIT_FILE_INDIRECT; + else + state = UNIT_FILE_STATIC; +@@ -2882,7 +2878,7 @@ int unit_file_get_state( + } + + int unit_file_exists(UnitFileScope scope, const LookupPaths *lp, const char *name) { +- _cleanup_(install_context_done) InstallContext c = {}; ++ _cleanup_(install_context_done) InstallContext c = { .scope = scope }; + int r; + + assert(lp); +@@ -2891,7 +2887,7 @@ int unit_file_exists(UnitFileScope scope, const LookupPaths *lp, const char *nam + if (!unit_name_is_valid(name, UNIT_NAME_ANY)) + return -EINVAL; + +- r = install_info_discover(scope, &c, lp, name, 0, NULL, NULL, NULL); ++ r = install_info_discover(&c, lp, name, 0, NULL, NULL, NULL); + if (r == -ENOENT) + return 0; + if (r < 0) +@@ -3150,7 +3146,6 @@ int unit_file_query_preset(UnitFileScope scope, const char *root_dir, const char + } + + static int execute_preset( +- UnitFileScope scope, + UnitFileFlags file_flags, + InstallContext *plus, + InstallContext *minus, +@@ -3171,7 +3166,7 @@ static int execute_preset( + if (mode != UNIT_FILE_PRESET_ENABLE_ONLY) { + _cleanup_set_free_free_ Set *remove_symlinks_to = NULL; + +- r = install_context_mark_for_removal(scope, minus, lp, &remove_symlinks_to, config_path, changes, n_changes); ++ r = install_context_mark_for_removal(minus, lp, &remove_symlinks_to, config_path, changes, n_changes); + if (r < 0) + return r; + +@@ -3183,9 +3178,10 @@ static int execute_preset( + int q; + + /* Returns number of symlinks that where supposed to be installed. */ +- q = install_context_apply(scope, ++ q = install_context_apply(plus, lp, + file_flags | UNIT_FILE_IGNORE_AUXILIARY_FAILURE, +- plus, lp, config_path, SEARCH_LOAD, changes, n_changes); ++ config_path, ++ SEARCH_LOAD, changes, n_changes); + if (r >= 0) { + if (q < 0) + r = q; +@@ -3207,20 +3203,20 @@ static int preset_prepare_one( + UnitFileChange **changes, + size_t *n_changes) { + +- _cleanup_(install_context_done) InstallContext tmp = {}; ++ _cleanup_(install_context_done) InstallContext tmp = { .scope = scope }; + _cleanup_strv_free_ char **instance_name_list = NULL; +- UnitFileInstallInfo *i; ++ UnitFileInstallInfo *info; + int r; + + if (install_info_find(plus, name) || install_info_find(minus, name)) + return 0; + +- r = install_info_discover(scope, &tmp, lp, name, SEARCH_FOLLOW_CONFIG_SYMLINKS, +- &i, changes, n_changes); ++ r = install_info_discover(&tmp, lp, name, SEARCH_FOLLOW_CONFIG_SYMLINKS, ++ &info, changes, n_changes); + if (r < 0) + return r; +- if (!streq(name, i->name)) { +- log_debug("Skipping %s because it is an alias for %s.", name, i->name); ++ if (!streq(name, info->name)) { ++ log_debug("Skipping %s because it is an alias for %s.", name, info->name); + return 0; + } + +@@ -3232,21 +3228,21 @@ static int preset_prepare_one( + if (instance_name_list) { + char **s; + STRV_FOREACH(s, instance_name_list) { +- r = install_info_discover_and_check(scope, plus, lp, *s, SEARCH_LOAD|SEARCH_FOLLOW_CONFIG_SYMLINKS, +- &i, changes, n_changes); ++ r = install_info_discover_and_check(plus, lp, *s, SEARCH_LOAD|SEARCH_FOLLOW_CONFIG_SYMLINKS, ++ &info, changes, n_changes); + if (r < 0) + return r; + } + } else { +- r = install_info_discover_and_check(scope, plus, lp, name, SEARCH_LOAD|SEARCH_FOLLOW_CONFIG_SYMLINKS, +- &i, changes, n_changes); ++ r = install_info_discover_and_check(plus, lp, name, SEARCH_LOAD|SEARCH_FOLLOW_CONFIG_SYMLINKS, ++ &info, changes, n_changes); + if (r < 0) + return r; + } + + } else +- r = install_info_discover(scope, minus, lp, name, SEARCH_FOLLOW_CONFIG_SYMLINKS, +- &i, changes, n_changes); ++ r = install_info_discover(minus, lp, name, SEARCH_FOLLOW_CONFIG_SYMLINKS, ++ &info, changes, n_changes); + + return r; + } +@@ -3289,7 +3285,7 @@ int unit_file_preset( + return r; + } + +- return execute_preset(scope, file_flags, &plus, &minus, &lp, config_path, files, mode, changes, n_changes); ++ return execute_preset(file_flags, &plus, &minus, &lp, config_path, files, mode, changes, n_changes); + } + + int unit_file_preset_all( +@@ -3351,7 +3347,7 @@ int unit_file_preset_all( + } + } + +- return execute_preset(scope, file_flags, &plus, &minus, &lp, config_path, NULL, mode, changes, n_changes); ++ return execute_preset(file_flags, &plus, &minus, &lp, config_path, NULL, mode, changes, n_changes); + } + + static UnitFileList* unit_file_list_free_one(UnitFileList *f) { diff --git a/0173-shared-specifier-fix-u-U-g-G-when-called-as-unprivil.patch b/0173-shared-specifier-fix-u-U-g-G-when-called-as-unprivil.patch new file mode 100644 index 0000000..ec381a7 --- /dev/null +++ b/0173-shared-specifier-fix-u-U-g-G-when-called-as-unprivil.patch @@ -0,0 +1,549 @@ +From 87df0601074b024ab591534e0e78b2d1e7013a8d Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Wed, 9 Mar 2022 22:29:19 +0100 +Subject: [PATCH] shared/specifier: fix %u/%U/%g/%G when called as unprivileged + user +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +We would resolve those specifiers to the calling user/group. This is mostly OK +when done in the manager, because the manager generally operates as root +in system mode, and a non-root in user mode. It would still be wrong if +called with --test though. But in systemctl, this would be generally wrong, +since we can call 'systemctl --system' as a normal user, either for testing +or even for actual operation with '--root=…'. + +When operating in --global mode, %u/%U/%g/%G should return an error. + +The information whether we're operating in system mode, user mode, or global +mode is passed as the data pointer to specifier_group_name(), specifier_user_name(), +specifier_group_id(), specifier_user_id(). We can't use userdata, because +it's already used for other things. + +(cherry picked from commit 172e9cc3ee3dcca288d04c744984a9a3b2a0d008) + +Related: #2082131 +--- + src/core/unit-printf.c | 4 +- + src/shared/install-printf.c | 9 ++- + src/shared/install-printf.h | 7 ++- + src/shared/install.c | 9 +-- + src/shared/specifier.c | 52 ++++++++++++++--- + src/shared/specifier.h | 10 ++-- + src/test/test-load-fragment.c | 101 +++++++++++++++++++--------------- + src/test/test-specifier.c | 3 +- + src/tmpfiles/tmpfiles.c | 53 +++++++++--------- + test/test-systemctl-enable.sh | 11 ++-- + test/test-systemd-tmpfiles.py | 8 +-- + 11 files changed, 163 insertions(+), 104 deletions(-) + +diff --git a/src/core/unit-printf.c b/src/core/unit-printf.c +index 46c383b841..3086356419 100644 +--- a/src/core/unit-printf.c ++++ b/src/core/unit-printf.c +@@ -190,7 +190,7 @@ int unit_name_printf(const Unit *u, const char* format, char **ret) { + + COMMON_SYSTEM_SPECIFIERS, + +- COMMON_CREDS_SPECIFIERS, ++ COMMON_CREDS_SPECIFIERS(u->manager->unit_file_scope), + {} + }; + +@@ -256,7 +256,7 @@ int unit_full_printf_full(const Unit *u, const char *format, size_t max_length, + + COMMON_SYSTEM_SPECIFIERS, + +- COMMON_CREDS_SPECIFIERS, ++ COMMON_CREDS_SPECIFIERS(u->manager->unit_file_scope), + + COMMON_TMP_SPECIFIERS, + {} +diff --git a/src/shared/install-printf.c b/src/shared/install-printf.c +index 6ff4198ac9..963102674b 100644 +--- a/src/shared/install-printf.c ++++ b/src/shared/install-printf.c +@@ -103,7 +103,12 @@ static int specifier_last_component(char specifier, const void *data, const char + return 0; + } + +-int install_name_printf(const UnitFileInstallInfo *i, const char *format, const char *root, char **ret) { ++int install_name_printf( ++ UnitFileScope scope, ++ const UnitFileInstallInfo *i, ++ const char *format, ++ const char *root, ++ char **ret) { + /* This is similar to unit_name_printf() */ + + const Specifier table[] = { +@@ -115,7 +120,7 @@ int install_name_printf(const UnitFileInstallInfo *i, const char *format, const + + COMMON_SYSTEM_SPECIFIERS, + +- COMMON_CREDS_SPECIFIERS, ++ COMMON_CREDS_SPECIFIERS(scope), + {} + }; + +diff --git a/src/shared/install-printf.h b/src/shared/install-printf.h +index 5ca9406797..d2cccdf66d 100644 +--- a/src/shared/install-printf.h ++++ b/src/shared/install-printf.h +@@ -4,4 +4,9 @@ + #include "install.h" + #include "unit-name.h" + +-int install_name_printf(const UnitFileInstallInfo *i, const char *format, const char *root, char **ret); ++int install_name_printf( ++ UnitFileScope scope, ++ const UnitFileInstallInfo *i, ++ const char *format, ++ const char *root, ++ char **ret); +diff --git a/src/shared/install.c b/src/shared/install.c +index bfdeee48bf..8d82cb6b16 100644 +--- a/src/shared/install.c ++++ b/src/shared/install.c +@@ -1160,7 +1160,7 @@ static int config_parse_also( + if (r == 0) + break; + +- r = install_name_printf(info, word, info->root, &printed); ++ r = install_name_printf(ctx->scope, info, word, info->root, &printed); + if (r < 0) + return log_syntax(unit, LOG_WARNING, filename, line, r, + "Failed to resolve unit name in Also=\"%s\": %m", word); +@@ -1191,6 +1191,7 @@ static int config_parse_default_instance( + void *data, + void *userdata) { + ++ InstallContext *ctx = ASSERT_PTR(data); + UnitFileInstallInfo *info = ASSERT_PTR(userdata); + _cleanup_free_ char *printed = NULL; + int r; +@@ -1208,7 +1209,7 @@ static int config_parse_default_instance( + return log_syntax(unit, LOG_WARNING, filename, line, 0, + "DefaultInstance= only makes sense for template units, ignoring."); + +- r = install_name_printf(info, rvalue, info->root, &printed); ++ r = install_name_printf(ctx->scope, info, rvalue, info->root, &printed); + if (r < 0) + return log_syntax(unit, LOG_WARNING, filename, line, r, + "Failed to resolve instance name in DefaultInstance=\"%s\": %m", rvalue); +@@ -1780,7 +1781,7 @@ static int install_info_symlink_alias( + STRV_FOREACH(s, info->aliases) { + _cleanup_free_ char *alias_path = NULL, *dst = NULL, *dst_updated = NULL; + +- q = install_name_printf(info, *s, info->root, &dst); ++ q = install_name_printf(scope, info, *s, info->root, &dst); + if (q < 0) { + unit_file_changes_add(changes, n_changes, q, *s, NULL); + return q; +@@ -1867,7 +1868,7 @@ static int install_info_symlink_wants( + STRV_FOREACH(s, list) { + _cleanup_free_ char *path = NULL, *dst = NULL; + +- q = install_name_printf(info, *s, info->root, &dst); ++ q = install_name_printf(scope, info, *s, info->root, &dst); + if (q < 0) { + unit_file_changes_add(changes, n_changes, q, *s, NULL); + return q; +diff --git a/src/shared/specifier.c b/src/shared/specifier.c +index a917378427..ac353a651c 100644 +--- a/src/shared/specifier.c ++++ b/src/shared/specifier.c +@@ -21,6 +21,7 @@ + #include "specifier.h" + #include "string-util.h" + #include "strv.h" ++#include "unit-file.h" + #include "user-util.h" + + /* +@@ -253,9 +254,15 @@ int specifier_os_image_version(char specifier, const void *data, const char *roo + } + + int specifier_group_name(char specifier, const void *data, const char *root, const void *userdata, char **ret) { ++ UnitFileScope scope = PTR_TO_INT(data); + char *t; + +- t = gid_to_name(getgid()); ++ assert(ret); ++ ++ if (scope == UNIT_FILE_GLOBAL) ++ return -EINVAL; ++ ++ t = gid_to_name(scope == UNIT_FILE_USER ? getgid() : 0); + if (!t) + return -ENOMEM; + +@@ -264,23 +271,42 @@ int specifier_group_name(char specifier, const void *data, const char *root, con + } + + int specifier_group_id(char specifier, const void *data, const char *root, const void *userdata, char **ret) { +- if (asprintf(ret, UID_FMT, getgid()) < 0) ++ UnitFileScope scope = PTR_TO_INT(data); ++ gid_t gid; ++ ++ assert(ret); ++ ++ if (scope == UNIT_FILE_GLOBAL) ++ return -EINVAL; ++ ++ gid = scope == UNIT_FILE_USER ? getgid() : 0; ++ ++ if (asprintf(ret, UID_FMT, gid) < 0) + return -ENOMEM; + + return 0; + } + + int specifier_user_name(char specifier, const void *data, const char *root, const void *userdata, char **ret) { ++ UnitFileScope scope = PTR_TO_INT(data); ++ uid_t uid; + char *t; + +- /* If we are UID 0 (root), this will not result in NSS, otherwise it might. This is good, as we want to be able +- * to run this in PID 1, where our user ID is 0, but where NSS lookups are not allowed. ++ assert(ret); + +- * We don't use getusername_malloc() here, because we don't want to look at $USER, to remain consistent with +- * specifer_user_id() below. ++ if (scope == UNIT_FILE_GLOBAL) ++ return -EINVAL; ++ ++ uid = scope == UNIT_FILE_USER ? getuid() : 0; ++ ++ /* If we are UID 0 (root), this will not result in NSS, otherwise it might. This is good, as we want ++ * to be able to run this in PID 1, where our user ID is 0, but where NSS lookups are not allowed. ++ ++ * We don't use getusername_malloc() here, because we don't want to look at $USER, to remain ++ * consistent with specifer_user_id() below. + */ + +- t = uid_to_name(getuid()); ++ t = uid_to_name(uid); + if (!t) + return -ENOMEM; + +@@ -289,7 +315,17 @@ int specifier_user_name(char specifier, const void *data, const char *root, cons + } + + int specifier_user_id(char specifier, const void *data, const char *root, const void *userdata, char **ret) { +- if (asprintf(ret, UID_FMT, getuid()) < 0) ++ UnitFileScope scope = PTR_TO_INT(data); ++ uid_t uid; ++ ++ assert(ret); ++ ++ if (scope == UNIT_FILE_GLOBAL) ++ return -EINVAL; ++ ++ uid = scope == UNIT_FILE_USER ? getuid() : 0; ++ ++ if (asprintf(ret, UID_FMT, uid) < 0) + return -ENOMEM; + + return 0; +diff --git a/src/shared/specifier.h b/src/shared/specifier.h +index c433ee2d63..3c619a6c8f 100644 +--- a/src/shared/specifier.h ++++ b/src/shared/specifier.h +@@ -80,11 +80,11 @@ int specifier_var_tmp_dir(char specifier, const void *data, const char *root, co + { 'w', specifier_os_version_id, NULL }, \ + { 'W', specifier_os_variant_id, NULL } + +-#define COMMON_CREDS_SPECIFIERS \ +- { 'g', specifier_group_name, NULL }, \ +- { 'G', specifier_group_id, NULL }, \ +- { 'u', specifier_user_name, NULL }, \ +- { 'U', specifier_user_id, NULL } ++#define COMMON_CREDS_SPECIFIERS(scope) \ ++ { 'g', specifier_group_name, INT_TO_PTR(scope) }, \ ++ { 'G', specifier_group_id, INT_TO_PTR(scope) }, \ ++ { 'u', specifier_user_name, INT_TO_PTR(scope) }, \ ++ { 'U', specifier_user_id, INT_TO_PTR(scope) } + + #define COMMON_TMP_SPECIFIERS \ + { 'T', specifier_tmp_dir, NULL }, \ +diff --git a/src/test/test-load-fragment.c b/src/test/test-load-fragment.c +index c579be4150..9df53cec2b 100644 +--- a/src/test/test-load-fragment.c ++++ b/src/test/test-load-fragment.c +@@ -526,59 +526,74 @@ TEST(install_printf, .sd_booted = true) { + assert_se(user = uid_to_name(getuid())); + assert_se(asprintf(&uid, UID_FMT, getuid()) >= 0); + +-#define expect(src, pattern, result) \ ++#define expect(scope, src, pattern, result) \ + do { \ +- _cleanup_free_ char *t = NULL; \ +- _cleanup_free_ char \ +- *d1 = strdup(i.name), \ +- *d2 = strdup(i.path); \ +- assert_se(install_name_printf(&src, pattern, NULL, &t) >= 0 || !result); \ ++ _cleanup_free_ char *t = NULL, \ ++ *d1 = ASSERT_PTR(strdup(i.name)), \ ++ *d2 = ASSERT_PTR(strdup(i.path)); \ ++ int r = install_name_printf(scope, &src, pattern, NULL, &t); \ ++ assert_se(result ? r >= 0 : r < 0); \ + memzero(i.name, strlen(i.name)); \ + memzero(i.path, strlen(i.path)); \ +- assert_se(d1 && d2); \ + if (result) { \ + printf("%s\n", t); \ + assert_se(streq(t, result)); \ +- } else assert_se(t == NULL); \ ++ } else \ ++ assert_se(!t); \ + strcpy(i.name, d1); \ + strcpy(i.path, d2); \ + } while (false) + +- expect(i, "%n", "name.service"); +- expect(i, "%N", "name"); +- expect(i, "%p", "name"); +- expect(i, "%i", ""); +- expect(i, "%j", "name"); +- expect(i, "%g", group); +- expect(i, "%G", gid); +- expect(i, "%u", user); +- expect(i, "%U", uid); +- +- expect(i, "%m", mid); +- expect(i, "%b", bid); +- expect(i, "%H", host); +- +- expect(i2, "%g", group); +- expect(i2, "%G", gid); +- expect(i2, "%u", user); +- expect(i2, "%U", uid); +- +- expect(i3, "%n", "name@inst.service"); +- expect(i3, "%N", "name@inst"); +- expect(i3, "%p", "name"); +- expect(i3, "%g", group); +- expect(i3, "%G", gid); +- expect(i3, "%u", user); +- expect(i3, "%U", uid); +- +- expect(i3, "%m", mid); +- expect(i3, "%b", bid); +- expect(i3, "%H", host); +- +- expect(i4, "%g", group); +- expect(i4, "%G", gid); +- expect(i4, "%u", user); +- expect(i4, "%U", uid); ++ expect(UNIT_FILE_SYSTEM, i, "%n", "name.service"); ++ expect(UNIT_FILE_SYSTEM, i, "%N", "name"); ++ expect(UNIT_FILE_SYSTEM, i, "%p", "name"); ++ expect(UNIT_FILE_SYSTEM, i, "%i", ""); ++ expect(UNIT_FILE_SYSTEM, i, "%j", "name"); ++ expect(UNIT_FILE_SYSTEM, i, "%g", "root"); ++ expect(UNIT_FILE_SYSTEM, i, "%G", "0"); ++ expect(UNIT_FILE_SYSTEM, i, "%u", "root"); ++ expect(UNIT_FILE_SYSTEM, i, "%U", "0"); ++ ++ expect(UNIT_FILE_SYSTEM, i, "%m", mid); ++ expect(UNIT_FILE_SYSTEM, i, "%b", bid); ++ expect(UNIT_FILE_SYSTEM, i, "%H", host); ++ ++ expect(UNIT_FILE_SYSTEM, i2, "%g", "root"); ++ expect(UNIT_FILE_SYSTEM, i2, "%G", "0"); ++ expect(UNIT_FILE_SYSTEM, i2, "%u", "root"); ++ expect(UNIT_FILE_SYSTEM, i2, "%U", "0"); ++ ++ expect(UNIT_FILE_USER, i2, "%g", group); ++ expect(UNIT_FILE_USER, i2, "%G", gid); ++ expect(UNIT_FILE_USER, i2, "%u", user); ++ expect(UNIT_FILE_USER, i2, "%U", uid); ++ ++ /* gcc-12.0.1-0.9.fc36.x86_64 insist that streq(…, NULL) is called, ++ * even though the call is inside of a conditional where the pointer is checked. :( */ ++#pragma GCC diagnostic push ++#pragma GCC diagnostic ignored "-Wnonnull" ++ expect(UNIT_FILE_GLOBAL, i2, "%g", NULL); ++ expect(UNIT_FILE_GLOBAL, i2, "%G", NULL); ++ expect(UNIT_FILE_GLOBAL, i2, "%u", NULL); ++ expect(UNIT_FILE_GLOBAL, i2, "%U", NULL); ++#pragma GCC diagnostic pop ++ ++ expect(UNIT_FILE_SYSTEM, i3, "%n", "name@inst.service"); ++ expect(UNIT_FILE_SYSTEM, i3, "%N", "name@inst"); ++ expect(UNIT_FILE_SYSTEM, i3, "%p", "name"); ++ expect(UNIT_FILE_USER, i3, "%g", group); ++ expect(UNIT_FILE_USER, i3, "%G", gid); ++ expect(UNIT_FILE_USER, i3, "%u", user); ++ expect(UNIT_FILE_USER, i3, "%U", uid); ++ ++ expect(UNIT_FILE_SYSTEM, i3, "%m", mid); ++ expect(UNIT_FILE_SYSTEM, i3, "%b", bid); ++ expect(UNIT_FILE_SYSTEM, i3, "%H", host); ++ ++ expect(UNIT_FILE_USER, i4, "%g", group); ++ expect(UNIT_FILE_USER, i4, "%G", gid); ++ expect(UNIT_FILE_USER, i4, "%u", user); ++ expect(UNIT_FILE_USER, i4, "%U", uid); + } + + static uint64_t make_cap(int cap) { +diff --git a/src/test/test-specifier.c b/src/test/test-specifier.c +index a45d1bd0b9..dd47f0285e 100644 +--- a/src/test/test-specifier.c ++++ b/src/test/test-specifier.c +@@ -7,6 +7,7 @@ + #include "string-util.h" + #include "strv.h" + #include "tests.h" ++#include "unit-file.h" + + static void test_specifier_escape_one(const char *a, const char *b) { + _cleanup_free_ char *x = NULL; +@@ -45,7 +46,7 @@ TEST(specifier_escape_strv) { + static const Specifier specifier_table[] = { + COMMON_SYSTEM_SPECIFIERS, + +- COMMON_CREDS_SPECIFIERS, ++ COMMON_CREDS_SPECIFIERS(UNIT_FILE_USER), + { 'h', specifier_user_home, NULL }, + + COMMON_TMP_SPECIFIERS, +diff --git a/src/tmpfiles/tmpfiles.c b/src/tmpfiles/tmpfiles.c +index fcab51c208..aa7ff73a36 100644 +--- a/src/tmpfiles/tmpfiles.c ++++ b/src/tmpfiles/tmpfiles.c +@@ -204,31 +204,6 @@ STATIC_DESTRUCTOR_REGISTER(arg_image, freep); + static int specifier_machine_id_safe(char specifier, const void *data, const char *root, const void *userdata, char **ret); + static int specifier_directory(char specifier, const void *data, const char *root, const void *userdata, char **ret); + +-static const Specifier specifier_table[] = { +- { 'a', specifier_architecture, NULL }, +- { 'b', specifier_boot_id, NULL }, +- { 'B', specifier_os_build_id, NULL }, +- { 'H', specifier_host_name, NULL }, +- { 'l', specifier_short_host_name, NULL }, +- { 'm', specifier_machine_id_safe, NULL }, +- { 'o', specifier_os_id, NULL }, +- { 'v', specifier_kernel_release, NULL }, +- { 'w', specifier_os_version_id, NULL }, +- { 'W', specifier_os_variant_id, NULL }, +- +- { 'h', specifier_user_home, NULL }, +- +- { 'C', specifier_directory, UINT_TO_PTR(DIRECTORY_CACHE) }, +- { 'L', specifier_directory, UINT_TO_PTR(DIRECTORY_LOGS) }, +- { 'S', specifier_directory, UINT_TO_PTR(DIRECTORY_STATE) }, +- { 't', specifier_directory, UINT_TO_PTR(DIRECTORY_RUNTIME) }, +- +- COMMON_CREDS_SPECIFIERS, +- +- COMMON_TMP_SPECIFIERS, +- {} +-}; +- + static int specifier_machine_id_safe(char specifier, const void *data, const char *root, const void *userdata, char **ret) { + int r; + +@@ -2743,7 +2718,7 @@ static bool should_include_path(const char *path) { + return false; + } + +-static int specifier_expansion_from_arg(Item *i) { ++static int specifier_expansion_from_arg(const Specifier *specifier_table, Item *i) { + int r; + + assert(i); +@@ -2951,6 +2926,30 @@ static int parse_line( + assert(line >= 1); + assert(buffer); + ++ const Specifier specifier_table[] = { ++ { 'a', specifier_architecture, NULL }, ++ { 'b', specifier_boot_id, NULL }, ++ { 'B', specifier_os_build_id, NULL }, ++ { 'H', specifier_host_name, NULL }, ++ { 'l', specifier_short_host_name, NULL }, ++ { 'm', specifier_machine_id_safe, NULL }, ++ { 'o', specifier_os_id, NULL }, ++ { 'v', specifier_kernel_release, NULL }, ++ { 'w', specifier_os_version_id, NULL }, ++ { 'W', specifier_os_variant_id, NULL }, ++ ++ { 'h', specifier_user_home, NULL }, ++ ++ { 'C', specifier_directory, UINT_TO_PTR(DIRECTORY_CACHE) }, ++ { 'L', specifier_directory, UINT_TO_PTR(DIRECTORY_LOGS) }, ++ { 'S', specifier_directory, UINT_TO_PTR(DIRECTORY_STATE) }, ++ { 't', specifier_directory, UINT_TO_PTR(DIRECTORY_RUNTIME) }, ++ ++ COMMON_CREDS_SPECIFIERS(arg_user ? UNIT_FILE_USER : UNIT_FILE_SYSTEM), ++ COMMON_TMP_SPECIFIERS, ++ {} ++ }; ++ + r = extract_many_words( + &buffer, + NULL, +@@ -3155,7 +3154,7 @@ static int parse_line( + if (!should_include_path(i.path)) + return 0; + +- r = specifier_expansion_from_arg(&i); ++ r = specifier_expansion_from_arg(specifier_table, &i); + if (r == -ENXIO) + return log_unresolvable_specifier(fname, line); + if (r < 0) { +diff --git a/test/test-systemctl-enable.sh b/test/test-systemctl-enable.sh +index da1fffe944..8ac1342b91 100644 +--- a/test/test-systemctl-enable.sh ++++ b/test/test-systemctl-enable.sh +@@ -500,9 +500,10 @@ check_alias t '' && { echo "Expected failure" >&2; exit 1; } + check_alias T '' && { echo "Expected failure" >&2; exit 1; } + check_alias V '' && { echo "Expected failure" >&2; exit 1; } + +-# FIXME: we use the calling user instead of root :( +-check_alias g root || : +-check_alias G 0 || : ++check_alias g root ++check_alias G 0 ++check_alias u root ++check_alias U 0 + + check_alias i "" + +@@ -521,10 +522,6 @@ check_alias N 'some-some-link6@' + + check_alias p 'some-some-link6' + +-# FIXME: we use the calling user instead of root :( +-check_alias u root || : +-check_alias U 0 || : +- + check_alias v "$(uname -r)" + + check_alias % '%' && { echo "Expected failure because % is not legal in unit name" >&2; exit 1; } +diff --git a/test/test-systemd-tmpfiles.py b/test/test-systemd-tmpfiles.py +index 3376029463..ba42b3fa37 100755 +--- a/test/test-systemd-tmpfiles.py ++++ b/test/test-systemd-tmpfiles.py +@@ -98,13 +98,13 @@ def test_valid_specifiers(*, user): + test_content('f {} - - - - %b', '{}'.format(id128.get_boot().hex), user=user) + test_content('f {} - - - - %H', '{}'.format(socket.gethostname()), user=user) + test_content('f {} - - - - %v', '{}'.format(os.uname().release), user=user) +- test_content('f {} - - - - %U', '{}'.format(os.getuid()), user=user) +- test_content('f {} - - - - %G', '{}'.format(os.getgid()), user=user) ++ test_content('f {} - - - - %U', '{}'.format(os.getuid() if user else 0), user=user) ++ test_content('f {} - - - - %G', '{}'.format(os.getgid() if user else 0), user=user) + +- puser = pwd.getpwuid(os.getuid()) ++ puser = pwd.getpwuid(os.getuid() if user else 0) + test_content('f {} - - - - %u', '{}'.format(puser.pw_name), user=user) + +- pgroup = grp.getgrgid(os.getgid()) ++ pgroup = grp.getgrgid(os.getgid() if user else 0) + test_content('f {} - - - - %g', '{}'.format(pgroup.gr_name), user=user) + + # Note that %h is the only specifier in which we look the environment, diff --git a/0174-shared-install-simplify-unit_file_dump_changes.patch b/0174-shared-install-simplify-unit_file_dump_changes.patch new file mode 100644 index 0000000..a463fab --- /dev/null +++ b/0174-shared-install-simplify-unit_file_dump_changes.patch @@ -0,0 +1,118 @@ +From cb49e80f8adf8fe81b6aa96b17a39a96850dcfa6 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Thu, 10 Mar 2022 09:19:37 +0100 +Subject: [PATCH] shared/install: simplify unit_file_dump_changes() + +No functional change. + +(cherry picked from commit 32450f5348c03262f3257af328b6547cbfba5859) + +Related: #2082131 +--- + src/shared/install.c | 63 +++++++++++++++++++------------------------- + 1 file changed, 27 insertions(+), 36 deletions(-) + +diff --git a/src/shared/install.c b/src/shared/install.c +index 8d82cb6b16..80863b448b 100644 +--- a/src/shared/install.c ++++ b/src/shared/install.c +@@ -320,7 +320,7 @@ void unit_file_changes_free(UnitFileChange *changes, size_t n_changes) { + } + + void unit_file_dump_changes(int r, const char *verb, const UnitFileChange *changes, size_t n_changes, bool quiet) { +- bool logged = false; ++ int err = 0; + + assert(changes || n_changes == 0); + /* If verb is not specified, errors are not allowed! */ +@@ -361,64 +361,55 @@ void unit_file_dump_changes(int r, const char *verb, const UnitFileChange *chang + break; + case -EEXIST: + if (changes[i].source) +- log_error_errno(changes[i].type_or_errno, +- "Failed to %s unit, file \"%s\" already exists and is a symlink to \"%s\".", +- verb, changes[i].path, changes[i].source); ++ err = log_error_errno(changes[i].type_or_errno, ++ "Failed to %s unit, file \"%s\" already exists and is a symlink to \"%s\".", ++ verb, changes[i].path, changes[i].source); + else +- log_error_errno(changes[i].type_or_errno, +- "Failed to %s unit, file \"%s\" already exists.", +- verb, changes[i].path); +- logged = true; ++ err = log_error_errno(changes[i].type_or_errno, ++ "Failed to %s unit, file \"%s\" already exists.", ++ verb, changes[i].path); + break; + case -ERFKILL: +- log_error_errno(changes[i].type_or_errno, "Failed to %s unit, unit %s is masked.", +- verb, changes[i].path); +- logged = true; ++ err = log_error_errno(changes[i].type_or_errno, "Failed to %s unit, unit %s is masked.", ++ verb, changes[i].path); + break; + case -EADDRNOTAVAIL: +- log_error_errno(changes[i].type_or_errno, "Failed to %s unit, unit %s is transient or generated.", +- verb, changes[i].path); +- logged = true; ++ err = log_error_errno(changes[i].type_or_errno, "Failed to %s unit, unit %s is transient or generated.", ++ verb, changes[i].path); + break; + case -EBADSLT: +- log_error_errno(changes[i].type_or_errno, "Failed to %s unit, invalid specifier in \"%s\".", +- verb, changes[i].path); +- logged = true; ++ err = log_error_errno(changes[i].type_or_errno, "Failed to %s unit, invalid specifier in \"%s\".", ++ verb, changes[i].path); + break; + case -EIDRM: +- log_error_errno(changes[i].type_or_errno, "Failed to %s %s, destination unit %s is a non-template unit.", +- verb, changes[i].source, changes[i].path); +- logged = true; ++ err = log_error_errno(changes[i].type_or_errno, "Failed to %s %s, destination unit %s is a non-template unit.", ++ verb, changes[i].source, changes[i].path); + break; + case -EUCLEAN: +- log_error_errno(changes[i].type_or_errno, +- "Failed to %s unit, \"%s\" is not a valid unit name.", +- verb, changes[i].path); +- logged = true; ++ err = log_error_errno(changes[i].type_or_errno, ++ "Failed to %s unit, \"%s\" is not a valid unit name.", ++ verb, changes[i].path); + break; + case -ELOOP: +- log_error_errno(changes[i].type_or_errno, "Failed to %s unit, refusing to operate on linked unit file %s.", +- verb, changes[i].path); +- logged = true; ++ err = log_error_errno(changes[i].type_or_errno, "Failed to %s unit, refusing to operate on linked unit file %s.", ++ verb, changes[i].path); + break; + case -ENOENT: +- log_error_errno(changes[i].type_or_errno, "Failed to %s unit, unit %s does not exist.", verb, changes[i].path); +- logged = true; ++ err = log_error_errno(changes[i].type_or_errno, "Failed to %s unit, unit %s does not exist.", ++ verb, changes[i].path); + break; + case -EUNATCH: +- log_error_errno(changes[i].type_or_errno, "Failed to %s unit, cannot resolve specifiers in \"%s\".", +- verb, changes[i].path); +- logged = true; ++ err = log_error_errno(changes[i].type_or_errno, "Failed to %s unit, cannot resolve specifiers in \"%s\".", ++ verb, changes[i].path); + break; + default: + assert(changes[i].type_or_errno < 0); +- log_error_errno(changes[i].type_or_errno, "Failed to %s unit, file \"%s\": %m", +- verb, changes[i].path); +- logged = true; ++ err = log_error_errno(changes[i].type_or_errno, "Failed to %s unit, file \"%s\": %m", ++ verb, changes[i].path); + } + } + +- if (r < 0 && !logged) ++ if (r < 0 && err >= 0) + log_error_errno(r, "Failed to %s: %m.", verb); + } + diff --git a/0175-shared-install-propagate-errors-about-invalid-aliase.patch b/0175-shared-install-propagate-errors-about-invalid-aliase.patch new file mode 100644 index 0000000..4fa41b3 --- /dev/null +++ b/0175-shared-install-propagate-errors-about-invalid-aliase.patch @@ -0,0 +1,325 @@ +From 35bcb96c1ac2db777db1649026f931ce77c9c7ba Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Thu, 10 Mar 2022 11:03:41 +0100 +Subject: [PATCH] shared/install: propagate errors about invalid aliases and + such too + +If an invalid arg appears in [Install] Alias=, WantedBy=, RequiredBy=, +we'd warn in the logs, but not propagate this information to the caller, +and in particular not over dbus. But if we call "systemctl enable" on a +unit, and the config if invalid, this information is quite important. + +(cherry picked from commit cbfdbffb618f1d75e668c59887a27c7a60950546) + +Related: #2082131 +--- + src/basic/unit-file.c | 44 +++++++++++++------------- + src/basic/unit-file.h | 2 +- + src/shared/install.c | 61 ++++++++++++++++++++++++++---------- + src/shared/install.h | 7 ++++- + src/test/test-install-root.c | 2 +- + src/test/test-unit-file.c | 28 ++++++++--------- + 6 files changed, 88 insertions(+), 56 deletions(-) + +diff --git a/src/basic/unit-file.c b/src/basic/unit-file.c +index f7a10b22c6..105dacc1b2 100644 +--- a/src/basic/unit-file.c ++++ b/src/basic/unit-file.c +@@ -69,7 +69,7 @@ int unit_symlink_name_compatible(const char *symlink, const char *target, bool i + return 0; + } + +-int unit_validate_alias_symlink_and_warn(const char *filename, const char *target) { ++int unit_validate_alias_symlink_or_warn(int log_level, const char *filename, const char *target) { + const char *src, *dst; + _cleanup_free_ char *src_instance = NULL, *dst_instance = NULL; + UnitType src_unit_type, dst_unit_type; +@@ -92,51 +92,51 @@ int unit_validate_alias_symlink_and_warn(const char *filename, const char *targe + + src_name_type = unit_name_to_instance(src, &src_instance); + if (src_name_type < 0) +- return log_notice_errno(src_name_type, +- "%s: not a valid unit name \"%s\": %m", filename, src); ++ return log_full_errno(log_level, src_name_type, ++ "%s: not a valid unit name \"%s\": %m", filename, src); + + src_unit_type = unit_name_to_type(src); + assert(src_unit_type >= 0); /* unit_name_to_instance() checked the suffix already */ + + if (!unit_type_may_alias(src_unit_type)) +- return log_notice_errno(SYNTHETIC_ERRNO(EINVAL), +- "%s: symlinks are not allowed for units of this type, rejecting.", +- filename); ++ return log_full_errno(log_level, SYNTHETIC_ERRNO(EINVAL), ++ "%s: symlinks are not allowed for units of this type, rejecting.", ++ filename); + + if (src_name_type != UNIT_NAME_PLAIN && + !unit_type_may_template(src_unit_type)) +- return log_notice_errno(SYNTHETIC_ERRNO(EINVAL), +- "%s: templates not allowed for %s units, rejecting.", +- filename, unit_type_to_string(src_unit_type)); ++ return log_full_errno(log_level, SYNTHETIC_ERRNO(EINVAL), ++ "%s: templates not allowed for %s units, rejecting.", ++ filename, unit_type_to_string(src_unit_type)); + + /* dst checks */ + + dst_name_type = unit_name_to_instance(dst, &dst_instance); + if (dst_name_type < 0) +- return log_notice_errno(dst_name_type == -EINVAL ? SYNTHETIC_ERRNO(EXDEV) : dst_name_type, +- "%s points to \"%s\" which is not a valid unit name: %m", +- filename, dst); ++ return log_full_errno(log_level, dst_name_type == -EINVAL ? SYNTHETIC_ERRNO(EXDEV) : dst_name_type, ++ "%s points to \"%s\" which is not a valid unit name: %m", ++ filename, dst); + + if (!(dst_name_type == src_name_type || + (src_name_type == UNIT_NAME_INSTANCE && dst_name_type == UNIT_NAME_TEMPLATE))) +- return log_notice_errno(SYNTHETIC_ERRNO(EXDEV), +- "%s: symlink target name type \"%s\" does not match source, rejecting.", +- filename, dst); ++ return log_full_errno(log_level, SYNTHETIC_ERRNO(EXDEV), ++ "%s: symlink target name type \"%s\" does not match source, rejecting.", ++ filename, dst); + + if (dst_name_type == UNIT_NAME_INSTANCE) { + assert(src_instance); + assert(dst_instance); + if (!streq(src_instance, dst_instance)) +- return log_notice_errno(SYNTHETIC_ERRNO(EXDEV), +- "%s: unit symlink target \"%s\" instance name doesn't match, rejecting.", +- filename, dst); ++ return log_full_errno(log_level, SYNTHETIC_ERRNO(EXDEV), ++ "%s: unit symlink target \"%s\" instance name doesn't match, rejecting.", ++ filename, dst); + } + + dst_unit_type = unit_name_to_type(dst); + if (dst_unit_type != src_unit_type) +- return log_notice_errno(SYNTHETIC_ERRNO(EXDEV), +- "%s: symlink target \"%s\" has incompatible suffix, rejecting.", +- filename, dst); ++ return log_full_errno(log_level, SYNTHETIC_ERRNO(EXDEV), ++ "%s: symlink target \"%s\" has incompatible suffix, rejecting.", ++ filename, dst); + + return 0; + } +@@ -355,7 +355,7 @@ int unit_file_resolve_symlink( + "Suspicious symlink %s/%s→%s, treating as alias.", + dir, filename, simplified); + +- r = unit_validate_alias_symlink_and_warn(filename, simplified); ++ r = unit_validate_alias_symlink_or_warn(LOG_NOTICE, filename, simplified); + if (r < 0) + return r; + +diff --git a/src/basic/unit-file.h b/src/basic/unit-file.h +index e29e878cfd..b7c03e9c2c 100644 +--- a/src/basic/unit-file.h ++++ b/src/basic/unit-file.h +@@ -41,7 +41,7 @@ bool unit_type_may_alias(UnitType type) _const_; + bool unit_type_may_template(UnitType type) _const_; + + int unit_symlink_name_compatible(const char *symlink, const char *target, bool instance_propagation); +-int unit_validate_alias_symlink_and_warn(const char *filename, const char *target); ++int unit_validate_alias_symlink_or_warn(int log_level, const char *filename, const char *target); + + bool lookup_paths_timestamp_hash_same(const LookupPaths *lp, uint64_t timestamp_hash, uint64_t *ret_new); + +diff --git a/src/shared/install.c b/src/shared/install.c +index 80863b448b..6da9ba6b0c 100644 +--- a/src/shared/install.c ++++ b/src/shared/install.c +@@ -394,6 +394,14 @@ void unit_file_dump_changes(int r, const char *verb, const UnitFileChange *chang + err = log_error_errno(changes[i].type_or_errno, "Failed to %s unit, refusing to operate on linked unit file %s.", + verb, changes[i].path); + break; ++ case -EXDEV: ++ if (changes[i].source) ++ err = log_error_errno(changes[i].type_or_errno, "Failed to %s unit, cannot alias %s as %s.", ++ verb, changes[i].source, changes[i].path); ++ else ++ err = log_error_errno(changes[i].type_or_errno, "Failed to %s unit, invalid unit reference \"%s\".", ++ verb, changes[i].path); ++ break; + case -ENOENT: + err = log_error_errno(changes[i].type_or_errno, "Failed to %s unit, unit %s does not exist.", + verb, changes[i].path); +@@ -1678,7 +1686,13 @@ static int install_info_discover_and_check( + return install_info_may_process(ret ? *ret : NULL, lp, changes, n_changes); + } + +-int unit_file_verify_alias(const UnitFileInstallInfo *info, const char *dst, char **ret_dst) { ++int unit_file_verify_alias( ++ const UnitFileInstallInfo *info, ++ const char *dst, ++ char **ret_dst, ++ UnitFileChange **changes, ++ size_t *n_changes) { ++ + _cleanup_free_ char *dst_updated = NULL; + int r; + +@@ -1705,15 +1719,19 @@ int unit_file_verify_alias(const UnitFileInstallInfo *info, const char *dst, cha + p = endswith(dir, ".wants"); + if (!p) + p = endswith(dir, ".requires"); +- if (!p) +- return log_warning_errno(SYNTHETIC_ERRNO(EXDEV), +- "Invalid path \"%s\" in alias.", dir); ++ if (!p) { ++ unit_file_changes_add(changes, n_changes, -EXDEV, dst, NULL); ++ return log_debug_errno(SYNTHETIC_ERRNO(EXDEV), "Invalid path \"%s\" in alias.", dir); ++ } ++ + *p = '\0'; /* dir should now be a unit name */ + + UnitNameFlags type = unit_name_classify(dir); +- if (type < 0) +- return log_warning_errno(SYNTHETIC_ERRNO(EXDEV), +- "Invalid unit name component \"%s\" in alias.", dir); ++ if (type < 0) { ++ unit_file_changes_add(changes, n_changes, -EXDEV, dst, NULL); ++ return log_debug_errno(SYNTHETIC_ERRNO(EXDEV), ++ "Invalid unit name component \"%s\" in alias.", dir); ++ } + + const bool instance_propagation = type == UNIT_NAME_TEMPLATE; + +@@ -1721,10 +1739,12 @@ int unit_file_verify_alias(const UnitFileInstallInfo *info, const char *dst, cha + r = unit_symlink_name_compatible(path_alias, info->name, instance_propagation); + if (r < 0) + return log_error_errno(r, "Failed to verify alias validity: %m"); +- if (r == 0) +- return log_warning_errno(SYNTHETIC_ERRNO(EXDEV), +- "Invalid unit \"%s\" symlink \"%s\".", +- info->name, dst); ++ if (r == 0) { ++ unit_file_changes_add(changes, n_changes, -EXDEV, dst, info->name); ++ return log_debug_errno(SYNTHETIC_ERRNO(EXDEV), ++ "Invalid unit \"%s\" symlink \"%s\".", ++ info->name, dst); ++ } + + } else { + /* If the symlink target has an instance set and the symlink source doesn't, we "propagate +@@ -1733,8 +1753,10 @@ int unit_file_verify_alias(const UnitFileInstallInfo *info, const char *dst, cha + _cleanup_free_ char *inst = NULL; + + UnitNameFlags type = unit_name_to_instance(info->name, &inst); +- if (type < 0) +- return log_error_errno(type, "Failed to extract instance name from \"%s\": %m", info->name); ++ if (type < 0) { ++ unit_file_changes_add(changes, n_changes, -EUCLEAN, info->name, NULL); ++ return log_debug_errno(type, "Failed to extract instance name from \"%s\": %m", info->name); ++ } + + if (type == UNIT_NAME_INSTANCE) { + r = unit_name_replace_instance(dst, inst, &dst_updated); +@@ -1744,9 +1766,14 @@ int unit_file_verify_alias(const UnitFileInstallInfo *info, const char *dst, cha + } + } + +- r = unit_validate_alias_symlink_and_warn(dst_updated ?: dst, info->name); +- if (r < 0) ++ r = unit_validate_alias_symlink_or_warn(LOG_DEBUG, dst_updated ?: dst, info->name); ++ if (r < 0) { ++ unit_file_changes_add(changes, n_changes, ++ r == -EINVAL ? -EXDEV : r, ++ dst_updated ?: dst, ++ info->name); + return r; ++ } + } + + *ret_dst = TAKE_PTR(dst_updated); +@@ -1778,7 +1805,7 @@ static int install_info_symlink_alias( + return q; + } + +- q = unit_file_verify_alias(info, dst, &dst_updated); ++ q = unit_file_verify_alias(info, dst, &dst_updated, changes, n_changes); + if (q < 0) + continue; + +@@ -3332,7 +3359,7 @@ int unit_file_preset_all( + + r = preset_prepare_one(scope, &plus, &minus, &lp, de->d_name, &presets, changes, n_changes); + if (r < 0 && +- !IN_SET(r, -EEXIST, -ERFKILL, -EADDRNOTAVAIL, -EBADSLT, -EIDRM, -EUCLEAN, -ELOOP, -ENOENT, -EUNATCH)) ++ !IN_SET(r, -EEXIST, -ERFKILL, -EADDRNOTAVAIL, -EBADSLT, -EIDRM, -EUCLEAN, -ELOOP, -ENOENT, -EUNATCH, -EXDEV)) + /* Ignore generated/transient/missing/invalid units when applying preset, propagate other errors. + * Coordinate with unit_file_dump_changes() above. */ + return r; +diff --git a/src/shared/install.h b/src/shared/install.h +index cdc5435035..d21e2aaa45 100644 +--- a/src/shared/install.h ++++ b/src/shared/install.h +@@ -193,7 +193,12 @@ int unit_file_changes_add(UnitFileChange **changes, size_t *n_changes, int type, + void unit_file_changes_free(UnitFileChange *changes, size_t n_changes); + void unit_file_dump_changes(int r, const char *verb, const UnitFileChange *changes, size_t n_changes, bool quiet); + +-int unit_file_verify_alias(const UnitFileInstallInfo *i, const char *dst, char **ret_dst); ++int unit_file_verify_alias( ++ const UnitFileInstallInfo *info, ++ const char *dst, ++ char **ret_dst, ++ UnitFileChange **changes, ++ size_t *n_changes); + + typedef struct UnitFilePresetRule UnitFilePresetRule; + +diff --git a/src/test/test-install-root.c b/src/test/test-install-root.c +index f718689c3a..4f66c12655 100644 +--- a/src/test/test-install-root.c ++++ b/src/test/test-install-root.c +@@ -1091,7 +1091,7 @@ static void verify_one( + if (i != last_info) + log_info("-- %s --", (last_info = i)->name); + +- r = unit_file_verify_alias(i, alias, &alias2); ++ r = unit_file_verify_alias(i, alias, &alias2, NULL, NULL); + log_info_errno(r, "alias %s ← %s: %d/%m (expected %d)%s%s%s", + i->name, alias, r, expected, + alias2 ? " [" : "", strempty(alias2), +diff --git a/src/test/test-unit-file.c b/src/test/test-unit-file.c +index cc08a4ae4b..8ed56ad3b8 100644 +--- a/src/test/test-unit-file.c ++++ b/src/test/test-unit-file.c +@@ -8,20 +8,20 @@ + #include "unit-file.h" + + TEST(unit_validate_alias_symlink_and_warn) { +- assert_se(unit_validate_alias_symlink_and_warn("/path/a.service", "/other/b.service") == 0); +- assert_se(unit_validate_alias_symlink_and_warn("/path/a.service", "/other/b.socket") == -EXDEV); +- assert_se(unit_validate_alias_symlink_and_warn("/path/a.service", "/other/b.foobar") == -EXDEV); +- assert_se(unit_validate_alias_symlink_and_warn("/path/a@.service", "/other/b@.service") == 0); +- assert_se(unit_validate_alias_symlink_and_warn("/path/a@.service", "/other/b@.socket") == -EXDEV); +- assert_se(unit_validate_alias_symlink_and_warn("/path/a@XXX.service", "/other/b@YYY.service") == -EXDEV); +- assert_se(unit_validate_alias_symlink_and_warn("/path/a@XXX.service", "/other/b@YYY.socket") == -EXDEV); +- assert_se(unit_validate_alias_symlink_and_warn("/path/a@.service", "/other/b@YYY.service") == -EXDEV); +- assert_se(unit_validate_alias_symlink_and_warn("/path/a@XXX.service", "/other/b@XXX.service") == 0); +- assert_se(unit_validate_alias_symlink_and_warn("/path/a@XXX.service", "/other/b@.service") == 0); +- assert_se(unit_validate_alias_symlink_and_warn("/path/a@.service", "/other/b.service") == -EXDEV); +- assert_se(unit_validate_alias_symlink_and_warn("/path/a.service", "/other/b@.service") == -EXDEV); +- assert_se(unit_validate_alias_symlink_and_warn("/path/a@.slice", "/other/b.slice") == -EINVAL); +- assert_se(unit_validate_alias_symlink_and_warn("/path/a.slice", "/other/b.slice") == -EINVAL); ++ assert_se(unit_validate_alias_symlink_or_warn(LOG_INFO, "/path/a.service", "/other/b.service") == 0); ++ assert_se(unit_validate_alias_symlink_or_warn(LOG_INFO, "/path/a.service", "/other/b.socket") == -EXDEV); ++ assert_se(unit_validate_alias_symlink_or_warn(LOG_INFO, "/path/a.service", "/other/b.foobar") == -EXDEV); ++ assert_se(unit_validate_alias_symlink_or_warn(LOG_INFO, "/path/a@.service", "/other/b@.service") == 0); ++ assert_se(unit_validate_alias_symlink_or_warn(LOG_INFO, "/path/a@.service", "/other/b@.socket") == -EXDEV); ++ assert_se(unit_validate_alias_symlink_or_warn(LOG_INFO, "/path/a@XXX.service", "/other/b@YYY.service") == -EXDEV); ++ assert_se(unit_validate_alias_symlink_or_warn(LOG_INFO, "/path/a@XXX.service", "/other/b@YYY.socket") == -EXDEV); ++ assert_se(unit_validate_alias_symlink_or_warn(LOG_INFO, "/path/a@.service", "/other/b@YYY.service") == -EXDEV); ++ assert_se(unit_validate_alias_symlink_or_warn(LOG_INFO, "/path/a@XXX.service", "/other/b@XXX.service") == 0); ++ assert_se(unit_validate_alias_symlink_or_warn(LOG_INFO, "/path/a@XXX.service", "/other/b@.service") == 0); ++ assert_se(unit_validate_alias_symlink_or_warn(LOG_INFO, "/path/a@.service", "/other/b.service") == -EXDEV); ++ assert_se(unit_validate_alias_symlink_or_warn(LOG_INFO, "/path/a.service", "/other/b@.service") == -EXDEV); ++ assert_se(unit_validate_alias_symlink_or_warn(LOG_INFO, "/path/a@.slice", "/other/b.slice") == -EINVAL); ++ assert_se(unit_validate_alias_symlink_or_warn(LOG_INFO, "/path/a.slice", "/other/b.slice") == -EINVAL); + } + + TEST(unit_file_build_name_map) { diff --git a/0176-shared-install-return-failure-when-enablement-fails-.patch b/0176-shared-install-return-failure-when-enablement-fails-.patch new file mode 100644 index 0000000..614089b --- /dev/null +++ b/0176-shared-install-return-failure-when-enablement-fails-.patch @@ -0,0 +1,165 @@ +From db20c5cec8adf865dd47672bc091092b8cea5e0e Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Thu, 10 Mar 2022 15:47:12 +0100 +Subject: [PATCH] shared/install: return failure when enablement fails, but + process as much as possible + +So far we'd issue a warning (before this series, just in the logs on the server +side, and before this commit, on stderr on the caller's side), but return +success. It seems that successfull return was introduced by mistake in +aa0f357fd833feecbea6c3e9be80b643e433bced (my fault :( ), which was supposed to +be a refactoring without a functional change. I think it's better to fail, +because if enablement fails, the user will most likely want to diagnose the +issue. + +Note that we still do partial enablement, as far as that is possible. So if +e.g. we have [Install] Alias=foo.service foobar, we'll create the symlink +'foo.service', but not 'foobar', since that's not a valid unit name. We'll +print info about the action taken, and about 'foobar' being invalid, and return +failure. + +(cherry picked from commit 0d11db59825a9deee0b56fdede0602ef1c37c5c5) + +Related: #2082131 +--- + src/shared/install.c | 10 +++++---- + test/test-systemctl-enable.sh | 39 ++++++++++++++++++----------------- + 2 files changed, 26 insertions(+), 23 deletions(-) + +diff --git a/src/shared/install.c b/src/shared/install.c +index 6da9ba6b0c..a541d32fb7 100644 +--- a/src/shared/install.c ++++ b/src/shared/install.c +@@ -1802,20 +1802,22 @@ static int install_info_symlink_alias( + q = install_name_printf(scope, info, *s, info->root, &dst); + if (q < 0) { + unit_file_changes_add(changes, n_changes, q, *s, NULL); +- return q; ++ r = r < 0 ? r : q; ++ continue; + } + + q = unit_file_verify_alias(info, dst, &dst_updated, changes, n_changes); +- if (q < 0) ++ if (q < 0) { ++ r = r < 0 ? r : q; + continue; ++ } + + alias_path = path_make_absolute(dst_updated ?: dst, config_path); + if (!alias_path) + return -ENOMEM; + + q = create_symlink(lp, info->path, alias_path, force, changes, n_changes); +- if (r == 0) +- r = q; ++ r = r < 0 ? r : q; + } + + return r; +diff --git a/test/test-systemctl-enable.sh b/test/test-systemctl-enable.sh +index 8ac1342b91..32bc6e5ef7 100644 +--- a/test/test-systemctl-enable.sh ++++ b/test/test-systemctl-enable.sh +@@ -56,19 +56,27 @@ test ! -e "$root/etc/systemd/system/default.target.wants/test1.service" + test ! -e "$root/etc/systemd/system/special.target.requires/test1.service" + + : -------aliases---------------------------------------------- +-"$systemctl" --root="$root" enable test1 +-test -h "$root/etc/systemd/system/default.target.wants/test1.service" +-test -h "$root/etc/systemd/system/special.target.requires/test1.service" +- + cat >>"$root/etc/systemd/system/test1.service" <&2; exit 1; } ++test -h "$root/etc/systemd/system/default.target.wants/test1.service" ++test -h "$root/etc/systemd/system/special.target.requires/test1.service" ++test ! -e "$root/etc/systemd/system/test1-goodalias.service" ++test -h "$root/etc/systemd/system/test1-goodalias.service" ++test ! -e "$root/etc/systemd/system/test1@badalias.service" ++test ! -e "$root/etc/systemd/system/test1-badalias.target" ++test ! -e "$root/etc/systemd/system/test1-badalias.socket" ++test -h "$root/etc/systemd/system/test1-goodalias2.service" ++ + : -------aliases in reeanble---------------------------------- +-"$systemctl" --root="$root" reenable test1 ++"$systemctl" --root="$root" reenable test1 && { echo "Expected failure" >&2; exit 1; } + test -h "$root/etc/systemd/system/default.target.wants/test1.service" + test ! -e "$root/etc/systemd/system/test1-goodalias.service" + test -h "$root/etc/systemd/system/test1-goodalias.service" +@@ -328,7 +336,7 @@ Alias=link4alias.service + Alias=link4alias2.service + EOF + +-"$systemctl" --root="$root" enable 'link4.service' ++"$systemctl" --root="$root" enable 'link4.service' && { echo "Expected failure" >&2; exit 1; } + test ! -h "$root/etc/systemd/system/link4.service" # this is our file + test ! -h "$root/etc/systemd/system/link4@.service" + test ! -h "$root/etc/systemd/system/link4@inst.service" +@@ -343,18 +351,20 @@ test ! -h "$root/etc/systemd/system/link4alias.service" + test ! -h "$root/etc/systemd/system/link4alias2.service" + + : -------systemctl enable on path to unit file---------------- ++cat >"$root/etc/systemd/system/link4.service" <"$root/etc/systemd/system/link5.service" <&2; exit 1; } + +-# FIXME: if there's an invalid Alias=, we shouldn't preach about empty [Install] +- + # TODO: repeat the tests above for presets + + : -------SYSTEMD_OS_RELEASE relative to root------------------ diff --git a/0177-systemctl-fix-silent-failure-when-root-is-not-found.patch b/0177-systemctl-fix-silent-failure-when-root-is-not-found.patch new file mode 100644 index 0000000..a9ce03e --- /dev/null +++ b/0177-systemctl-fix-silent-failure-when-root-is-not-found.patch @@ -0,0 +1,545 @@ +From 8fa3444f3ca7add9af40ab565e045c2754e5a855 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Thu, 10 Mar 2022 16:47:51 +0100 +Subject: [PATCH] systemctl: fix silent failure when --root is not found + +Some calls to lookup_path_init() were not followed by any log emission. +E.g.: +$ SYSTEMD_LOG_LEVEL=debug systemctl --root=/missing enable unit; echo $? +1 + +Let's add a helper function and use it in various places. + +$ SYSTEMD_LOG_LEVEL=debug build/systemctl --root=/missing enable unit; echo $? +Failed to initialize unit search paths for root directory /missing: No such file or directory +1 +$ SYSTEMCTL_SKIP_SYSV=1 build/systemctl --root=/missing enable unit; echo $? +Failed to initialize unit search paths for root directory /missing: No such file or directory +Failed to enable: No such file or directory. +1 + +The repeated error in the second case is not very nice, but this is a niche +case and I don't think it's worth the trouble to trying to avoid it. + +(cherry picked from commit 99aad9a2b9e2c06023a2043976fd9395332ff097) + +Related: #2082131 +--- + src/basic/env-file.c | 83 +++++++++------------------ + src/basic/path-lookup.c | 56 ++++++++++-------- + src/basic/path-lookup.h | 3 +- + src/core/manager.c | 12 ++-- + src/shared/condition.c | 3 +- + src/shared/install.c | 2 +- + src/systemctl/systemctl-edit.c | 8 +-- + src/systemctl/systemctl-enable.c | 2 +- + src/systemctl/systemctl-sysv-compat.c | 2 +- + src/sysv-generator/sysv-generator.c | 4 +- + src/test/test-fileio.c | 3 +- + src/test/test-os-util.c | 7 +-- + 12 files changed, 84 insertions(+), 101 deletions(-) + +diff --git a/src/basic/env-file.c b/src/basic/env-file.c +index 0353f3f2a0..0e272da083 100644 +--- a/src/basic/env-file.c ++++ b/src/basic/env-file.c +@@ -16,9 +16,8 @@ static int parse_env_file_internal( + FILE *f, + const char *fname, + int (*push) (const char *filename, unsigned line, +- const char *key, char *value, void *userdata, int *n_pushed), +- void *userdata, +- int *n_pushed) { ++ const char *key, char *value, void *userdata), ++ void *userdata) { + + size_t n_key = 0, n_value = 0, last_value_whitespace = SIZE_MAX, last_key_whitespace = SIZE_MAX; + _cleanup_free_ char *contents = NULL, *key = NULL, *value = NULL; +@@ -100,7 +99,7 @@ static int parse_env_file_internal( + if (last_key_whitespace != SIZE_MAX) + key[last_key_whitespace] = 0; + +- r = push(fname, line, key, value, userdata, n_pushed); ++ r = push(fname, line, key, value, userdata); + if (r < 0) + return r; + +@@ -143,7 +142,7 @@ static int parse_env_file_internal( + if (last_key_whitespace != SIZE_MAX) + key[last_key_whitespace] = 0; + +- r = push(fname, line, key, value, userdata, n_pushed); ++ r = push(fname, line, key, value, userdata); + if (r < 0) + return r; + +@@ -262,7 +261,7 @@ static int parse_env_file_internal( + if (last_key_whitespace != SIZE_MAX) + key[last_key_whitespace] = 0; + +- r = push(fname, line, key, value, userdata, n_pushed); ++ r = push(fname, line, key, value, userdata); + if (r < 0) + return r; + +@@ -300,8 +299,7 @@ static int check_utf8ness_and_warn( + static int parse_env_file_push( + const char *filename, unsigned line, + const char *key, char *value, +- void *userdata, +- int *n_pushed) { ++ void *userdata) { + + const char *k; + va_list aq, *ap = userdata; +@@ -323,9 +321,6 @@ static int parse_env_file_push( + free(*v); + *v = value; + +- if (n_pushed) +- (*n_pushed)++; +- + return 1; + } + } +@@ -341,16 +336,13 @@ int parse_env_filev( + const char *fname, + va_list ap) { + +- int r, n_pushed = 0; ++ int r; + va_list aq; + + va_copy(aq, ap); +- r = parse_env_file_internal(f, fname, parse_env_file_push, &aq, &n_pushed); ++ r = parse_env_file_internal(f, fname, parse_env_file_push, &aq); + va_end(aq); +- if (r < 0) +- return r; +- +- return n_pushed; ++ return r; + } + + int parse_env_file_sentinel( +@@ -371,8 +363,7 @@ int parse_env_file_sentinel( + static int load_env_file_push( + const char *filename, unsigned line, + const char *key, char *value, +- void *userdata, +- int *n_pushed) { ++ void *userdata) { + char ***m = userdata; + char *p; + int r; +@@ -389,34 +380,28 @@ static int load_env_file_push( + if (r < 0) + return r; + +- if (n_pushed) +- (*n_pushed)++; +- + free(value); + return 0; + } + + int load_env_file(FILE *f, const char *fname, char ***rl) { +- char **m = NULL; ++ _cleanup_strv_free_ char **m = NULL; + int r; + +- r = parse_env_file_internal(f, fname, load_env_file_push, &m, NULL); +- if (r < 0) { +- strv_free(m); ++ r = parse_env_file_internal(f, fname, load_env_file_push, &m); ++ if (r < 0) + return r; +- } + +- *rl = m; ++ *rl = TAKE_PTR(m); + return 0; + } + + static int load_env_file_push_pairs( + const char *filename, unsigned line, + const char *key, char *value, +- void *userdata, +- int *n_pushed) { ++ void *userdata) { ++ + char ***m = ASSERT_PTR(userdata); +- bool added = false; + int r; + + r = check_utf8ness_and_warn(filename, line, key, value); +@@ -427,49 +412,37 @@ static int load_env_file_push_pairs( + for (char **t = *m; t && *t; t += 2) + if (streq(t[0], key)) { + if (value) +- r = free_and_replace(t[1], value); ++ return free_and_replace(t[1], value); + else +- r = free_and_strdup(t+1, ""); +- goto finish; ++ return free_and_strdup(t+1, ""); + } + + r = strv_extend(m, key); + if (r < 0) +- return -ENOMEM; ++ return r; + + if (value) +- r = strv_push(m, value); ++ return strv_push(m, value); + else +- r = strv_extend(m, ""); +- added = true; +- finish: +- if (r < 0) +- return r; +- +- if (n_pushed && added) +- (*n_pushed)++; +- return 0; ++ return strv_extend(m, ""); + } + + int load_env_file_pairs(FILE *f, const char *fname, char ***rl) { +- char **m = NULL; ++ _cleanup_strv_free_ char **m = NULL; + int r; + +- r = parse_env_file_internal(f, fname, load_env_file_push_pairs, &m, NULL); +- if (r < 0) { +- strv_free(m); ++ r = parse_env_file_internal(f, fname, load_env_file_push_pairs, &m); ++ if (r < 0) + return r; +- } + +- *rl = m; ++ *rl = TAKE_PTR(m); + return 0; + } + + static int merge_env_file_push( + const char *filename, unsigned line, + const char *key, char *value, +- void *userdata, +- int *n_pushed) { ++ void *userdata) { + + char ***env = userdata; + char *expanded_value; +@@ -498,7 +471,7 @@ static int merge_env_file_push( + + log_debug("%s:%u: setting %s=%s", filename, line, key, value); + +- return load_env_file_push(filename, line, key, value, env, n_pushed); ++ return load_env_file_push(filename, line, key, value, env); + } + + int merge_env_file( +@@ -510,7 +483,7 @@ int merge_env_file( + * plus "extended" substitutions, unlike other exported parsing functions. + */ + +- return parse_env_file_internal(f, fname, merge_env_file_push, env, NULL); ++ return parse_env_file_internal(f, fname, merge_env_file_push, env); + } + + static void write_env_var(FILE *f, const char *v) { +diff --git a/src/basic/path-lookup.c b/src/basic/path-lookup.c +index 921a30cef7..ab51955e34 100644 +--- a/src/basic/path-lookup.c ++++ b/src/basic/path-lookup.c +@@ -509,7 +509,7 @@ static int get_paths_from_environ(const char *var, char ***paths, bool *append) + } + + int lookup_paths_init( +- LookupPaths *p, ++ LookupPaths *lp, + UnitFileScope scope, + LookupPathsFlags flags, + const char *root_dir) { +@@ -527,7 +527,7 @@ int lookup_paths_init( + _cleanup_strv_free_ char **paths = NULL; + int r; + +- assert(p); ++ assert(lp); + assert(scope >= 0); + assert(scope < _UNIT_FILE_SCOPE_MAX); + +@@ -717,7 +717,7 @@ int lookup_paths_init( + if (r < 0) + return -ENOMEM; + +- *p = (LookupPaths) { ++ *lp = (LookupPaths) { + .search_path = strv_uniq(TAKE_PTR(paths)), + + .persistent_config = TAKE_PTR(persistent_config), +@@ -742,41 +742,51 @@ int lookup_paths_init( + return 0; + } + +-void lookup_paths_free(LookupPaths *p) { +- if (!p) ++int lookup_paths_init_or_warn(LookupPaths *lp, UnitFileScope scope, LookupPathsFlags flags, const char *root_dir) { ++ int r; ++ ++ r = lookup_paths_init(lp, scope, flags, root_dir); ++ if (r < 0) ++ return log_error_errno(r, "Failed to initialize unit search paths%s%s: %m", ++ isempty(root_dir) ? "" : " for root directory ", strempty(root_dir)); ++ return r; ++} ++ ++void lookup_paths_free(LookupPaths *lp) { ++ if (!lp) + return; + +- p->search_path = strv_free(p->search_path); ++ lp->search_path = strv_free(lp->search_path); + +- p->persistent_config = mfree(p->persistent_config); +- p->runtime_config = mfree(p->runtime_config); ++ lp->persistent_config = mfree(lp->persistent_config); ++ lp->runtime_config = mfree(lp->runtime_config); + +- p->persistent_attached = mfree(p->persistent_attached); +- p->runtime_attached = mfree(p->runtime_attached); ++ lp->persistent_attached = mfree(lp->persistent_attached); ++ lp->runtime_attached = mfree(lp->runtime_attached); + +- p->generator = mfree(p->generator); +- p->generator_early = mfree(p->generator_early); +- p->generator_late = mfree(p->generator_late); ++ lp->generator = mfree(lp->generator); ++ lp->generator_early = mfree(lp->generator_early); ++ lp->generator_late = mfree(lp->generator_late); + +- p->transient = mfree(p->transient); ++ lp->transient = mfree(lp->transient); + +- p->persistent_control = mfree(p->persistent_control); +- p->runtime_control = mfree(p->runtime_control); ++ lp->persistent_control = mfree(lp->persistent_control); ++ lp->runtime_control = mfree(lp->runtime_control); + +- p->root_dir = mfree(p->root_dir); +- p->temporary_dir = mfree(p->temporary_dir); ++ lp->root_dir = mfree(lp->root_dir); ++ lp->temporary_dir = mfree(lp->temporary_dir); + } + +-void lookup_paths_log(LookupPaths *p) { +- assert(p); ++void lookup_paths_log(LookupPaths *lp) { ++ assert(lp); + +- if (strv_isempty(p->search_path)) { ++ if (strv_isempty(lp->search_path)) { + log_debug("Ignoring unit files."); +- p->search_path = strv_free(p->search_path); ++ lp->search_path = strv_free(lp->search_path); + } else { + _cleanup_free_ char *t = NULL; + +- t = strv_join(p->search_path, "\n\t"); ++ t = strv_join(lp->search_path, "\n\t"); + log_debug("Looking for unit files in (higher priority first):\n\t%s", strna(t)); + } + } +diff --git a/src/basic/path-lookup.h b/src/basic/path-lookup.h +index af85dc7b4f..1f0e5ea271 100644 +--- a/src/basic/path-lookup.h ++++ b/src/basic/path-lookup.h +@@ -54,7 +54,8 @@ struct LookupPaths { + char *temporary_dir; + }; + +-int lookup_paths_init(LookupPaths *p, UnitFileScope scope, LookupPathsFlags flags, const char *root_dir); ++int lookup_paths_init(LookupPaths *lp, UnitFileScope scope, LookupPathsFlags flags, const char *root_dir); ++int lookup_paths_init_or_warn(LookupPaths *lp, UnitFileScope scope, LookupPathsFlags flags, const char *root_dir); + + int xdg_user_dirs(char ***ret_config_dirs, char ***ret_data_dirs); + int xdg_user_runtime_dir(char **ret, const char *suffix); +diff --git a/src/core/manager.c b/src/core/manager.c +index 12c49e7fca..22bd0866c5 100644 +--- a/src/core/manager.c ++++ b/src/core/manager.c +@@ -1756,11 +1756,11 @@ int manager_startup(Manager *m, FILE *serialization, FDSet *fds, const char *roo + + /* If we are running in test mode, we still want to run the generators, + * but we should not touch the real generator directories. */ +- r = lookup_paths_init(&m->lookup_paths, m->unit_file_scope, +- MANAGER_IS_TEST_RUN(m) ? LOOKUP_PATHS_TEMPORARY_GENERATED : 0, +- root); ++ r = lookup_paths_init_or_warn(&m->lookup_paths, m->unit_file_scope, ++ MANAGER_IS_TEST_RUN(m) ? LOOKUP_PATHS_TEMPORARY_GENERATED : 0, ++ root); + if (r < 0) +- return log_error_errno(r, "Failed to initialize path lookup table: %m"); ++ return r; + + dual_timestamp_get(m->timestamps + manager_timestamp_initrd_mangle(MANAGER_TIMESTAMP_GENERATORS_START)); + r = manager_run_environment_generators(m); +@@ -3302,9 +3302,9 @@ int manager_reload(Manager *m) { + m->uid_refs = hashmap_free(m->uid_refs); + m->gid_refs = hashmap_free(m->gid_refs); + +- r = lookup_paths_init(&m->lookup_paths, m->unit_file_scope, 0, NULL); ++ r = lookup_paths_init_or_warn(&m->lookup_paths, m->unit_file_scope, 0, NULL); + if (r < 0) +- log_warning_errno(r, "Failed to initialize path lookup table, ignoring: %m"); ++ return r; + + (void) manager_run_environment_generators(m); + (void) manager_run_generators(m); +diff --git a/src/shared/condition.c b/src/shared/condition.c +index 68fbbf643a..21f3714eba 100644 +--- a/src/shared/condition.c ++++ b/src/shared/condition.c +@@ -787,7 +787,8 @@ static int condition_test_needs_update(Condition *c, char **env) { + if (r < 0) { + log_debug_errno(r, "Failed to parse timestamp file '%s', using mtime: %m", p); + return true; +- } else if (r == 0) { ++ } ++ if (isempty(timestamp_str)) { + log_debug("No data in timestamp file '%s', using mtime.", p); + return true; + } +diff --git a/src/shared/install.c b/src/shared/install.c +index a541d32fb7..f1a8b7eb9b 100644 +--- a/src/shared/install.c ++++ b/src/shared/install.c +@@ -2615,7 +2615,7 @@ int unit_file_enable( + assert(scope >= 0); + assert(scope < _UNIT_FILE_SCOPE_MAX); + +- r = lookup_paths_init(&lp, scope, 0, root_dir); ++ r = lookup_paths_init_or_warn(&lp, scope, 0, root_dir); + if (r < 0) + return r; + +diff --git a/src/systemctl/systemctl-edit.c b/src/systemctl/systemctl-edit.c +index a97aa7be4c..92abd15636 100644 +--- a/src/systemctl/systemctl-edit.c ++++ b/src/systemctl/systemctl-edit.c +@@ -38,9 +38,9 @@ int cat(int argc, char *argv[], void *userdata) { + if (arg_transport != BUS_TRANSPORT_LOCAL) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Cannot remotely cat units."); + +- r = lookup_paths_init(&lp, arg_scope, 0, arg_root); ++ r = lookup_paths_init_or_warn(&lp, arg_scope, 0, arg_root); + if (r < 0) +- return log_error_errno(r, "Failed to determine unit paths: %m"); ++ return r; + + r = acquire_bus(BUS_MANAGER, &bus); + if (r < 0) +@@ -511,9 +511,9 @@ int edit(int argc, char *argv[], void *userdata) { + if (arg_transport != BUS_TRANSPORT_LOCAL) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Cannot edit units remotely."); + +- r = lookup_paths_init(&lp, arg_scope, 0, arg_root); ++ r = lookup_paths_init_or_warn(&lp, arg_scope, 0, arg_root); + if (r < 0) +- return log_error_errno(r, "Failed to determine unit paths: %m"); ++ return r; + + r = mac_selinux_init(); + if (r < 0) +diff --git a/src/systemctl/systemctl-enable.c b/src/systemctl/systemctl-enable.c +index dcbe2c7302..7860f3dc6c 100644 +--- a/src/systemctl/systemctl-enable.c ++++ b/src/systemctl/systemctl-enable.c +@@ -142,7 +142,7 @@ int enable_unit(int argc, char *argv[], void *userdata) { + char **name; + _cleanup_(lookup_paths_free) LookupPaths lp = {}; + +- r = lookup_paths_init(&lp, arg_scope, 0, arg_root); ++ r = lookup_paths_init_or_warn(&lp, arg_scope, 0, arg_root); + if (r < 0) + return r; + +diff --git a/src/systemctl/systemctl-sysv-compat.c b/src/systemctl/systemctl-sysv-compat.c +index 017dba2034..c6e8defd1b 100644 +--- a/src/systemctl/systemctl-sysv-compat.c ++++ b/src/systemctl/systemctl-sysv-compat.c +@@ -128,7 +128,7 @@ int enable_sysv_units(const char *verb, char **args) { + "is-enabled")) + return 0; + +- r = lookup_paths_init(&paths, arg_scope, LOOKUP_PATHS_EXCLUDE_GENERATED, arg_root); ++ r = lookup_paths_init_or_warn(&paths, arg_scope, LOOKUP_PATHS_EXCLUDE_GENERATED, arg_root); + if (r < 0) + return r; + +diff --git a/src/sysv-generator/sysv-generator.c b/src/sysv-generator/sysv-generator.c +index e9976540b5..bb74b486be 100644 +--- a/src/sysv-generator/sysv-generator.c ++++ b/src/sysv-generator/sysv-generator.c +@@ -894,9 +894,9 @@ static int run(const char *dest, const char *dest_early, const char *dest_late) + + assert_se(arg_dest = dest_late); + +- r = lookup_paths_init(&lp, UNIT_FILE_SYSTEM, LOOKUP_PATHS_EXCLUDE_GENERATED, NULL); ++ r = lookup_paths_init_or_warn(&lp, UNIT_FILE_SYSTEM, LOOKUP_PATHS_EXCLUDE_GENERATED, NULL); + if (r < 0) +- return log_error_errno(r, "Failed to find lookup paths: %m"); ++ return r; + + all_services = hashmap_new(&string_hash_ops); + if (!all_services) +diff --git a/src/test/test-fileio.c b/src/test/test-fileio.c +index 4f91d94709..238ae8f586 100644 +--- a/src/test/test-fileio.c ++++ b/src/test/test-fileio.c +@@ -110,8 +110,7 @@ TEST(parse_env_file) { + "eleven", &eleven, + "twelve", &twelve, + "thirteen", &thirteen); +- +- assert_se(r >= 0); ++ assert_se(r == 0); + + log_info("one=[%s]", strna(one)); + log_info("two=[%s]", strna(two)); +diff --git a/src/test/test-os-util.c b/src/test/test-os-util.c +index d6336c53e9..2cee6470c4 100644 +--- a/src/test/test-os-util.c ++++ b/src/test/test-os-util.c +@@ -18,7 +18,7 @@ TEST(path_is_os_tree) { + TEST(parse_os_release) { + /* Let's assume that we're running in a valid system, so os-release is available */ + _cleanup_free_ char *id = NULL, *id2 = NULL, *name = NULL, *foobar = NULL; +- assert_se(parse_os_release(NULL, "ID", &id) == 1); ++ assert_se(parse_os_release(NULL, "ID", &id) == 0); + log_info("ID: %s", id); + + assert_se(setenv("SYSTEMD_OS_RELEASE", "/dev/null", 1) == 0); +@@ -31,7 +31,7 @@ TEST(parse_os_release) { + "NAME=the-name") == 0); + + assert_se(setenv("SYSTEMD_OS_RELEASE", tmpfile, 1) == 0); +- assert_se(parse_os_release(NULL, "ID", &id, "NAME", &name) == 2); ++ assert_se(parse_os_release(NULL, "ID", &id, "NAME", &name) == 0); + log_info("ID: %s NAME: %s", id, name); + assert_se(streq(id, "the-id")); + assert_se(streq(name, "the-name")); +@@ -43,8 +43,7 @@ TEST(parse_os_release) { + "NAME='the-name'") == 0); + + assert_se(setenv("SYSTEMD_OS_RELEASE", tmpfile2, 1) == 0); +- // FIXME: we return 3, which means that the return value is useless in face of repeats +- assert_se(parse_os_release(NULL, "ID", &id, "NAME", &name) == 3); ++ assert_se(parse_os_release(NULL, "ID", &id, "NAME", &name) == 0); + log_info("ID: %s NAME: %s", id, name); + assert_se(streq(id, "the-id")); + assert_se(streq(name, "the-name")); diff --git a/0178-shared-install-also-check-for-self-aliases-during-in.patch b/0178-shared-install-also-check-for-self-aliases-during-in.patch new file mode 100644 index 0000000..f97f386 --- /dev/null +++ b/0178-shared-install-also-check-for-self-aliases-during-in.patch @@ -0,0 +1,134 @@ +From c892aaa100fa04f877c7bf66e3cce846a7aa834c Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Thu, 10 Mar 2022 20:26:59 +0100 +Subject: [PATCH] shared/install: also check for self-aliases during + installation and ignore them + +We had a check that was done in unit_file_resolve_symlink(). Let's move +the check to unit_validate_alias_symlink_or_warn(), which makes it available +to the code in install.c. + +With this, unit_file_resolve_symlink() behaves almost the same. The warning +about "suspicious symlink" is done a bit later. I think this should be OK. + +(cherry picked from commit f663e6468ff6f667a67fa1a0f9ca5c4962d4c605) + +Related: #2082131 +--- + src/basic/unit-file.c | 26 ++++++++++---------------- + src/shared/install.c | 9 +++++++++ + test/test-systemctl-enable.sh | 6 ++---- + 3 files changed, 21 insertions(+), 20 deletions(-) + +diff --git a/src/basic/unit-file.c b/src/basic/unit-file.c +index 105dacc1b2..142ba006f8 100644 +--- a/src/basic/unit-file.c ++++ b/src/basic/unit-file.c +@@ -82,7 +82,8 @@ int unit_validate_alias_symlink_or_warn(int log_level, const char *filename, con + * + * -EINVAL is returned if the something is wrong with the source filename or the source unit type is + * not allowed to symlink, +- * -EXDEV if the target filename is not a valid unit name or doesn't match the source. ++ * -EXDEV if the target filename is not a valid unit name or doesn't match the source, ++ * -ELOOP for an alias to self. + */ + + src = basename(filename); +@@ -111,6 +112,11 @@ int unit_validate_alias_symlink_or_warn(int log_level, const char *filename, con + + /* dst checks */ + ++ if (streq(src, dst)) ++ return log_debug_errno(SYNTHETIC_ERRNO(ELOOP), ++ "%s: unit self-alias: %s → %s, ignoring.", ++ filename, src, dst); ++ + dst_name_type = unit_name_to_instance(dst, &dst_instance); + if (dst_name_type < 0) + return log_full_errno(log_level, dst_name_type == -EINVAL ? SYNTHETIC_ERRNO(EXDEV) : dst_name_type, +@@ -348,24 +354,12 @@ int unit_file_resolve_symlink( + if (r < 0) + return r; + +- bool self_alias = streq(target_name, filename); +- +- if (is_path(tail)) +- log_full(self_alias ? LOG_DEBUG : LOG_WARNING, +- "Suspicious symlink %s/%s→%s, treating as alias.", +- dir, filename, simplified); +- + r = unit_validate_alias_symlink_or_warn(LOG_NOTICE, filename, simplified); + if (r < 0) + return r; +- +- if (self_alias && !resolve_destination_target) +- /* A self-alias that has no effect when loading, let's just ignore it. */ +- return log_debug_errno(SYNTHETIC_ERRNO(ELOOP), +- "Unit file self-alias: %s/%s → %s, ignoring.", +- dir, filename, target_name); +- +- log_debug("Unit file alias: %s/%s → %s", dir, filename, target_name); ++ if (is_path(tail)) ++ log_warning("Suspicious symlink %s/%s→%s, treating as alias.", ++ dir, filename, simplified); + + dst = resolve_destination_target ? TAKE_PTR(simplified) : TAKE_PTR(target_name); + } +diff --git a/src/shared/install.c b/src/shared/install.c +index f1a8b7eb9b..459e8a6951 100644 +--- a/src/shared/install.c ++++ b/src/shared/install.c +@@ -1702,6 +1702,11 @@ int unit_file_verify_alias( + * ret_dst is set in cases where "instance propagation" happens, i.e. when the instance part is + * inserted into dst. It is not normally set, even on success, so that the caller can easily + * distinguish the case where instance propagation occurred. ++ * ++ * Returns: ++ * -EXDEV when the alias doesn't match the unit, ++ * -EUCLEAN when the name is invalid, ++ * -ELOOP when the alias it to the unit itself. + */ + + const char *path_alias = strrchr(dst, '/'); +@@ -1767,6 +1772,8 @@ int unit_file_verify_alias( + } + + r = unit_validate_alias_symlink_or_warn(LOG_DEBUG, dst_updated ?: dst, info->name); ++ if (r == -ELOOP) /* -ELOOP means self-alias, which we (quietly) ignore */ ++ return r; + if (r < 0) { + unit_file_changes_add(changes, n_changes, + r == -EINVAL ? -EXDEV : r, +@@ -1807,6 +1814,8 @@ static int install_info_symlink_alias( + } + + q = unit_file_verify_alias(info, dst, &dst_updated, changes, n_changes); ++ if (q == -ELOOP) ++ continue; + if (q < 0) { + r = r < 0 ? r : q; + continue; +diff --git a/test/test-systemctl-enable.sh b/test/test-systemctl-enable.sh +index 32bc6e5ef7..4117436462 100644 +--- a/test/test-systemctl-enable.sh ++++ b/test/test-systemctl-enable.sh +@@ -328,8 +328,7 @@ test ! -h "$root/etc/systemd/system/services.target.wants/templ1@two.service" + test ! -e "$root/etc/systemd/system/link4.service" + cat >"$root/etc/systemd/system/link4.service" <"$root/etc/systemd/system/link5.service" < +Date: Sun, 13 Feb 2022 15:16:05 +0100 +Subject: [PATCH] docs: Correct WantedBy= regarding template units + +(cherry picked from commit f55fe53ffce351bb55b6190cf36511c37f99d766) + +Related: #2082131 +--- + man/systemd.unit.xml | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/man/systemd.unit.xml b/man/systemd.unit.xml +index 4ba602b5ad..2e6261c1ed 100644 +--- a/man/systemd.unit.xml ++++ b/man/systemd.unit.xml +@@ -1922,9 +1922,9 @@ + WantedBy=foo.service in a service + bar.service is mostly equivalent to + Alias=foo.service.wants/bar.service in the +- same file. In case of template units, systemctl +- enable must be called with an instance name, and +- this instance will be added to the ++ same file. In case of template units listing non template units, ++ systemctl enable must be called with an ++ instance name, and this instance will be added to the + .wants/ or + .requires/ list of the listed unit. E.g. + WantedBy=getty.target in a service diff --git a/0180-man-fix-invalid-description-of-template-handling-in-.patch b/0180-man-fix-invalid-description-of-template-handling-in-.patch new file mode 100644 index 0000000..2fc62e6 --- /dev/null +++ b/0180-man-fix-invalid-description-of-template-handling-in-.patch @@ -0,0 +1,152 @@ +From 842c3bade0b593e5c4eabbe1c18dfab503683cc6 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Thu, 10 Mar 2022 21:33:25 +0100 +Subject: [PATCH] man: fix invalid description of template handling in + WantedBy= + +We don't need to talk about Alias=. The approach of using Alias= to enable +units is still supported, but hasn't been advertised as the way to do thing +for many years. Using it as an explanation is just confusing. + +Also, the description of templated units did not take DefaultInstance= +into account. It is updated and extended. + +(cherry picked from commit 17a2679e9925c9ec3c5764d01def92c5627973e4) + +Related: #2082131 +--- + man/systemd.unit.xml | 53 +++++++++++++++++------------------ + test/test-systemctl-enable.sh | 49 ++++++++++++++++++++++++++++++++ + 2 files changed, 74 insertions(+), 28 deletions(-) + +diff --git a/man/systemd.unit.xml b/man/systemd.unit.xml +index 2e6261c1ed..caebaecfdc 100644 +--- a/man/systemd.unit.xml ++++ b/man/systemd.unit.xml +@@ -1906,34 +1906,31 @@ + WantedBy= + RequiredBy= + +- This option may be used more than once, or a +- space-separated list of unit names may be given. A symbolic +- link is created in the .wants/ or +- .requires/ directory of each of the +- listed units when this unit is installed by systemctl +- enable. This has the effect that a dependency of +- type Wants= or Requires= +- is added from the listed unit to the current unit. The primary +- result is that the current unit will be started when the +- listed unit is started. See the description of +- Wants= and Requires= in +- the [Unit] section for details. +- +- WantedBy=foo.service in a service +- bar.service is mostly equivalent to +- Alias=foo.service.wants/bar.service in the +- same file. In case of template units listing non template units, +- systemctl enable must be called with an +- instance name, and this instance will be added to the +- .wants/ or +- .requires/ list of the listed unit. E.g. +- WantedBy=getty.target in a service +- getty@.service will result in +- systemctl enable getty@tty2.service +- creating a +- getty.target.wants/getty@tty2.service +- link to getty@.service. +- ++ This option may be used more than once, or a space-separated list of unit names may ++ be given. A symbolic link is created in the .wants/ or ++ .requires/ directory of each of the listed units when this unit is installed by ++ systemctl enable. This has the effect of a dependency of type ++ Wants= or Requires= being added from the listed unit to the ++ current unit. The primary result is that the current unit will be started when the listed unit is ++ started, see the description of Wants= and Requires= in the ++ [Unit] section for details. ++ ++ In case of template units listing non template units, the listing unit must have ++ DefaultInstance= set, or systemctl enable must be called with ++ an instance name. The instance (default or specified) will be added to the ++ .wants/ or .requires/ list of the listed unit. For example, ++ WantedBy=getty.target in a service getty@.service will result ++ in systemctl enable getty@tty2.service creating a ++ getty.target.wants/getty@tty2.service link to ++ getty@.service. This also applies to listing specific instances of templated ++ units: this specific instance will gain the dependency. A template unit may also list a template ++ unit, in which case a generic dependency will be added where each instance of the listing unit will ++ have a dependency on an instance of the listed template with the same instance value. For example, ++ WantedBy=container@.target in a service monitor@.service will ++ result in systemctl enable monitor@.service creating a ++ container@.target.wants/monitor@.service link to ++ monitor@.service, which applies to all instances of ++ container@.target. + + + +diff --git a/test/test-systemctl-enable.sh b/test/test-systemctl-enable.sh +index 4117436462..3aa61222a8 100644 +--- a/test/test-systemctl-enable.sh ++++ b/test/test-systemctl-enable.sh +@@ -324,6 +324,31 @@ test ! -h "$root/etc/systemd/system/services.target.wants/templ1@333.service" + test ! -h "$root/etc/systemd/system/services.target.wants/templ1@one.service" + test ! -h "$root/etc/systemd/system/services.target.wants/templ1@two.service" + ++: -------template enablement for another template------------- ++cat >"$root/etc/systemd/system/templ2@.service" <"$root/etc/systemd/system/link4.service" <&2; exit 1; } + ++: -------specifiers in WantedBy------------------------------- ++# We don't need to repeat all the tests. Let's do a basic check that specifier ++# expansion is performed. ++ ++cat >"$root/etc/systemd/system/some-some-link7.socket" < +Date: Wed, 2 Mar 2022 17:19:56 +0100 +Subject: [PATCH] shared/install: drop unnecessary casts + +The compiler coerces to bool for us, no need to do it explicitly. + +(cherry picked from commit d3e85c9c81b1dd55eed2a33e8c25cef38db665f9) + +Related: #2082131 +--- + src/shared/install.c | 9 ++++----- + 1 file changed, 4 insertions(+), 5 deletions(-) + +diff --git a/src/shared/install.c b/src/shared/install.c +index 459e8a6951..f1ee3c2716 100644 +--- a/src/shared/install.c ++++ b/src/shared/install.c +@@ -2178,7 +2178,7 @@ int unit_file_mask( + if (!path) + return -ENOMEM; + +- q = create_symlink(&lp, "/dev/null", path, !!(flags & UNIT_FILE_FORCE), changes, n_changes); ++ q = create_symlink(&lp, "/dev/null", path, flags & UNIT_FILE_FORCE, changes, n_changes); + if (q < 0 && r >= 0) + r = q; + } +@@ -2199,7 +2199,6 @@ int unit_file_unmask( + _cleanup_strv_free_ char **todo = NULL; + const char *config_path; + size_t n_todo = 0; +- bool dry_run; + char **i; + int r, q; + +@@ -2214,7 +2213,7 @@ int unit_file_unmask( + if (!config_path) + return -ENXIO; + +- dry_run = !!(flags & UNIT_FILE_DRY_RUN); ++ bool dry_run = flags & UNIT_FILE_DRY_RUN; + + STRV_FOREACH(i, files) { + _cleanup_free_ char *path = NULL; +@@ -2354,7 +2353,7 @@ int unit_file_link( + if (!new_path) + return -ENOMEM; + +- q = create_symlink(&lp, *i, new_path, !!(flags & UNIT_FILE_FORCE), changes, n_changes); ++ q = create_symlink(&lp, *i, new_path, flags & UNIT_FILE_FORCE, changes, n_changes); + if (q < 0 && r >= 0) + r = q; + } +@@ -2689,7 +2688,7 @@ int unit_file_disable( + if (r < 0) + return r; + +- return remove_marked_symlinks(remove_symlinks_to, config_path, &lp, !!(flags & UNIT_FILE_DRY_RUN), changes, n_changes); ++ return remove_marked_symlinks(remove_symlinks_to, config_path, &lp, flags & UNIT_FILE_DRY_RUN, changes, n_changes); + } + + int unit_file_reenable( diff --git a/0182-strv-make-iterator-in-STRV_FOREACH-declaread-in-the-.patch b/0182-strv-make-iterator-in-STRV_FOREACH-declaread-in-the-.patch new file mode 100644 index 0000000..7679d6c --- /dev/null +++ b/0182-strv-make-iterator-in-STRV_FOREACH-declaread-in-the-.patch @@ -0,0 +1,5179 @@ +From 86eae9a1dade5ba15990196b1459e1394bf0a632 Mon Sep 17 00:00:00 2001 +From: Yu Watanabe +Date: Wed, 16 Mar 2022 22:32:23 +0900 +Subject: [PATCH] strv: make iterator in STRV_FOREACH() declaread in the loop + +This also avoids multiple evaluations in STRV_FOREACH_BACKWARDS() + +(cherry picked from commit de010b0b2e50cf0b3837ce350b116bc92605f67a) + +Related: #2082131 +--- + src/activate/activate.c | 3 -- + src/analyze/analyze-condition.c | 2 -- + src/analyze/analyze-elf.c | 1 - + src/analyze/analyze-security.c | 7 +--- + src/analyze/analyze-verify.c | 3 -- + src/analyze/analyze.c | 27 ++------------ + src/ask-password/ask-password.c | 1 - + src/basic/conf-files.c | 9 ++--- + src/basic/env-file.c | 1 - + src/basic/env-util.c | 19 +++------- + src/basic/escape.c | 1 - + src/basic/fileio.c | 2 -- + src/basic/hashmap.c | 1 - + src/basic/ordered-set.c | 1 - + src/basic/os-util.c | 1 - + src/basic/path-lookup.c | 1 - + src/basic/path-util.c | 20 ++++------- + src/basic/process-util.c | 1 - + src/basic/strv.c | 28 ++------------- + src/basic/strv.h | 35 ++++++++++++------- + src/basic/unit-file.c | 8 ++--- + src/binfmt/binfmt.c | 1 - + src/boot/bless-boot.c | 2 -- + src/boot/bootctl.c | 2 -- + src/busctl/busctl.c | 5 +-- + src/cgls/cgls.c | 1 - + src/core/bpf-firewall.c | 2 -- + src/core/cgroup.c | 1 - + src/core/dbus-cgroup.c | 2 -- + src/core/dbus-execute.c | 26 +++----------- + src/core/dbus-manager.c | 1 - + src/core/dbus-socket.c | 4 +-- + src/core/dbus-unit.c | 5 +-- + src/core/device.c | 16 +++------ + src/core/execute.c | 16 +++------ + src/core/load-dropin.c | 2 -- + src/core/load-fragment.c | 1 - + src/core/main.c | 1 - + src/core/manager.c | 1 - + src/core/namespace.c | 6 ---- + src/core/service.c | 2 -- + src/core/socket.c | 4 --- + src/core/transaction.c | 3 +- + src/core/unit-serialize.c | 2 +- + src/core/unit.c | 6 ---- + src/coredump/coredumpctl.c | 1 - + src/creds/creds.c | 1 - + src/cryptenroll/cryptenroll.c | 1 - + src/cryptsetup/cryptsetup-keyfile.c | 1 - + src/cryptsetup/cryptsetup.c | 4 +-- + src/debug-generator/debug-generator.c | 2 -- + src/delta/delta.c | 2 -- + src/dissect/dissect.c | 3 -- + .../environment-d-generator.c | 1 - + src/escape/escape.c | 1 - + src/fstab-generator/fstab-generator.c | 3 -- + src/home/homectl.c | 11 ++---- + src/home/homed-manager-bus.c | 1 - + src/home/homed-manager.c | 1 - + src/home/homed-varlink.c | 6 +--- + src/home/homework-cifs.c | 1 - + src/home/homework-fscrypt.c | 3 -- + src/home/homework-luks.c | 3 -- + src/home/homework-pkcs11.c | 1 - + src/home/homework.c | 13 ++----- + src/home/user-record-pwquality.c | 3 +- + src/home/user-record-util.c | 3 -- + src/id128/id128.c | 1 - + src/journal-remote/journal-remote-main.c | 1 - + src/journal-remote/microhttpd-util.c | 5 ++- + src/journal/journalctl.c | 5 +-- + src/libsystemd-network/dhcp-option.c | 1 - + src/libsystemd-network/dhcp6-option.c | 2 -- + src/libsystemd-network/sd-dhcp-client.c | 1 - + src/libsystemd-network/sd-dhcp6-client.c | 2 -- + src/libsystemd-network/sd-radv.c | 1 - + src/libsystemd/sd-bus/bus-dump.c | 4 --- + src/libsystemd/sd-bus/bus-match.c | 6 ---- + src/libsystemd/sd-bus/bus-message.c | 1 - + src/libsystemd/sd-bus/bus-objects.c | 4 +-- + src/libsystemd/sd-bus/test-bus-address.c | 1 - + src/libsystemd/sd-device/device-private.c | 1 - + src/libsystemd/sd-journal/catalog.c | 2 -- + src/libsystemd/sd-journal/sd-journal.c | 1 - + src/libsystemd/sd-netlink/netlink-message.c | 1 - + src/libsystemd/sd-path/sd-path.c | 2 +- + src/locale/localectl.c | 2 -- + src/locale/localed.c | 1 - + src/login/loginctl.c | 2 -- + src/login/logind-dbus.c | 1 - + src/login/pam_systemd.c | 1 - + src/modules-load/modules-load.c | 1 - + src/network/generator/network-generator.c | 1 - + src/network/netdev/netdev.c | 1 - + src/network/networkctl.c | 1 - + src/network/networkd-dhcp-server.c | 2 -- + src/network/networkd-json.c | 3 +- + src/network/networkd-link-bus.c | 2 -- + src/network/networkd-link.c | 3 -- + src/network/networkd-ndisc.c | 1 - + src/network/networkd-network.c | 1 - + src/nspawn/nspawn-bind-user.c | 1 - + src/nspawn/nspawn-mount.c | 4 --- + src/nspawn/nspawn-network.c | 5 --- + src/nspawn/nspawn-oci.c | 1 - + src/nspawn/nspawn-seccomp.c | 1 - + src/nspawn/nspawn.c | 1 - + src/nss-systemd/userdb-glue.c | 2 +- + src/partition/repart.c | 3 -- + src/portable/portable.c | 7 ---- + src/portable/portablectl.c | 2 -- + src/resolve/resolvectl.c | 9 +---- + src/resolve/resolved-dns-trust-anchor.c | 1 - + src/resolve/resolved-dnssd.c | 1 - + src/resolve/resolved-etc-hosts.c | 3 -- + src/resolve/resolved-link-bus.c | 1 - + src/resolve/resolved-link.c | 2 -- + src/run-generator/run-generator.c | 1 - + src/shared/acl-util.c | 1 - + src/shared/bootspec.c | 4 --- + src/shared/bus-polkit.c | 1 - + src/shared/bus-unit-util.c | 3 -- + src/shared/bus-util.c | 2 -- + src/shared/cgroup-setup.c | 1 - + src/shared/condition.c | 1 - + src/shared/conf-parser.c | 1 - + src/shared/discover-image.c | 6 +--- + src/shared/dissect-image.c | 1 - + src/shared/dropin.c | 1 - + src/shared/exec-util.c | 4 +-- + src/shared/format-table.c | 1 - + src/shared/hwdb-util.c | 3 +- + src/shared/install.c | 28 +++------------ + src/shared/libcrypt-util.c | 1 - + src/shared/libfido2-util.c | 3 -- + src/shared/mount-setup.c | 3 -- + src/shared/mount-util.c | 1 - + src/shared/net-condition.c | 4 --- + src/shared/nscd-flush.c | 1 - + src/shared/pkcs11-util.c | 2 +- + src/shared/pretty-print.c | 4 +-- + src/shared/seccomp-util.c | 1 - + src/shared/serialize.c | 1 - + src/shared/tests.c | 1 - + src/shared/user-record-show.c | 13 ++----- + src/sleep/sleep.c | 2 -- + src/sysctl/sysctl.c | 4 --- + src/sysext/sysext.c | 6 ---- + src/systemctl/systemctl-cancel-job.c | 1 - + src/systemctl/systemctl-clean-or-freeze.c | 1 - + src/systemctl/systemctl-edit.c | 6 +--- + src/systemctl/systemctl-enable.c | 3 -- + src/systemctl/systemctl-is-active.c | 1 - + src/systemctl/systemctl-is-enabled.c | 1 - + src/systemctl/systemctl-kill.c | 2 +- + src/systemctl/systemctl-list-dependencies.c | 3 +- + src/systemctl/systemctl-list-machines.c | 1 - + src/systemctl/systemctl-list-units.c | 1 - + src/systemctl/systemctl-logind.c | 2 -- + src/systemctl/systemctl-reset-failed.c | 1 - + src/systemctl/systemctl-set-environment.c | 3 -- + src/systemctl/systemctl-set-property.c | 1 - + src/systemctl/systemctl-show.c | 7 ---- + src/systemctl/systemctl-start-unit.c | 6 +--- + src/systemctl/systemctl-util.c | 7 +--- + src/sysusers/sysusers.c | 6 ---- + src/sysv-generator/sysv-generator.c | 3 -- + src/test/test-bpf-foreign-programs.c | 2 -- + src/test/test-bpf-lsm.c | 1 - + src/test/test-copy.c | 1 - + src/test/test-env-util.c | 1 - + src/test/test-exec-util.c | 4 +-- + src/test/test-execute.c | 2 -- + src/test/test-fileio.c | 5 --- + src/test/test-fs-util.c | 1 - + src/test/test-kbd-util.c | 1 - + src/test/test-locale-util.c | 2 -- + src/test/test-nss-hosts.c | 5 --- + src/test/test-nss-users.c | 2 -- + src/test/test-path-lookup.c | 3 +- + src/test/test-path-util.c | 1 - + src/test/test-path.c | 1 - + src/test/test-sd-path.c | 1 - + src/test/test-socket-bind.c | 3 +- + src/test/test-string-util.c | 1 - + src/test/test-strv.c | 5 --- + src/test/test-sysctl-util.c | 1 - + src/test/test-time-util.c | 1 - + src/test/test-unit-file.c | 1 - + src/timedate/timedated.c | 1 - + src/timesync/timesyncd-manager.c | 1 - + src/tmpfiles/tmpfiles.c | 14 ++------ + .../tty-ask-password-agent.c | 5 +-- + src/udev/net/link-config.c | 2 -- + src/udev/udev-event.c | 1 - + src/udev/udev-rules.c | 4 +-- + src/udev/udevadm-info.c | 1 - + src/userdb/userdbctl.c | 24 ++++--------- + .../xdg-autostart-condition.c | 1 - + .../xdg-autostart-generator.c | 1 - + 200 files changed, 110 insertions(+), 611 deletions(-) + +diff --git a/src/activate/activate.c b/src/activate/activate.c +index b625d97f2e..8ee7a3ec60 100644 +--- a/src/activate/activate.c ++++ b/src/activate/activate.c +@@ -49,7 +49,6 @@ static int add_epoll(int epoll_fd, int fd) { + } + + static int open_sockets(int *epoll_fd, bool accept) { +- char **address; + int n, fd, r, count = 0; + + n = sd_listen_fds(true); +@@ -124,7 +123,6 @@ static int open_sockets(int *epoll_fd, bool accept) { + + static int exec_process(const char *name, char **argv, int start_fd, size_t n_fds) { + _cleanup_strv_free_ char **envp = NULL; +- char **s; + int r; + + if (arg_inetd && n_fds != 1) +@@ -389,7 +387,6 @@ static int parse_argv(int argc, char *argv[]) { + + case ARG_FDNAME: { + _cleanup_strv_free_ char **names = NULL; +- char **s; + + names = strv_split(optarg, ":"); + if (!names) +diff --git a/src/analyze/analyze-condition.c b/src/analyze/analyze-condition.c +index f57bb27b9a..a7ad085f46 100644 +--- a/src/analyze/analyze-condition.c ++++ b/src/analyze/analyze-condition.c +@@ -113,8 +113,6 @@ int verify_conditions(char **lines, UnitFileScope scope, const char *unit, const + if (r < 0) + return r; + } else { +- char **line; +- + r = unit_new_for_name(m, sizeof(Service), "test.service", &u); + if (r < 0) + return log_error_errno(r, "Failed to create test.service: %m"); +diff --git a/src/analyze/analyze-elf.c b/src/analyze/analyze-elf.c +index 741cd20f99..a0aa97da69 100644 +--- a/src/analyze/analyze-elf.c ++++ b/src/analyze/analyze-elf.c +@@ -11,7 +11,6 @@ + #include "strv.h" + + int analyze_elf(char **filenames, JsonFormatFlags json_flags) { +- char **filename; + int r; + + STRV_FOREACH(filename, filenames) { +diff --git a/src/analyze/analyze-security.c b/src/analyze/analyze-security.c +index 2691dc2c86..d8ccbf8c54 100644 +--- a/src/analyze/analyze-security.c ++++ b/src/analyze/analyze-security.c +@@ -2663,7 +2663,6 @@ static int offline_security_checks(char **filenames, + _cleanup_free_ char *var = NULL; + int r, k; + size_t count = 0; +- char **filename; + + if (strv_isempty(filenames)) + return 0; +@@ -2786,7 +2785,6 @@ int analyze_security(sd_bus *bus, + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; + _cleanup_strv_free_ char **list = NULL; + size_t n = 0; +- char **i; + + r = sd_bus_call_method( + bus, +@@ -2838,9 +2836,7 @@ int analyze_security(sd_bus *bus, + ret = r; + } + +- } else { +- char **i; +- ++ } else + STRV_FOREACH(i, units) { + _cleanup_free_ char *mangled = NULL, *instance = NULL; + const char *name; +@@ -2872,7 +2868,6 @@ int analyze_security(sd_bus *bus, + if (r < 0 && ret >= 0) + ret = r; + } +- } + + if (overview_table) { + if (!FLAGS_SET(flags, ANALYZE_SECURITY_SHORT)) { +diff --git a/src/analyze/analyze-verify.c b/src/analyze/analyze-verify.c +index 943a1f27de..39eb5cf93b 100644 +--- a/src/analyze/analyze-verify.c ++++ b/src/analyze/analyze-verify.c +@@ -75,7 +75,6 @@ int verify_prepare_filename(const char *filename, char **ret) { + + int verify_generate_path(char **var, char **filenames) { + const char *old; +- char **filename; + + _cleanup_strv_free_ char **ans = NULL; + int r; +@@ -184,7 +183,6 @@ static int verify_executables(Unit *u, const char *root) { + } + + static int verify_documentation(Unit *u, bool check_man) { +- char **p; + int r = 0, k; + + STRV_FOREACH(p, u->documentation) { +@@ -258,7 +256,6 @@ int verify_units(char **filenames, UnitFileScope scope, bool check_man, bool run + Unit *units[strv_length(filenames)]; + _cleanup_free_ char *var = NULL; + int r, k, i, count = 0; +- char **filename; + + if (strv_isempty(filenames)) + return 0; +diff --git a/src/analyze/analyze.c b/src/analyze/analyze.c +index a1908ff442..846acf31d3 100644 +--- a/src/analyze/analyze.c ++++ b/src/analyze/analyze.c +@@ -239,7 +239,6 @@ static int compare_unit_start(const UnitTimes *a, const UnitTimes *b) { + + static int process_aliases(char *argv[], char *tempdir, char ***ret) { + _cleanup_strv_free_ char **filenames = NULL; +- char **filename; + int r; + + assert(argv); +@@ -961,7 +960,6 @@ static bool times_in_range(const UnitTimes *times, const BootTimes *boot) { + + static int list_dependencies_one(sd_bus *bus, const char *name, unsigned level, char ***units, unsigned branches) { + _cleanup_strv_free_ char **deps = NULL; +- char **c; + int r; + usec_t service_longest = 0; + int to_print = 0; +@@ -1111,7 +1109,6 @@ static int analyze_critical_chain(int argc, char *argv[], void *userdata) { + "The time the unit took to start is printed after the \"+\" character.\n"); + + if (argc > 1) { +- char **name; + STRV_FOREACH(name, strv_skip(argv, 1)) + list_dependencies(bus, *name); + } else +@@ -1207,7 +1204,6 @@ static int graph_one_property( + char *to_patterns[]) { + + _cleanup_strv_free_ char **units = NULL; +- char **unit; + int r; + bool match_patterns; + +@@ -1273,7 +1269,6 @@ static int graph_one(sd_bus *bus, const UnitInfo *u, char *patterns[], char *fro + + static int expand_patterns(sd_bus *bus, char **patterns, char ***ret) { + _cleanup_strv_free_ char **expanded_patterns = NULL; +- char **pattern; + int r; + + STRV_FOREACH(pattern, patterns) { +@@ -1427,7 +1422,7 @@ static int dump(int argc, char *argv[], void *userdata) { + } + + static int cat_config(int argc, char *argv[], void *userdata) { +- char **arg, **list; ++ char **list; + int r; + + pager_open(arg_pager_flags); +@@ -1476,7 +1471,6 @@ static int verb_log_control(int argc, char *argv[], void *userdata) { + } + + static bool strv_fnmatch_strv_or_empty(char* const* patterns, char **strv, int flags) { +- char **s; + STRV_FOREACH(s, strv) + if (strv_fnmatch_or_empty(patterns, *s, flags)) + return true; +@@ -1524,7 +1518,6 @@ static int do_unit_files(int argc, char *argv[], void *userdata) { + static int dump_unit_paths(int argc, char *argv[], void *userdata) { + _cleanup_(lookup_paths_free) LookupPaths paths = {}; + int r; +- char **p; + + r = lookup_paths_init(&paths, arg_scope, 0, NULL); + if (r < 0) +@@ -1737,7 +1730,6 @@ static int dump_syscall_filters(int argc, char *argv[], void *userdata) { + + if (!set_isempty(known)) { + _cleanup_free_ char **l = NULL; +- char **syscall; + + printf("\n" + "# %sUngrouped System Calls%s (known but not included in any of the groups except @known):\n", +@@ -1760,7 +1752,6 @@ static int dump_syscall_filters(int argc, char *argv[], void *userdata) { + log_notice_errno(k, "# Not showing unlisted system calls, couldn't retrieve kernel system call list: %m"); + } else if (!set_isempty(kernel)) { + _cleanup_free_ char **l = NULL; +- char **syscall; + + printf("\n" + "# %sUnlisted System Calls%s (supported by the local kernel, but not included in any of the groups listed above):\n", +@@ -1775,9 +1766,7 @@ static int dump_syscall_filters(int argc, char *argv[], void *userdata) { + STRV_FOREACH(syscall, l) + printf("# %s\n", *syscall); + } +- } else { +- char **name; +- ++ } else + STRV_FOREACH(name, strv_skip(argv, 1)) { + const SyscallFilterSet *set; + +@@ -1796,7 +1785,6 @@ static int dump_syscall_filters(int argc, char *argv[], void *userdata) { + dump_syscall_filter(set); + first = false; + } +- } + + return 0; + } +@@ -1944,7 +1932,6 @@ static int dump_filesystems(int argc, char *argv[], void *userdata) { + + if (!set_isempty(known)) { + _cleanup_free_ char **l = NULL; +- char **filesystem; + + printf("\n" + "# %sUngrouped filesystems%s (known but not included in any of the groups except @known):\n", +@@ -1987,7 +1974,6 @@ static int dump_filesystems(int argc, char *argv[], void *userdata) { + log_notice_errno(k, "# Not showing unlisted filesystems, couldn't retrieve kernel filesystem list: %m"); + } else if (!set_isempty(kernel)) { + _cleanup_free_ char **l = NULL; +- char **filesystem; + + printf("\n" + "# %sUnlisted filesystems%s (available to the local kernel, but not included in any of the groups listed above):\n", +@@ -2002,9 +1988,7 @@ static int dump_filesystems(int argc, char *argv[], void *userdata) { + STRV_FOREACH(filesystem, l) + printf("# %s\n", *filesystem); + } +- } else { +- char **name; +- ++ } else + STRV_FOREACH(name, strv_skip(argv, 1)) { + const FilesystemSet *set; + +@@ -2023,7 +2007,6 @@ static int dump_filesystems(int argc, char *argv[], void *userdata) { + dump_filesystem_set(set); + first = false; + } +- } + + return 0; + } +@@ -2041,8 +2024,6 @@ static void parsing_hint(const char *p, bool calendar, bool timestamp, bool time + } + + static int dump_timespan(int argc, char *argv[], void *userdata) { +- char **input_timespan; +- + STRV_FOREACH(input_timespan, strv_skip(argv, 1)) { + _cleanup_(table_unrefp) Table *table = NULL; + usec_t output_usecs; +@@ -2180,7 +2161,6 @@ static int test_timestamp_one(const char *p) { + + static int test_timestamp(int argc, char *argv[], void *userdata) { + int ret = 0, r; +- char **p; + + STRV_FOREACH(p, strv_skip(argv, 1)) { + r = test_timestamp_one(*p); +@@ -2312,7 +2292,6 @@ static int test_calendar_one(usec_t n, const char *p) { + + static int test_calendar(int argc, char *argv[], void *userdata) { + int ret = 0, r; +- char **p; + usec_t n; + + if (arg_base_time != USEC_INFINITY) +diff --git a/src/ask-password/ask-password.c b/src/ask-password/ask-password.c +index a100679af2..093533182f 100644 +--- a/src/ask-password/ask-password.c ++++ b/src/ask-password/ask-password.c +@@ -223,7 +223,6 @@ static int parse_argv(int argc, char *argv[]) { + static int run(int argc, char *argv[]) { + _cleanup_strv_free_erase_ char **l = NULL; + usec_t timeout; +- char **p; + int r; + + log_show_color(true); +diff --git a/src/basic/conf-files.c b/src/basic/conf-files.c +index 287428b561..82c6dc5677 100644 +--- a/src/basic/conf-files.c ++++ b/src/basic/conf-files.c +@@ -145,7 +145,7 @@ static int conf_files_list_strv_internal( + + _cleanup_hashmap_free_ Hashmap *fh = NULL; + _cleanup_set_free_free_ Set *masked = NULL; +- char **files, **p; ++ char **files; + int r; + + assert(ret); +@@ -202,11 +202,8 @@ int conf_files_insert(char ***strv, const char *root, char **dirs, const char *p + int c; + + c = base_cmp((char* const*) *strv + i, (char* const*) &path); +- if (c == 0) { +- char **dir; +- ++ if (c == 0) + /* Oh, there already is an entry with a matching name (the last component). */ +- + STRV_FOREACH(dir, dirs) { + _cleanup_free_ char *rdir = NULL; + char *p1, *p2; +@@ -233,7 +230,7 @@ int conf_files_insert(char ***strv, const char *root, char **dirs, const char *p + } + } + +- } else if (c > 0) ++ else if (c > 0) + /* Following files have lower priority, let's go insert our + * new entry. */ + break; +diff --git a/src/basic/env-file.c b/src/basic/env-file.c +index 0e272da083..b46a679e06 100644 +--- a/src/basic/env-file.c ++++ b/src/basic/env-file.c +@@ -520,7 +520,6 @@ static void write_env_var(FILE *f, const char *v) { + int write_env_file(const char *fname, char **l) { + _cleanup_fclose_ FILE *f = NULL; + _cleanup_free_ char *p = NULL; +- char **i; + int r; + + assert(fname); +diff --git a/src/basic/env-util.c b/src/basic/env-util.c +index 885967e7f3..455f5d76f5 100644 +--- a/src/basic/env-util.c ++++ b/src/basic/env-util.c +@@ -96,8 +96,6 @@ bool env_assignment_is_valid(const char *e) { + } + + bool strv_env_is_valid(char **e) { +- char **p, **q; +- + STRV_FOREACH(p, e) { + size_t k; + +@@ -115,8 +113,6 @@ bool strv_env_is_valid(char **e) { + } + + bool strv_env_name_is_valid(char **l) { +- char **p; +- + STRV_FOREACH(p, l) { + if (!env_name_is_valid(*p)) + return false; +@@ -129,8 +125,6 @@ bool strv_env_name_is_valid(char **l) { + } + + bool strv_env_name_or_assignment_is_valid(char **l) { +- char **p; +- + STRV_FOREACH(p, l) { + if (!env_assignment_is_valid(*p) && !env_name_is_valid(*p)) + return false; +@@ -272,7 +266,7 @@ static bool env_entry_has_name(const char *entry, const char *name) { + + char **strv_env_delete(char **x, size_t n_lists, ...) { + size_t n, i = 0; +- char **k, **r; ++ char **r; + va_list ap; + + /* Deletes every entry from x that is mentioned in the other +@@ -287,7 +281,7 @@ char **strv_env_delete(char **x, size_t n_lists, ...) { + STRV_FOREACH(k, x) { + va_start(ap, n_lists); + for (size_t v = 0; v < n_lists; v++) { +- char **l, **j; ++ char **l; + + l = va_arg(ap, char**); + STRV_FOREACH(j, l) +@@ -379,7 +373,6 @@ char **strv_env_unset_many(char **l, ...) { + + int strv_env_replace_consume(char ***l, char *p) { + const char *t, *name; +- char **f; + int r; + + assert(p); +@@ -467,8 +460,6 @@ int strv_env_assign(char ***l, const char *key, const char *value) { + } + + char *strv_env_get_n(char **l, const char *name, size_t k, unsigned flags) { +- char **i; +- + assert(name); + + if (k <= 0) +@@ -496,7 +487,7 @@ char *strv_env_get(char **l, const char *name) { + } + + char *strv_env_pairs_get(char **l, const char *name) { +- char **key, **value, *result = NULL; ++ char *result = NULL; + + assert(name); + +@@ -508,7 +499,6 @@ char *strv_env_pairs_get(char **l, const char *name) { + } + + char **strv_env_clean_with_callback(char **e, void (*invalid_callback)(const char *p, void *userdata), void *userdata) { +- char **p, **q; + int k = 0; + + STRV_FOREACH(p, e) { +@@ -702,7 +692,7 @@ char *replace_env_n(const char *format, size_t n, char **env, unsigned flags) { + } + + char **replace_env_argv(char **argv, char **env) { +- char **ret, **i; ++ char **ret; + size_t k = 0, l = 0; + + l = strv_length(argv); +@@ -832,7 +822,6 @@ int setenv_systemd_exec_pid(bool update_only) { + int getenv_path_list(const char *name, char ***ret_paths) { + _cleanup_strv_free_ char **l = NULL; + const char *e; +- char **p; + int r; + + assert(name); +diff --git a/src/basic/escape.c b/src/basic/escape.c +index ce57fcc762..1cb7ced545 100644 +--- a/src/basic/escape.c ++++ b/src/basic/escape.c +@@ -549,7 +549,6 @@ char* quote_command_line(char **argv, ShellEscapeFlags flags) { + + assert(argv); + +- char **a; + STRV_FOREACH(a, argv) { + _cleanup_free_ char *t = NULL; + +diff --git a/src/basic/fileio.c b/src/basic/fileio.c +index 8d92da327e..d9b988d117 100644 +--- a/src/basic/fileio.c ++++ b/src/basic/fileio.c +@@ -1042,8 +1042,6 @@ static int search_and_fopen_internal( + FILE **ret, + char **ret_path) { + +- char **i; +- + assert(path); + assert(mode); + assert(ret); +diff --git a/src/basic/hashmap.c b/src/basic/hashmap.c +index b51d70bc87..bd7a6b0d6e 100644 +--- a/src/basic/hashmap.c ++++ b/src/basic/hashmap.c +@@ -1864,7 +1864,6 @@ int _set_put_strdup_full(Set **s, const struct hash_ops *hash_ops, const char *p + + int _set_put_strdupv_full(Set **s, const struct hash_ops *hash_ops, char **l HASHMAP_DEBUG_PARAMS) { + int n = 0, r; +- char **i; + + assert(s); + +diff --git a/src/basic/ordered-set.c b/src/basic/ordered-set.c +index 0a76f04561..b4c2588395 100644 +--- a/src/basic/ordered-set.c ++++ b/src/basic/ordered-set.c +@@ -58,7 +58,6 @@ int _ordered_set_put_strdup(OrderedSet **s, const char *p HASHMAP_DEBUG_PARAMS) + + int _ordered_set_put_strdupv(OrderedSet **s, char **l HASHMAP_DEBUG_PARAMS) { + int n = 0, r; +- char **i; + + STRV_FOREACH(i, l) { + r = _ordered_set_put_strdup(s, *i HASHMAP_DEBUG_PASS_ARGS); +diff --git a/src/basic/os-util.c b/src/basic/os-util.c +index 38b2179e48..acfff24319 100644 +--- a/src/basic/os-util.c ++++ b/src/basic/os-util.c +@@ -277,7 +277,6 @@ int load_os_release_pairs(const char *root, char ***ret) { + + int load_os_release_pairs_with_prefix(const char *root, const char *prefix, char ***ret) { + _cleanup_strv_free_ char **os_release_pairs = NULL, **os_release_pairs_prefixed = NULL; +- char **p, **q; + int r; + + r = load_os_release_pairs(root, &os_release_pairs); +diff --git a/src/basic/path-lookup.c b/src/basic/path-lookup.c +index ab51955e34..b699756658 100644 +--- a/src/basic/path-lookup.c ++++ b/src/basic/path-lookup.c +@@ -463,7 +463,6 @@ static int patch_root_prefix(char **p, const char *root_dir) { + } + + static int patch_root_prefix_strv(char **l, const char *root_dir) { +- char **i; + int r; + + if (!root_dir) +diff --git a/src/basic/path-util.c b/src/basic/path-util.c +index 4c952d863c..76af40aaf2 100644 +--- a/src/basic/path-util.c ++++ b/src/basic/path-util.c +@@ -202,9 +202,9 @@ int path_make_relative(const char *from, const char *to, char **ret) { + } + + char* path_startswith_strv(const char *p, char **set) { +- char **s, *t; +- + STRV_FOREACH(s, set) { ++ char *t; ++ + t = path_startswith(p, *s); + if (t) + return t; +@@ -214,7 +214,6 @@ char* path_startswith_strv(const char *p, char **set) { + } + + int path_strv_make_absolute_cwd(char **l) { +- char **s; + int r; + + /* Goes through every item in the string list and makes it +@@ -236,7 +235,6 @@ int path_strv_make_absolute_cwd(char **l) { + } + + char **path_strv_resolve(char **l, const char *root) { +- char **s; + unsigned k = 0; + bool enomem = false; + int r; +@@ -700,12 +698,12 @@ int find_executable_full(const char *name, const char *root, char **exec_search_ + p = DEFAULT_PATH; + + if (exec_search_path) { +- char **element; +- + STRV_FOREACH(element, exec_search_path) { + _cleanup_free_ char *full_path = NULL; ++ + if (!path_is_absolute(*element)) + continue; ++ + full_path = path_join(*element, name); + if (!full_path) + return -ENOMEM; +@@ -754,7 +752,6 @@ int find_executable_full(const char *name, const char *root, char **exec_search_ + + bool paths_check_timestamp(const char* const* paths, usec_t *timestamp, bool update) { + bool changed = false, originally_unset; +- const char* const* i; + + assert(timestamp); + +@@ -1339,7 +1336,7 @@ int systemd_installation_has_version(const char *root, unsigned minimal_version) + + _cleanup_strv_free_ char **names = NULL; + _cleanup_free_ char *path = NULL; +- char *c, **name; ++ char *c; + + path = path_join(root, pattern); + if (!path) +@@ -1411,8 +1408,6 @@ bool empty_or_root(const char *path) { + } + + bool path_strv_contains(char **l, const char *path) { +- char **i; +- + STRV_FOREACH(i, l) + if (path_equal(*i, path)) + return true; +@@ -1421,10 +1416,9 @@ bool path_strv_contains(char **l, const char *path) { + } + + bool prefixed_path_strv_contains(char **l, const char *path) { +- char **i, *j; +- + STRV_FOREACH(i, l) { +- j = *i; ++ const char *j = *i; ++ + if (*j == '-') + j++; + if (*j == '+') +diff --git a/src/basic/process-util.c b/src/basic/process-util.c +index c971852158..c09d7d0321 100644 +--- a/src/basic/process-util.c ++++ b/src/basic/process-util.c +@@ -214,7 +214,6 @@ int get_process_cmdline(pid_t pid, size_t max_columns, ProcessCmdlineFlags flags + assert(!(flags & PROCESS_CMDLINE_USE_LOCALE)); + + _cleanup_strv_free_ char **args = NULL; +- char **p; + + args = strv_parse_nulstr(t, k); + if (!args) +diff --git a/src/basic/strv.c b/src/basic/strv.c +index 2ba5a94839..d195606fff 100644 +--- a/src/basic/strv.c ++++ b/src/basic/strv.c +@@ -17,8 +17,6 @@ + #include "strv.h" + + char* strv_find(char * const *l, const char *name) { +- char * const *i; +- + assert(name); + + STRV_FOREACH(i, l) +@@ -29,8 +27,6 @@ char* strv_find(char * const *l, const char *name) { + } + + char* strv_find_case(char * const *l, const char *name) { +- char * const *i; +- + assert(name); + + STRV_FOREACH(i, l) +@@ -41,8 +37,6 @@ char* strv_find_case(char * const *l, const char *name) { + } + + char* strv_find_prefix(char * const *l, const char *name) { +- char * const *i; +- + assert(name); + + STRV_FOREACH(i, l) +@@ -53,14 +47,14 @@ char* strv_find_prefix(char * const *l, const char *name) { + } + + char* strv_find_startswith(char * const *l, const char *name) { +- char * const *i, *e; +- + assert(name); + + /* Like strv_find_prefix, but actually returns only the + * suffix, not the whole item */ + + STRV_FOREACH(i, l) { ++ char *e; ++ + e = startswith(*i, name); + if (e) + return e; +@@ -80,8 +74,6 @@ char** strv_free(char **l) { + } + + char** strv_free_erase(char **l) { +- char **i; +- + STRV_FOREACH(i, l) + erase_and_freep(i); + +@@ -171,8 +163,8 @@ char** strv_new_internal(const char *x, ...) { + } + + int strv_extend_strv(char ***a, char * const *b, bool filter_duplicates) { +- char * const *s, **t; + size_t p, q, i = 0; ++ char **t; + + assert(a); + +@@ -217,7 +209,6 @@ rollback: + } + + int strv_extend_strv_concat(char ***a, char * const *b, const char *suffix) { +- char * const *s; + int r; + + STRV_FOREACH(s, b) { +@@ -367,7 +358,6 @@ int strv_split_colon_pairs(char ***t, const char *s) { + } + + char* strv_join_full(char * const *l, const char *separator, const char *prefix, bool unescape_separators) { +- char * const *s; + char *r, *e; + size_t n, k, m; + +@@ -595,8 +585,6 @@ int strv_extend_front(char ***l, const char *value) { + } + + char** strv_uniq(char **l) { +- char **i; +- + /* Drops duplicate entries. The first identical string will be + * kept, the others dropped */ + +@@ -607,8 +595,6 @@ char** strv_uniq(char **l) { + } + + bool strv_is_uniq(char * const *l) { +- char * const *i; +- + STRV_FOREACH(i, l) + if (strv_find(i+1, *i)) + return false; +@@ -717,7 +703,6 @@ int strv_make_nulstr(char * const *l, char **ret, size_t *ret_size) { + */ + + _cleanup_free_ char *m = NULL; +- char * const *i; + size_t n = 0; + + assert(ret); +@@ -754,8 +739,6 @@ int strv_make_nulstr(char * const *l, char **ret, size_t *ret_size) { + } + + bool strv_overlap(char * const *a, char * const *b) { +- char * const *i; +- + STRV_FOREACH(i, a) + if (strv_contains(b, *i)) + return true; +@@ -795,8 +778,6 @@ int strv_compare(char * const *a, char * const *b) { + } + + void strv_print(char * const *l) { +- char * const *s; +- + STRV_FOREACH(s, l) + puts(*s); + } +@@ -830,8 +811,6 @@ char** strv_reverse(char **l) { + } + + char** strv_shell_escape(char **l, const char *bad) { +- char **s; +- + /* Escapes every character in every string in l that is in bad, + * edits in-place, does not roll-back on error. */ + +@@ -914,7 +893,6 @@ rollback: + + int fputstrv(FILE *f, char * const *l, const char *separator, bool *space) { + bool b = false; +- char * const *s; + int r; + + /* Like fputs(), but for strv, and with a less stupid argument order */ +diff --git a/src/basic/strv.h b/src/basic/strv.h +index 27d4450468..3acf0a48f3 100644 +--- a/src/basic/strv.h ++++ b/src/basic/strv.h +@@ -122,19 +122,30 @@ static inline int strv_from_nulstr(char ***a, const char *nulstr) { + + bool strv_overlap(char * const *a, char * const *b) _pure_; + ++#define _STRV_FOREACH(s, l, i) \ ++ for (typeof(*(l)) *s, *i = (l); (s = i) && *i; i++) ++ + #define STRV_FOREACH(s, l) \ +- for ((s) = (l); (s) && *(s); (s)++) ++ _STRV_FOREACH(s, l, UNIQ_T(i, UNIQ)) ++ ++#define _STRV_FOREACH_BACKWARDS(s, l, h, i) \ ++ for (typeof(*(l)) *s, *h = (l), *i = ({ \ ++ size_t _len = strv_length(h); \ ++ _len > 0 ? h + _len - 1 : NULL; \ ++ }); \ ++ i && (s = i) >= h; \ ++ i--) ++ ++#define STRV_FOREACH_BACKWARDS(s, l) \ ++ _STRV_FOREACH_BACKWARDS(s, l, UNIQ_T(h, UNIQ), UNIQ_T(i, UNIQ)) + +-#define STRV_FOREACH_BACKWARDS(s, l) \ +- for (s = ({ \ +- typeof(l) _l = l; \ +- _l ? _l + strv_length(_l) - 1U : NULL; \ +- }); \ +- (l) && ((s) >= (l)); \ +- (s)--) ++#define _STRV_FOREACH_PAIR(x, y, l, i) \ ++ for (typeof(*l) *x, *y, *i = (l); \ ++ i && *(x = i) && *(y = i + 1); \ ++ i += 2) + +-#define STRV_FOREACH_PAIR(x, y, l) \ +- for ((x) = (l), (y) = (x) ? (x+1) : NULL; (x) && *(x) && *(y); (x) += 2, (y) = (x + 1)) ++#define STRV_FOREACH_PAIR(x, y, l) \ ++ _STRV_FOREACH_PAIR(x, y, l, UNIQ_T(i, UNIQ)) + + char** strv_sort(char **l); + void strv_print(char * const *l); +@@ -185,7 +196,7 @@ void strv_print(char * const *l); + #define STARTSWITH_SET(p, ...) \ + ({ \ + const char *_p = (p); \ +- char *_found = NULL, **_i; \ ++ char *_found = NULL; \ + STRV_FOREACH(_i, STRV_MAKE(__VA_ARGS__)) { \ + _found = startswith(_p, *_i); \ + if (_found) \ +@@ -197,7 +208,7 @@ void strv_print(char * const *l); + #define ENDSWITH_SET(p, ...) \ + ({ \ + const char *_p = (p); \ +- char *_found = NULL, **_i; \ ++ char *_found = NULL; \ + STRV_FOREACH(_i, STRV_MAKE(__VA_ARGS__)) { \ + _found = endswith(_p, *_i); \ + if (_found) \ +diff --git a/src/basic/unit-file.c b/src/basic/unit-file.c +index 142ba006f8..6cf66b45cf 100644 +--- a/src/basic/unit-file.c ++++ b/src/basic/unit-file.c +@@ -215,8 +215,7 @@ bool lookup_paths_timestamp_hash_same(const LookupPaths *lp, uint64_t timestamp_ + + siphash24_init(&state, HASH_KEY.bytes); + +- char **dir; +- STRV_FOREACH(dir, (char**) lp->search_path) { ++ STRV_FOREACH(dir, lp->search_path) { + struct stat st; + + if (lookup_paths_mtime_exclude(lp, *dir)) +@@ -388,7 +387,6 @@ int unit_file_build_name_map( + _cleanup_hashmap_free_ Hashmap *ids = NULL, *names = NULL; + _cleanup_set_free_free_ Set *paths = NULL; + uint64_t timestamp_hash; +- char **dir; + int r; + + /* Before doing anything, check if the timestamp hash that was passed is still valid. +@@ -406,7 +404,7 @@ int unit_file_build_name_map( + return log_oom(); + } + +- STRV_FOREACH(dir, (char**) lp->search_path) { ++ STRV_FOREACH(dir, lp->search_path) { + _cleanup_closedir_ DIR *d = NULL; + + d = opendir(*dir); +@@ -614,7 +612,7 @@ static int add_names( + Set **names, + const char *name) { + +- char **aliases, **alias; ++ char **aliases; + int r; + + assert(name_type == UNIT_NAME_PLAIN || instance); +diff --git a/src/binfmt/binfmt.c b/src/binfmt/binfmt.c +index 18231c2618..817ee387ff 100644 +--- a/src/binfmt/binfmt.c ++++ b/src/binfmt/binfmt.c +@@ -213,7 +213,6 @@ static int run(int argc, char *argv[]) { + } + else { + _cleanup_strv_free_ char **files = NULL; +- char **f; + + r = conf_files_list_strv(&files, ".conf", NULL, 0, (const char**) CONF_PATHS_STRV("binfmt.d")); + if (r < 0) +diff --git a/src/boot/bless-boot.c b/src/boot/bless-boot.c +index 9e4b0d1f72..49009cb1eb 100644 +--- a/src/boot/bless-boot.c ++++ b/src/boot/bless-boot.c +@@ -320,7 +320,6 @@ static const char *skip_slash(const char *path) { + static int verb_status(int argc, char *argv[], void *userdata) { + _cleanup_free_ char *path = NULL, *prefix = NULL, *suffix = NULL, *good = NULL, *bad = NULL; + uint64_t left, done; +- char **p; + int r; + + r = acquire_boot_count_path(&path, &prefix, &left, &done, &suffix); +@@ -397,7 +396,6 @@ static int verb_set(int argc, char *argv[], void *userdata) { + _cleanup_free_ char *path = NULL, *prefix = NULL, *suffix = NULL, *good = NULL, *bad = NULL, *parent = NULL; + const char *target, *source1, *source2; + uint64_t done; +- char **p; + int r; + + r = acquire_boot_count_path(&path, &prefix, NULL, &done, &suffix); +diff --git a/src/boot/bootctl.c b/src/boot/bootctl.c +index 9427a0e4ce..c1adae4962 100644 +--- a/src/boot/bootctl.c ++++ b/src/boot/bootctl.c +@@ -440,7 +440,6 @@ static int boot_entry_show(const BootEntry *e, bool show_as_default) { + if (e->kernel) + boot_entry_file_list("linux", e->root, e->kernel, &status); + +- char **s; + STRV_FOREACH(s, e->initrd) + boot_entry_file_list(s == e->initrd ? "initrd" : NULL, + e->root, +@@ -669,7 +668,6 @@ static const char *const dollar_boot_subdirs[] = { + }; + + static int create_subdirs(const char *root, const char * const *subdirs) { +- const char *const *i; + int r; + + STRV_FOREACH(i, subdirs) { +diff --git a/src/busctl/busctl.c b/src/busctl/busctl.c +index c0c9b23ae9..fd646784b9 100644 +--- a/src/busctl/busctl.c ++++ b/src/busctl/busctl.c +@@ -141,7 +141,7 @@ static int list_bus_names(int argc, char **argv, void *userdata) { + _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL; + _cleanup_hashmap_free_ Hashmap *names = NULL; + _cleanup_(table_unrefp) Table *table = NULL; +- char **i, *k; ++ char *k; + void *v; + int r; + +@@ -502,7 +502,6 @@ static int tree_one(sd_bus *bus, const char *service) { + + static int tree(int argc, char **argv, void *userdata) { + _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL; +- char **i; + int r; + + /* Do superficial verification of arguments before even opening the bus */ +@@ -1206,7 +1205,6 @@ static int monitor(int argc, char **argv, int (*dump)(sd_bus_message *m, FILE *f + _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *message = NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; +- char **i; + uint32_t flags = 0; + const char *unique_name; + bool is_monitor = false; +@@ -2115,7 +2113,6 @@ static int emit_signal(int argc, char **argv, void *userdata) { + static int get_property(int argc, char **argv, void *userdata) { + _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; +- char **i; + int r; + + r = acquire_bus(false, &bus); +diff --git a/src/cgls/cgls.c b/src/cgls/cgls.c +index 775bd84ad2..8e8f97b3ce 100644 +--- a/src/cgls/cgls.c ++++ b/src/cgls/cgls.c +@@ -201,7 +201,6 @@ static int run(int argc, char *argv[]) { + if (arg_names) { + _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL; + _cleanup_free_ char *root = NULL; +- char **name; + + STRV_FOREACH(name, arg_names) { + int q; +diff --git a/src/core/bpf-firewall.c b/src/core/bpf-firewall.c +index 3c1c02e444..c149c0afff 100644 +--- a/src/core/bpf-firewall.c ++++ b/src/core/bpf-firewall.c +@@ -596,8 +596,6 @@ int bpf_firewall_compile(Unit *u) { + } + + static int load_bpf_progs_from_fs_to_set(Unit *u, char **filter_paths, Set **set) { +- char **bpf_fs_path; +- + set_clear(*set); + + STRV_FOREACH(bpf_fs_path, filter_paths) { +diff --git a/src/core/cgroup.c b/src/core/cgroup.c +index f58de95a49..17ec70567c 100644 +--- a/src/core/cgroup.c ++++ b/src/core/cgroup.c +@@ -430,7 +430,6 @@ void cgroup_context_dump(Unit *u, FILE* f, const char *prefix) { + CGroupContext *c; + CGroupSocketBindItem *bi; + struct in_addr_prefix *iaai; +- char **path; + + char cda[FORMAT_CGROUP_DIFF_MAX]; + char cdb[FORMAT_CGROUP_DIFF_MAX]; +diff --git a/src/core/dbus-cgroup.c b/src/core/dbus-cgroup.c +index f0d8759e85..bd76ce7117 100644 +--- a/src/core/dbus-cgroup.c ++++ b/src/core/dbus-cgroup.c +@@ -640,7 +640,6 @@ static int bus_cgroup_set_transient_property( + if (!UNIT_WRITE_FLAGS_NOOP(flags)) { + _cleanup_free_ char *buf = NULL; + _cleanup_fclose_ FILE *f = NULL; +- char **entry; + size_t size = 0; + + if (n == 0) +@@ -2050,7 +2049,6 @@ int bus_cgroup_set_property( + + if (!UNIT_WRITE_FLAGS_NOOP(flags)) { + _cleanup_free_ char *joined = NULL; +- char **s; + + if (strv_isempty(l)) { + c->restrict_network_interfaces_is_allow_list = false; +diff --git a/src/core/dbus-execute.c b/src/core/dbus-execute.c +index 5c499e5d06..2d49f86366 100644 +--- a/src/core/dbus-execute.c ++++ b/src/core/dbus-execute.c +@@ -74,7 +74,6 @@ static int property_get_environment_files( + sd_bus_error *error) { + + ExecContext *c = userdata; +- char **j; + int r; + + assert(bus); +@@ -1143,15 +1142,12 @@ static int bus_property_get_exec_dir_symlink( + if (r < 0) + return r; + +- for (size_t i = 0; i < d->n_items; i++) { +- char **dst; +- ++ for (size_t i = 0; i < d->n_items; i++) + STRV_FOREACH(dst, d->items[i].symlinks) { + r = sd_bus_message_append(reply, "(sst)", d->items[i].path, *dst, 0 /* flags, unused for now */); + if (r < 0) + return r; + } +- } + + return sd_bus_message_close_container(reply); + } +@@ -2021,7 +2017,6 @@ int bus_exec_context_set_transient_property( + if (!UNIT_WRITE_FLAGS_NOOP(flags)) { + _cleanup_free_ char *joined = NULL; + FilesystemParseFlags invert_flag = allow_list ? 0 : FILESYSTEM_PARSE_INVERT; +- char **s; + + if (strv_isempty(l)) { + c->restrict_filesystems_allow_list = false; +@@ -2067,7 +2062,6 @@ int bus_exec_context_set_transient_property( + + if (streq(name, "SupplementaryGroups")) { + _cleanup_strv_free_ char **l = NULL; +- char **p; + + r = sd_bus_message_read_strv(message, &l); + if (r < 0) +@@ -2432,7 +2426,6 @@ int bus_exec_context_set_transient_property( + if (!UNIT_WRITE_FLAGS_NOOP(flags)) { + _cleanup_free_ char *joined = NULL; + SeccompParseFlags invert_flag = allow_list ? 0 : SECCOMP_PARSE_INVERT; +- char **s; + + if (strv_isempty(l)) { + c->syscall_allow_list = false; +@@ -2517,7 +2510,6 @@ int bus_exec_context_set_transient_property( + if (!UNIT_WRITE_FLAGS_NOOP(flags)) { + _cleanup_free_ char *joined = NULL; + SeccompParseFlags invert_flag = allow_list ? 0 : SECCOMP_PARSE_INVERT; +- char **s; + + if (strv_isempty(l)) { + c->syscall_log_allow_list = false; +@@ -2569,9 +2561,7 @@ int bus_exec_context_set_transient_property( + + if (strv_isempty(l)) + c->syscall_archs = set_free(c->syscall_archs); +- else { +- char **s; +- ++ else + STRV_FOREACH(s, l) { + uint32_t a; + +@@ -2584,8 +2574,6 @@ int bus_exec_context_set_transient_property( + return r; + } + +- } +- + joined = strv_join(l, " "); + if (!joined) + return -ENOMEM; +@@ -2617,7 +2605,6 @@ int bus_exec_context_set_transient_property( + + if (!UNIT_WRITE_FLAGS_NOOP(flags)) { + _cleanup_free_ char *joined = NULL; +- char **s; + + if (strv_isempty(l)) { + c->address_families_allow_list = allow_list; +@@ -3146,7 +3133,6 @@ int bus_exec_context_set_transient_property( + _cleanup_fclose_ FILE *f = NULL; + _cleanup_strv_free_ char **l = NULL; + size_t size = 0; +- char **i; + + r = sd_bus_message_enter_container(message, 'a', "(sb)"); + if (r < 0) +@@ -3264,7 +3250,6 @@ int bus_exec_context_set_transient_property( + "ReadWritePaths", "ReadOnlyPaths", "InaccessiblePaths", "ExecPaths", "NoExecPaths")) { + _cleanup_strv_free_ char **l = NULL; + char ***dirs; +- char **p; + + r = sd_bus_message_read_strv(message, &l); + if (r < 0) +@@ -3316,16 +3301,15 @@ int bus_exec_context_set_transient_property( + + } else if (streq(name, "ExecSearchPath")) { + _cleanup_strv_free_ char **l = NULL; +- char **p; + + r = sd_bus_message_read_strv(message, &l); + if (r < 0) + return r; + +- STRV_FOREACH(p, l) { ++ STRV_FOREACH(p, l) + if (!path_is_absolute(*p) || !path_is_normalized(*p) || strchr(*p, ':')) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid %s", name); +- } ++ + if (!UNIT_WRITE_FLAGS_NOOP(flags)) { + if (strv_isempty(l)) { + c->exec_search_path = strv_free(c->exec_search_path); +@@ -3346,7 +3330,6 @@ int bus_exec_context_set_transient_property( + + } else if (STR_IN_SET(name, "RuntimeDirectory", "StateDirectory", "CacheDirectory", "LogsDirectory", "ConfigurationDirectory")) { + _cleanup_strv_free_ char **l = NULL; +- char **p; + + r = sd_bus_message_read_strv(message, &l); + if (r < 0) +@@ -3375,7 +3358,6 @@ int bus_exec_context_set_transient_property( + unit_write_settingf(u, flags, name, "%s=", name); + } else { + _cleanup_free_ char *joined = NULL; +- char **source; + + STRV_FOREACH(source, l) { + r = exec_directory_add(&d->items, &d->n_items, *source, NULL); +diff --git a/src/core/dbus-manager.c b/src/core/dbus-manager.c +index 1a3098ceb1..0e3590d1c9 100644 +--- a/src/core/dbus-manager.c ++++ b/src/core/dbus-manager.c +@@ -817,7 +817,6 @@ static int method_list_units_by_names(sd_bus_message *message, void *userdata, s + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; + Manager *m = userdata; + int r; +- char **unit; + _cleanup_strv_free_ char **units = NULL; + + assert(message); +diff --git a/src/core/dbus-socket.c b/src/core/dbus-socket.c +index a3b1e0442f..989c3f74db 100644 +--- a/src/core/dbus-socket.c ++++ b/src/core/dbus-socket.c +@@ -326,16 +326,14 @@ static int bus_socket_set_transient_property( + + if (streq(name, "Symlinks")) { + _cleanup_strv_free_ char **l = NULL; +- char **p; + + r = sd_bus_message_read_strv(message, &l); + if (r < 0) + return r; + +- STRV_FOREACH(p, l) { ++ STRV_FOREACH(p, l) + if (!path_is_absolute(*p)) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Symlink path is not absolute: %s", *p); +- } + + if (!UNIT_WRITE_FLAGS_NOOP(flags)) { + if (strv_isempty(l)) { +diff --git a/src/core/dbus-unit.c b/src/core/dbus-unit.c +index 1128c42ad9..c1cf6dfb6f 100644 +--- a/src/core/dbus-unit.c ++++ b/src/core/dbus-unit.c +@@ -2245,16 +2245,14 @@ static int bus_unit_set_transient_property( + + if (streq(name, "Documentation")) { + _cleanup_strv_free_ char **l = NULL; +- char **p; + + r = sd_bus_message_read_strv(message, &l); + if (r < 0) + return r; + +- STRV_FOREACH(p, l) { ++ STRV_FOREACH(p, l) + if (!documentation_url_is_valid(*p)) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid URL in %s: %s", name, *p); +- } + + if (!UNIT_WRITE_FLAGS_NOOP(flags)) { + if (strv_isempty(l)) { +@@ -2310,7 +2308,6 @@ static int bus_unit_set_transient_property( + + } else if (streq(name, "RequiresMountsFor")) { + _cleanup_strv_free_ char **l = NULL; +- char **p; + + r = sd_bus_message_read_strv(message, &l); + if (r < 0) +diff --git a/src/core/device.c b/src/core/device.c +index 43f49573b9..d2c5febd3f 100644 +--- a/src/core/device.c ++++ b/src/core/device.c +@@ -307,13 +307,9 @@ static void device_dump(Unit *u, FILE *f, const char *prefix) { + prefix, strna(d->sysfs), + prefix, strna(s)); + +- if (!strv_isempty(d->wants_property)) { +- char **i; +- +- STRV_FOREACH(i, d->wants_property) +- fprintf(f, "%sudev SYSTEMD_WANTS: %s\n", +- prefix, *i); +- } ++ STRV_FOREACH(i, d->wants_property) ++ fprintf(f, "%sudev SYSTEMD_WANTS: %s\n", ++ prefix, *i); + } + + _pure_ static UnitActiveState device_active_state(Unit *u) { +@@ -419,9 +415,7 @@ static int device_add_udev_wants(Unit *u, sd_device *dev) { + k = NULL; + } + +- if (d->state != DEVICE_DEAD) { +- char **i; +- ++ if (d->state != DEVICE_DEAD) + /* So here's a special hack, to compensate for the fact that the udev database's reload cycles are not + * synchronized with our own reload cycles: when we detect that the SYSTEMD_WANTS property of a device + * changes while the device unit is already up, let's manually trigger any new units listed in it not +@@ -431,7 +425,6 @@ static int device_add_udev_wants(Unit *u, sd_device *dev) { + * + * We do this only if the device has been up already when we parse this, as otherwise the usual + * dependency logic that is run from the dead → plugged transition will trigger these deps. */ +- + STRV_FOREACH(i, added) { + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; + +@@ -442,7 +435,6 @@ static int device_add_udev_wants(Unit *u, sd_device *dev) { + if (r < 0) + log_unit_warning_errno(u, r, "Failed to enqueue SYSTEMD_WANTS= job, ignoring: %s", bus_error_message(&error, r)); + } +- } + + return strv_free_and_replace(d->wants_property, added); + } +diff --git a/src/core/execute.c b/src/core/execute.c +index 3cafd0f17d..306e563e4f 100644 +--- a/src/core/execute.c ++++ b/src/core/execute.c +@@ -994,7 +994,6 @@ static int get_fixed_group(const ExecContext *c, const char **group, gid_t *gid) + static int get_supplementary_groups(const ExecContext *c, const char *user, + const char *group, gid_t gid, + gid_t **supplementary_gids, int *ngids) { +- char **i; + int r, k = 0; + int ngroups_max; + bool keep_groups = false; +@@ -1185,7 +1184,7 @@ static int setup_pam( + pam_handle_t *handle = NULL; + sigset_t old_ss; + int pam_code = PAM_SUCCESS, r; +- char **nv, **e = NULL; ++ char **e = NULL; + bool close_session = false; + pid_t pam_pid = 0, parent_pid; + int flags = 0; +@@ -2010,7 +2009,6 @@ static int build_environment( + static int build_pass_environment(const ExecContext *c, char ***ret) { + _cleanup_strv_free_ char **pass_env = NULL; + size_t n_env = 0; +- char **i; + + STRV_FOREACH(i, c->pass_environment) { + _cleanup_free_ char *x = NULL; +@@ -2283,7 +2281,6 @@ static bool exec_directory_is_private(const ExecContext *context, ExecDirectoryT + + static int create_many_symlinks(const char *root, const char *source, char **symlinks) { + _cleanup_free_ char *src_abs = NULL; +- char **dst; + int r; + + assert(source); +@@ -3221,7 +3218,6 @@ static int compile_symlinks( + for (ExecDirectoryType dt = 0; dt < _EXEC_DIRECTORY_TYPE_MAX; dt++) { + for (size_t i = 0; i < context->directories[dt].n_items; i++) { + _cleanup_free_ char *private_path = NULL, *path = NULL; +- char **symlink; + + STRV_FOREACH(symlink, context->directories[dt].items[i].symlinks) { + _cleanup_free_ char *src_abs = NULL, *dst_abs = NULL; +@@ -5190,7 +5186,6 @@ int exec_context_destroy_runtime_directory(const ExecContext *c, const char *run + * service next. */ + (void) rm_rf(p, REMOVE_ROOT); + +- char **symlink; + STRV_FOREACH(symlink, c->directories[EXEC_DIRECTORY_RUNTIME].items[i].symlinks) { + _cleanup_free_ char *symlink_abs = NULL; + +@@ -5364,7 +5359,6 @@ static int exec_context_named_iofds( + + static int exec_context_load_environment(const Unit *unit, const ExecContext *c, char ***ret) { + _cleanup_strv_free_ char **v = NULL; +- char **i; + int r; + + assert(c); +@@ -5471,8 +5465,6 @@ bool exec_context_may_touch_console(const ExecContext *ec) { + } + + static void strv_fprintf(FILE *f, char **l) { +- char **g; +- + assert(f); + + STRV_FOREACH(g, l) +@@ -5492,7 +5484,6 @@ static void strv_dump(FILE* f, const char *prefix, const char *name, char **strv + } + + void exec_context_dump(const ExecContext *c, FILE* f, const char *prefix) { +- char **e, **d; + int r; + + assert(c); +@@ -5924,9 +5915,11 @@ void exec_context_dump(const ExecContext *c, FILE* f, const char *prefix) { + } + + #if HAVE_LIBBPF +- if (exec_context_restrict_filesystems_set(c)) ++ if (exec_context_restrict_filesystems_set(c)) { ++ char **e; + SET_FOREACH(e, c->restrict_filesystems) + fprintf(f, "%sRestrictFileSystems: %s\n", prefix, *e); ++ } + #endif + + if (c->network_namespace_path) +@@ -6117,7 +6110,6 @@ int exec_context_get_clean_directories( + return r; + } + +- char **symlink; + STRV_FOREACH(symlink, c->directories[t].items[i].symlinks) { + j = path_join(prefix[t], *symlink); + if (!j) +diff --git a/src/core/load-dropin.c b/src/core/load-dropin.c +index 080a63bc7e..53d2a3daa1 100644 +--- a/src/core/load-dropin.c ++++ b/src/core/load-dropin.c +@@ -13,7 +13,6 @@ + + static int process_deps(Unit *u, UnitDependency dependency, const char *dir_suffix) { + _cleanup_strv_free_ char **paths = NULL; +- char **p; + int r; + + r = unit_file_find_dropin_paths(NULL, +@@ -85,7 +84,6 @@ static int process_deps(Unit *u, UnitDependency dependency, const char *dir_suff + + int unit_load_dropin(Unit *u) { + _cleanup_strv_free_ char **l = NULL; +- char **f; + int r; + + assert(u); +diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c +index 461e073269..0acc350389 100644 +--- a/src/core/load-fragment.c ++++ b/src/core/load-fragment.c +@@ -1634,7 +1634,6 @@ int config_parse_root_image_options( + + _cleanup_(mount_options_free_allp) MountOptions *options = NULL; + _cleanup_strv_free_ char **l = NULL; +- char **first = NULL, **second = NULL; + ExecContext *c = data; + const Unit *u = userdata; + int r; +diff --git a/src/core/main.c b/src/core/main.c +index cb3131c12a..4bad2e84a0 100644 +--- a/src/core/main.c ++++ b/src/core/main.c +@@ -2409,7 +2409,6 @@ static void fallback_rlimit_memlock(const struct rlimit *saved_rlimit_memlock) { + } + + static void setenv_manager_environment(void) { +- char **p; + int r; + + STRV_FOREACH(p, arg_manager_environment) { +diff --git a/src/core/manager.c b/src/core/manager.c +index 22bd0866c5..60846a66e6 100644 +--- a/src/core/manager.c ++++ b/src/core/manager.c +@@ -3582,7 +3582,6 @@ void manager_check_finished(Manager *m) { + } + + static bool generator_path_any(const char* const* paths) { +- char **path; + bool found = false; + + /* Optimize by skipping the whole process by not creating output directories +diff --git a/src/core/namespace.c b/src/core/namespace.c +index c549dcc96b..4bd63f6227 100644 +--- a/src/core/namespace.c ++++ b/src/core/namespace.c +@@ -313,8 +313,6 @@ static void mount_entry_done(MountEntry *p) { + } + + static int append_access_mounts(MountEntry **p, char **strv, MountMode mode, bool forcibly_require_prefix) { +- char **i; +- + assert(p); + + /* Adds a list of user-supplied READWRITE/READWRITE_IMPLICIT/READONLY/INACCESSIBLE entries */ +@@ -349,8 +347,6 @@ static int append_access_mounts(MountEntry **p, char **strv, MountMode mode, boo + } + + static int append_empty_dir_mounts(MountEntry **p, char **strv) { +- char **i; +- + assert(p); + + /* Adds tmpfs mounts to provide readable but empty directories. This is primarily used to implement the +@@ -417,7 +413,6 @@ static int append_extension_images( + size_t n) { + + _cleanup_strv_free_ char **overlays = NULL; +- char **hierarchy; + int r; + + assert(p); +@@ -1590,7 +1585,6 @@ static void normalize_mounts(const char *root_directory, MountEntry *mounts, siz + } + + static int create_symlinks_from_tuples(const char *root, char **strv_symlinks) { +- char **src, **dst; + int r; + + STRV_FOREACH_PAIR(src, dst, strv_symlinks) { +diff --git a/src/core/service.c b/src/core/service.c +index 49579f7998..5d9464d588 100644 +--- a/src/core/service.c ++++ b/src/core/service.c +@@ -2592,7 +2592,6 @@ static int service_serialize_exec_command(Unit *u, FILE *f, ExecCommand *command + ServiceExecCommand id; + size_t length = 0; + unsigned idx; +- char **arg; + + assert(s); + assert(f); +@@ -4028,7 +4027,6 @@ static void service_notify_message( + Service *s = SERVICE(u); + bool notify_dbus = false; + const char *e; +- char * const *i; + int r; + + assert(u); +diff --git a/src/core/socket.c b/src/core/socket.c +index 8a5c7fdd0a..8da9f14db6 100644 +--- a/src/core/socket.c ++++ b/src/core/socket.c +@@ -781,8 +781,6 @@ static void socket_dump(Unit *u, FILE *f, const char *prefix) { + fprintf(f, "%sSocketProtocol: %s\n", prefix, str); + + if (!strv_isempty(s->symlinks)) { +- char **q; +- + fprintf(f, "%sSymlinks:", prefix); + STRV_FOREACH(q, s->symlinks) + fprintf(f, " %s", *q); +@@ -924,7 +922,6 @@ static int instance_from_socket(int fd, unsigned nr, char **instance) { + + static void socket_close_fds(Socket *s) { + SocketPort *p; +- char **i; + + assert(s); + +@@ -1271,7 +1268,6 @@ static int mq_address_create( + + static int socket_symlink(Socket *s) { + const char *p; +- char **i; + int r; + + assert(s); +diff --git a/src/core/transaction.c b/src/core/transaction.c +index ebe5f1910d..32badaaef1 100644 +--- a/src/core/transaction.c ++++ b/src/core/transaction.c +@@ -329,7 +329,7 @@ _pure_ static bool unit_matters_to_anchor(Unit *u, Job *j) { + } + + static char* merge_unit_ids(const char* unit_log_field, char **pairs) { +- char **unit_id, **job_type, *ans = NULL; ++ char *ans = NULL; + size_t size = 0, next; + + STRV_FOREACH_PAIR(unit_id, job_type, pairs) { +@@ -366,7 +366,6 @@ static int transaction_verify_order_one(Transaction *tr, Job *j, Job *from, unsi + if (j->generation == generation) { + Job *k, *delete = NULL; + _cleanup_free_ char **array = NULL, *unit_ids = NULL; +- char **unit_id, **job_type; + + /* If the marker is NULL we have been here already and decided the job was loop-free from + * here. Hence shortcut things and return right-away. */ +diff --git a/src/core/unit-serialize.c b/src/core/unit-serialize.c +index 7d2e6bc130..65ed110ce6 100644 +--- a/src/core/unit-serialize.c ++++ b/src/core/unit-serialize.c +@@ -623,7 +623,7 @@ static void print_unit_dependency_mask(FILE *f, const char *kind, UnitDependency + } + + void unit_dump(Unit *u, FILE *f, const char *prefix) { +- char *t, **j; ++ char *t; + const char *prefix2; + Unit *following; + _cleanup_set_free_ Set *following_set = NULL; +diff --git a/src/core/unit.c b/src/core/unit.c +index 3d30f3807c..6eaa553255 100644 +--- a/src/core/unit.c ++++ b/src/core/unit.c +@@ -568,8 +568,6 @@ static void unit_clear_dependencies(Unit *u) { + } + + static void unit_remove_transient(Unit *u) { +- char **i; +- + assert(u); + + if (!u->transient) +@@ -3594,7 +3592,6 @@ int unit_add_blockdev_dependency(Unit *u, const char *what, UnitDependencyMask m + + int unit_coldplug(Unit *u) { + int r = 0, q; +- char **i; + + assert(u); + +@@ -3667,7 +3664,6 @@ static bool fragment_mtime_newer(const char *path, usec_t mtime, bool path_maske + + bool unit_need_daemon_reload(Unit *u) { + _cleanup_strv_free_ char **t = NULL; +- char **path; + + assert(u); + +@@ -4251,7 +4247,6 @@ char* unit_escape_setting(const char *s, UnitWriteFlags flags, char **buf) { + char* unit_concat_strv(char **l, UnitWriteFlags flags) { + _cleanup_free_ char *result = NULL; + size_t n = 0; +- char **i; + + /* Takes a list of strings, escapes them, and concatenates them. This may be used to format command lines in a + * way suitable for ExecStart= stanzas */ +@@ -5052,7 +5047,6 @@ int unit_fork_and_watch_rm_rf(Unit *u, char **paths, pid_t *ret_pid) { + return r; + if (r == 0) { + int ret = EXIT_SUCCESS; +- char **i; + + STRV_FOREACH(i, paths) { + r = rm_rf(*i, REMOVE_ROOT|REMOVE_PHYSICAL|REMOVE_MISSING_OK); +diff --git a/src/coredump/coredumpctl.c b/src/coredump/coredumpctl.c +index 2904de3728..7235544285 100644 +--- a/src/coredump/coredumpctl.c ++++ b/src/coredump/coredumpctl.c +@@ -91,7 +91,6 @@ static int add_match(sd_journal *j, const char *match) { + } + + static int add_matches(sd_journal *j, char **matches) { +- char **match; + int r; + + r = sd_journal_add_match(j, "MESSAGE_ID=" SD_MESSAGE_COREDUMP_STR, 0); +diff --git a/src/creds/creds.c b/src/creds/creds.c +index 3d2841c07d..2fd314ff37 100644 +--- a/src/creds/creds.c ++++ b/src/creds/creds.c +@@ -311,7 +311,6 @@ static int write_blob(FILE *f, const void *data, size_t size) { + static int verb_cat(int argc, char **argv, void *userdata) { + _cleanup_(closedirp) DIR *d = NULL; + int r, ret = 0; +- char **cn; + + r = open_credential_directory(&d); + if (r == -ENXIO) +diff --git a/src/cryptenroll/cryptenroll.c b/src/cryptenroll/cryptenroll.c +index c9bc9a2489..7f397f197f 100644 +--- a/src/cryptenroll/cryptenroll.c ++++ b/src/cryptenroll/cryptenroll.c +@@ -482,7 +482,6 @@ static int prepare_luks( + + for (;;) { + _cleanup_strv_free_erase_ char **passwords = NULL; +- char **p; + + if (--i == 0) + return log_error_errno(SYNTHETIC_ERRNO(ENOKEY), +diff --git a/src/cryptsetup/cryptsetup-keyfile.c b/src/cryptsetup/cryptsetup-keyfile.c +index 924555d262..1867e9012c 100644 +--- a/src/cryptsetup/cryptsetup-keyfile.c ++++ b/src/cryptsetup/cryptsetup-keyfile.c +@@ -12,7 +12,6 @@ int find_key_file( + void **ret_key, + size_t *ret_key_size) { + +- char **i; + int r; + + assert(key_file); +diff --git a/src/cryptsetup/cryptsetup.c b/src/cryptsetup/cryptsetup.c +index 250a8314f6..dddd976dc8 100644 +--- a/src/cryptsetup/cryptsetup.c ++++ b/src/cryptsetup/cryptsetup.c +@@ -562,7 +562,7 @@ static int get_password( + + _cleanup_free_ char *friendly = NULL, *text = NULL, *disk_path = NULL; + _cleanup_strv_free_erase_ char **passwords = NULL; +- char **p, *id; ++ char *id; + int r = 0; + AskPasswordFlags flags = arg_ask_password_flags | ASK_PASSWORD_PUSH_CACHE; + +@@ -851,7 +851,6 @@ static int attach_luks2_by_fido2( + #if HAVE_LIBCRYPTSETUP_PLUGINS + AskPasswordFlags flags = ASK_PASSWORD_PUSH_CACHE | ASK_PASSWORD_ACCEPT_CACHED; + _cleanup_strv_free_erase_ char **pins = NULL; +- char **p; + int r; + + r = crypt_activate_by_token_pin(cd, name, "systemd-fido2", CRYPT_ANY_TOKEN, NULL, 0, usrptr, activation_flags); +@@ -1523,7 +1522,6 @@ static int attach_luks_or_plain_or_bitlk_by_passphrase( + uint32_t flags, + bool pass_volume_key) { + +- char **p; + int r; + + assert(cd); +diff --git a/src/debug-generator/debug-generator.c b/src/debug-generator/debug-generator.c +index a724ae510d..e2e1df5715 100644 +--- a/src/debug-generator/debug-generator.c ++++ b/src/debug-generator/debug-generator.c +@@ -89,7 +89,6 @@ static int parse_proc_cmdline_item(const char *key, const char *value, void *dat + } + + static int generate_mask_symlinks(void) { +- char **u; + int r = 0; + + if (strv_isempty(arg_mask)) +@@ -112,7 +111,6 @@ static int generate_mask_symlinks(void) { + } + + static int generate_wants_symlinks(void) { +- char **u; + int r = 0; + + if (strv_isempty(arg_wants)) +diff --git a/src/delta/delta.c b/src/delta/delta.c +index 3f1b206e6c..eafe1c05c4 100644 +--- a/src/delta/delta.c ++++ b/src/delta/delta.c +@@ -195,7 +195,6 @@ static int enumerate_dir_d( + _cleanup_free_ char *unit = NULL; + _cleanup_free_ char *path = NULL; + _cleanup_strv_free_ char **list = NULL; +- char **file; + char *c; + int r; + +@@ -292,7 +291,6 @@ static int enumerate_dir( + _cleanup_closedir_ DIR *d = NULL; + _cleanup_strv_free_ char **files = NULL, **dirs = NULL; + size_t n_files = 0, n_dirs = 0; +- char **t; + int r; + + assert(top); +diff --git a/src/dissect/dissect.c b/src/dissect/dissect.c +index a9632a3f16..1d78dc5085 100644 +--- a/src/dissect/dissect.c ++++ b/src/dissect/dissect.c +@@ -354,7 +354,6 @@ static int parse_argv(int argc, char *argv[]) { + + static int strv_pair_to_json(char **l, JsonVariant **ret) { + _cleanup_strv_free_ char **jl = NULL; +- char **a, **b; + + STRV_FOREACH_PAIR(a, b, l) { + char *j; +@@ -371,8 +370,6 @@ static int strv_pair_to_json(char **l, JsonVariant **ret) { + } + + static void strv_pair_print(char **l, const char *prefix) { +- char **p, **q; +- + assert(prefix); + + STRV_FOREACH_PAIR(p, q, l) { +diff --git a/src/environment-d-generator/environment-d-generator.c b/src/environment-d-generator/environment-d-generator.c +index 1171fdc290..39c46c7c2b 100644 +--- a/src/environment-d-generator/environment-d-generator.c ++++ b/src/environment-d-generator/environment-d-generator.c +@@ -41,7 +41,6 @@ static int environment_dirs(char ***ret) { + + static int load_and_print(void) { + _cleanup_strv_free_ char **dirs = NULL, **files = NULL, **env = NULL; +- char **i; + int r; + + r = environment_dirs(&dirs); +diff --git a/src/escape/escape.c b/src/escape/escape.c +index 676b7dce54..0ad77f3f94 100644 +--- a/src/escape/escape.c ++++ b/src/escape/escape.c +@@ -155,7 +155,6 @@ static int parse_argv(int argc, char *argv[]) { + } + + static int run(int argc, char *argv[]) { +- char **i; + int r; + + log_setup(); +diff --git a/src/fstab-generator/fstab-generator.c b/src/fstab-generator/fstab-generator.c +index 9b32383a76..355f2b8668 100644 +--- a/src/fstab-generator/fstab-generator.c ++++ b/src/fstab-generator/fstab-generator.c +@@ -237,7 +237,6 @@ static int write_dependency( + + _cleanup_strv_free_ char **names = NULL, **units = NULL; + _cleanup_free_ char *res = NULL; +- char **s; + int r; + + assert(f); +@@ -518,8 +517,6 @@ static int add_mount( + if (r < 0) + return r; + } else { +- char **s; +- + STRV_FOREACH(s, wanted_by) { + r = generator_add_symlink(dest, *s, "wants", name); + if (r < 0) +diff --git a/src/home/homectl.c b/src/home/homectl.c +index ac7b00889d..4aeaaf6b9a 100644 +--- a/src/home/homectl.c ++++ b/src/home/homectl.c +@@ -554,7 +554,6 @@ static int acquire_passed_secrets(const char *user_name, UserRecord **ret) { + static int activate_home(int argc, char *argv[], void *userdata) { + _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL; + int r, ret = 0; +- char **i; + + r = acquire_bus(&bus); + if (r < 0) +@@ -603,7 +602,6 @@ static int activate_home(int argc, char *argv[], void *userdata) { + static int deactivate_home(int argc, char *argv[], void *userdata) { + _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL; + int r, ret = 0; +- char **i; + + r = acquire_bus(&bus); + if (r < 0) +@@ -690,7 +688,7 @@ static int inspect_home(int argc, char *argv[], void *userdata) { + _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL; + _cleanup_(strv_freep) char **mangled_list = NULL; + int r, ret = 0; +- char **items, **i; ++ char **items; + + pager_open(arg_pager_flags); + +@@ -774,7 +772,7 @@ static int authenticate_home(int argc, char *argv[], void *userdata) { + _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL; + _cleanup_(strv_freep) char **mangled_list = NULL; + int r, ret = 0; +- char **i, **items; ++ char **items; + + items = mangle_user_list(strv_skip(argv, 1), &mangled_list); + if (!items) +@@ -1084,7 +1082,6 @@ static int add_disposition(JsonVariant **v) { + static int acquire_new_home_record(UserRecord **ret) { + _cleanup_(json_variant_unrefp) JsonVariant *v = NULL; + _cleanup_(user_record_unrefp) UserRecord *hr = NULL; +- char **i; + int r; + + assert(ret); +@@ -1375,7 +1372,6 @@ static int create_home(int argc, char *argv[], void *userdata) { + static int remove_home(int argc, char *argv[], void *userdata) { + _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL; + int r, ret = 0; +- char **i; + + r = acquire_bus(&bus); + if (r < 0) +@@ -1413,7 +1409,6 @@ static int acquire_updated_home_record( + + _cleanup_(json_variant_unrefp) JsonVariant *json = NULL; + _cleanup_(user_record_unrefp) UserRecord *hr = NULL; +- char **i; + int r; + + assert(ret); +@@ -1863,7 +1858,6 @@ static int resize_home(int argc, char *argv[], void *userdata) { + static int lock_home(int argc, char *argv[], void *userdata) { + _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL; + int r, ret = 0; +- char **i; + + r = acquire_bus(&bus); + if (r < 0) +@@ -1895,7 +1889,6 @@ static int lock_home(int argc, char *argv[], void *userdata) { + static int unlock_home(int argc, char *argv[], void *userdata) { + _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL; + int r, ret = 0; +- char **i; + + r = acquire_bus(&bus); + if (r < 0) +diff --git a/src/home/homed-manager-bus.c b/src/home/homed-manager-bus.c +index 47eb287aa9..ba5ca42ed3 100644 +--- a/src/home/homed-manager-bus.c ++++ b/src/home/homed-manager-bus.c +@@ -39,7 +39,6 @@ static int property_get_auto_login( + HASHMAP_FOREACH(h, m->homes_by_name) { + _cleanup_(strv_freep) char **seats = NULL; + _cleanup_free_ char *home_path = NULL; +- char **s; + + r = home_auto_login(h, &seats); + if (r < 0) { +diff --git a/src/home/homed-manager.c b/src/home/homed-manager.c +index a02248a6de..f04b87e366 100644 +--- a/src/home/homed-manager.c ++++ b/src/home/homed-manager.c +@@ -1553,7 +1553,6 @@ static int manager_load_public_key_one(Manager *m, const char *path) { + + static int manager_load_public_keys(Manager *m) { + _cleanup_strv_free_ char **files = NULL; +- char **i; + int r; + + assert(m); +diff --git a/src/home/homed-varlink.c b/src/home/homed-varlink.c +index 96a6ea754e..3dd5a14802 100644 +--- a/src/home/homed-varlink.c ++++ b/src/home/homed-varlink.c +@@ -282,7 +282,6 @@ int vl_method_get_memberships(Varlink *link, JsonVariant *parameters, VarlinkMet + + if (p.user_name) { + const char *last = NULL; +- char **i; + + h = hashmap_get(m->homes_by_name, p.user_name); + if (!h) +@@ -335,9 +334,7 @@ int vl_method_get_memberships(Varlink *link, JsonVariant *parameters, VarlinkMet + } else { + const char *last_user_name = NULL, *last_group_name = NULL; + +- HASHMAP_FOREACH(h, m->homes_by_name) { +- char **j; +- ++ HASHMAP_FOREACH(h, m->homes_by_name) + STRV_FOREACH(j, h->record->member_of) { + + if (last_user_name) { +@@ -353,7 +350,6 @@ int vl_method_get_memberships(Varlink *link, JsonVariant *parameters, VarlinkMet + last_user_name = h->user_name; + last_group_name = *j; + } +- } + + if (last_user_name) { + assert(last_group_name); +diff --git a/src/home/homework-cifs.c b/src/home/homework-cifs.c +index ed06d1f221..6d499f76b2 100644 +--- a/src/home/homework-cifs.c ++++ b/src/home/homework-cifs.c +@@ -20,7 +20,6 @@ int home_setup_cifs( + HomeSetup *setup) { + + _cleanup_free_ char *chost = NULL, *cservice = NULL, *cdir = NULL, *chost_and_service = NULL, *j = NULL; +- char **pw; + int r; + + assert(h); +diff --git a/src/home/homework-fscrypt.c b/src/home/homework-fscrypt.c +index f9fef73f75..afa706a1bf 100644 +--- a/src/home/homework-fscrypt.c ++++ b/src/home/homework-fscrypt.c +@@ -197,7 +197,6 @@ static int fscrypt_slot_try_many( + const uint8_t match_key_descriptor[static FS_KEY_DESCRIPTOR_SIZE], + void **ret_decrypted, size_t *ret_decrypted_size) { + +- char **i; + int r; + + STRV_FOREACH(i, passwords) { +@@ -499,7 +498,6 @@ int home_create_fscrypt( + _cleanup_free_ char *d = NULL; + uint32_t nr = 0; + const char *ip; +- char **i; + int r; + + assert(h); +@@ -649,7 +647,6 @@ int home_passwd_fscrypt( + size_t volume_key_size = 0; + uint32_t slot = 0; + const char *xa; +- char **p; + int r; + + assert(h); +diff --git a/src/home/homework-luks.c b/src/home/homework-luks.c +index 8063206358..f8f4afb253 100644 +--- a/src/home/homework-luks.c ++++ b/src/home/homework-luks.c +@@ -303,7 +303,6 @@ static int luks_try_passwords( + size_t *volume_key_size, + key_serial_t *ret_key_serial) { + +- char **pp; + int r; + + assert(h); +@@ -1721,7 +1720,6 @@ static int luks_format( + _cleanup_free_ char *text = NULL; + size_t volume_key_size; + int slot = 0, r; +- char **pp; + + assert(node); + assert(dm_name); +@@ -3664,7 +3662,6 @@ static int luks_try_resume( + const char *dm_name, + char **password) { + +- char **pp; + int r; + + assert(cd); +diff --git a/src/home/homework-pkcs11.c b/src/home/homework-pkcs11.c +index 15402b1002..7868fb6064 100644 +--- a/src/home/homework-pkcs11.c ++++ b/src/home/homework-pkcs11.c +@@ -20,7 +20,6 @@ int pkcs11_callback( + CK_TOKEN_INFO updated_token_info; + size_t decrypted_key_size; + CK_OBJECT_HANDLE object; +- char **i; + CK_RV rv; + int r; + +diff --git a/src/home/homework.c b/src/home/homework.c +index 9fdc74b775..0014a7f598 100644 +--- a/src/home/homework.c ++++ b/src/home/homework.c +@@ -97,9 +97,7 @@ int user_record_authenticate( + log_info("None of the supplied plaintext passwords unlock the user record's hashed recovery keys."); + + /* Second, test cached PKCS#11 passwords */ +- for (size_t n = 0; n < h->n_pkcs11_encrypted_key; n++) { +- char **pp; +- ++ for (size_t n = 0; n < h->n_pkcs11_encrypted_key; n++) + STRV_FOREACH(pp, cache->pkcs11_passwords) { + r = test_password_one(h->pkcs11_encrypted_key[n].hashed_password, *pp); + if (r < 0) +@@ -109,12 +107,9 @@ int user_record_authenticate( + return 1; + } + } +- } + + /* Third, test cached FIDO2 passwords */ +- for (size_t n = 0; n < h->n_fido2_hmac_salt; n++) { +- char **pp; +- ++ for (size_t n = 0; n < h->n_fido2_hmac_salt; n++) + /* See if any of the previously calculated passwords work */ + STRV_FOREACH(pp, cache->fido2_passwords) { + r = test_password_one(h->fido2_hmac_salt[n].hashed_password, *pp); +@@ -125,7 +120,6 @@ int user_record_authenticate( + return 1; + } + } +- } + + /* Fourth, let's see if any of the PKCS#11 security tokens are plugged in and help us */ + for (size_t n = 0; n < h->n_pkcs11_encrypted_key; n++) { +@@ -1096,7 +1090,6 @@ static int user_record_compile_effective_passwords( + + _cleanup_(strv_free_erasep) char **effective = NULL; + size_t n; +- char **i; + int r; + + assert(h); +@@ -1116,7 +1109,6 @@ static int user_record_compile_effective_passwords( + + STRV_FOREACH(i, h->hashed_password) { + bool found = false; +- char **j; + + log_debug("Looking for plaintext password for: %s", *i); + +@@ -1144,7 +1136,6 @@ static int user_record_compile_effective_passwords( + + for (n = 0; n < h->n_recovery_key; n++) { + bool found = false; +- char **j; + + log_debug("Looking for plaintext recovery key for: %s", h->recovery_key[n].hashed_password); + +diff --git a/src/home/user-record-pwquality.c b/src/home/user-record-pwquality.c +index 23c3357836..609e620511 100644 +--- a/src/home/user-record-pwquality.c ++++ b/src/home/user-record-pwquality.c +@@ -17,7 +17,7 @@ int user_record_quality_check_password( + sd_bus_error *error) { + + _cleanup_(sym_pwquality_free_settingsp) pwquality_settings_t *pwq = NULL; +- char buf[PWQ_MAX_ERROR_MESSAGE_LEN], **pp; ++ char buf[PWQ_MAX_ERROR_MESSAGE_LEN]; + void *auxerror; + int r; + +@@ -37,7 +37,6 @@ int user_record_quality_check_password( + /* Iterate through all new passwords */ + STRV_FOREACH(pp, secret->password) { + bool called = false; +- char **old; + + r = test_password_many(hr->hashed_password, *pp); + if (r < 0) +diff --git a/src/home/user-record-util.c b/src/home/user-record-util.c +index f4578783f3..1ae3e82bce 100644 +--- a/src/home/user-record-util.c ++++ b/src/home/user-record-util.c +@@ -563,7 +563,6 @@ int user_record_test_image_path_and_warn(UserRecord *h) { + } + + int user_record_test_password(UserRecord *h, UserRecord *secret) { +- char **i; + int r; + + assert(h); +@@ -585,7 +584,6 @@ int user_record_test_password(UserRecord *h, UserRecord *secret) { + } + + int user_record_test_recovery_key(UserRecord *h, UserRecord *secret) { +- char **i; + int r; + + assert(h); +@@ -779,7 +777,6 @@ int user_record_update_last_changed(UserRecord *h, bool with_password) { + int user_record_make_hashed_password(UserRecord *h, char **secret, bool extend) { + _cleanup_(json_variant_unrefp) JsonVariant *priv = NULL; + _cleanup_strv_free_ char **np = NULL; +- char **i; + int r; + + assert(h); +diff --git a/src/id128/id128.c b/src/id128/id128.c +index 484a72677d..6f4d65103c 100644 +--- a/src/id128/id128.c ++++ b/src/id128/id128.c +@@ -102,7 +102,6 @@ static int show_one(Table **table, const char *name, sd_id128_t uuid, bool first + + static int verb_show(int argc, char **argv, void *userdata) { + _cleanup_(table_unrefp) Table *table = NULL; +- char **p; + int r; + + argv = strv_skip(argv, 1); +diff --git a/src/journal-remote/journal-remote-main.c b/src/journal-remote/journal-remote-main.c +index 6ab91263b1..13ca22ef26 100644 +--- a/src/journal-remote/journal-remote-main.c ++++ b/src/journal-remote/journal-remote-main.c +@@ -594,7 +594,6 @@ static int create_remoteserver( + const char* trust) { + + int r, n, fd; +- char **file; + + r = journal_remote_server_init(s, arg_output, arg_split_mode, arg_compress, arg_seal); + if (r < 0) +diff --git a/src/journal-remote/microhttpd-util.c b/src/journal-remote/microhttpd-util.c +index e6a8254491..a8119bd687 100644 +--- a/src/journal-remote/microhttpd-util.c ++++ b/src/journal-remote/microhttpd-util.c +@@ -151,18 +151,17 @@ static int log_enable_gnutls_category(const char *cat) { + } + + int setup_gnutls_logger(char **categories) { +- char **cat; + int r; + + gnutls_global_set_log_function(log_func_gnutls); + +- if (categories) { ++ if (categories) + STRV_FOREACH(cat, categories) { + r = log_enable_gnutls_category(*cat); + if (r < 0) + return r; + } +- } else ++ else + log_reset_gnutls_level(); + + return 0; +diff --git a/src/journal/journalctl.c b/src/journal/journalctl.c +index 3c4a7c0a7a..6353c77c91 100644 +--- a/src/journal/journalctl.c ++++ b/src/journal/journalctl.c +@@ -1139,7 +1139,6 @@ static int parse_argv(int argc, char *argv[]) { + } + + static int add_matches(sd_journal *j, char **args) { +- char **i; + bool have_term = false; + + assert(j); +@@ -1562,7 +1561,7 @@ static int get_possible_units( + return r; + + SD_JOURNAL_FOREACH_UNIQUE(j, data, size) { +- char **pattern, *eq; ++ char *eq; + size_t prefix; + _cleanup_free_ char *u = NULL; + +@@ -1615,7 +1614,6 @@ static int get_possible_units( + static int add_units(sd_journal *j) { + _cleanup_strv_free_ char **patterns = NULL; + int r, count = 0; +- char **i; + + assert(j); + +@@ -1760,7 +1758,6 @@ static int add_facilities(sd_journal *j) { + + static int add_syslog_identifier(sd_journal *j) { + int r; +- char **i; + + assert(j); + +diff --git a/src/libsystemd-network/dhcp-option.c b/src/libsystemd-network/dhcp-option.c +index ebe8eecc9d..efb676e60b 100644 +--- a/src/libsystemd-network/dhcp-option.c ++++ b/src/libsystemd-network/dhcp-option.c +@@ -58,7 +58,6 @@ static int option_append(uint8_t options[], size_t size, size_t *offset, + + case SD_DHCP_OPTION_USER_CLASS: { + size_t total = 0; +- char **s; + + if (strv_isempty((char **) optval)) + return -EINVAL; +diff --git a/src/libsystemd-network/dhcp6-option.c b/src/libsystemd-network/dhcp6-option.c +index 28fe036a40..8b2ecfc44b 100644 +--- a/src/libsystemd-network/dhcp6-option.c ++++ b/src/libsystemd-network/dhcp6-option.c +@@ -468,7 +468,6 @@ int dhcp6_option_append_fqdn(uint8_t **buf, size_t *buflen, const char *fqdn) { + int dhcp6_option_append_user_class(uint8_t **buf, size_t *buflen, char * const *user_class) { + _cleanup_free_ uint8_t *p = NULL; + size_t total = 0, offset = 0; +- char * const *s; + + assert(buf); + assert(*buf); +@@ -501,7 +500,6 @@ int dhcp6_option_append_vendor_class(uint8_t **buf, size_t *buflen, char * const + _cleanup_free_ uint8_t *p = NULL; + uint32_t enterprise_identifier; + size_t total, offset; +- char * const *s; + + assert(buf); + assert(*buf); +diff --git a/src/libsystemd-network/sd-dhcp-client.c b/src/libsystemd-network/sd-dhcp-client.c +index c33be947b7..1c34893de6 100644 +--- a/src/libsystemd-network/sd-dhcp-client.c ++++ b/src/libsystemd-network/sd-dhcp-client.c +@@ -612,7 +612,6 @@ int sd_dhcp_client_set_user_class( + sd_dhcp_client *client, + char * const *user_class) { + +- char * const *p; + char **s = NULL; + + assert_return(client, -EINVAL); +diff --git a/src/libsystemd-network/sd-dhcp6-client.c b/src/libsystemd-network/sd-dhcp6-client.c +index 706904c720..122c878a66 100644 +--- a/src/libsystemd-network/sd-dhcp6-client.c ++++ b/src/libsystemd-network/sd-dhcp6-client.c +@@ -510,7 +510,6 @@ int sd_dhcp6_client_set_request_mud_url(sd_dhcp6_client *client, const char *mud + } + + int sd_dhcp6_client_set_request_user_class(sd_dhcp6_client *client, char * const *user_class) { +- char * const *p; + char **s; + + assert_return(client, -EINVAL); +@@ -532,7 +531,6 @@ int sd_dhcp6_client_set_request_user_class(sd_dhcp6_client *client, char * const + } + + int sd_dhcp6_client_set_request_vendor_class(sd_dhcp6_client *client, char * const *vendor_class) { +- char * const *p; + char **s; + + assert_return(client, -EINVAL); +diff --git a/src/libsystemd-network/sd-radv.c b/src/libsystemd-network/sd-radv.c +index e332f6a2ab..26f782208e 100644 +--- a/src/libsystemd-network/sd-radv.c ++++ b/src/libsystemd-network/sd-radv.c +@@ -800,7 +800,6 @@ int sd_radv_set_dnssl(sd_radv *ra, uint32_t lifetime, + char **search_list) { + _cleanup_free_ struct sd_radv_opt_dns *opt_dnssl = NULL; + size_t len = 0; +- char **s; + uint8_t *p; + + assert_return(ra, -EINVAL); +diff --git a/src/libsystemd/sd-bus/bus-dump.c b/src/libsystemd/sd-bus/bus-dump.c +index 0a4b3cbf68..42790ee3b4 100644 +--- a/src/libsystemd/sd-bus/bus-dump.c ++++ b/src/libsystemd/sd-bus/bus-dump.c +@@ -412,8 +412,6 @@ int bus_creds_dump(sd_bus_creds *c, FILE *f, bool terse) { + + r = sd_bus_creds_get_cmdline(c, &cmdline); + if (r >= 0) { +- char **i; +- + fprintf(f, "%sCommandLine=%s", prefix, color); + STRV_FOREACH(i, cmdline) { + if (i != cmdline) +@@ -478,8 +476,6 @@ int bus_creds_dump(sd_bus_creds *c, FILE *f, bool terse) { + fprintf(f, "%sUniqueName=%s%s%s", prefix, color, c->unique_name, suffix); + + if (sd_bus_creds_get_well_known_names(c, &well_known) >= 0) { +- char **i; +- + fprintf(f, "%sWellKnownNames=%s", prefix, color); + STRV_FOREACH(i, well_known) { + if (i != well_known) +diff --git a/src/libsystemd/sd-bus/bus-match.c b/src/libsystemd/sd-bus/bus-match.c +index 12a50845db..d4da60717e 100644 +--- a/src/libsystemd/sd-bus/bus-match.c ++++ b/src/libsystemd/sd-bus/bus-match.c +@@ -139,8 +139,6 @@ static bool value_node_test( + return true; + + if (m->creds.mask & SD_BUS_CREDS_WELL_KNOWN_NAMES) { +- char **i; +- + /* on kdbus we have the well known names list + * in the credentials, let's make use of that + * for an accurate match */ +@@ -174,8 +172,6 @@ static bool value_node_test( + return false; + + case BUS_MATCH_ARG_HAS ... BUS_MATCH_ARG_HAS_LAST: { +- char **i; +- + STRV_FOREACH(i, value_strv) + if (streq_ptr(node->value.str, *i)) + return true; +@@ -386,8 +382,6 @@ int bus_match_run( + if (test_str) + found = hashmap_get(node->compare.children, test_str); + else if (test_strv) { +- char **i; +- + STRV_FOREACH(i, test_strv) { + found = hashmap_get(node->compare.children, *i); + if (found) { +diff --git a/src/libsystemd/sd-bus/bus-message.c b/src/libsystemd/sd-bus/bus-message.c +index 96529b422b..b77372c3a0 100644 +--- a/src/libsystemd/sd-bus/bus-message.c ++++ b/src/libsystemd/sd-bus/bus-message.c +@@ -2815,7 +2815,6 @@ _public_ int sd_bus_message_append_string_memfd( + } + + _public_ int sd_bus_message_append_strv(sd_bus_message *m, char **l) { +- char **i; + int r; + + assert_return(m, -EINVAL); +diff --git a/src/libsystemd/sd-bus/bus-objects.c b/src/libsystemd/sd-bus/bus-objects.c +index 40158a7326..35546afebc 100644 +--- a/src/libsystemd/sd-bus/bus-objects.c ++++ b/src/libsystemd/sd-bus/bus-objects.c +@@ -109,7 +109,7 @@ static int add_enumerated_to_set( + assert(s); + + LIST_FOREACH(enumerators, c, first) { +- char **children = NULL, **k; ++ char **children = NULL; + sd_bus_slot *slot; + + if (bus->nodes_modified) +@@ -2072,7 +2072,6 @@ static int emit_properties_changed_on_interface( + struct vtable_member key = {}; + struct node_vtable *c; + struct node *n; +- char **property; + void *u = NULL; + int r; + +@@ -2854,7 +2853,6 @@ static int interfaces_added_append_one( + _public_ int sd_bus_emit_interfaces_added_strv(sd_bus *bus, const char *path, char **interfaces) { + _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL; + struct node *object_manager; +- char **i; + int r; + + assert_return(bus, -EINVAL); +diff --git a/src/libsystemd/sd-bus/test-bus-address.c b/src/libsystemd/sd-bus/test-bus-address.c +index 59421094c5..6de9f7cd57 100644 +--- a/src/libsystemd/sd-bus/test-bus-address.c ++++ b/src/libsystemd/sd-bus/test-bus-address.c +@@ -27,7 +27,6 @@ static void test_bus_set_address_system_remote(char **args) { + + assert_se(sd_bus_new(&b) >= 0); + if (!strv_isempty(args)) { +- char **a; + STRV_FOREACH(a, args) + test_one_address(b, *a, 0, NULL); + return; +diff --git a/src/libsystemd/sd-device/device-private.c b/src/libsystemd/sd-device/device-private.c +index 37eda23a5f..d3898ba959 100644 +--- a/src/libsystemd/sd-device/device-private.c ++++ b/src/libsystemd/sd-device/device-private.c +@@ -429,7 +429,6 @@ static int device_verify(sd_device *device) { + + int device_new_from_strv(sd_device **ret, char **strv) { + _cleanup_(sd_device_unrefp) sd_device *device = NULL; +- char **key; + const char *major = NULL, *minor = NULL; + int r; + +diff --git a/src/libsystemd/sd-journal/catalog.c b/src/libsystemd/sd-journal/catalog.c +index 4a2ba02ad0..d9ba9d11d3 100644 +--- a/src/libsystemd/sd-journal/catalog.c ++++ b/src/libsystemd/sd-journal/catalog.c +@@ -442,7 +442,6 @@ error: + + int catalog_update(const char* database, const char* root, const char* const* dirs) { + _cleanup_strv_free_ char **files = NULL; +- char **f; + _cleanup_(strbuf_freep) struct strbuf *sb = NULL; + _cleanup_ordered_hashmap_free_free_free_ OrderedHashmap *h = NULL; + _cleanup_free_ CatalogItem *items = NULL; +@@ -709,7 +708,6 @@ int catalog_list(FILE *f, const char *database, bool oneline) { + } + + int catalog_list_items(FILE *f, const char *database, bool oneline, char **items) { +- char **item; + int r = 0; + + STRV_FOREACH(item, items) { +diff --git a/src/libsystemd/sd-journal/sd-journal.c b/src/libsystemd/sd-journal/sd-journal.c +index 7a6cc4aca3..ecd755c705 100644 +--- a/src/libsystemd/sd-journal/sd-journal.c ++++ b/src/libsystemd/sd-journal/sd-journal.c +@@ -2029,7 +2029,6 @@ _public_ int sd_journal_open_directory(sd_journal **ret, const char *path, int f + + _public_ int sd_journal_open_files(sd_journal **ret, const char **paths, int flags) { + _cleanup_(sd_journal_closep) sd_journal *j = NULL; +- const char **path; + int r; + + assert_return(ret, -EINVAL); +diff --git a/src/libsystemd/sd-netlink/netlink-message.c b/src/libsystemd/sd-netlink/netlink-message.c +index 182c74ed3d..469076ae23 100644 +--- a/src/libsystemd/sd-netlink/netlink-message.c ++++ b/src/libsystemd/sd-netlink/netlink-message.c +@@ -258,7 +258,6 @@ int sd_netlink_message_append_string(sd_netlink_message *m, unsigned short type, + + int sd_netlink_message_append_strv(sd_netlink_message *m, unsigned short type, char * const *data) { + size_t length, size; +- char * const *p; + int r; + + assert_return(m, -EINVAL); +diff --git a/src/libsystemd/sd-path/sd-path.c b/src/libsystemd/sd-path/sd-path.c +index ff1e0d5f8e..8d9cfbc0af 100644 +--- a/src/libsystemd/sd-path/sd-path.c ++++ b/src/libsystemd/sd-path/sd-path.c +@@ -669,7 +669,7 @@ _public_ int sd_path_lookup_strv(uint64_t type, const char *suffix, char ***path + if (!n) + return -ENOMEM; + +- char **i, **j = n; ++ char **j = n; + STRV_FOREACH(i, l) { + *j = path_join(*i, suffix); + if (!*j) +diff --git a/src/locale/localectl.c b/src/locale/localectl.c +index b5624209dc..661d54c27d 100644 +--- a/src/locale/localectl.c ++++ b/src/locale/localectl.c +@@ -98,8 +98,6 @@ static void print_status_info(StatusInfo *i) { + if (strv_isempty(i->locale)) + puts(" System Locale: n/a"); + else { +- char **j; +- + printf(" System Locale: %s\n", i->locale[0]); + STRV_FOREACH(j, i->locale + 1) + printf(" %s\n", *j); +diff --git a/src/locale/localed.c b/src/locale/localed.c +index f3e6ef2db1..89bf9c6fba 100644 +--- a/src/locale/localed.c ++++ b/src/locale/localed.c +@@ -346,7 +346,6 @@ static int method_set_locale(sd_bus_message *m, void *userdata, sd_bus_error *er + Context *c = userdata; + bool modified = false; + int interactive, r; +- char **i; + bool use_localegen; + + assert(m); +diff --git a/src/login/loginctl.c b/src/login/loginctl.c +index 3e1916725d..4198f13f00 100644 +--- a/src/login/loginctl.c ++++ b/src/login/loginctl.c +@@ -601,7 +601,6 @@ static int print_user_status_info(sd_bus *bus, const char *path, bool *new_line) + printf("\t State: %s\n", i.state); + + if (!strv_isempty(i.sessions)) { +- char **l; + printf("\tSessions:"); + + STRV_FOREACH(l, i.sessions) +@@ -662,7 +661,6 @@ static int print_seat_status_info(sd_bus *bus, const char *path, bool *new_line) + printf("%s\n", strna(i.id)); + + if (!strv_isempty(i.sessions)) { +- char **l; + printf("\tSessions:"); + + STRV_FOREACH(l, i.sessions) { +diff --git a/src/login/logind-dbus.c b/src/login/logind-dbus.c +index c05c0d02cc..31a41bd271 100644 +--- a/src/login/logind-dbus.c ++++ b/src/login/logind-dbus.c +@@ -3947,7 +3947,6 @@ int manager_start_scope( + char **job) { + + _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL, *reply = NULL; +- char **i; + int r; + + assert(manager); +diff --git a/src/login/pam_systemd.c b/src/login/pam_systemd.c +index 5bd7efc3e8..2047dc1817 100644 +--- a/src/login/pam_systemd.c ++++ b/src/login/pam_systemd.c +@@ -533,7 +533,6 @@ static int pam_putenv_and_log(pam_handle_t *handle, const char *e, bool debug) { + } + + static int apply_user_record_settings(pam_handle_t *handle, UserRecord *ur, bool debug) { +- char **i; + int r; + + assert(handle); +diff --git a/src/modules-load/modules-load.c b/src/modules-load/modules-load.c +index eda847cb4a..9e20d59389 100644 +--- a/src/modules-load/modules-load.c ++++ b/src/modules-load/modules-load.c +@@ -194,7 +194,6 @@ static int run(int argc, char *argv[]) { + + } else { + _cleanup_strv_free_ char **files = NULL; +- char **fn, **i; + + STRV_FOREACH(i, arg_proc_cmdline_modules) { + k = module_load_and_warn(ctx, *i, true); +diff --git a/src/network/generator/network-generator.c b/src/network/generator/network-generator.c +index c081ec673c..7d7f35253b 100644 +--- a/src/network/generator/network-generator.c ++++ b/src/network/generator/network-generator.c +@@ -1132,7 +1132,6 @@ void network_dump(Network *network, FILE *f) { + Address *address; + Route *route; + const char *dhcp; +- char **dns; + + assert(network); + assert(f); +diff --git a/src/network/netdev/netdev.c b/src/network/netdev/netdev.c +index 8e7fe11c18..7b15c281e3 100644 +--- a/src/network/netdev/netdev.c ++++ b/src/network/netdev/netdev.c +@@ -866,7 +866,6 @@ int netdev_load_one(Manager *manager, const char *filename) { + + int netdev_load(Manager *manager, bool reload) { + _cleanup_strv_free_ char **files = NULL; +- char **f; + int r; + + assert(manager); +diff --git a/src/network/networkctl.c b/src/network/networkctl.c +index c35f851bdb..3eb63efa9c 100644 +--- a/src/network/networkctl.c ++++ b/src/network/networkctl.c +@@ -525,7 +525,6 @@ static int decode_link(sd_netlink_message *m, LinkInfo *info, char **patterns, b + if (!strv_fnmatch_full(patterns, str, 0, &pos) && + !strv_fnmatch_full(patterns, name, 0, &pos)) { + bool match = false; +- char **p; + + STRV_FOREACH(p, altnames) + if (strv_fnmatch_full(patterns, *p, 0, &pos)) { +diff --git a/src/network/networkd-dhcp-server.c b/src/network/networkd-dhcp-server.c +index 9acfd17d49..41c8122b5a 100644 +--- a/src/network/networkd-dhcp-server.c ++++ b/src/network/networkd-dhcp-server.c +@@ -206,8 +206,6 @@ static int link_push_uplink_to_dhcp_server( + break; + + case SD_DHCP_LEASE_NTP: { +- char **i; +- + /* For NTP things are similar, but for NTP hostnames can be configured too, which we cannot + * propagate via DHCP. Hence let's only propagate those which are IP addresses. */ + +diff --git a/src/network/networkd-json.c b/src/network/networkd-json.c +index fb1f50063e..dc9823c375 100644 +--- a/src/network/networkd-json.c ++++ b/src/network/networkd-json.c +@@ -699,7 +699,6 @@ static int server_build_json_one_string(const char *str, NetworkConfigSource s, + static int ntp_build_json(Link *link, JsonVariant **ret) { + JsonVariant **elements = NULL; + size_t n = 0; +- char **p; + int r; + + assert(link); +@@ -878,7 +877,7 @@ static int domains_build_json(Link *link, bool is_route, JsonVariant **ret) { + JsonVariant **elements = NULL; + DHCPUseDomains use_domains; + union in_addr_union s; +- char **p, **domains; ++ char **domains; + const char *domain; + size_t n = 0; + int r; +diff --git a/src/network/networkd-link-bus.c b/src/network/networkd-link-bus.c +index 765733b38c..4173eaa15f 100644 +--- a/src/network/networkd-link-bus.c ++++ b/src/network/networkd-link-bus.c +@@ -81,7 +81,6 @@ int bus_link_method_set_ntp_servers(sd_bus_message *message, void *userdata, sd_ + _cleanup_strv_free_ char **ntp = NULL; + Link *l = userdata; + int r; +- char **i; + + assert(message); + assert(l); +@@ -484,7 +483,6 @@ int bus_link_method_set_dnssec_negative_trust_anchors(sd_bus_message *message, v + _cleanup_strv_free_ char **ntas = NULL; + Link *l = userdata; + int r; +- char **i; + + assert(message); + assert(l); +diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c +index 7bc391d68d..f409d1f33a 100644 +--- a/src/network/networkd-link.c ++++ b/src/network/networkd-link.c +@@ -998,8 +998,6 @@ static void link_drop_requests(Link *link) { + } + + static Link *link_drop(Link *link) { +- char **n; +- + if (!link) + return NULL; + +@@ -2280,7 +2278,6 @@ static int link_update_mtu(Link *link, sd_netlink_message *message) { + + static int link_update_alternative_names(Link *link, sd_netlink_message *message) { + _cleanup_strv_free_ char **altnames = NULL; +- char **n; + int r; + + assert(link); +diff --git a/src/network/networkd-ndisc.c b/src/network/networkd-ndisc.c +index f616f2c9bc..3be078b179 100644 +--- a/src/network/networkd-ndisc.c ++++ b/src/network/networkd-ndisc.c +@@ -786,7 +786,6 @@ static int ndisc_router_process_dnssl(Link *link, sd_ndisc_router *rt) { + struct in6_addr router; + uint32_t lifetime_sec; + bool updated = false; +- char **j; + int r; + + assert(link); +diff --git a/src/network/networkd-network.c b/src/network/networkd-network.c +index 873ad2e703..03f09d730f 100644 +--- a/src/network/networkd-network.c ++++ b/src/network/networkd-network.c +@@ -573,7 +573,6 @@ int network_load_one(Manager *manager, OrderedHashmap **networks, const char *fi + + int network_load(Manager *manager, OrderedHashmap **networks) { + _cleanup_strv_free_ char **files = NULL; +- char **f; + int r; + + assert(manager); +diff --git a/src/nspawn/nspawn-bind-user.c b/src/nspawn/nspawn-bind-user.c +index d3113c303e..c9386e91f7 100644 +--- a/src/nspawn/nspawn-bind-user.c ++++ b/src/nspawn/nspawn-bind-user.c +@@ -203,7 +203,6 @@ int bind_user_prepare( + + _cleanup_(bind_user_context_freep) BindUserContext *c = NULL; + uid_t current_uid = MAP_UID_START; +- char **n; + int r; + + assert(custom_mounts); +diff --git a/src/nspawn/nspawn-mount.c b/src/nspawn/nspawn-mount.c +index 678fde3669..4379bd9b37 100644 +--- a/src/nspawn/nspawn-mount.c ++++ b/src/nspawn/nspawn-mount.c +@@ -166,8 +166,6 @@ int custom_mount_prepare_all(const char *dest, CustomMount *l, size_t n) { + } + + if (m->type == CUSTOM_MOUNT_OVERLAY) { +- char **j; +- + STRV_FOREACH(j, m->lower) { + char *s; + +@@ -319,8 +317,6 @@ int overlay_mount_parse(CustomMount **l, size_t *n, const char *s, bool read_onl + if (!destination) + return -ENOMEM; + } else { +- char **i; +- + /* If more than two parameters are specified, the last one is the destination, the second to last one + * the "upper", and all before that the "lower" directories. */ + +diff --git a/src/nspawn/nspawn-network.c b/src/nspawn/nspawn-network.c +index 023b1e7e1a..fab4eb9609 100644 +--- a/src/nspawn/nspawn-network.c ++++ b/src/nspawn/nspawn-network.c +@@ -288,7 +288,6 @@ int setup_veth_extra( + + _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL; + uint64_t idx = 0; +- char **a, **b; + int r; + + assert(machine_name); +@@ -495,7 +494,6 @@ int test_network_interface_initialized(const char *name) { + + int move_network_interfaces(int netns_fd, char **ifaces) { + _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL; +- char **i; + int r; + + if (strv_isempty(ifaces)) +@@ -532,7 +530,6 @@ int move_network_interfaces(int netns_fd, char **ifaces) { + int setup_macvlan(const char *machine_name, pid_t pid, char **ifaces) { + _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL; + unsigned idx = 0; +- char **i; + int r; + + if (strv_isempty(ifaces)) +@@ -619,7 +616,6 @@ int setup_macvlan(const char *machine_name, pid_t pid, char **ifaces) { + + int setup_ipvlan(const char *machine_name, pid_t pid, char **ifaces) { + _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL; +- char **i; + int r; + + if (strv_isempty(ifaces)) +@@ -728,7 +724,6 @@ int veth_extra_parse(char ***l, const char *p) { + + int remove_veth_links(const char *primary, char **pairs) { + _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL; +- char **a, **b; + int r; + + /* In some cases the kernel might pin the veth links between host and container even after the namespace +diff --git a/src/nspawn/nspawn-oci.c b/src/nspawn/nspawn-oci.c +index 9e59d6a814..afdac67427 100644 +--- a/src/nspawn/nspawn-oci.c ++++ b/src/nspawn/nspawn-oci.c +@@ -1892,7 +1892,6 @@ static int oci_seccomp_syscalls(const char *name, JsonVariant *v, JsonDispatchFl + struct syscall_rule rule = { + .action = UINT32_MAX, + }; +- char **i; + + r = json_dispatch(e, table, oci_unexpected, flags, &rule); + if (r < 0) +diff --git a/src/nspawn/nspawn-seccomp.c b/src/nspawn/nspawn-seccomp.c +index c94512ef30..77f4c2ac88 100644 +--- a/src/nspawn/nspawn-seccomp.c ++++ b/src/nspawn/nspawn-seccomp.c +@@ -140,7 +140,6 @@ static int add_syscall_filters( + }; + + _cleanup_strv_free_ char **added = NULL; +- char **p; + int r; + + for (size_t i = 0; i < ELEMENTSOF(allow_list); i++) { +diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c +index 1333a8702a..dd1cdb74b7 100644 +--- a/src/nspawn/nspawn.c ++++ b/src/nspawn/nspawn.c +@@ -3149,7 +3149,6 @@ static int patch_sysctl(void) { + }; + + unsigned long flags; +- char **k, **v; + int r; + + flags = effective_clone_ns_flags(); +diff --git a/src/nss-systemd/userdb-glue.c b/src/nss-systemd/userdb-glue.c +index 002e6925f9..c69667d660 100644 +--- a/src/nss-systemd/userdb-glue.c ++++ b/src/nss-systemd/userdb-glue.c +@@ -217,7 +217,7 @@ int nss_pack_group_record( + char *buffer, + size_t buflen) { + +- char **array = NULL, *p, **m; ++ char **array = NULL, *p; + size_t required, n = 0, i = 0; + + assert(g); +diff --git a/src/partition/repart.c b/src/partition/repart.c +index 509cf69b5d..2f70796e58 100644 +--- a/src/partition/repart.c ++++ b/src/partition/repart.c +@@ -1404,7 +1404,6 @@ static int context_read_definitions( + + _cleanup_strv_free_ char **files = NULL; + Partition *last = NULL; +- char **f; + int r; + + assert(context); +@@ -2832,7 +2831,6 @@ static int context_copy_blocks(Context *context) { + } + + static int do_copy_files(Partition *p, const char *fs) { +- char **source, **target; + int r; + + assert(p); +@@ -2929,7 +2927,6 @@ static int do_copy_files(Partition *p, const char *fs) { + } + + static int do_make_directories(Partition *p, const char *fs) { +- char **d; + int r; + + assert(p); +diff --git a/src/portable/portable.c b/src/portable/portable.c +index bdc10da36f..5be7ea854d 100644 +--- a/src/portable/portable.c ++++ b/src/portable/portable.c +@@ -58,7 +58,6 @@ static bool prefix_match(const char *unit, const char *prefix) { + + static bool unit_match(const char *unit, char **matches) { + const char *dot; +- char **i; + + dot = strrchr(unit, '.'); + if (!dot) +@@ -182,7 +181,6 @@ static int extract_now( + _cleanup_close_ int os_release_fd = -1; + _cleanup_free_ char *os_release_path = NULL; + const char *os_release_id; +- char **i; + int r; + + /* Extracts the metadata from a directory tree 'where'. Extracts two kinds of information: the /etc/os-release +@@ -527,8 +525,6 @@ static int extract_image_and_extensions( + return r; + + if (!strv_isempty(extension_image_paths)) { +- char **p; +- + extension_images = ordered_hashmap_new(&image_hash_ops); + if (!extension_images) + return -ENOMEM; +@@ -1224,8 +1220,6 @@ static int install_image_and_extensions_symlinks( + } + + static bool prefix_matches_compatible(char **matches, char **valid_prefixes) { +- char **m; +- + /* Checks if all 'matches' are included in the list of 'valid_prefixes' */ + + STRV_FOREACH(m, matches) +@@ -1342,7 +1336,6 @@ int portable_attach( + + static bool marker_matches_images(const char *marker, const char *name_or_path, char **extension_image_paths) { + _cleanup_strv_free_ char **root_and_extensions = NULL; +- char **image_name_or_path; + const char *a; + int r; + +diff --git a/src/portable/portablectl.c b/src/portable/portablectl.c +index 60feac6f5d..f4c57e14ae 100644 +--- a/src/portable/portablectl.c ++++ b/src/portable/portablectl.c +@@ -90,7 +90,6 @@ static int determine_image(const char *image, bool permit_non_existing, char **r + } + + static int attach_extensions_to_message(sd_bus_message *m, char **extensions) { +- char **p; + int r; + + assert(m); +@@ -1067,7 +1066,6 @@ static int dump_profiles(void) { + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL; + _cleanup_strv_free_ char **l = NULL; +- char **i; + int r; + + r = acquire_bus(&bus); +diff --git a/src/resolve/resolvectl.c b/src/resolve/resolvectl.c +index 5b3ceeff36..96a505f5e1 100644 +--- a/src/resolve/resolvectl.c ++++ b/src/resolve/resolvectl.c +@@ -705,7 +705,6 @@ invalid: + + static int verb_query(int argc, char **argv, void *userdata) { + sd_bus *bus = userdata; +- char **p; + int q, r = 0; + + if (arg_type != 0) +@@ -975,7 +974,6 @@ static int resolve_openpgp(sd_bus *bus, const char *address) { + + static int verb_openpgp(int argc, char **argv, void *userdata) { + sd_bus *bus = userdata; +- char **p; + int q, r = 0; + + STRV_FOREACH(p, argv + 1) { +@@ -1025,7 +1023,7 @@ static bool service_family_is_valid(const char *s) { + + static int verb_tlsa(int argc, char **argv, void *userdata) { + sd_bus *bus = userdata; +- char **p, **args = argv + 1; ++ char **args = argv + 1; + const char *family = "tcp"; + int q, r = 0; + +@@ -1389,7 +1387,6 @@ static int status_print_strv_ifindex(int ifindex, const char *ifname, char **p) + printf("%s%nGlobal%n%s:", ansi_highlight(), &pos1, &pos2, ansi_normal()); + + size_t cols = columns(), position = pos2 - pos1 + 2; +- char **i; + + STRV_FOREACH(i, p) { + size_t our_len = utf8_console_width(*i); /* This returns -1 on invalid utf-8 (which shouldn't happen). +@@ -2025,7 +2022,6 @@ static int verb_status(int argc, char **argv, void *userdata) { + int r = 0; + + if (argc > 1) { +- char **ifname; + bool empty_line = false; + + STRV_FOREACH(ifname, argv + 1) { +@@ -2049,7 +2045,6 @@ static int verb_status(int argc, char **argv, void *userdata) { + + static int call_dns(sd_bus *bus, char **dns, const BusLocator *locator, sd_bus_error *error, bool extended) { + _cleanup_(sd_bus_message_unrefp) sd_bus_message *req = NULL; +- char **p; + int r; + + r = bus_message_new_method_call(bus, &req, locator, extended ? "SetLinkDNSEx" : "SetLinkDNS"); +@@ -2157,7 +2152,6 @@ static int verb_dns(int argc, char **argv, void *userdata) { + + static int call_domain(sd_bus *bus, char **domain, const BusLocator *locator, sd_bus_error *error) { + _cleanup_(sd_bus_message_unrefp) sd_bus_message *req = NULL; +- char **p; + int r; + + r = bus_message_new_method_call(bus, &req, locator, "SetLinkDomains"); +@@ -2454,7 +2448,6 @@ static int call_nta(sd_bus *bus, char **nta, const BusLocator *locator, sd_bus_ + static int verb_nta(int argc, char **argv, void *userdata) { + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; + sd_bus *bus = userdata; +- char **p; + int r; + bool clear; + +diff --git a/src/resolve/resolved-dns-trust-anchor.c b/src/resolve/resolved-dns-trust-anchor.c +index b036aa402c..4a6c06d13d 100644 +--- a/src/resolve/resolved-dns-trust-anchor.c ++++ b/src/resolve/resolved-dns-trust-anchor.c +@@ -409,7 +409,6 @@ static int dns_trust_anchor_load_files( + int (*loader)(DnsTrustAnchor *d, const char *path, unsigned n, const char *line)) { + + _cleanup_strv_free_ char **files = NULL; +- char **f; + int r; + + assert(d); +diff --git a/src/resolve/resolved-dnssd.c b/src/resolve/resolved-dnssd.c +index ab2773e4e4..a05bd20199 100644 +--- a/src/resolve/resolved-dnssd.c ++++ b/src/resolve/resolved-dnssd.c +@@ -186,7 +186,6 @@ int dnssd_render_instance_name(DnssdService *s, char **ret_name) { + + int dnssd_load(Manager *manager) { + _cleanup_strv_free_ char **files = NULL; +- char **f; + int r; + + assert(manager); +diff --git a/src/resolve/resolved-etc-hosts.c b/src/resolve/resolved-etc-hosts.c +index 9af3a27bb1..c33bbbeb79 100644 +--- a/src/resolve/resolved-etc-hosts.c ++++ b/src/resolve/resolved-etc-hosts.c +@@ -189,7 +189,6 @@ static void strip_localhost(EtcHosts *hosts) { + + for (size_t j = 0; j < ELEMENTSOF(local_in_addrs); j++) { + bool all_localhost, in_order; +- char **i; + + item = hashmap_get(hosts->by_address, local_in_addrs + j); + if (!item) +@@ -389,8 +388,6 @@ int manager_etc_hosts_lookup(Manager *m, DnsQuestion* q, DnsAnswer **answer) { + } + + if (found_ptr) { +- char **n; +- + r = dns_answer_reserve(answer, strv_length(item->names)); + if (r < 0) + return r; +diff --git a/src/resolve/resolved-link-bus.c b/src/resolve/resolved-link-bus.c +index 8d533d7ecf..97f6eb70ca 100644 +--- a/src/resolve/resolved-link-bus.c ++++ b/src/resolve/resolved-link-bus.c +@@ -706,7 +706,6 @@ int bus_link_method_set_dnssec_negative_trust_anchors(sd_bus_message *message, v + _cleanup_free_ char *j = NULL; + Link *l = userdata; + int r; +- char **i; + + assert(message); + assert(l); +diff --git a/src/resolve/resolved-link.c b/src/resolve/resolved-link.c +index 6c910498a2..e6b46aed8e 100644 +--- a/src/resolve/resolved-link.c ++++ b/src/resolve/resolved-link.c +@@ -282,7 +282,6 @@ static int link_update_dns_server_one(Link *l, const char *str) { + + static int link_update_dns_servers(Link *l) { + _cleanup_strv_free_ char **nameservers = NULL; +- char **nameserver; + int r; + + assert(l); +@@ -511,7 +510,6 @@ static int link_update_search_domain_one(Link *l, const char *name, bool route_o + + static int link_update_search_domains(Link *l) { + _cleanup_strv_free_ char **sdomains = NULL, **rdomains = NULL; +- char **i; + int r, q; + + assert(l); +diff --git a/src/run-generator/run-generator.c b/src/run-generator/run-generator.c +index 1cf14e71fc..fb62209704 100644 +--- a/src/run-generator/run-generator.c ++++ b/src/run-generator/run-generator.c +@@ -55,7 +55,6 @@ static int parse(const char *key, const char *value, void *data) { + static int generate(void) { + _cleanup_fclose_ FILE *f = NULL; + const char *p; +- char **c; + int r; + + if (strv_isempty(arg_commands) && !arg_success_action) +diff --git a/src/shared/acl-util.c b/src/shared/acl-util.c +index 3f286a888b..2bdc529b80 100644 +--- a/src/shared/acl-util.c ++++ b/src/shared/acl-util.c +@@ -212,7 +212,6 @@ int acl_search_groups(const char *path, char ***ret_groups) { + int parse_acl(const char *text, acl_t *acl_access, acl_t *acl_default, bool want_mask) { + _cleanup_free_ char **a = NULL, **d = NULL; /* strings are not freed */ + _cleanup_strv_free_ char **split = NULL; +- char **entry; + int r = -EINVAL; + _cleanup_(acl_freep) acl_t a_acl = NULL, d_acl = NULL; + +diff --git a/src/shared/bootspec.c b/src/shared/bootspec.c +index a17375eb4c..4c39ce2f0e 100644 +--- a/src/shared/bootspec.c ++++ b/src/shared/bootspec.c +@@ -256,7 +256,6 @@ static int boot_entries_find( + size_t *n_entries) { + + _cleanup_strv_free_ char **files = NULL; +- char **f; + int r; + + assert(root); +@@ -771,8 +770,6 @@ int boot_entries_augment_from_loader( + "auto-reboot-to-firmware-setup", "Reboot Into Firmware Interface", + }; + +- char **i; +- + assert(config); + + /* Let's add the entries discovered by the boot loader to the end of our list, unless they are +@@ -780,7 +777,6 @@ int boot_entries_augment_from_loader( + + STRV_FOREACH(i, found_by_loader) { + _cleanup_free_ char *c = NULL, *t = NULL, *p = NULL; +- char **a, **b; + + if (boot_config_has_entry(config, *i)) + continue; +diff --git a/src/shared/bus-polkit.c b/src/shared/bus-polkit.c +index bbe04bea37..4d733a8173 100644 +--- a/src/shared/bus-polkit.c ++++ b/src/shared/bus-polkit.c +@@ -36,7 +36,6 @@ static int bus_message_append_strv_key_value( + sd_bus_message *m, + const char **l) { + +- const char **k, **v; + int r; + + assert(m); +diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c +index ef134bcee4..c211fe34d5 100644 +--- a/src/shared/bus-unit-util.c ++++ b/src/shared/bus-unit-util.c +@@ -1674,7 +1674,6 @@ static int bus_append_execute_property(sd_bus_message *m, const char *field, con + + if (streq(field, "RootImageOptions")) { + _cleanup_strv_free_ char **l = NULL; +- char **first = NULL, **second = NULL; + const char *p = eq; + + r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv"); +@@ -2023,7 +2022,6 @@ static int bus_append_execute_property(sd_bus_message *m, const char *field, con + if (r < 0) + return bus_log_create_error(r); + +- char **source, **destination; + STRV_FOREACH_PAIR(source, destination, symlinks) { + r = sd_bus_message_append(m, "(sst)", *source, *destination, 0); + if (r < 0) +@@ -2647,7 +2645,6 @@ int bus_append_unit_property_assignment(sd_bus_message *m, UnitType t, const cha + } + + int bus_append_unit_property_assignment_many(sd_bus_message *m, UnitType t, char **l) { +- char **i; + int r; + + assert(m); +diff --git a/src/shared/bus-util.c b/src/shared/bus-util.c +index 4a2b7684bc..a907b67a70 100644 +--- a/src/shared/bus-util.c ++++ b/src/shared/bus-util.c +@@ -490,7 +490,6 @@ int bus_path_decode_unique(const char *path, const char *prefix, char **ret_send + + int bus_track_add_name_many(sd_bus_track *t, char **l) { + int r = 0; +- char **i; + + assert(t); + +@@ -562,7 +561,6 @@ int bus_open_system_watch_bind_with_description(sd_bus **ret, const char *descri + + int bus_reply_pair_array(sd_bus_message *m, char **l) { + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; +- char **k, **v; + int r; + + assert(m); +diff --git a/src/shared/cgroup-setup.c b/src/shared/cgroup-setup.c +index 8bda66ca36..3532d55286 100644 +--- a/src/shared/cgroup-setup.c ++++ b/src/shared/cgroup-setup.c +@@ -22,7 +22,6 @@ + static int cg_any_controller_used_for_v1(void) { + _cleanup_free_ char *buf = NULL; + _cleanup_strv_free_ char **lines = NULL; +- char **line; + int r; + + r = read_full_virtual_file("/proc/cgroups", &buf, NULL); +diff --git a/src/shared/condition.c b/src/shared/condition.c +index 21f3714eba..d0f2ebfc23 100644 +--- a/src/shared/condition.c ++++ b/src/shared/condition.c +@@ -830,7 +830,6 @@ static int condition_test_first_boot(Condition *c, char **env) { + + static int condition_test_environment(Condition *c, char **env) { + bool equal; +- char **i; + + assert(c); + assert(c->parameter); +diff --git a/src/shared/conf-parser.c b/src/shared/conf-parser.c +index 1e1967d7ea..d19041207c 100644 +--- a/src/shared/conf-parser.c ++++ b/src/shared/conf-parser.c +@@ -474,7 +474,6 @@ static int config_parse_many_files( + + _cleanup_hashmap_free_ Hashmap *stats_by_path = NULL; + struct stat st; +- char **fn; + int r; + + if (ret_stats_by_path) { +diff --git a/src/shared/discover-image.c b/src/shared/discover-image.c +index 1d432328e7..3f1644ea85 100644 +--- a/src/shared/discover-image.c ++++ b/src/shared/discover-image.c +@@ -632,7 +632,6 @@ int image_remove(Image *i) { + _cleanup_(release_lock_file) LockFile global_lock = LOCK_FILE_INIT, local_lock = LOCK_FILE_INIT; + _cleanup_strv_free_ char **settings = NULL; + _cleanup_free_ char *roothash = NULL; +- char **j; + int r; + + assert(i); +@@ -695,10 +694,9 @@ int image_remove(Image *i) { + return -EOPNOTSUPP; + } + +- STRV_FOREACH(j, settings) { ++ STRV_FOREACH(j, settings) + if (unlink(*j) < 0 && errno != ENOENT) + log_debug_errno(errno, "Failed to unlink %s, ignoring: %m", *j); +- } + + if (unlink(roothash) < 0 && errno != ENOENT) + log_debug_errno(errno, "Failed to unlink %s, ignoring: %m", roothash); +@@ -724,7 +722,6 @@ int image_rename(Image *i, const char *new_name) { + _cleanup_free_ char *new_path = NULL, *nn = NULL, *roothash = NULL; + _cleanup_strv_free_ char **settings = NULL; + unsigned file_attr = 0; +- char **j; + int r; + + assert(i); +@@ -845,7 +842,6 @@ int image_clone(Image *i, const char *new_name, bool read_only) { + _cleanup_strv_free_ char **settings = NULL; + _cleanup_free_ char *roothash = NULL; + const char *new_path; +- char **j; + int r; + + assert(i); +diff --git a/src/shared/dissect-image.c b/src/shared/dissect-image.c +index b38f16c37a..79438c69d2 100644 +--- a/src/shared/dissect-image.c ++++ b/src/shared/dissect-image.c +@@ -2208,7 +2208,6 @@ static int validate_signature_userspace(const VeritySettings *verity) { + _cleanup_(BIO_freep) BIO *bio = NULL; /* 'bio' must be freed first, 's' second, hence keep this order + * of declaration in place, please */ + const unsigned char *d; +- char **i; + int r; + + assert(verity); +diff --git a/src/shared/dropin.c b/src/shared/dropin.c +index eb016eb114..375a3ca600 100644 +--- a/src/shared/dropin.c ++++ b/src/shared/dropin.c +@@ -232,7 +232,6 @@ int unit_file_find_dropin_paths( + + _cleanup_strv_free_ char **dirs = NULL; + const char *n; +- char **p; + int r; + + assert(ret); +diff --git a/src/shared/exec-util.c b/src/shared/exec-util.c +index b93de9c922..918f997e5a 100644 +--- a/src/shared/exec-util.c ++++ b/src/shared/exec-util.c +@@ -91,7 +91,6 @@ static int do_execute( + + _cleanup_hashmap_free_free_ Hashmap *pids = NULL; + _cleanup_strv_free_ char **paths = NULL; +- char **path, **e; + int r; + bool parallel_execution; + +@@ -254,7 +253,7 @@ int execute_directories( + } + + static int gather_environment_generate(int fd, void *arg) { +- char ***env = arg, **x, **y; ++ char ***env = arg; + _cleanup_fclose_ FILE *f = NULL; + _cleanup_strv_free_ char **new = NULL; + int r; +@@ -369,7 +368,6 @@ static int gather_environment_consume(int fd, void *arg) { + + int exec_command_flags_from_strv(char **ex_opts, ExecCommandFlags *flags) { + ExecCommandFlags ex_flag, ret_flags = 0; +- char **opt; + + assert(flags); + +diff --git a/src/shared/format-table.c b/src/shared/format-table.c +index b95680b365..b756c5286b 100644 +--- a/src/shared/format-table.c ++++ b/src/shared/format-table.c +@@ -1364,7 +1364,6 @@ static char* format_strv_width(char **strv, size_t column_width) { + return NULL; + + size_t position = 0; +- char **p; + STRV_FOREACH(p, strv) { + size_t our_len = utf8_console_width(*p); /* This returns -1 on invalid utf-8 (which shouldn't happen). + * If that happens, we'll just print one item per line. */ +diff --git a/src/shared/hwdb-util.c b/src/shared/hwdb-util.c +index fe4785f3e5..f98d03f766 100644 +--- a/src/shared/hwdb-util.c ++++ b/src/shared/hwdb-util.c +@@ -434,7 +434,7 @@ static int trie_store(struct trie *trie, const char *filename, bool compat) { + + static int insert_data(struct trie *trie, char **match_list, char *line, const char *filename, + uint16_t file_priority, uint32_t line_number, bool compat) { +- char *value, **entry; ++ char *value; + + assert(line[0] == ' '); + +@@ -583,7 +583,6 @@ int hwdb_update(const char *root, const char *hwdb_bin_dir, bool strict, bool co + _cleanup_free_ char *hwdb_bin = NULL; + _cleanup_(trie_freep) struct trie *trie = NULL; + _cleanup_strv_free_ char **files = NULL; +- char **f; + uint16_t file_priority = 1; + int r = 0, err; + +diff --git a/src/shared/install.c b/src/shared/install.c +index f1ee3c2716..785ef55dbd 100644 +--- a/src/shared/install.c ++++ b/src/shared/install.c +@@ -874,7 +874,6 @@ static int find_symlinks_in_scope( + bool same_name_link_runtime = false, same_name_link_config = false; + bool enabled_in_runtime = false, enabled_at_all = false; + bool ignore_same_name = false; +- char **p; + int r; + + assert(lp); +@@ -1381,7 +1380,6 @@ static int unit_file_search( + _cleanup_free_ char *template = NULL; + bool found_unit = false; + int r, result; +- char **p; + + assert(info); + assert(lp); +@@ -1796,7 +1794,6 @@ static int install_info_symlink_alias( + UnitFileChange **changes, + size_t *n_changes) { + +- char **s; + int r = 0, q; + + assert(info); +@@ -1846,7 +1843,6 @@ static int install_info_symlink_wants( + _cleanup_free_ char *buf = NULL; + UnitNameFlags valid_dst_type = UNIT_NAME_ANY; + const char *n; +- char **s; + int r = 0, q; + + assert(info); +@@ -2150,7 +2146,6 @@ int unit_file_mask( + + _cleanup_(lookup_paths_free) LookupPaths lp = {}; + const char *config_path; +- char **i; + int r; + + assert(scope >= 0); +@@ -2199,7 +2194,6 @@ int unit_file_unmask( + _cleanup_strv_free_ char **todo = NULL; + const char *config_path; + size_t n_todo = 0; +- char **i; + int r, q; + + assert(scope >= 0); +@@ -2291,7 +2285,6 @@ int unit_file_link( + _cleanup_strv_free_ char **todo = NULL; + const char *config_path; + size_t n_todo = 0; +- char **i; + int r, q; + + assert(scope >= 0); +@@ -2391,7 +2384,6 @@ int unit_file_revert( + _cleanup_(lookup_paths_free) LookupPaths lp = {}; + _cleanup_strv_free_ char **todo = NULL; + size_t n_todo = 0; +- char **i; + int r, q; + + /* Puts a unit file back into vendor state. This means: +@@ -2411,7 +2403,6 @@ int unit_file_revert( + + STRV_FOREACH(i, files) { + bool has_vendor = false; +- char **p; + + if (!unit_name_is_valid(*i, UNIT_NAME_ANY)) + return -EINVAL; +@@ -2495,7 +2486,6 @@ int unit_file_revert( + STRV_FOREACH(i, todo) { + _cleanup_strv_free_ char **fs = NULL; + const char *rp; +- char **j; + + (void) get_files_in_directory(*i, &fs); + +@@ -2548,7 +2538,6 @@ int unit_file_add_dependency( + _cleanup_(install_context_done) InstallContext ctx = { .scope = scope }; + UnitFileInstallInfo *info, *target_info; + const char *config_path; +- char **f; + int r; + + assert(scope >= 0); +@@ -2617,7 +2606,6 @@ int unit_file_enable( + _cleanup_(install_context_done) InstallContext ctx = { .scope = scope }; + const char *config_path; + UnitFileInstallInfo *info; +- char **f; + int r; + + assert(scope >= 0); +@@ -2661,7 +2649,6 @@ int unit_file_disable( + _cleanup_(install_context_done) InstallContext ctx = { .scope = scope }; + _cleanup_set_free_free_ Set *remove_symlinks_to = NULL; + const char *config_path; +- char **i; + int r; + + assert(scope >= 0); +@@ -2979,7 +2966,6 @@ static int presets_find_config(UnitFileScope scope, const char *root_dir, char * + static int read_presets(UnitFileScope scope, const char *root_dir, UnitFilePresets *presets) { + _cleanup_(unit_file_presets_freep) UnitFilePresets ps = {}; + _cleanup_strv_free_ char **files = NULL; +- char **p; + int r; + + assert(scope >= 0); +@@ -3097,7 +3083,6 @@ static int pattern_match_multiple_instances( + if (unit_name_is_valid(unit_name, UNIT_NAME_TEMPLATE)) { + _cleanup_strv_free_ char **out_strv = NULL; + +- char **iter; + STRV_FOREACH(iter, rule.instances) { + _cleanup_free_ char *name = NULL; + +@@ -3144,11 +3129,10 @@ static int query_presets(const char *name, const UnitFilePresets *presets, char + log_debug("Preset files don't specify rule for %s. Enabling.", name); + return 1; + case PRESET_ENABLE: +- if (instance_name_list && *instance_name_list) { +- char **s; ++ if (instance_name_list && *instance_name_list) + STRV_FOREACH(s, *instance_name_list) + log_debug("Preset files say enable %s.", *s); +- } else ++ else + log_debug("Preset files say enable %s.", name); + return 1; + case PRESET_DISABLE: +@@ -3254,15 +3238,14 @@ static int preset_prepare_one( + return r; + + if (r > 0) { +- if (instance_name_list) { +- char **s; ++ if (instance_name_list) + STRV_FOREACH(s, instance_name_list) { + r = install_info_discover_and_check(plus, lp, *s, SEARCH_LOAD|SEARCH_FOLLOW_CONFIG_SYMLINKS, + &info, changes, n_changes); + if (r < 0) + return r; + } +- } else { ++ else { + r = install_info_discover_and_check(plus, lp, name, SEARCH_LOAD|SEARCH_FOLLOW_CONFIG_SYMLINKS, + &info, changes, n_changes); + if (r < 0) +@@ -3289,7 +3272,6 @@ int unit_file_preset( + _cleanup_(lookup_paths_free) LookupPaths lp = {}; + _cleanup_(unit_file_presets_freep) UnitFilePresets presets = {}; + const char *config_path; +- char **i; + int r; + + assert(scope >= 0); +@@ -3329,7 +3311,6 @@ int unit_file_preset_all( + _cleanup_(lookup_paths_free) LookupPaths lp = {}; + _cleanup_(unit_file_presets_freep) UnitFilePresets presets = {}; + const char *config_path = NULL; +- char **i; + int r; + + assert(scope >= 0); +@@ -3401,7 +3382,6 @@ int unit_file_get_list( + char **patterns) { + + _cleanup_(lookup_paths_free) LookupPaths lp = {}; +- char **dirname; + int r; + + assert(scope >= 0); +diff --git a/src/shared/libcrypt-util.c b/src/shared/libcrypt-util.c +index 5b315413aa..0d72032f53 100644 +--- a/src/shared/libcrypt-util.c ++++ b/src/shared/libcrypt-util.c +@@ -197,7 +197,6 @@ int test_password_one(const char *hashed_password, const char *password) { + } + + int test_password_many(char **hashed_password, const char *password) { +- char **hpw; + int r; + + STRV_FOREACH(hpw, hashed_password) { +diff --git a/src/shared/libfido2-util.c b/src/shared/libfido2-util.c +index 87b88f04d6..8c9fa88e32 100644 +--- a/src/shared/libfido2-util.c ++++ b/src/shared/libfido2-util.c +@@ -313,8 +313,6 @@ static int fido2_use_hmac_hash_specific_token( + bool retry_with_up = false, retry_with_pin = false; + + if (FLAGS_SET(required, FIDO2ENROLL_PIN)) { +- char **i; +- + /* OK, we need a pin, try with all pins in turn */ + if (strv_isempty(pins)) + r = FIDO_ERR_PIN_REQUIRED; +@@ -683,7 +681,6 @@ int fido2_generate_hmac_hash( + + for (;;) { + _cleanup_(strv_free_erasep) char **pin = NULL; +- char **i; + + r = ask_password_auto("Please enter security token PIN:", askpw_icon_name, NULL, "fido2-pin", "fido2-pin", USEC_INFINITY, 0, &pin); + if (r < 0) +diff --git a/src/shared/mount-setup.c b/src/shared/mount-setup.c +index 7eadff3ace..975c027f47 100644 +--- a/src/shared/mount-setup.c ++++ b/src/shared/mount-setup.c +@@ -244,8 +244,6 @@ static const char *join_with(const char *controller) { + NULL + }; + +- const char *const *x, *const *y; +- + assert(controller); + + /* This will lookup which controller to mount another controller with. Input is a controller name, and output +@@ -433,7 +431,6 @@ static int relabel_cgroup_filesystems(void) { + + static int relabel_extra(void) { + _cleanup_strv_free_ char **files = NULL; +- char **file; + int r, c = 0; + + /* Support for relabelling additional files or directories after loading the policy. For this, code in the +diff --git a/src/shared/mount-util.c b/src/shared/mount-util.c +index c75c02f5be..12c7044f04 100644 +--- a/src/shared/mount-util.c ++++ b/src/shared/mount-util.c +@@ -274,7 +274,6 @@ int bind_remount_recursive_with_mountinfo( + * we shall operate on. */ + if (!path_equal(path, prefix)) { + bool deny_listed = false; +- char **i; + + STRV_FOREACH(i, deny_list) { + if (path_equal(*i, prefix)) +diff --git a/src/shared/net-condition.c b/src/shared/net-condition.c +index 006676d973..2bb4c0b509 100644 +--- a/src/shared/net-condition.c ++++ b/src/shared/net-condition.c +@@ -46,7 +46,6 @@ bool net_match_is_empty(const NetMatch *match) { + } + + static bool net_condition_test_strv(char * const *patterns, const char *string) { +- char * const *p; + bool match = false, has_positive_rule = false; + + if (strv_isempty(patterns)) +@@ -77,7 +76,6 @@ static bool net_condition_test_ifname(char * const *patterns, const char *ifname + if (net_condition_test_strv(patterns, ifname)) + return true; + +- char * const *p; + STRV_FOREACH(p, alternative_names) + if (net_condition_test_strv(patterns, *p)) + return true; +@@ -86,8 +84,6 @@ static bool net_condition_test_ifname(char * const *patterns, const char *ifname + } + + static int net_condition_test_property(char * const *match_property, sd_device *device) { +- char * const *p; +- + if (strv_isempty(match_property)) + return true; + +diff --git a/src/shared/nscd-flush.c b/src/shared/nscd-flush.c +index 0655030633..95dfe24b22 100644 +--- a/src/shared/nscd-flush.c ++++ b/src/shared/nscd-flush.c +@@ -132,7 +132,6 @@ static int nscd_flush_cache_one(const char *database, usec_t end) { + int nscd_flush_cache(char **databases) { + usec_t end; + int r = 0; +- char **i; + + /* Tries to invalidate the specified database in nscd. We do this carefully, with a 5s timeout, so that we + * don't block indefinitely on another service. */ +diff --git a/src/shared/pkcs11-util.c b/src/shared/pkcs11-util.c +index 67ea44515a..4f9ec1fbd6 100644 +--- a/src/shared/pkcs11-util.c ++++ b/src/shared/pkcs11-util.c +@@ -275,7 +275,7 @@ int pkcs11_token_login( + + for (unsigned tries = 0; tries < 3; tries++) { + _cleanup_strv_free_erase_ char **passwords = NULL; +- char **i, *e; ++ char *e; + + e = getenv("PIN"); + if (e) { +diff --git a/src/shared/pretty-print.c b/src/shared/pretty-print.c +index 26daec3450..98619c25d4 100644 +--- a/src/shared/pretty-print.c ++++ b/src/shared/pretty-print.c +@@ -168,7 +168,6 @@ static int cat_file(const char *filename, bool newline) { + } + + int cat_files(const char *file, char **dropins, CatFlags flags) { +- char **path; + int r; + + if (file) { +@@ -284,10 +283,9 @@ static int guess_type(const char **name, char ***prefixes, bool *is_collection, + int conf_files_cat(const char *root, const char *name) { + _cleanup_strv_free_ char **dirs = NULL, **files = NULL; + _cleanup_free_ char *path = NULL; +- char **prefix, **prefixes = NULL; /* explicit initialization to appease gcc */ ++ char **prefixes = NULL; /* explicit initialization to appease gcc */ + bool is_collection; + const char *extension; +- char **t; + int r; + + r = guess_type(&name, &prefixes, &is_collection, &extension); +diff --git a/src/shared/seccomp-util.c b/src/shared/seccomp-util.c +index 32bd8aa73b..e597a156cf 100644 +--- a/src/shared/seccomp-util.c ++++ b/src/shared/seccomp-util.c +@@ -1837,7 +1837,6 @@ int seccomp_restrict_archs(Set *archs) { + + int parse_syscall_archs(char **l, Set **ret_archs) { + _cleanup_set_free_ Set *archs = NULL; +- char **s; + int r; + + assert(l); +diff --git a/src/shared/serialize.c b/src/shared/serialize.c +index 47996b9ead..cd48286355 100644 +--- a/src/shared/serialize.c ++++ b/src/shared/serialize.c +@@ -117,7 +117,6 @@ int serialize_dual_timestamp(FILE *f, const char *name, const dual_timestamp *t) + + int serialize_strv(FILE *f, const char *key, char **l) { + int ret = 0, r; +- char **i; + + /* Returns the first error, or positive if anything was serialized, 0 otherwise. */ + +diff --git a/src/shared/tests.c b/src/shared/tests.c +index 307f796fe2..70fbbb45a5 100644 +--- a/src/shared/tests.c ++++ b/src/shared/tests.c +@@ -51,7 +51,6 @@ static void load_testdata_env(void) { + _cleanup_free_ char *s = NULL; + _cleanup_free_ char *envpath = NULL; + _cleanup_strv_free_ char **pairs = NULL; +- char **k, **v; + + if (called) + return; +diff --git a/src/shared/user-record-show.c b/src/shared/user-record-show.c +index 7c2751f3a7..95895a8e45 100644 +--- a/src/shared/user-record-show.c ++++ b/src/shared/user-record-show.c +@@ -143,7 +143,6 @@ void user_record_show(UserRecord *hr, bool show_full_group_info) { + break; + } + bool has_valid_passwords = false; +- char **p; + STRV_FOREACH(p, hr->hashed_password) + if (!hashed_password_is_locked_or_invalid(*p)) { + has_valid_passwords = true; +@@ -240,15 +239,12 @@ void user_record_show(UserRecord *hr, bool show_full_group_info) { + if (hr->preferred_language) + printf(" Language: %s\n", hr->preferred_language); + +- if (!strv_isempty(hr->environment)) { +- char **i; +- ++ if (!strv_isempty(hr->environment)) + STRV_FOREACH(i, hr->environment) { + printf(i == hr->environment ? + " Environment: %s\n" : + " %s\n", *i); + } +- } + + if (hr->locked >= 0) + printf(" Locked: %s\n", yes_no(hr->locked)); +@@ -478,14 +474,11 @@ void user_record_show(UserRecord *hr, bool show_full_group_info) { + if (!strv_isempty(hr->ssh_authorized_keys)) + printf("SSH Pub. Key: %zu\n", strv_length(hr->ssh_authorized_keys)); + +- if (!strv_isempty(hr->pkcs11_token_uri)) { +- char **i; +- ++ if (!strv_isempty(hr->pkcs11_token_uri)) + STRV_FOREACH(i, hr->pkcs11_token_uri) + printf(i == hr->pkcs11_token_uri ? + "PKCS11 Token: %s\n" : + " %s\n", *i); +- } + + if (hr->n_fido2_hmac_credential > 0) + printf(" FIDO2 Token: %zu\n", hr->n_fido2_hmac_credential); +@@ -558,7 +551,6 @@ void group_record_show(GroupRecord *gr, bool show_full_user_info) { + } + } else { + const char *prefix = " Members:"; +- char **i; + + STRV_FOREACH(i, gr->members) { + printf("%s %s\n", prefix, *i); +@@ -568,7 +560,6 @@ void group_record_show(GroupRecord *gr, bool show_full_user_info) { + + if (!strv_isempty(gr->administrators)) { + const char *prefix = " Admins:"; +- char **i; + + STRV_FOREACH(i, gr->administrators) { + printf("%s %s\n", prefix, *i); +diff --git a/src/sleep/sleep.c b/src/sleep/sleep.c +index 7064f3a905..f108529bbd 100644 +--- a/src/sleep/sleep.c ++++ b/src/sleep/sleep.c +@@ -85,7 +85,6 @@ static int write_hibernate_location_info(const HibernateLocation *hibernate_loca + + static int write_mode(char **modes) { + int r = 0; +- char **mode; + + STRV_FOREACH(mode, modes) { + int k; +@@ -103,7 +102,6 @@ static int write_mode(char **modes) { + } + + static int write_state(FILE **f, char **states) { +- char **state; + int r = 0; + + assert(f); +diff --git a/src/sysctl/sysctl.c b/src/sysctl/sysctl.c +index 408ac3b8be..24c8baab03 100644 +--- a/src/sysctl/sysctl.c ++++ b/src/sysctl/sysctl.c +@@ -51,8 +51,6 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(Option*, option_free); + DEFINE_HASH_OPS_WITH_VALUE_DESTRUCTOR(option_hash_ops, char, string_hash_func, string_compare_func, Option, option_free); + + static bool test_prefix(const char *p) { +- char **i; +- + if (strv_isempty(arg_prefixes)) + return true; + +@@ -131,7 +129,6 @@ static int apply_all(OrderedHashmap *sysctl_options) { + if (string_is_glob(option->key)) { + _cleanup_strv_free_ char **paths = NULL; + _cleanup_free_ char *pattern = NULL; +- char **s; + + pattern = path_join("/proc/sys", option->key); + if (!pattern) +@@ -403,7 +400,6 @@ static int run(int argc, char *argv[]) { + } + } else { + _cleanup_strv_free_ char **files = NULL; +- char **f; + + r = conf_files_list_strv(&files, ".conf", NULL, 0, (const char**) CONF_PATHS_STRV("sysctl.d")); + if (r < 0) +diff --git a/src/sysext/sysext.c b/src/sysext/sysext.c +index 5abf1bb418..6a2dc16ab9 100644 +--- a/src/sysext/sysext.c ++++ b/src/sysext/sysext.c +@@ -123,7 +123,6 @@ static int unmerge_hierarchy(const char *p) { + + static int unmerge(void) { + int r, ret = 0; +- char **p; + + STRV_FOREACH(p, arg_hierarchies) { + _cleanup_free_ char *resolved = NULL; +@@ -160,7 +159,6 @@ static int verb_unmerge(int argc, char **argv, void *userdata) { + static int verb_status(int argc, char **argv, void *userdata) { + _cleanup_(table_unrefp) Table *t = NULL; + int r, ret = 0; +- char **p; + + t = table_new("hierarchy", "extensions", "since"); + if (!t) +@@ -244,7 +242,6 @@ static int mount_overlayfs( + + _cleanup_free_ char *options = NULL; + bool separator = false; +- char **l; + int r; + + assert(where); +@@ -284,7 +281,6 @@ static int merge_hierarchy( + _cleanup_free_ char *resolved_hierarchy = NULL, *f = NULL, *buf = NULL; + _cleanup_strv_free_ char **layers = NULL; + struct stat st; +- char **p; + int r; + + assert(hierarchy); +@@ -452,7 +448,6 @@ static int merge_subprocess(Hashmap *images, const char *workspace) { + size_t n_extensions = 0; + unsigned n_ignored = 0; + Image *img; +- char **h; + int r; + + /* Mark the whole of /run as MS_SLAVE, so that we can mount stuff below it that doesn't show up on +@@ -759,7 +754,6 @@ static int image_discover_and_read_metadata(Hashmap **ret_images) { + + static int verb_merge(int argc, char **argv, void *userdata) { + _cleanup_(hashmap_freep) Hashmap *images = NULL; +- char **p; + int r; + + if (!have_effective_cap(CAP_SYS_ADMIN)) +diff --git a/src/systemctl/systemctl-cancel-job.c b/src/systemctl/systemctl-cancel-job.c +index 4c5203c1f9..647e70767e 100644 +--- a/src/systemctl/systemctl-cancel-job.c ++++ b/src/systemctl/systemctl-cancel-job.c +@@ -10,7 +10,6 @@ + + int cancel_job(int argc, char *argv[], void *userdata) { + sd_bus *bus; +- char **name; + int r; + + if (argc <= 1) /* Shortcut to trivial_method() if no argument is given */ +diff --git a/src/systemctl/systemctl-clean-or-freeze.c b/src/systemctl/systemctl-clean-or-freeze.c +index fb4d643517..dc44110c72 100644 +--- a/src/systemctl/systemctl-clean-or-freeze.c ++++ b/src/systemctl/systemctl-clean-or-freeze.c +@@ -11,7 +11,6 @@ int clean_or_freeze_unit(int argc, char *argv[], void *userdata) { + _cleanup_(bus_wait_for_units_freep) BusWaitForUnits *w = NULL; + _cleanup_strv_free_ char **names = NULL; + int r, ret = EXIT_SUCCESS; +- char **name; + const char *method; + sd_bus *bus; + +diff --git a/src/systemctl/systemctl-edit.c b/src/systemctl/systemctl-edit.c +index 92abd15636..328168e4bb 100644 +--- a/src/systemctl/systemctl-edit.c ++++ b/src/systemctl/systemctl-edit.c +@@ -26,7 +26,6 @@ int cat(int argc, char *argv[], void *userdata) { + _cleanup_(hashmap_freep) Hashmap *cached_name_map = NULL, *cached_id_map = NULL; + _cleanup_(lookup_paths_free) LookupPaths lp = {}; + _cleanup_strv_free_ char **names = NULL; +- char **name; + sd_bus *bus; + bool first = true; + int r, rc = 0; +@@ -145,7 +144,6 @@ static int create_edit_temp_file(const char *new_path, const char *original_path + } else if (original_unit_paths) { + _cleanup_free_ char *new_contents = NULL; + _cleanup_fclose_ FILE *f = NULL; +- char **path; + + r = mac_selinux_create_file_prepare(new_path, S_IFREG); + if (r < 0) +@@ -318,7 +316,7 @@ static int run_editor(char **paths) { + if (r < 0) + return r; + if (r == 0) { +- char **editor_args = NULL, **tmp_path, **original_path; ++ char **editor_args = NULL; + size_t n_editor_args = 0, i = 1, argc; + const char **args, *editor; + +@@ -379,7 +377,6 @@ static int run_editor(char **paths) { + static int find_paths_to_edit(sd_bus *bus, char **names, char ***paths) { + _cleanup_(hashmap_freep) Hashmap *cached_name_map = NULL, *cached_id_map = NULL; + _cleanup_(lookup_paths_free) LookupPaths lp = {}; +- char **name; + int r; + + assert(names); +@@ -501,7 +498,6 @@ int edit(int argc, char *argv[], void *userdata) { + _cleanup_(lookup_paths_free) LookupPaths lp = {}; + _cleanup_strv_free_ char **names = NULL; + _cleanup_strv_free_ char **paths = NULL; +- char **original, **tmp; + sd_bus *bus; + int r; + +diff --git a/src/systemctl/systemctl-enable.c b/src/systemctl/systemctl-enable.c +index 7860f3dc6c..6266363f00 100644 +--- a/src/systemctl/systemctl-enable.c ++++ b/src/systemctl/systemctl-enable.c +@@ -12,7 +12,6 @@ + #include "systemctl.h" + + static int normalize_filenames(char **names) { +- char **u; + int r; + + STRV_FOREACH(u, names) +@@ -40,7 +39,6 @@ static int normalize_filenames(char **names) { + } + + static int normalize_names(char **names, bool warn_if_path) { +- char **u; + bool was_path = false; + + STRV_FOREACH(u, names) { +@@ -139,7 +137,6 @@ int enable_unit(int argc, char *argv[], void *userdata) { + sd_bus *bus; + + if (STR_IN_SET(verb, "mask", "unmask")) { +- char **name; + _cleanup_(lookup_paths_free) LookupPaths lp = {}; + + r = lookup_paths_init_or_warn(&lp, arg_scope, 0, arg_root); +diff --git a/src/systemctl/systemctl-is-active.c b/src/systemctl/systemctl-is-active.c +index d83736e94a..e7c8431ac6 100644 +--- a/src/systemctl/systemctl-is-active.c ++++ b/src/systemctl/systemctl-is-active.c +@@ -13,7 +13,6 @@ static int check_unit_generic(int code, const UnitActiveState good_states[], int + _cleanup_strv_free_ char **names = NULL; + UnitActiveState active_state; + sd_bus *bus; +- char **name; + int r; + bool found = false; + +diff --git a/src/systemctl/systemctl-is-enabled.c b/src/systemctl/systemctl-is-enabled.c +index e33dffaf29..eaf25217a8 100644 +--- a/src/systemctl/systemctl-is-enabled.c ++++ b/src/systemctl/systemctl-is-enabled.c +@@ -59,7 +59,6 @@ static int show_installation_targets(sd_bus *bus, const char *name) { + int unit_is_enabled(int argc, char *argv[], void *userdata) { + _cleanup_strv_free_ char **names = NULL; + bool enabled; +- char **name; + int r; + + r = mangle_names("to check", strv_skip(argv, 1), &names); +diff --git a/src/systemctl/systemctl-kill.c b/src/systemctl/systemctl-kill.c +index 489e754752..94489423e8 100644 +--- a/src/systemctl/systemctl-kill.c ++++ b/src/systemctl/systemctl-kill.c +@@ -8,7 +8,7 @@ + + int kill_unit(int argc, char *argv[], void *userdata) { + _cleanup_strv_free_ char **names = NULL; +- char *kill_who = NULL, **name; ++ char *kill_who = NULL; + sd_bus *bus; + int r, q; + +diff --git a/src/systemctl/systemctl-list-dependencies.c b/src/systemctl/systemctl-list-dependencies.c +index a536240a9f..4d58869416 100644 +--- a/src/systemctl/systemctl-list-dependencies.c ++++ b/src/systemctl/systemctl-list-dependencies.c +@@ -63,7 +63,6 @@ static int list_dependencies_one( + unsigned branches) { + + _cleanup_strv_free_ char **deps = NULL; +- char **c; + int r; + + assert(bus); +@@ -138,7 +137,7 @@ static int list_dependencies_one( + + int list_dependencies(int argc, char *argv[], void *userdata) { + _cleanup_strv_free_ char **units = NULL, **done = NULL; +- char **u, **patterns; ++ char **patterns; + sd_bus *bus; + int r; + +diff --git a/src/systemctl/systemctl-list-machines.c b/src/systemctl/systemctl-list-machines.c +index b4eb0bd4b6..6d0acc4d50 100644 +--- a/src/systemctl/systemctl-list-machines.c ++++ b/src/systemctl/systemctl-list-machines.c +@@ -93,7 +93,6 @@ static int get_machine_list( + struct machine_info *machine_infos = NULL; + _cleanup_strv_free_ char **m = NULL; + _cleanup_free_ char *hn = NULL; +- char **i; + int c = 0, r; + + hn = gethostname_malloc(); +diff --git a/src/systemctl/systemctl-list-units.c b/src/systemctl/systemctl-list-units.c +index 0c405fb7e8..35037d29ba 100644 +--- a/src/systemctl/systemctl-list-units.c ++++ b/src/systemctl/systemctl-list-units.c +@@ -49,7 +49,6 @@ static int get_unit_list_recursive( + + if (arg_recursive) { + _cleanup_strv_free_ char **machines = NULL; +- char **i; + + r = sd_get_machine_names(&machines); + if (r < 0) +diff --git a/src/systemctl/systemctl-logind.c b/src/systemctl/systemctl-logind.c +index 114641cdc7..843f6141ab 100644 +--- a/src/systemctl/systemctl-logind.c ++++ b/src/systemctl/systemctl-logind.c +@@ -112,7 +112,6 @@ int logind_check_inhibitors(enum action a) { + uint32_t uid, pid; + sd_bus *bus; + unsigned c = 0; +- char **s; + int r; + + if (arg_check_inhibitors == 0 || arg_force > 0) +@@ -412,7 +411,6 @@ int help_boot_loader_entry(void) { + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_strv_free_ char **l = NULL; + sd_bus *bus; +- char **i; + int r; + + r = acquire_bus(BUS_FULL, &bus); +diff --git a/src/systemctl/systemctl-reset-failed.c b/src/systemctl/systemctl-reset-failed.c +index eee7586465..0b7e01429f 100644 +--- a/src/systemctl/systemctl-reset-failed.c ++++ b/src/systemctl/systemctl-reset-failed.c +@@ -10,7 +10,6 @@ + int reset_failed(int argc, char *argv[], void *userdata) { + _cleanup_strv_free_ char **names = NULL; + sd_bus *bus; +- char **name; + int r, q; + + if (argc <= 1) /* Shortcut to trivial_method() if no argument is given */ +diff --git a/src/systemctl/systemctl-set-environment.c b/src/systemctl/systemctl-set-environment.c +index aab0fe5fd0..8c529181da 100644 +--- a/src/systemctl/systemctl-set-environment.c ++++ b/src/systemctl/systemctl-set-environment.c +@@ -172,7 +172,6 @@ int import_environment(int argc, char *argv[], void *userdata) { + + strv_env_clean_with_callback(copy, invalid_callback, NULL); + +- char **e; + STRV_FOREACH(e, copy) + if (string_has_cc(*e, NULL)) + log_notice("Environment variable $%.*s contains control characters, importing anyway.", +@@ -181,8 +180,6 @@ int import_environment(int argc, char *argv[], void *userdata) { + r = sd_bus_message_append_strv(m, copy); + + } else { +- char **a, **b; +- + r = sd_bus_message_open_container(m, 'a', "s"); + if (r < 0) + return bus_log_create_error(r); +diff --git a/src/systemctl/systemctl-set-property.c b/src/systemctl/systemctl-set-property.c +index 5739bac070..4407c2354d 100644 +--- a/src/systemctl/systemctl-set-property.c ++++ b/src/systemctl/systemctl-set-property.c +@@ -46,7 +46,6 @@ static int set_property_one(sd_bus *bus, const char *name, char **properties) { + int set_property(int argc, char *argv[], void *userdata) { + sd_bus *bus; + _cleanup_strv_free_ char **names = NULL; +- char **name; + int r, k; + + r = acquire_bus(BUS_MANAGER, &bus); +diff --git a/src/systemctl/systemctl-show.c b/src/systemctl/systemctl-show.c +index 7a6655da74..ee96dac457 100644 +--- a/src/systemctl/systemctl-show.c ++++ b/src/systemctl/systemctl-show.c +@@ -308,7 +308,6 @@ static void print_status_info( + ExecStatusInfo *p; + usec_t timestamp; + const char *path; +- char **t, **t2; + int r; + + assert(i); +@@ -367,7 +366,6 @@ static void print_status_info( + if (!strv_isempty(i->dropin_paths)) { + _cleanup_free_ char *dir = NULL; + bool last = false; +- char ** dropin; + + STRV_FOREACH(dropin, i->dropin_paths) { + _cleanup_free_ char *dropin_formatted = NULL; +@@ -774,8 +772,6 @@ static void print_status_info( + } + + static void show_unit_help(UnitStatusInfo *i) { +- char **p; +- + assert(i); + + if (!i->documentation) { +@@ -1078,7 +1074,6 @@ static int print_property(const char *name, const char *expected_value, sd_bus_m + + if (FLAGS_SET(flags, BUS_PRINT_PROPERTY_SHOW_EMPTY) || allow_list || !strv_isempty(l)) { + bool first = true; +- char **i; + + if (!FLAGS_SET(flags, BUS_PRINT_PROPERTY_ONLY_VALUE)) { + fputs(name, stdout); +@@ -1970,7 +1965,6 @@ static int show_one( + .io_read_bytes = UINT64_MAX, + .io_write_bytes = UINT64_MAX, + }; +- char **pp; + int r; + + assert(path); +@@ -2194,7 +2188,6 @@ int show(int argc, char *argv[], void *userdata) { + ret = show_all(bus, &new_line, &ellipsized); + } else { + _cleanup_free_ char **patterns = NULL; +- char **name; + + STRV_FOREACH(name, strv_skip(argv, 1)) { + _cleanup_free_ char *path = NULL, *unit = NULL; +diff --git a/src/systemctl/systemctl-start-unit.c b/src/systemctl/systemctl-start-unit.c +index 274b278d2d..b45495d51d 100644 +--- a/src/systemctl/systemctl-start-unit.c ++++ b/src/systemctl/systemctl-start-unit.c +@@ -199,16 +199,13 @@ static int enqueue_marked_jobs( + if (r < 0) + return bus_log_parse_error(r); + +- if (w) { +- char **path; +- ++ if (w) + STRV_FOREACH(path, paths) { + log_debug("Adding %s to the set", *path); + r = bus_wait_for_jobs_add(w, *path); + if (r < 0) + return log_error_errno(r, "Failed to watch job %s: %m", *path); + } +- } + + return 0; + } +@@ -269,7 +266,6 @@ int start_unit(int argc, char *argv[], void *userdata) { + _cleanup_strv_free_ char **names = NULL; + int r, ret = EXIT_SUCCESS; + sd_bus *bus; +- char **name; + + if (arg_wait && !STR_IN_SET(argv[0], "start", "restart")) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), +diff --git a/src/systemctl/systemctl-util.c b/src/systemctl/systemctl-util.c +index ae02af280e..db40154943 100644 +--- a/src/systemctl/systemctl-util.c ++++ b/src/systemctl/systemctl-util.c +@@ -234,7 +234,6 @@ int get_unit_list( + + int expand_unit_names(sd_bus *bus, char **names, const char* suffix, char ***ret, bool *ret_expanded) { + _cleanup_strv_free_ char **mangled = NULL, **globs = NULL; +- char **name; + int r; + + assert(bus); +@@ -294,7 +293,6 @@ int check_triggering_units(sd_bus *bus, const char *unit) { + _cleanup_strv_free_ char **triggered_by = NULL; + bool print_warning_label = true; + UnitActiveState active_state; +- char **i; + int r; + + r = unit_name_mangle(unit, 0, &n); +@@ -386,8 +384,6 @@ void warn_unit_file_changed(const char *unit) { + } + + int unit_file_find_path(LookupPaths *lp, const char *unit_name, char **ret_unit_path) { +- char **p; +- + assert(lp); + assert(unit_name); + +@@ -666,7 +662,6 @@ int unit_exists(LookupPaths *lp, const char *unit) { + + int append_unit_dependencies(sd_bus *bus, char **names, char ***ret) { + _cleanup_strv_free_ char **with_deps = NULL; +- char **name; + + assert(bus); + assert(ret); +@@ -860,7 +855,7 @@ UnitFileFlags unit_file_flags_from_args(void) { + + int mangle_names(const char *operation, char **original_names, char ***ret_mangled_names) { + _cleanup_strv_free_ char **l = NULL; +- char **i, **name; ++ char **i; + int r; + + assert(ret_mangled_names); +diff --git a/src/sysusers/sysusers.c b/src/sysusers/sysusers.c +index 07a65a2ebc..6a2ca1afbb 100644 +--- a/src/sysusers/sysusers.c ++++ b/src/sysusers/sysusers.c +@@ -312,7 +312,6 @@ static int putgrent_with_members(const struct group *gr, FILE *group) { + if (a) { + _cleanup_strv_free_ char **l = NULL; + bool added = false; +- char **i; + + l = strv_copy(gr->gr_mem); + if (!l) +@@ -357,7 +356,6 @@ static int putsgent_with_members(const struct sgrp *sg, FILE *gshadow) { + if (a) { + _cleanup_strv_free_ char **l = NULL; + bool added = false; +- char **i; + + l = strv_copy(sg->sg_mem); + if (!l) +@@ -1406,8 +1404,6 @@ static int add_implicit(void) { + + /* Implicitly create additional users and groups, if they were listed in "m" lines */ + ORDERED_HASHMAP_FOREACH_KEY(l, g, members) { +- char **m; +- + STRV_FOREACH(m, l) + if (!ordered_hashmap_get(users, *m)) { + _cleanup_(item_freep) Item *j = NULL; +@@ -1977,7 +1973,6 @@ static int parse_argv(int argc, char *argv[]) { + } + + static int parse_arguments(char **args) { +- char **arg; + unsigned pos = 1; + int r; + +@@ -1999,7 +1994,6 @@ static int parse_arguments(char **args) { + static int read_config_files(char **args) { + _cleanup_strv_free_ char **files = NULL; + _cleanup_free_ char *p = NULL; +- char **f; + int r; + + r = conf_files_list_with_replacement(arg_root, CONF_PATHS_STRV("sysusers.d"), arg_replace, &files, &p); +diff --git a/src/sysv-generator/sysv-generator.c b/src/sysv-generator/sysv-generator.c +index bb74b486be..428509f4ce 100644 +--- a/src/sysv-generator/sysv-generator.c ++++ b/src/sysv-generator/sysv-generator.c +@@ -103,7 +103,6 @@ static int generate_unit_file(SysvStub *s) { + _cleanup_free_ char *path_escaped = NULL; + _cleanup_fclose_ FILE *f = NULL; + const char *unit; +- char **p; + int r; + + assert(s); +@@ -707,7 +706,6 @@ static int acquire_search_path(const char *def, const char *envvar, char ***ret) + + static int enumerate_sysv(const LookupPaths *lp, Hashmap *all_services) { + _cleanup_strv_free_ char **sysvinit_path = NULL; +- char **path; + int r; + + assert(lp); +@@ -791,7 +789,6 @@ static int set_dependencies_from_rcnd(const LookupPaths *lp, Hashmap *all_servic + Set *runlevel_services[ELEMENTSOF(rcnd_table)] = {}; + _cleanup_strv_free_ char **sysvrcnd_path = NULL; + SysvStub *service; +- char **p; + int r; + + assert(lp); +diff --git a/src/test/test-bpf-foreign-programs.c b/src/test/test-bpf-foreign-programs.c +index 1765dc7a9b..56933c87bf 100644 +--- a/src/test/test-bpf-foreign-programs.c ++++ b/src/test/test-bpf-foreign-programs.c +@@ -133,8 +133,6 @@ static int bpf_foreign_test_to_string(enum bpf_attach_type attach_type, const ch + } + + static char **unlink_paths_and_free(char **paths) { +- char **i; +- + STRV_FOREACH(i, paths) + (void) unlink(*i); + +diff --git a/src/test/test-bpf-lsm.c b/src/test/test-bpf-lsm.c +index 258c2e575e..4a3b327a3f 100644 +--- a/src/test/test-bpf-lsm.c ++++ b/src/test/test-bpf-lsm.c +@@ -16,7 +16,6 @@ static int test_restrict_filesystems(Manager *m, const char *unit_name, const ch + _cleanup_free_ char *exec_start = NULL; + _cleanup_(unit_freep) Unit *u = NULL; + ExecContext *ec = NULL; +- char **allow_filesystem; + int cld_code, r; + + assert_se(u = unit_new(m, sizeof(Service))); +diff --git a/src/test/test-copy.c b/src/test/test-copy.c +index c7ed054207..01c6638dcf 100644 +--- a/src/test/test-copy.c ++++ b/src/test/test-copy.c +@@ -83,7 +83,6 @@ TEST(copy_tree) { + char **hardlinks = STRV_MAKE("hlink", "file", + "hlink2", "dir1/file"); + const char *unixsockp; +- char **p, **ll; + struct stat st; + int xattr_worked = -1; /* xattr support is optional in temporary directories, hence use it if we can, + * but don't fail if we can't */ +diff --git a/src/test/test-env-util.c b/src/test/test-env-util.c +index 19523aa0d9..4d5f39b5b7 100644 +--- a/src/test/test-env-util.c ++++ b/src/test/test-env-util.c +@@ -412,7 +412,6 @@ TEST(unsetenv_erase) { + r = safe_fork("(sd-unsetenverase)", FORK_DEATHSIG|FORK_LOG|FORK_WAIT, NULL); + if (r == 0) { + _cleanup_strv_free_ char **l = NULL; +- char **e; + + /* child */ + +diff --git a/src/test/test-exec-util.c b/src/test/test-exec-util.c +index 47a82eb969..d6ee16b1fe 100644 +--- a/src/test/test-exec-util.c ++++ b/src/test/test-exec-util.c +@@ -217,7 +217,7 @@ static int gather_stdout_one(int fd, void *arg) { + return 0; + } + static int gather_stdout_two(int fd, void *arg) { +- char ***s = arg, **t; ++ char ***s = arg; + + STRV_FOREACH(t, *s) + assert_se(write(fd, *t, strlen(*t)) == (ssize_t) strlen(*t)); +@@ -287,7 +287,7 @@ TEST(stdout_gathering) { + } + + TEST(environment_gathering) { +- char template[] = "/tmp/test-exec-util.XXXXXXX", **p; ++ char template[] = "/tmp/test-exec-util.XXXXXXX"; + const char *dirs[] = {template, NULL}; + const char *name, *name2, *name3, *old; + int r; +diff --git a/src/test/test-execute.c b/src/test/test-execute.c +index 0760df6603..3b4b02184c 100644 +--- a/src/test/test-execute.c ++++ b/src/test/test-execute.c +@@ -606,7 +606,6 @@ static int find_libraries(const char *exec, char ***ret) { + _cleanup_strv_free_ char **v = NULL; + assert_se(strv_split_newlines_full(&v, result, 0) >= 0); + +- char **q; + STRV_FOREACH(q, v) { + _cleanup_free_ char *word = NULL; + const char *p = *q; +@@ -674,7 +673,6 @@ static void test_exec_mount_apivfs(Manager *m) { + assert_se(strextend(&data, "BindReadOnlyPaths=", fullpath_touch, "\n")); + assert_se(strextend(&data, "BindReadOnlyPaths=", fullpath_test, "\n")); + +- char **p; + STRV_FOREACH(p, libraries) + assert_se(strextend(&data, "BindReadOnlyPaths=", *p, "\n")); + +diff --git a/src/test/test-fileio.c b/src/test/test-fileio.c +index 238ae8f586..3e98d94019 100644 +--- a/src/test/test-fileio.c ++++ b/src/test/test-fileio.c +@@ -35,7 +35,6 @@ TEST(parse_env_file) { + *six = NULL, *seven = NULL, *eight = NULL, *nine = NULL, *ten = NULL, + *eleven = NULL, *twelve = NULL, *thirteen = NULL; + _cleanup_strv_free_ char **a = NULL, **b = NULL; +- char **i; + unsigned k; + int r; + +@@ -171,7 +170,6 @@ TEST(parse_multiline_env_file) { + p[] = "/tmp/test-fileio-out-XXXXXX"; + FILE *f; + _cleanup_strv_free_ char **a = NULL, **b = NULL; +- char **i; + int r; + + assert_se(fmkostemp_safe(t, "w", &f) == 0); +@@ -221,7 +219,6 @@ TEST(merge_env_file) { + _cleanup_(unlink_tempfilep) char t[] = "/tmp/test-fileio-XXXXXX"; + _cleanup_fclose_ FILE *f = NULL; + _cleanup_strv_free_ char **a = NULL; +- char **i; + int r; + + assert_se(fmkostemp_safe(t, "w", &f) == 0); +@@ -285,7 +282,6 @@ TEST(merge_env_file_invalid) { + _cleanup_(unlink_tempfilep) char t[] = "/tmp/test-fileio-XXXXXX"; + _cleanup_fclose_ FILE *f = NULL; + _cleanup_strv_free_ char **a = NULL; +- char **i; + int r; + + assert_se(fmkostemp_safe(t, "w", &f) == 0); +@@ -486,7 +482,6 @@ TEST(load_env_file_pairs) { + int fd, r; + _cleanup_fclose_ FILE *f = NULL; + _cleanup_strv_free_ char **l = NULL; +- char **k, **v; + + fd = mkostemp_safe(fn); + assert_se(fd >= 0); +diff --git a/src/test/test-fs-util.c b/src/test/test-fs-util.c +index f53a3ebf59..67b6996907 100644 +--- a/src/test/test-fs-util.c ++++ b/src/test/test-fs-util.c +@@ -692,7 +692,6 @@ TEST(rename_noreplace) { + + _cleanup_(rm_rf_physical_and_freep) char *z = NULL; + const char *j = NULL; +- char **a, **b; + + if (arg_test_dir) + j = strjoina(arg_test_dir, "/testXXXXXX"); +diff --git a/src/test/test-kbd-util.c b/src/test/test-kbd-util.c +index f15cff4794..0a166c6e1f 100644 +--- a/src/test/test-kbd-util.c ++++ b/src/test/test-kbd-util.c +@@ -7,7 +7,6 @@ + + int main(int argc, char *argv[]) { + _cleanup_strv_free_ char **maps = NULL; +- char **m; + int r; + + log_show_color(true); +diff --git a/src/test/test-locale-util.c b/src/test/test-locale-util.c +index 55f86f7c2f..3243e3c567 100644 +--- a/src/test/test-locale-util.c ++++ b/src/test/test-locale-util.c +@@ -10,7 +10,6 @@ + + TEST(get_locales) { + _cleanup_strv_free_ char **locales = NULL; +- char **p; + int r; + + r = get_locales(&locales); +@@ -58,7 +57,6 @@ TEST(locale_is_installed) { + + TEST(keymaps) { + _cleanup_strv_free_ char **kmaps = NULL; +- char **p; + int r; + + assert_se(!keymap_is_valid("")); +diff --git a/src/test/test-nss-hosts.c b/src/test/test-nss-hosts.c +index eac2c74f4c..70dbb30ed4 100644 +--- a/src/test/test-nss-hosts.c ++++ b/src/test/test-nss-hosts.c +@@ -67,8 +67,6 @@ static int print_gaih_addrtuples(const struct gaih_addrtuple *tuples) { + } + + static void print_struct_hostent(struct hostent *host, const char *canon) { +- char **s; +- + log_info(" \"%s\"", host->h_name); + STRV_FOREACH(s, host->h_aliases) + log_info(" alias \"%s\"", *s); +@@ -376,7 +374,6 @@ static int test_one_module(const char *dir, + if (!handle) + return -EINVAL; + +- char **name; + STRV_FOREACH(name, names) + test_byname(handle, module, *name); + +@@ -424,7 +421,6 @@ static int parse_argv(int argc, char **argv, + assert_se(modules); + + if (argc > 2) { +- char **name; + int family; + union in_addr_union address; + +@@ -463,7 +459,6 @@ static int run(int argc, char **argv) { + _cleanup_strv_free_ char **modules = NULL, **names = NULL; + _cleanup_free_ struct local_address *addresses = NULL; + int n_addresses = 0; +- char **module; + int r; + + test_setup_logging(LOG_INFO); +diff --git a/src/test/test-nss-users.c b/src/test/test-nss-users.c +index c415c0ca3b..70c5f25e08 100644 +--- a/src/test/test-nss-users.c ++++ b/src/test/test-nss-users.c +@@ -170,7 +170,6 @@ static int test_one_module(const char *dir, + if (!handle) + return -EINVAL; + +- char **name; + STRV_FOREACH(name, names) + test_byname(handle, module, *name); + +@@ -235,7 +234,6 @@ static int parse_argv(int argc, char **argv, + static int run(int argc, char **argv) { + _cleanup_free_ char *dir = NULL; + _cleanup_strv_free_ char **modules = NULL, **names = NULL; +- char **module; + int r; + + test_setup_logging(LOG_INFO); +diff --git a/src/test/test-path-lookup.c b/src/test/test-path-lookup.c +index a19a33c64b..2c30260f7b 100644 +--- a/src/test/test-path-lookup.c ++++ b/src/test/test-path-lookup.c +@@ -43,7 +43,7 @@ TEST(paths) { + + TEST(user_and_global_paths) { + _cleanup_(lookup_paths_free) LookupPaths lp_global = {}, lp_user = {}; +- char **u, **g, **p; ++ char **u, **g; + unsigned k = 0; + + assert_se(unsetenv("SYSTEMD_UNIT_PATH") == 0); +@@ -81,7 +81,6 @@ static void test_generator_binary_paths_one(UnitFileScope scope) { + _cleanup_strv_free_ char **env_gp_with_env = NULL; + char *systemd_generator_path = NULL; + char *systemd_env_generator_path = NULL; +- char **dir; + + assert_se(mkdtemp(template)); + +diff --git a/src/test/test-path-util.c b/src/test/test-path-util.c +index b9c4ef4126..d40febef5f 100644 +--- a/src/test/test-path-util.c ++++ b/src/test/test-path-util.c +@@ -481,7 +481,6 @@ TEST(path_strv_resolve) { + char tmp_dir[] = "/tmp/test-path-util-XXXXXX"; + _cleanup_strv_free_ char **search_dirs = NULL; + _cleanup_strv_free_ char **absolute_dirs = NULL; +- char **d; + + assert_se(mkdtemp(tmp_dir) != NULL); + +diff --git a/src/test/test-path.c b/src/test/test-path.c +index 529487d1ad..2690dc0aa4 100644 +--- a/src/test/test-path.c ++++ b/src/test/test-path.c +@@ -24,7 +24,6 @@ typedef void (*test_function_t)(Manager *m); + static int setup_test(Manager **m) { + char **tests_path = STRV_MAKE("exists", "existsglobFOOBAR", "changed", "modified", "unit", + "directorynotempty", "makedirectory"); +- char **test_path; + Manager *tmp = NULL; + int r; + +diff --git a/src/test/test-sd-path.c b/src/test/test-sd-path.c +index 10a8a4a63f..4f23e3bb69 100644 +--- a/src/test/test-sd-path.c ++++ b/src/test/test-sd-path.c +@@ -32,7 +32,6 @@ TEST(sd_path_lookup) { + TEST(sd_path_lookup_strv) { + for (uint64_t i = 0; i < _SD_PATH_MAX; i++) { + _cleanup_strv_free_ char **t = NULL, **s = NULL; +- char **item; + int r; + + r = sd_path_lookup_strv(i, NULL, &t); +diff --git a/src/test/test-socket-bind.c b/src/test/test-socket-bind.c +index ecad86baeb..c5c5477f69 100644 +--- a/src/test/test-socket-bind.c ++++ b/src/test/test-socket-bind.c +@@ -13,7 +13,7 @@ + #include "virt.h" + + static int find_netcat_executable(char **ret_path) { +- char **candidates = STRV_MAKE("ncat", "nc", "netcat"), **c; ++ char **candidates = STRV_MAKE("ncat", "nc", "netcat"); + int r = 0; + + STRV_FOREACH(c, candidates) { +@@ -36,7 +36,6 @@ static int test_socket_bind( + _cleanup_(unit_freep) Unit *u = NULL; + CGroupSocketBindItem *bi; + CGroupContext *cc = NULL; +- char **rule; + int cld_code, r; + + assert_se(u = unit_new(m, sizeof(Service))); +diff --git a/src/test/test-string-util.c b/src/test/test-string-util.c +index 071b391361..93b674baab 100644 +--- a/src/test/test-string-util.c ++++ b/src/test/test-string-util.c +@@ -865,7 +865,6 @@ TEST(strverscmp_improved) { + "124", + NULL, + }; +- const char * const *p, * const *q; + + STRV_FOREACH(p, versions) + STRV_FOREACH(q, p + 1) +diff --git a/src/test/test-strv.c b/src/test/test-strv.c +index 0ece342521..e6aa2e793e 100644 +--- a/src/test/test-strv.c ++++ b/src/test/test-strv.c +@@ -204,7 +204,6 @@ static void test_strv_unquote_one(const char *quoted, char **list) { + _cleanup_strv_free_ char **s; + _cleanup_free_ char *j; + unsigned i = 0; +- char **t; + int r; + + log_info("/* %s */", __func__); +@@ -446,7 +445,6 @@ TEST(strv_split_colon_pairs) { + + TEST(strv_split_newlines) { + unsigned i = 0; +- char **s; + _cleanup_strv_free_ char **l = NULL; + const char str[] = "one\ntwo\nthree"; + +@@ -619,7 +617,6 @@ TEST(strv_extendf) { + TEST(strv_foreach) { + _cleanup_strv_free_ char **a; + unsigned i = 0; +- char **check; + + a = strv_new("one", "two", "three"); + assert_se(a); +@@ -631,7 +628,6 @@ TEST(strv_foreach) { + TEST(strv_foreach_backwards) { + _cleanup_strv_free_ char **a; + unsigned i = 2; +- char **check; + + a = strv_new("one", "two", "three"); + +@@ -649,7 +645,6 @@ TEST(strv_foreach_backwards) { + + TEST(strv_foreach_pair) { + _cleanup_strv_free_ char **a = NULL; +- char **x, **y; + + a = strv_new("pair_one", "pair_one", + "pair_two", "pair_two", +diff --git a/src/test/test-sysctl-util.c b/src/test/test-sysctl-util.c +index 8bd3c26152..02180dc4be 100644 +--- a/src/test/test-sysctl-util.c ++++ b/src/test/test-sysctl-util.c +@@ -27,7 +27,6 @@ static const char* const cases[] = { + }; + + TEST(sysctl_normalize) { +- const char **s, **expected; + STRV_FOREACH_PAIR(s, expected, (const char**) cases) { + _cleanup_free_ char *t; + +diff --git a/src/test/test-time-util.c b/src/test/test-time-util.c +index 799d271a44..15f4a0c169 100644 +--- a/src/test/test-time-util.c ++++ b/src/test/test-time-util.c +@@ -258,7 +258,6 @@ TEST(timezone_is_valid) { + TEST(get_timezones) { + _cleanup_strv_free_ char **zones = NULL; + int r; +- char **zone; + + r = get_timezones(&zones); + assert_se(r == 0); +diff --git a/src/test/test-unit-file.c b/src/test/test-unit-file.c +index 8ed56ad3b8..261bd7412f 100644 +--- a/src/test/test-unit-file.c ++++ b/src/test/test-unit-file.c +@@ -55,7 +55,6 @@ TEST(unit_file_build_name_map) { + if (r == 0) + log_debug("Cache rebuild skipped based on mtime."); + +- char **id; + STRV_FOREACH(id, ids) { + const char *fragment, *name; + _cleanup_set_free_free_ Set *names = NULL; +diff --git a/src/timedate/timedated.c b/src/timedate/timedated.c +index 66b454269d..874ff773e1 100644 +--- a/src/timedate/timedated.c ++++ b/src/timedate/timedated.c +@@ -190,7 +190,6 @@ static int context_parse_ntp_services_from_environment(Context *c) { + + static int context_parse_ntp_services_from_disk(Context *c) { + _cleanup_strv_free_ char **files = NULL; +- char **f; + int r; + + r = conf_files_list_strv(&files, ".list", NULL, CONF_FILES_FILTER_MASKED, UNIT_LIST_DIRS); +diff --git a/src/timesync/timesyncd-manager.c b/src/timesync/timesyncd-manager.c +index 918da195d8..67f9a33993 100644 +--- a/src/timesync/timesyncd-manager.c ++++ b/src/timesync/timesyncd-manager.c +@@ -961,7 +961,6 @@ Manager* manager_free(Manager *m) { + static int manager_network_read_link_servers(Manager *m) { + _cleanup_strv_free_ char **ntp = NULL; + ServerName *n, *nx; +- char **i; + bool changed = false; + int r; + +diff --git a/src/tmpfiles/tmpfiles.c b/src/tmpfiles/tmpfiles.c +index aa7ff73a36..17b9c6ab9a 100644 +--- a/src/tmpfiles/tmpfiles.c ++++ b/src/tmpfiles/tmpfiles.c +@@ -1019,8 +1019,6 @@ static int parse_xattrs_from_arg(Item *i) { + } + + static int fd_set_xattrs(Item *i, int fd, const char *path, const struct stat *st) { +- char **name, **value; +- + assert(i); + assert(fd >= 0); + assert(path); +@@ -1939,7 +1937,6 @@ static int glob_item(Item *i, action_t action) { + .gl_opendir = (void *(*)(const char *)) opendir_nomod, + }; + int r = 0, k; +- char **fn; + + k = safe_glob(i->path, GLOB_NOSORT|GLOB_BRACE, &g); + if (k < 0 && k != -ENOENT) +@@ -1959,7 +1956,6 @@ static int glob_item_recursively(Item *i, fdaction_t action) { + .gl_opendir = (void *(*)(const char *)) opendir_nomod, + }; + int r = 0, k; +- char **fn; + + k = safe_glob(i->path, GLOB_NOSORT|GLOB_BRACE, &g); + if (k < 0 && k != -ENOENT) +@@ -2695,8 +2691,6 @@ static bool item_compatible(Item *a, Item *b) { + } + + static bool should_include_path(const char *path) { +- char **prefix; +- + STRV_FOREACH(prefix, arg_exclude_prefixes) + if (path_startswith(path, *prefix)) { + log_debug("Entry \"%s\" matches exclude prefix \"%s\", skipping.", +@@ -2746,8 +2740,7 @@ static int specifier_expansion_from_arg(const Specifier *specifier_table, Item * + return free_and_replace(i->argument, resolved); + } + case SET_XATTR: +- case RECURSIVE_SET_XATTR: { +- char **xattr; ++ case RECURSIVE_SET_XATTR: + STRV_FOREACH(xattr, i->xattrs) { + _cleanup_free_ char *resolved = NULL; + +@@ -2758,7 +2751,7 @@ static int specifier_expansion_from_arg(const Specifier *specifier_table, Item * + free_and_replace(*xattr, resolved); + } + return 0; +- } ++ + default: + return 0; + } +@@ -3611,7 +3604,6 @@ static int read_config_file(char **config_dirs, const char *fn, bool ignore_enoe + } + + static int parse_arguments(char **config_dirs, char **args, bool *invalid_config) { +- char **arg; + int r; + + STRV_FOREACH(arg, args) { +@@ -3626,7 +3618,6 @@ static int parse_arguments(char **config_dirs, char **args, bool *invalid_config + static int read_config_files(char **config_dirs, char **args, bool *invalid_config) { + _cleanup_strv_free_ char **files = NULL; + _cleanup_free_ char *p = NULL; +- char **f; + int r; + + r = conf_files_list_with_replacement(arg_root, config_dirs, arg_replace, &files, &p); +@@ -3733,7 +3724,6 @@ static int run(int argc, char *argv[]) { + + if (DEBUG_LOGGING) { + _cleanup_free_ char *t = NULL; +- char **i; + + STRV_FOREACH(i, config_dirs) { + _cleanup_free_ char *j = NULL; +diff --git a/src/tty-ask-password-agent/tty-ask-password-agent.c b/src/tty-ask-password-agent/tty-ask-password-agent.c +index 54a03af082..15a1faedce 100644 +--- a/src/tty-ask-password-agent/tty-ask-password-agent.c ++++ b/src/tty-ask-password-agent/tty-ask-password-agent.c +@@ -59,7 +59,7 @@ static int send_passwords(const char *socket_name, char **passwords) { + union sockaddr_union sa; + socklen_t sa_len; + size_t packet_length = 1; +- char **p, *d; ++ char *d; + ssize_t n; + int r; + +@@ -554,8 +554,6 @@ static int ask_on_this_console(const char *tty, pid_t *ret_pid, char **arguments + if (r < 0) + return r; + if (r == 0) { +- char **i; +- + assert_se(prctl(PR_SET_PDEATHSIG, SIGHUP) >= 0); + + STRV_FOREACH(i, arguments) { +@@ -635,7 +633,6 @@ static int ask_on_consoles(char *argv[]) { + _cleanup_set_free_ Set *pids = NULL; + _cleanup_strv_free_ char **consoles = NULL, **arguments = NULL; + siginfo_t status = {}; +- char **tty; + pid_t pid; + int r; + +diff --git a/src/udev/net/link-config.c b/src/udev/net/link-config.c +index 05f0f2e0a6..1ac89496c9 100644 +--- a/src/udev/net/link-config.c ++++ b/src/udev/net/link-config.c +@@ -315,7 +315,6 @@ static int device_unsigned_attribute(sd_device *device, const char *attr, unsign + + int link_config_load(LinkConfigContext *ctx) { + _cleanup_strv_free_ char **files = NULL; +- char **f; + int r; + + link_configs_free(ctx); +@@ -816,7 +815,6 @@ static int link_apply_alternative_names(Link *link, sd_netlink **rtnl) { + if (r < 0) + log_link_debug_errno(link, r, "Failed to get alternative names, ignoring: %m"); + +- char **p; + STRV_FOREACH(p, current_altnames) + strv_remove(altnames, *p); + +diff --git a/src/udev/udev-event.c b/src/udev/udev-event.c +index a60e4f294c..e3065ee923 100644 +--- a/src/udev/udev-event.c ++++ b/src/udev/udev-event.c +@@ -573,7 +573,6 @@ static int on_spawn_io(sd_event_source *s, int fd, uint32_t revents, void *userd + /* Log output only if we watch stderr. */ + if (l > 0 && spawn->fd_stderr >= 0) { + _cleanup_strv_free_ char **v = NULL; +- char **q; + + r = strv_split_newlines_full(&v, p, EXTRACT_RETAIN_ESCAPE); + if (r < 0) +diff --git a/src/udev/udev-rules.c b/src/udev/udev-rules.c +index 243a792662..29b6ae3961 100644 +--- a/src/udev/udev-rules.c ++++ b/src/udev/udev-rules.c +@@ -1348,7 +1348,6 @@ UdevRules* udev_rules_new(ResolveNameTiming resolve_name_timing) { + int udev_rules_load(UdevRules **ret_rules, ResolveNameTiming resolve_name_timing) { + _cleanup_(udev_rules_freep) UdevRules *rules = NULL; + _cleanup_strv_free_ char **files = NULL; +- char **f; + int r; + + rules = udev_rules_new(resolve_name_timing); +@@ -1823,7 +1822,7 @@ static int udev_rule_apply_token_to_event( + } + case TK_M_IMPORT_PROGRAM: { + _cleanup_strv_free_ char **lines = NULL; +- char buf[UDEV_PATH_SIZE], result[UDEV_LINE_SIZE], **line; ++ char buf[UDEV_PATH_SIZE], result[UDEV_LINE_SIZE]; + + (void) udev_event_apply_format(event, token->value, buf, sizeof(buf), false); + log_rule_debug(dev, rules, "Importing properties from results of '%s'", buf); +@@ -2422,7 +2421,6 @@ static int apply_static_dev_perms(const char *devnode, uid_t uid, gid_t gid, mod + char device_node[UDEV_PATH_SIZE], tags_dir[UDEV_PATH_SIZE], tag_symlink[UDEV_PATH_SIZE]; + _cleanup_free_ char *unescaped_filename = NULL; + struct stat stats; +- char **t; + int r; + + assert(devnode); +diff --git a/src/udev/udevadm-info.c b/src/udev/udevadm-info.c +index 740434bb41..b985961c62 100644 +--- a/src/udev/udevadm-info.c ++++ b/src/udev/udevadm-info.c +@@ -522,7 +522,6 @@ int info_main(int argc, char *argv[], void *userdata) { + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), + "-x/--export or -P/--export-prefix cannot be used with --value"); + +- char **p; + STRV_FOREACH(p, devices) { + _cleanup_(sd_device_unrefp) sd_device *device = NULL; + +diff --git a/src/userdb/userdbctl.c b/src/userdb/userdbctl.c +index c2acd85742..85aa6c752c 100644 +--- a/src/userdb/userdbctl.c ++++ b/src/userdb/userdbctl.c +@@ -119,9 +119,7 @@ static int display_user(int argc, char *argv[], void *userdata) { + (void) table_set_display(table, (size_t) 0, (size_t) 1, (size_t) 2, (size_t) 3, (size_t) 4, (size_t) 5, (size_t) 6); + } + +- if (argc > 1) { +- char **i; +- ++ if (argc > 1) + STRV_FOREACH(i, argv + 1) { + _cleanup_(user_record_unrefp) UserRecord *ur = NULL; + uid_t uid; +@@ -151,7 +149,7 @@ static int display_user(int argc, char *argv[], void *userdata) { + draw_separator = true; + } + } +- } else { ++ else { + _cleanup_(userdb_iterator_freep) UserDBIterator *iterator = NULL; + + r = userdb_all(arg_userdb_flags, &iterator); +@@ -283,9 +281,7 @@ static int display_group(int argc, char *argv[], void *userdata) { + (void) table_set_display(table, (size_t) 0, (size_t) 1, (size_t) 2, (size_t) 3); + } + +- if (argc > 1) { +- char **i; +- ++ if (argc > 1) + STRV_FOREACH(i, argv + 1) { + _cleanup_(group_record_unrefp) GroupRecord *gr = NULL; + gid_t gid; +@@ -315,8 +311,7 @@ static int display_group(int argc, char *argv[], void *userdata) { + draw_separator = true; + } + } +- +- } else { ++ else { + _cleanup_(userdb_iterator_freep) UserDBIterator *iterator = NULL; + + r = groupdb_all(arg_userdb_flags, &iterator); +@@ -435,9 +430,7 @@ static int display_memberships(int argc, char *argv[], void *userdata) { + (void) table_set_sort(table, (size_t) 0, (size_t) 1); + } + +- if (argc > 1) { +- char **i; +- ++ if (argc > 1) + STRV_FOREACH(i, argv + 1) { + _cleanup_(userdb_iterator_freep) UserDBIterator *iterator = NULL; + +@@ -468,7 +461,7 @@ static int display_memberships(int argc, char *argv[], void *userdata) { + return r; + } + } +- } else { ++ else { + _cleanup_(userdb_iterator_freep) UserDBIterator *iterator = NULL; + + r = membershipdb_all(arg_userdb_flags, &iterator); +@@ -630,12 +623,9 @@ static int ssh_authorized_keys(int argc, char *argv[], void *userdata) { + else { + if (strv_isempty(ur->ssh_authorized_keys)) + log_debug("User record for %s has no public SSH keys.", argv[1]); +- else { +- char **i; +- ++ else + STRV_FOREACH(i, ur->ssh_authorized_keys) + printf("%s\n", *i); +- } + + if (ur->incomplete) { + fflush(stdout); +diff --git a/src/xdg-autostart-generator/xdg-autostart-condition.c b/src/xdg-autostart-generator/xdg-autostart-condition.c +index c4485cf625..9ceea61547 100644 +--- a/src/xdg-autostart-generator/xdg-autostart-condition.c ++++ b/src/xdg-autostart-generator/xdg-autostart-condition.c +@@ -13,7 +13,6 @@ + static int run(int argc, char *argv[]) { + _cleanup_strv_free_ char **only_show_in = NULL, **not_show_in = NULL, **desktops = NULL; + const char *xdg_current_desktop; +- char **d; + + if (argc != 3) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), +diff --git a/src/xdg-autostart-generator/xdg-autostart-generator.c b/src/xdg-autostart-generator/xdg-autostart-generator.c +index c5c6b54fdc..39ab81c1f2 100644 +--- a/src/xdg-autostart-generator/xdg-autostart-generator.c ++++ b/src/xdg-autostart-generator/xdg-autostart-generator.c +@@ -24,7 +24,6 @@ static int enumerate_xdg_autostart(Hashmap *all_services) { + _cleanup_strv_free_ char **config_dirs = NULL; + _unused_ _cleanup_strv_free_ char **data_dirs = NULL; + _cleanup_free_ char *user_config_autostart_dir = NULL; +- char **path; + int r; + + r = xdg_user_config_dir(&user_config_autostart_dir, "/autostart"); diff --git a/0183-core-ExecContext-restrict_filesystems-is-set-of-stri.patch b/0183-core-ExecContext-restrict_filesystems-is-set-of-stri.patch new file mode 100644 index 0000000..a36deb0 --- /dev/null +++ b/0183-core-ExecContext-restrict_filesystems-is-set-of-stri.patch @@ -0,0 +1,29 @@ +From 607c82526a5085885f4af96f1979572c72c300a4 Mon Sep 17 00:00:00 2001 +From: Yu Watanabe +Date: Thu, 17 Mar 2022 03:42:41 +0900 +Subject: [PATCH] core: ExecContext::restrict_filesystems is set of string + +(cherry picked from commit 8fe84dc8de60ae8995e53e4d47b44c61626c0526) + +Related: #2082131 +--- + src/core/execute.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/src/core/execute.c b/src/core/execute.c +index 306e563e4f..34b0478ead 100644 +--- a/src/core/execute.c ++++ b/src/core/execute.c +@@ -5916,9 +5916,9 @@ void exec_context_dump(const ExecContext *c, FILE* f, const char *prefix) { + + #if HAVE_LIBBPF + if (exec_context_restrict_filesystems_set(c)) { +- char **e; +- SET_FOREACH(e, c->restrict_filesystems) +- fprintf(f, "%sRestrictFileSystems: %s\n", prefix, *e); ++ char *fs; ++ SET_FOREACH(fs, c->restrict_filesystems) ++ fprintf(f, "%sRestrictFileSystems: %s\n", prefix, fs); + } + #endif + diff --git a/0184-install-when-linking-a-file-create-the-link-first-or.patch b/0184-install-when-linking-a-file-create-the-link-first-or.patch new file mode 100644 index 0000000..6b88602 --- /dev/null +++ b/0184-install-when-linking-a-file-create-the-link-first-or.patch @@ -0,0 +1,67 @@ +From 9b655d805e78a314a24b8493c6c116a4d943beb9 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Fri, 11 Mar 2022 14:27:46 +0100 +Subject: [PATCH] install: when linking a file, create the link first or abort + +We'd create aliases and other symlinks first, and only then try to create +the main link. Since that can fail, let's do things in opposite order, and +abort immediately if we can't link the file itself. + +(cherry picked from commit 20d68b3aec62110351bdc695fd1a55adcf3a6ee5) + +Related: #2082131 +--- + src/shared/install.c | 12 +++++++----- + test/test-systemctl-enable.sh | 9 +++------ + 2 files changed, 10 insertions(+), 11 deletions(-) + +diff --git a/src/shared/install.c b/src/shared/install.c +index 785ef55dbd..fadd2be248 100644 +--- a/src/shared/install.c ++++ b/src/shared/install.c +@@ -1985,6 +1985,13 @@ static int install_info_apply( + + bool force = file_flags & UNIT_FILE_FORCE; + ++ r = install_info_symlink_link(info, lp, config_path, force, changes, n_changes); ++ /* Do not count links to the unit file towards the "carries_install_info" count */ ++ if (r < 0) ++ /* If linking of the file failed, do not try to create other symlinks, ++ * because they might would pointing to a non-existent or wrong unit. */ ++ return r; ++ + r = install_info_symlink_alias(scope, info, lp, config_path, force, changes, n_changes); + + q = install_info_symlink_wants(scope, file_flags, info, lp, config_path, info->wanted_by, ".wants/", changes, n_changes); +@@ -1995,11 +2002,6 @@ static int install_info_apply( + if (r == 0) + r = q; + +- q = install_info_symlink_link(info, lp, config_path, force, changes, n_changes); +- /* Do not count links to the unit file towards the "carries_install_info" count */ +- if (r == 0 && q < 0) +- r = q; +- + return r; + } + +diff --git a/test/test-systemctl-enable.sh b/test/test-systemctl-enable.sh +index 3aa61222a8..c1fb9626ab 100644 +--- a/test/test-systemctl-enable.sh ++++ b/test/test-systemctl-enable.sh +@@ -173,12 +173,9 @@ islink "$root/etc/systemd/system/link1.path" "/link1.path" + islink "$root/etc/systemd/system/paths.target.wants/link1.path" "/link1.path" + + : -------enable already linked different path----------------- +-# FIXME +-# "$systemctl" --root="$root" enable '/subdir/link1.path' && { echo "Expected failure" >&2; exit 1; } +-# test -h "$root/etc/systemd/system/link1.path" +-# readlink "$root/etc/systemd/system/link1.path" +-# test -h "$root/etc/systemd/system/paths.target.wants/link1.path" +-# readlink "$root/etc/systemd/system/paths.target.wants/link1.path" ++"$systemctl" --root="$root" enable '/subdir/link1.path' && { echo "Expected failure" >&2; exit 1; } ++islink "$root/etc/systemd/system/link1.path" "/link1.path" ++islink "$root/etc/systemd/system/paths.target.wants/link1.path" "/link1.path" + + : -------enable bad suffix------------------------------------ + cp "$root/link1.path" "$root/subdir/link1.suffix" diff --git a/0185-shared-install-split-unit_file_-disable-enable-so-_r.patch b/0185-shared-install-split-unit_file_-disable-enable-so-_r.patch new file mode 100644 index 0000000..5b7ca2b --- /dev/null +++ b/0185-shared-install-split-unit_file_-disable-enable-so-_r.patch @@ -0,0 +1,199 @@ +From caaea62c2c32e6aedb24288d5f51e6c35187e14c Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Mon, 14 Mar 2022 12:09:31 +0100 +Subject: [PATCH] shared/install: split unit_file_{disable,enable}() so + _reenable doesn't do setup twice + +It was pretty ugly that we were creating LookupPaths twice. + +(cherry picked from commit ec7eaff3c2abf3048f3fba98bfbe08a0c7c898b0) + +Related: #2082131 +--- + src/shared/install.c | 105 +++++++++++++++++++++++++++++-------------- + 1 file changed, 72 insertions(+), 33 deletions(-) + +diff --git a/src/shared/install.c b/src/shared/install.c +index fadd2be248..1018e4fbf3 100644 +--- a/src/shared/install.c ++++ b/src/shared/install.c +@@ -2596,33 +2596,21 @@ int unit_file_add_dependency( + SEARCH_FOLLOW_CONFIG_SYMLINKS, changes, n_changes); + } + +-int unit_file_enable( ++static int do_unit_file_enable( ++ const LookupPaths *lp, + UnitFileScope scope, +- UnitFileFlags file_flags, +- const char *root_dir, ++ UnitFileFlags flags, ++ const char *config_path, + char **files, + UnitFileChange **changes, + size_t *n_changes) { + +- _cleanup_(lookup_paths_free) LookupPaths lp = {}; + _cleanup_(install_context_done) InstallContext ctx = { .scope = scope }; +- const char *config_path; + UnitFileInstallInfo *info; + int r; + +- assert(scope >= 0); +- assert(scope < _UNIT_FILE_SCOPE_MAX); +- +- r = lookup_paths_init_or_warn(&lp, scope, 0, root_dir); +- if (r < 0) +- return r; +- +- config_path = config_path_from_flags(&lp, file_flags); +- if (!config_path) +- return -ENXIO; +- + STRV_FOREACH(f, files) { +- r = install_info_discover_and_check(&ctx, &lp, *f, SEARCH_LOAD|SEARCH_FOLLOW_CONFIG_SYMLINKS, ++ r = install_info_discover_and_check(&ctx, lp, *f, SEARCH_LOAD|SEARCH_FOLLOW_CONFIG_SYMLINKS, + &info, changes, n_changes); + if (r < 0) + return r; +@@ -2635,11 +2623,11 @@ int unit_file_enable( + is useful to determine whether the passed files had any + installation data at all. */ + +- return install_context_apply(&ctx, &lp, file_flags, config_path, ++ return install_context_apply(&ctx, lp, flags, config_path, + SEARCH_LOAD, changes, n_changes); + } + +-int unit_file_disable( ++int unit_file_enable( + UnitFileScope scope, + UnitFileFlags flags, + const char *root_dir, +@@ -2648,9 +2636,6 @@ int unit_file_disable( + size_t *n_changes) { + + _cleanup_(lookup_paths_free) LookupPaths lp = {}; +- _cleanup_(install_context_done) InstallContext ctx = { .scope = scope }; +- _cleanup_set_free_free_ Set *remove_symlinks_to = NULL; +- const char *config_path; + int r; + + assert(scope >= 0); +@@ -2660,27 +2645,44 @@ int unit_file_disable( + if (r < 0) + return r; + +- config_path = config_path_from_flags(&lp, flags); ++ const char *config_path = config_path_from_flags(&lp, flags); + if (!config_path) + return -ENXIO; + ++ return do_unit_file_enable(&lp, scope, flags, config_path, files, changes, n_changes); ++} ++ ++static int do_unit_file_disable( ++ const LookupPaths *lp, ++ UnitFileScope scope, ++ UnitFileFlags flags, ++ const char *config_path, ++ char **files, ++ UnitFileChange **changes, ++ size_t *n_changes) { ++ ++ _cleanup_(install_context_done) InstallContext ctx = { .scope = scope }; ++ _cleanup_set_free_free_ Set *remove_symlinks_to = NULL; ++ int r; ++ + STRV_FOREACH(i, files) { + if (!unit_name_is_valid(*i, UNIT_NAME_ANY)) + return -EINVAL; + +- r = install_info_add(&ctx, *i, NULL, lp.root_dir, /* auxiliary= */ false, NULL); ++ r = install_info_add(&ctx, *i, NULL, lp->root_dir, /* auxiliary= */ false, NULL); + if (r < 0) + return r; + } + +- r = install_context_mark_for_removal(&ctx, &lp, &remove_symlinks_to, config_path, changes, n_changes); ++ r = install_context_mark_for_removal(&ctx, lp, &remove_symlinks_to, config_path, changes, n_changes); + if (r < 0) + return r; + +- return remove_marked_symlinks(remove_symlinks_to, config_path, &lp, flags & UNIT_FILE_DRY_RUN, changes, n_changes); ++ return remove_marked_symlinks(remove_symlinks_to, config_path, lp, flags & UNIT_FILE_DRY_RUN, changes, n_changes); + } + +-int unit_file_reenable( ++ ++int unit_file_disable( + UnitFileScope scope, + UnitFileFlags flags, + const char *root_dir, +@@ -2688,23 +2690,60 @@ int unit_file_reenable( + UnitFileChange **changes, + size_t *n_changes) { + +- char **n; ++ _cleanup_(lookup_paths_free) LookupPaths lp = {}; + int r; ++ ++ assert(scope >= 0); ++ assert(scope < _UNIT_FILE_SCOPE_MAX); ++ ++ r = lookup_paths_init(&lp, scope, 0, root_dir); ++ if (r < 0) ++ return r; ++ ++ const char *config_path = config_path_from_flags(&lp, flags); ++ if (!config_path) ++ return -ENXIO; ++ ++ return do_unit_file_disable(&lp, scope, flags, config_path, files, changes, n_changes); ++} ++ ++int unit_file_reenable( ++ UnitFileScope scope, ++ UnitFileFlags flags, ++ const char *root_dir, ++ char **files, ++ UnitFileChange **changes, ++ size_t *n_changes) { ++ ++ _cleanup_(lookup_paths_free) LookupPaths lp = {}; + size_t l, i; ++ char **names; ++ int r; ++ ++ assert(scope >= 0); ++ assert(scope < _UNIT_FILE_SCOPE_MAX); ++ ++ r = lookup_paths_init(&lp, scope, 0, root_dir); ++ if (r < 0) ++ return r; ++ ++ const char *config_path = config_path_from_flags(&lp, flags); ++ if (!config_path) ++ return -ENXIO; + + /* First, we invoke the disable command with only the basename... */ + l = strv_length(files); +- n = newa(char*, l+1); ++ names = newa(char*, l+1); + for (i = 0; i < l; i++) +- n[i] = basename(files[i]); +- n[i] = NULL; ++ names[i] = basename(files[i]); ++ names[i] = NULL; + +- r = unit_file_disable(scope, flags, root_dir, n, changes, n_changes); ++ r = do_unit_file_disable(&lp, scope, flags, config_path, names, changes, n_changes); + if (r < 0) + return r; + + /* But the enable command with the full name */ +- return unit_file_enable(scope, flags, root_dir, files, changes, n_changes); ++ return do_unit_file_enable(&lp, scope, flags, config_path, files, changes, n_changes); + } + + int unit_file_set_default( diff --git a/0186-shared-install-fix-reenable-on-linked-unit-files.patch b/0186-shared-install-fix-reenable-on-linked-unit-files.patch new file mode 100644 index 0000000..d5bdcb5 --- /dev/null +++ b/0186-shared-install-fix-reenable-on-linked-unit-files.patch @@ -0,0 +1,146 @@ +From f88f7c68264f9cfef78f4a4e2f68e45de8f1f055 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Tue, 15 Mar 2022 09:44:39 +0100 +Subject: [PATCH] shared/install: fix reenable on linked unit files + +(cherry picked from commit 29a7c59abbe594422f1ed7602263420745339a3e) + +Related: #2082131 +--- + src/shared/install.c | 73 ++++++++++++++++++++++++++++++----- + src/shared/install.h | 2 +- + test/test-systemctl-enable.sh | 8 ++-- + 3 files changed, 68 insertions(+), 15 deletions(-) + +diff --git a/src/shared/install.c b/src/shared/install.c +index 1018e4fbf3..bf11e5bdce 100644 +--- a/src/shared/install.c ++++ b/src/shared/install.c +@@ -2707,17 +2707,74 @@ int unit_file_disable( + return do_unit_file_disable(&lp, scope, flags, config_path, files, changes, n_changes); + } + ++static int normalize_linked_files( ++ UnitFileScope scope, ++ const LookupPaths *lp, ++ char **names_or_paths, ++ char ***ret_names, ++ char ***ret_files) { ++ ++ /* This is similar to normalize_filenames()/normalize_names() in src/systemctl/, ++ * but operates on real unit names. For each argument we we look up the actual path ++ * where the unit is found. This way linked units can be reenabled successfully. */ ++ ++ _cleanup_free_ char **files = NULL, **names = NULL; ++ int r; ++ ++ STRV_FOREACH(a, names_or_paths) { ++ _cleanup_(install_context_done) InstallContext ctx = { .scope = scope }; ++ UnitFileInstallInfo *i = NULL; ++ _cleanup_free_ char *n = NULL; ++ ++ r = path_extract_filename(*a, &n); ++ if (r < 0) ++ return r; ++ if (r == O_DIRECTORY) ++ return log_debug_errno(SYNTHETIC_ERRNO(EISDIR), ++ "Unexpected path to a directory \"%s\", refusing.", *a); ++ ++ if (!is_path(*a)) { ++ r = install_info_discover(&ctx, lp, n, SEARCH_LOAD|SEARCH_FOLLOW_CONFIG_SYMLINKS, &i, NULL, NULL); ++ if (r < 0) ++ log_debug_errno(r, "Failed to discover unit \"%s\", operating on name: %m", n); ++ } ++ ++ r = strv_consume(&names, TAKE_PTR(n)); ++ if (r < 0) ++ return r; ++ ++ const char *p = NULL; ++ if (i && i->path) ++ /* Use startswith here, because we know that paths are normalized, and ++ * path_startswith() would give us a relative path, but we need an absolute path ++ * relative to i->root. ++ * ++ * In other words: /var/tmp/instroot.1234/etc/systemd/system/frobnicator.service ++ * is replaced by /etc/systemd/system/frobnicator.service, which is "absolute" ++ * in a sense, but only makes sense "relative" to /var/tmp/instroot.1234/. ++ */ ++ p = startswith(i->path, i->root); ++ ++ r = strv_extend(&files, p ?: *a); ++ if (r < 0) ++ return r; ++ } ++ ++ *ret_names = TAKE_PTR(names); ++ *ret_files = TAKE_PTR(files); ++ return 0; ++} ++ + int unit_file_reenable( + UnitFileScope scope, + UnitFileFlags flags, + const char *root_dir, +- char **files, ++ char **names_or_paths, + UnitFileChange **changes, + size_t *n_changes) { + + _cleanup_(lookup_paths_free) LookupPaths lp = {}; +- size_t l, i; +- char **names; ++ _cleanup_strv_free_ char **names = NULL, **files = NULL; + int r; + + assert(scope >= 0); +@@ -2731,13 +2788,11 @@ int unit_file_reenable( + if (!config_path) + return -ENXIO; + +- /* First, we invoke the disable command with only the basename... */ +- l = strv_length(files); +- names = newa(char*, l+1); +- for (i = 0; i < l; i++) +- names[i] = basename(files[i]); +- names[i] = NULL; ++ r = normalize_linked_files(scope, &lp, names_or_paths, &names, &files); ++ if (r < 0) ++ return r; + ++ /* First, we invoke the disable command with only the basename... */ + r = do_unit_file_disable(&lp, scope, flags, config_path, names, changes, n_changes); + if (r < 0) + return r; +diff --git a/src/shared/install.h b/src/shared/install.h +index d21e2aaa45..dba6987406 100644 +--- a/src/shared/install.h ++++ b/src/shared/install.h +@@ -111,7 +111,7 @@ int unit_file_reenable( + UnitFileScope scope, + UnitFileFlags flags, + const char *root_dir, +- char **files, ++ char **names_or_paths, + UnitFileChange **changes, + size_t *n_changes); + int unit_file_preset( +diff --git a/test/test-systemctl-enable.sh b/test/test-systemctl-enable.sh +index c1fb9626ab..0ed08a9da3 100644 +--- a/test/test-systemctl-enable.sh ++++ b/test/test-systemctl-enable.sh +@@ -206,11 +206,9 @@ test ! -h "$root/etc/systemd/system/paths.target.wants/link1.path" + islink "$root/etc/systemd/system/link1.path" "/link1.path" + islink "$root/etc/systemd/system/paths.target.wants/link1.path" "/link1.path" + +-# FIXME +-# "$systemctl" --root="$root" reenable 'link1.path' +-# islink "$root/etc/systemd/system/link1.path" "/link1.path" +-# islink "$root/etc/systemd/system/paths.target.wants/link1.path" "/link1.path" +- ++"$systemctl" --root="$root" reenable 'link1.path' ++islink "$root/etc/systemd/system/link1.path" "/link1.path" ++islink "$root/etc/systemd/system/paths.target.wants/link1.path" "/link1.path" + + : -------manual link------------------------------------------ + cat >"$root/link3.suffix" < +Date: Tue, 15 Mar 2022 10:13:18 +0100 +Subject: [PATCH] test-systemctl-enable: extend the test for repeated + WantedBy/RequiredBy + +I was considering deduplicating the list of target units in +WantedBy/RequiredBy. But to do this meaningfully, we'd need to do alias +expansion first, i.e. after the initial parsing is done. This seems to be +more trouble than it would be worth. + +Instead, I added tests that we're doing the right thing and creating symlinks +as expected. For duplicate links, we create the link, and on the second time we +see that the link is already there, so the output is correct. + +(cherry picked from commit 0c003e8305188f25429938c7c4d09c0a5dfc961b) + +Related: #2082131 +--- + test/test-systemctl-enable.sh | 22 ++++++++++++++++++---- + 1 file changed, 18 insertions(+), 4 deletions(-) + +diff --git a/test/test-systemctl-enable.sh b/test/test-systemctl-enable.sh +index 0ed08a9da3..0a0123b9d7 100644 +--- a/test/test-systemctl-enable.sh ++++ b/test/test-systemctl-enable.sh +@@ -285,39 +285,53 @@ test ! -h "$root/etc/systemd/system/services.target.wants/templ1@one.service" + test ! -h "$root/etc/systemd/system/services.target.wants/templ1@two.service" + + : -------template enablement w/ default instance-------------- +-cat >>"$root/etc/systemd/system/templ1@.service" <"$root/etc/systemd/system/templ1@.service" <"$root/etc/systemd/system/templ2@.service" < +Date: Wed, 2 Mar 2022 16:53:54 +0100 +Subject: [PATCH] shared/install: when we fail to chase a symlink, show some + logs + +When chase_symlinks() fails, we'd get the generic error: + + Failed to disable: Permission denied. + +Let's at least add the failure to changes list, so the user gets +a slightly better message. Ideally, we'd say where exactly the permission +failure occured, but chase_symlinks() is a library level function and I don't +think we should add logging there. The output looks like this now: + + Failed to resolve symlink "/tmp/systemctl-test.1r7Roj/etc/systemd/system/link5alias2.service": Permission denied + Failed to resolve symlink "/tmp/systemctl-test.1r7Roj/etc/systemd/system/link5alias.service": Permission denied + Failed to disable unit, file /tmp/systemctl-test.1r7Roj/etc/systemd/system/link5alias2.service: Permission denied. + Failed to disable unit, file /tmp/systemctl-test.1r7Roj/etc/systemd/system/link5alias.service: Permission denied. + +(cherry picked from commit 212a24f0bbe4c54183d3b0ad9579a995007e29a8) + +Related: #2082131 +--- + src/shared/install.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/src/shared/install.c b/src/shared/install.c +index bf11e5bdce..ce045d02be 100644 +--- a/src/shared/install.c ++++ b/src/shared/install.c +@@ -616,6 +616,9 @@ static int remove_marked_symlinks_fd( + if (q == -ENOENT) + continue; + if (q < 0) { ++ log_debug_errno(q, "Failed to resolve symlink \"%s\": %m", p); ++ unit_file_changes_add(changes, n_changes, q, p, NULL); ++ + if (r == 0) + r = q; + continue; diff --git a/0189-shared-install-do-not-try-to-resolve-symlinks-outsid.patch b/0189-shared-install-do-not-try-to-resolve-symlinks-outsid.patch new file mode 100644 index 0000000..1dee0c7 --- /dev/null +++ b/0189-shared-install-do-not-try-to-resolve-symlinks-outsid.patch @@ -0,0 +1,42 @@ +From 64fa6f059ae0b491fdb52c7375d59774ff9c237a Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Tue, 15 Mar 2022 16:35:47 +0100 +Subject: [PATCH] shared/install: do not try to resolve symlinks outside of + root directory +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +I linked a file as root, so I had a symlink /root/test.service ← /etc/systemd/system/test.service. +To my surpise, when running test-systemctl-enable, it failed with a cryptic EACCES. +The previous commit made the logs a bit better. Strace shows that we +were trying to follow the symlink without taking --root into account. + +It seems that this bug was introduced in 66a19d85a533b15ed32f4066ec880b5a8c06babd: +before it, we'd do readlink_malloc(), which returned a path relative to root. But +we only used that path for checking if the path is in remove_symlinks_to set, which +contains relative paths. So if the path was relative, we'd get a false-negative +answer, but we didn't go outside of the root. (We need to canonicalize the symlink +to get a consistent answer.) But after 66a19 we use chase_symlinks(), without taking +root into account which is completely bogus. + +(cherry picked from commit 40276314afc4fb5c35c6b3da3e6185af6ed3886b) + +Related: #2082131 +--- + src/shared/install.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/shared/install.c b/src/shared/install.c +index ce045d02be..ad0238ab50 100644 +--- a/src/shared/install.c ++++ b/src/shared/install.c +@@ -612,7 +612,7 @@ static int remove_marked_symlinks_fd( + return -ENOMEM; + path_simplify(p); + +- q = chase_symlinks(p, NULL, CHASE_NONEXISTENT, &dest, NULL); ++ q = chase_symlinks(p, lp->root_dir, CHASE_NONEXISTENT, &dest, NULL); + if (q == -ENOENT) + continue; + if (q < 0) { diff --git a/0190-test-systemctl-enable-enhance-the-test-for-unit-file.patch b/0190-test-systemctl-enable-enhance-the-test-for-unit-file.patch new file mode 100644 index 0000000..a74db25 --- /dev/null +++ b/0190-test-systemctl-enable-enhance-the-test-for-unit-file.patch @@ -0,0 +1,79 @@ +From 2a11a51491d3113f8d198c7d30ead8b555e60a61 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Tue, 15 Mar 2022 17:45:34 +0100 +Subject: [PATCH] test-systemctl-enable: enhance the test for unit file linking + +Current behaviour is wrong, but it cannot be shown in this test, because we +don't have a running systemd instance here. + +(cherry picked from commit 85516075a24fd2f1316575570d7d5f5a37f43dbd) + +Related: #2082131 +--- + test/test-systemctl-enable.sh | 39 ++++++++++++++++++++++++++++++++--- + 1 file changed, 36 insertions(+), 3 deletions(-) + +diff --git a/test/test-systemctl-enable.sh b/test/test-systemctl-enable.sh +index 0a0123b9d7..220ebfdab7 100644 +--- a/test/test-systemctl-enable.sh ++++ b/test/test-systemctl-enable.sh +@@ -401,7 +401,7 @@ test ! -h "$root/etc/systemd/system/link4.service" + test ! -h "$root/etc/systemd/system/link4alias.service" + test ! -h "$root/etc/systemd/system/link4alias2.service" + +-: -------issue 661: link and enable on unit file-------------- ++: -------issue 661: enable on unit file-------------- + test ! -e "$root/etc/systemd/system/link5.service" + cat >"$root/etc/systemd/system/link5.service" <"$root/link5copy.service" <"$root/etc/systemd/system/link5@.path" < +Date: Wed, 16 Mar 2022 09:28:46 +0100 +Subject: [PATCH] shared/install: skip unnecessary chasing of symlinks in + disable + +We use the symlink source name and destination names to decide whether to remove +the symlink. But if the source name is enough to decide to remove the symlink, +we'd still look up the destination for no good reason. This is a slow operation, +let's skip it. + +(cherry picked from commit 7a6c73dabf6451d6ef22d0cdfbb1749a77450d5b) + +Related: #2082131 +--- + src/shared/install.c | 43 +++++++++++++++++++++++++------------------ + 1 file changed, 25 insertions(+), 18 deletions(-) + +diff --git a/src/shared/install.c b/src/shared/install.c +index ad0238ab50..08a9892260 100644 +--- a/src/shared/install.c ++++ b/src/shared/install.c +@@ -599,8 +599,7 @@ static int remove_marked_symlinks_fd( + r = q; + + } else if (de->d_type == DT_LNK) { +- _cleanup_free_ char *p = NULL, *dest = NULL; +- const char *rp; ++ _cleanup_free_ char *p = NULL; + bool found; + int q; + +@@ -612,24 +611,32 @@ static int remove_marked_symlinks_fd( + return -ENOMEM; + path_simplify(p); + +- q = chase_symlinks(p, lp->root_dir, CHASE_NONEXISTENT, &dest, NULL); +- if (q == -ENOENT) +- continue; +- if (q < 0) { +- log_debug_errno(q, "Failed to resolve symlink \"%s\": %m", p); +- unit_file_changes_add(changes, n_changes, q, p, NULL); ++ /* We remove all links pointing to a file or path that is marked, as well as all ++ * files sharing the same name as a file that is marked. Do path chasing only if ++ * we don't already know that we want to remove the symlink. */ ++ found = set_contains(remove_symlinks_to, de->d_name); + +- if (r == 0) +- r = q; +- continue; +- } ++ if (!found) { ++ _cleanup_free_ char *dest = NULL; ++ ++ ++ q = chase_symlinks(p, lp->root_dir, CHASE_NONEXISTENT, &dest, NULL); ++ if (q == -ENOENT) ++ continue; ++ if (q < 0) { ++ log_debug_errno(q, "Failed to resolve symlink \"%s\": %m", p); ++ unit_file_changes_add(changes, n_changes, q, p, NULL); + +- /* We remove all links pointing to a file or path that is marked, as well as all files sharing +- * the same name as a file that is marked. */ ++ if (r == 0) ++ r = q; ++ continue; ++ } ++ ++ found = set_contains(remove_symlinks_to, dest) || ++ set_contains(remove_symlinks_to, basename(dest)); ++ ++ } + +- found = set_contains(remove_symlinks_to, dest) || +- set_contains(remove_symlinks_to, basename(dest)) || +- set_contains(remove_symlinks_to, de->d_name); + + if (!found) + continue; +@@ -650,7 +657,7 @@ static int remove_marked_symlinks_fd( + /* Now, remember the full path (but with the root prefix removed) of + * the symlink we just removed, and remove any symlinks to it, too. */ + +- rp = skip_root(lp->root_dir, p); ++ const char *rp = skip_root(lp->root_dir, p); + q = mark_symlink_for_removal(&remove_symlinks_to, rp ?: p); + if (q < 0) + return q; diff --git a/0192-shared-install-also-remove-symlinks-like-.wants-foo-.patch b/0192-shared-install-also-remove-symlinks-like-.wants-foo-.patch new file mode 100644 index 0000000..3682ca1 --- /dev/null +++ b/0192-shared-install-also-remove-symlinks-like-.wants-foo-.patch @@ -0,0 +1,116 @@ +From 5aa2be25e7de16f4d3ff3b322cf8c35574e712c5 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Wed, 16 Mar 2022 09:51:24 +0100 +Subject: [PATCH] =?UTF-8?q?shared/install:=20also=20remove=20symlinks=20li?= + =?UTF-8?q?ke=20.wants/foo@one.service=20=E2=86=92=20../foo@one.service?= +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +So far 'systemctl enable' would create absolute links to the target template +name. And we would remove such symlinks just fine. But the user may create +symlinks manually in a different form. In particular, symlinks for instanced +units *must* have the instance in the source name, and then it is natural to +also include it in the target name (.wants/foo@one.service → ../foo@one.service +rather than .wants/foo@one.service → ../foo@.service). We would choke on such +links, or not remove them at all. A test is added: + +before: + ++ build-rawhide/systemctl --root=/tmp/systemctl-test.001xda disable templ1@.service +Removed "/tmp/systemctl-test.001xda/etc/systemd/system/services.target.wants/templ1@seven.service". +Removed "/tmp/systemctl-test.001xda/etc/systemd/system/services.target.wants/templ1@six.service". +Removed "/tmp/systemctl-test.001xda/etc/systemd/system/services.target.wants/templ1@five.service". +Removed "/tmp/systemctl-test.001xda/etc/systemd/system/services.target.wants/templ1@four.service". +Removed "/tmp/systemctl-test.001xda/etc/systemd/system/services.target.wants/templ1@three.service". +Failed to disable unit, refusing to operate on linked unit file /tmp/systemctl-test.001xda/etc/systemd/system/services.target.wants/templ1@two.service. +Failed to disable unit, refusing to operate on linked unit file /tmp/systemctl-test.001xda/etc/systemd/system/services.target.wants/templ1@two.service. + +after: + ++ build-rawhide/systemctl --root=/tmp/systemctl-test.QVP0ev disable templ1@.service +Removed "/tmp/systemctl-test.QVP0ev/etc/systemd/system/services.target.wants/templ1@seven.service". +Removed "/tmp/systemctl-test.QVP0ev/etc/systemd/system/services.target.wants/templ1@six.service". +Removed "/tmp/systemctl-test.QVP0ev/etc/systemd/system/services.target.wants/templ1@five.service". +Removed "/tmp/systemctl-test.QVP0ev/etc/systemd/system/services.target.wants/templ1@four.service". +Removed "/tmp/systemctl-test.QVP0ev/etc/systemd/system/services.target.wants/templ1@three.service". +Removed "/tmp/systemctl-test.QVP0ev/etc/systemd/system/services.target.wants/templ1@two.service". +Removed "/tmp/systemctl-test.QVP0ev/etc/systemd/system/services.target.wants/templ1@one.service". ++ test '!' -h /tmp/systemctl-test.QVP0ev/etc/systemd/system/services.target.wants/templ1@one.service ++ test '!' -h /tmp/systemctl-test.QVP0ev/etc/systemd/system/services.target.wants/templ1@two.service ++ test '!' -h /tmp/systemctl-test.QVP0ev/etc/systemd/system/services.target.wants/templ1@three.service ++ test '!' -h /tmp/systemctl-test.QVP0ev/etc/systemd/system/services.target.wants/templ1@four.service ++ test '!' -h /tmp/systemctl-test.QVP0ev/etc/systemd/system/services.target.wants/templ1@five.service ++ test '!' -h /tmp/systemctl-test.QVP0ev/etc/systemd/system/services.target.wants/templ1@six.service ++ test '!' -h /tmp/systemctl-test.QVP0ev/etc/systemd/system/services.target.wants/templ1@seven.service + +(cherry picked from commit 9f61c9f79e0f77044b71ef2ba5edde20e15c6ad2) + +Related: #2082131 +--- + src/shared/install.c | 16 +++++++++++++--- + test/test-systemctl-enable.sh | 20 ++++++++++++++++++++ + 2 files changed, 33 insertions(+), 3 deletions(-) + +diff --git a/src/shared/install.c b/src/shared/install.c +index 08a9892260..43955519ae 100644 +--- a/src/shared/install.c ++++ b/src/shared/install.c +@@ -612,13 +612,23 @@ static int remove_marked_symlinks_fd( + path_simplify(p); + + /* We remove all links pointing to a file or path that is marked, as well as all +- * files sharing the same name as a file that is marked. Do path chasing only if +- * we don't already know that we want to remove the symlink. */ ++ * files sharing the same name as a file that is marked, and files sharing the same ++ * name after the instance has been removed. Do path chasing only if we don't already ++ * know that we want to remove the symlink. */ + found = set_contains(remove_symlinks_to, de->d_name); + + if (!found) { +- _cleanup_free_ char *dest = NULL; ++ _cleanup_free_ char *template = NULL; ++ ++ q = unit_name_template(de->d_name, &template); ++ if (q < 0 && q != -EINVAL) ++ return q; ++ if (q >= 0) ++ found = set_contains(remove_symlinks_to, template); ++ } + ++ if (!found) { ++ _cleanup_free_ char *dest = NULL; + + q = chase_symlinks(p, lp->root_dir, CHASE_NONEXISTENT, &dest, NULL); + if (q == -ENOENT) +diff --git a/test/test-systemctl-enable.sh b/test/test-systemctl-enable.sh +index 220ebfdab7..4462fb386e 100644 +--- a/test/test-systemctl-enable.sh ++++ b/test/test-systemctl-enable.sh +@@ -333,6 +333,26 @@ test ! -h "$root/etc/systemd/system/other@templ1.target.requires/templ1@one.serv + test ! -h "$root/etc/systemd/system/services.target.wants/templ1@two.service" + test ! -h "$root/etc/systemd/system/other@templ1.target.requires/templ1@two.service" + ++: -------removal of relative enablement symlinks-------------- ++test ! -h "$root/etc/systemd/system/services.target.wants/templ1@.service" ++ln -s '../templ1@one.service' "$root/etc/systemd/system/services.target.wants/templ1@one.service" ++ln -s 'templ1@two.service' "$root/etc/systemd/system/services.target.wants/templ1@two.service" ++ln -s '../templ1@.service' "$root/etc/systemd/system/services.target.wants/templ1@three.service" ++ln -s 'templ1@.service' "$root/etc/systemd/system/services.target.wants/templ1@four.service" ++ln -s '/usr/lib/systemd/system/templ1@.service' "$root/etc/systemd/system/services.target.wants/templ1@five.service" ++ln -s '/etc/systemd/system/templ1@.service' "$root/etc/systemd/system/services.target.wants/templ1@six.service" ++ln -s '/run/system/templ1@.service' "$root/etc/systemd/system/services.target.wants/templ1@seven.service" ++ ++# this should remove all links ++"$systemctl" --root="$root" disable 'templ1@.service' ++test ! -h "$root/etc/systemd/system/services.target.wants/templ1@one.service" ++test ! -h "$root/etc/systemd/system/services.target.wants/templ1@two.service" ++test ! -h "$root/etc/systemd/system/services.target.wants/templ1@three.service" ++test ! -h "$root/etc/systemd/system/services.target.wants/templ1@four.service" ++test ! -h "$root/etc/systemd/system/services.target.wants/templ1@five.service" ++test ! -h "$root/etc/systemd/system/services.target.wants/templ1@six.service" ++test ! -h "$root/etc/systemd/system/services.target.wants/templ1@seven.service" ++ + : -------template enablement for another template------------- + cat >"$root/etc/systemd/system/templ2@.service" < +Date: Wed, 16 Mar 2022 10:17:32 +0100 +Subject: [PATCH] shared/install: create relative symlinks for enablement and + aliasing +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This is a fairly noticable change, but I think it needs to be done. +So far we'd create an absolute symlink to the target unit file: + .wants/foo.service → /usr/lib/systemd/system/foo.service +or + alias.service → /etc/systemd/system/aliased.service. + +This works reasonably well, except in one case: where the unit file +is linked. When we look at a file link, the name of the physical file +isn't used, and we only take the account the symlink source name. +(In fact, the destination filename may not even be a well-formed unit name, +so we couldn't use it, even if we wanted to.) But this means that if +a file is linked, and specifies aliases, we'd create absolute links for +those aliases, and systemd would consider each "alias" to be a separate +unit. This isn't checked by the tests here, because we don't have a running +systemd instance, but it is easy enough to check manually. + +The most reasonable way to fix this is to create relative links to the +unit file: + .wants/foo.service → ../foo.service + alias.service → aliased.service. + +I opted to use no prefix for aliases, both normal and 'default.target', +and to add "../" for .wants/ and .requires/. Note that the link that is +created doesn't necessarily point to the file. E.g. if we're enabling +a file under /usr/lib/systemd/system, and create a symlink in /etc/systemd/system, +it'll still be "../foo.service", not "../../usr/lib/systemd/system/foo.service". +For our unit loading logic this doesn't matter, and figuring out a path +that actually leads somewhere would be more work. Since the user is allowed +to move the unit file, or add a new unit file in a different location, and +we don't actually follow the symlink, I think it's OK to create a dangling +symlink. The prefix of "../" is useful to give a hint that the link points +to files that are conceptually "one level up" in the directory hierarchy. + +With the relative symlinks, systemd knows that those are aliases. + +The tests are adjusted to use the new forms. There were a few tests that +weren't really testing something useful: 'test -e x' fails if 'x' is a +a dangling symlink. Absolute links in the chroot would be dangling, even +though the target existed in the expected path, but become non-dangling +when made relative and the test fails. + +This should be described in NEWS, but I'm not adding that here, because +it'd likely result in conflicts. + +(cherry picked from commit d6c9411072901556176ac130f2ce71a33107aa93) + +Related: #2082131 +--- + src/shared/install.c | 14 ++-- + src/test/test-install-root.c | 65 +++++++++-------- + test/test-systemctl-enable.sh | 128 ++++++++++++++++------------------ + 3 files changed, 105 insertions(+), 102 deletions(-) + +diff --git a/src/shared/install.c b/src/shared/install.c +index 43955519ae..1a2b0ccf24 100644 +--- a/src/shared/install.c ++++ b/src/shared/install.c +@@ -1842,7 +1842,7 @@ static int install_info_symlink_alias( + if (!alias_path) + return -ENOMEM; + +- q = create_symlink(lp, info->path, alias_path, force, changes, n_changes); ++ q = create_symlink(lp, info->name, alias_path, force, changes, n_changes); + r = r < 0 ? r : q; + } + +@@ -1911,7 +1911,7 @@ static int install_info_symlink_wants( + } + + STRV_FOREACH(s, list) { +- _cleanup_free_ char *path = NULL, *dst = NULL; ++ _cleanup_free_ char *dst = NULL; + + q = install_name_printf(scope, info, *s, info->root, &dst); + if (q < 0) { +@@ -1941,11 +1941,15 @@ static int install_info_symlink_wants( + continue; + } + +- path = strjoin(config_path, "/", dst, suffix, n); ++ _cleanup_free_ char *path = strjoin(config_path, "/", dst, suffix, n); + if (!path) + return -ENOMEM; + +- q = create_symlink(lp, info->path, path, true, changes, n_changes); ++ _cleanup_free_ char *target = strjoin("../", info->name); ++ if (!target) ++ return -ENOMEM; ++ ++ q = create_symlink(lp, target, path, true, changes, n_changes); + if (r == 0) + r = q; + +@@ -2853,7 +2857,7 @@ int unit_file_set_default( + return r; + + new_path = strjoina(lp.persistent_config, "/" SPECIAL_DEFAULT_TARGET); +- return create_symlink(&lp, info->path, new_path, flags & UNIT_FILE_FORCE, changes, n_changes); ++ return create_symlink(&lp, info->name, new_path, flags & UNIT_FILE_FORCE, changes, n_changes); + } + + int unit_file_get_default( +diff --git a/src/test/test-install-root.c b/src/test/test-install-root.c +index 4f66c12655..dca695d124 100644 +--- a/src/test/test-install-root.c ++++ b/src/test/test-install-root.c +@@ -88,7 +88,7 @@ TEST(basic_mask_and_enable) { + assert_se(unit_file_enable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("a.service"), &changes, &n_changes) == 1); + assert_se(n_changes == 1); + assert_se(changes[0].type_or_errno == UNIT_FILE_SYMLINK); +- assert_se(streq(changes[0].source, "/usr/lib/systemd/system/a.service")); ++ assert_se(streq(changes[0].source, "../a.service")); + p = strjoina(root, SYSTEM_CONFIG_UNIT_DIR"/multi-user.target.wants/a.service"); + assert_se(streq(changes[0].path, p)); + unit_file_changes_free(changes, n_changes); +@@ -128,7 +128,7 @@ TEST(basic_mask_and_enable) { + assert_se(unit_file_enable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("d.service"), &changes, &n_changes) >= 0); + assert_se(n_changes == 1); + assert_se(changes[0].type_or_errno == UNIT_FILE_SYMLINK); +- assert_se(streq(changes[0].source, "/usr/lib/systemd/system/a.service")); ++ assert_se(streq(changes[0].source, "../a.service")); + p = strjoina(root, SYSTEM_CONFIG_UNIT_DIR"/multi-user.target.wants/a.service"); + assert_se(streq(changes[0].path, p)); + unit_file_changes_free(changes, n_changes); +@@ -147,7 +147,7 @@ TEST(basic_mask_and_enable) { + p = strjoina(root, SYSTEM_CONFIG_UNIT_DIR"/multi-user.target.wants/a.service"); + assert_se(streq(changes[0].path, p)); + assert_se(changes[1].type_or_errno == UNIT_FILE_SYMLINK); +- assert_se(streq(changes[1].source, "/usr/lib/systemd/system/a.service")); ++ assert_se(streq(changes[1].source, "../a.service")); + assert_se(streq(changes[1].path, p)); + unit_file_changes_free(changes, n_changes); + changes = NULL; n_changes = 0; +@@ -186,7 +186,7 @@ TEST(basic_mask_and_enable) { + assert_se(unit_file_enable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("f.service"), &changes, &n_changes) == 1); + assert_se(n_changes == 2); + assert_se(changes[0].type_or_errno == UNIT_FILE_SYMLINK); +- assert_se(streq(changes[0].source, "/usr/lib/systemd/system/f.service")); ++ assert_se(streq(changes[0].source, "../f.service")); + p = strjoina(root, SYSTEM_CONFIG_UNIT_DIR"/x.target.wants/f.service"); + assert_se(streq(changes[0].path, p)); + assert_se(changes[1].type_or_errno == UNIT_FILE_DESTINATION_NOT_PRESENT); +@@ -280,7 +280,8 @@ TEST(linked_units) { + q = strjoina(root, SYSTEM_CONFIG_UNIT_DIR"/linked.service"); + for (i = 0 ; i < n_changes; i++) { + assert_se(changes[i].type_or_errno == UNIT_FILE_SYMLINK); +- assert_se(streq(changes[i].source, "/opt/linked.service")); ++ assert_se(STR_IN_SET(changes[i].source, ++ "../linked.service", "/opt/linked.service")); + + if (p && streq(changes[i].path, p)) + p = NULL; +@@ -322,7 +323,8 @@ TEST(linked_units) { + q = strjoina(root, SYSTEM_CONFIG_UNIT_DIR"/linked2.service"); + for (i = 0 ; i < n_changes; i++) { + assert_se(changes[i].type_or_errno == UNIT_FILE_SYMLINK); +- assert_se(streq(changes[i].source, "/opt/linked2.service")); ++ assert_se(STR_IN_SET(changes[i].source, ++ "../linked2.service", "/opt/linked2.service")); + + if (p && streq(changes[i].path, p)) + p = NULL; +@@ -340,7 +342,7 @@ TEST(linked_units) { + assert_se(changes[0].type_or_errno == UNIT_FILE_SYMLINK); + assert_se(startswith(changes[0].path, root)); + assert_se(endswith(changes[0].path, "linked3.service")); +- assert_se(streq(changes[0].source, "/opt/linked3.service")); ++ assert_se(streq(changes[0].source, "../linked3.service")); + unit_file_changes_free(changes, n_changes); + changes = NULL; n_changes = 0; + } +@@ -371,7 +373,7 @@ TEST(default) { + assert_se(unit_file_set_default(UNIT_FILE_SYSTEM, 0, root, "test-default.target", &changes, &n_changes) >= 0); + assert_se(n_changes == 1); + assert_se(changes[0].type_or_errno == UNIT_FILE_SYMLINK); +- assert_se(streq(changes[0].source, "/usr/lib/systemd/system/test-default-real.target")); ++ assert_se(streq(changes[0].source, "test-default-real.target")); + p = strjoina(root, SYSTEM_CONFIG_UNIT_DIR "/" SPECIAL_DEFAULT_TARGET); + assert_se(streq(changes[0].path, p)); + unit_file_changes_free(changes, n_changes); +@@ -401,7 +403,7 @@ TEST(add_dependency) { + assert_se(unit_file_add_dependency(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("add-dependency-test-service.service"), "add-dependency-test-target.target", UNIT_WANTS, &changes, &n_changes) >= 0); + assert_se(n_changes == 1); + assert_se(changes[0].type_or_errno == UNIT_FILE_SYMLINK); +- assert_se(streq(changes[0].source, "/usr/lib/systemd/system/real-add-dependency-test-service.service")); ++ assert_se(streq(changes[0].source, "../real-add-dependency-test-service.service")); + p = strjoina(root, SYSTEM_CONFIG_UNIT_DIR"/real-add-dependency-test-target.target.wants/real-add-dependency-test-service.service"); + assert_se(streq(changes[0].path, p)); + unit_file_changes_free(changes, n_changes); +@@ -442,7 +444,7 @@ TEST(template_enable) { + assert_se(unit_file_enable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("template@.service"), &changes, &n_changes) >= 0); + assert_se(n_changes == 1); + assert_se(changes[0].type_or_errno == UNIT_FILE_SYMLINK); +- assert_se(streq(changes[0].source, "/usr/lib/systemd/system/template@.service")); ++ assert_se(streq(changes[0].source, "../template@.service")); + p = strjoina(root, SYSTEM_CONFIG_UNIT_DIR"/multi-user.target.wants/template@def.service"); + assert_se(streq(changes[0].path, p)); + unit_file_changes_free(changes, n_changes); +@@ -473,13 +475,14 @@ TEST(template_enable) { + + assert_se(unit_file_enable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("template@foo.service"), &changes, &n_changes) >= 0); + assert_se(changes[0].type_or_errno == UNIT_FILE_SYMLINK); +- assert_se(streq(changes[0].source, "/usr/lib/systemd/system/template@.service")); ++ assert_se(streq(changes[0].source, "../template@foo.service")); + p = strjoina(root, SYSTEM_CONFIG_UNIT_DIR"/multi-user.target.wants/template@foo.service"); + assert_se(streq(changes[0].path, p)); + unit_file_changes_free(changes, n_changes); + changes = NULL; n_changes = 0; + +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@.service", &state) >= 0 && state == UNIT_FILE_INDIRECT); ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@.service", &state) >= 0); ++ assert_se(state == UNIT_FILE_INDIRECT); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@def.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@foo.service", &state) >= 0 && state == UNIT_FILE_ENABLED); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@foo.service", &state) >= 0 && state == UNIT_FILE_ENABLED); +@@ -506,7 +509,7 @@ TEST(template_enable) { + + assert_se(unit_file_enable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("template-symlink@quux.service"), &changes, &n_changes) >= 0); + assert_se(changes[0].type_or_errno == UNIT_FILE_SYMLINK); +- assert_se(streq(changes[0].source, "/usr/lib/systemd/system/template@.service")); ++ assert_se(streq(changes[0].source, "../template@quux.service")); + p = strjoina(root, SYSTEM_CONFIG_UNIT_DIR"/multi-user.target.wants/template@quux.service"); + assert_se(streq(changes[0].path, p)); + unit_file_changes_free(changes, n_changes); +@@ -552,7 +555,7 @@ TEST(indirect) { + assert_se(unit_file_enable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("indirectc.service"), &changes, &n_changes) >= 0); + assert_se(n_changes == 1); + assert_se(changes[0].type_or_errno == UNIT_FILE_SYMLINK); +- assert_se(streq(changes[0].source, "/usr/lib/systemd/system/indirectb.service")); ++ assert_se(streq(changes[0].source, "../indirectb.service")); + p = strjoina(root, SYSTEM_CONFIG_UNIT_DIR"/multi-user.target.wants/indirectb.service"); + assert_se(streq(changes[0].path, p)); + unit_file_changes_free(changes, n_changes); +@@ -604,7 +607,7 @@ TEST(preset_and_list) { + assert_se(unit_file_preset(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("preset-yes.service"), UNIT_FILE_PRESET_FULL, &changes, &n_changes) >= 0); + assert_se(n_changes == 1); + assert_se(changes[0].type_or_errno == UNIT_FILE_SYMLINK); +- assert_se(streq(changes[0].source, "/usr/lib/systemd/system/preset-yes.service")); ++ assert_se(streq(changes[0].source, "../preset-yes.service")); + p = strjoina(root, SYSTEM_CONFIG_UNIT_DIR"/multi-user.target.wants/preset-yes.service"); + assert_se(streq(changes[0].path, p)); + unit_file_changes_free(changes, n_changes); +@@ -641,7 +644,7 @@ TEST(preset_and_list) { + for (i = 0; i < n_changes; i++) { + + if (changes[i].type_or_errno == UNIT_FILE_SYMLINK) { +- assert_se(streq(changes[i].source, "/usr/lib/systemd/system/preset-yes.service")); ++ assert_se(streq(changes[i].source, "../preset-yes.service")); + assert_se(streq(changes[i].path, p)); + } else + assert_se(changes[i].type_or_errno == UNIT_FILE_UNLINK); +@@ -757,7 +760,7 @@ TEST(preset_order) { + assert_se(unit_file_preset(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("prefix-1.service"), UNIT_FILE_PRESET_FULL, &changes, &n_changes) >= 0); + assert_se(n_changes == 1); + assert_se(changes[0].type_or_errno == UNIT_FILE_SYMLINK); +- assert_se(streq(changes[0].source, "/usr/lib/systemd/system/prefix-1.service")); ++ assert_se(streq(changes[0].source, "../prefix-1.service")); + p = strjoina(root, SYSTEM_CONFIG_UNIT_DIR"/multi-user.target.wants/prefix-1.service"); + assert_se(streq(changes[0].path, p)); + unit_file_changes_free(changes, n_changes); +@@ -866,8 +869,8 @@ TEST(with_dropin) { + assert_se(n_changes == 2); + assert_se(changes[0].type_or_errno == UNIT_FILE_SYMLINK); + assert_se(changes[1].type_or_errno == UNIT_FILE_SYMLINK); +- assert_se(streq(changes[0].source, "/usr/lib/systemd/system/with-dropin-1.service")); +- assert_se(streq(changes[1].source, "/usr/lib/systemd/system/with-dropin-1.service")); ++ assert_se(streq(changes[0].source, "../with-dropin-1.service")); ++ assert_se(streq(changes[1].source, "../with-dropin-1.service")); + p = strjoina(root, SYSTEM_CONFIG_UNIT_DIR"/multi-user.target.wants/with-dropin-1.service"); + assert_se(streq(changes[0].path, p)); + p = strjoina(root, SYSTEM_CONFIG_UNIT_DIR"/graphical.target.wants/with-dropin-1.service"); +@@ -880,8 +883,8 @@ TEST(with_dropin) { + assert_se(n_changes == 2); + assert_se(changes[0].type_or_errno == UNIT_FILE_SYMLINK); + assert_se(changes[1].type_or_errno == UNIT_FILE_SYMLINK); +- assert_se(streq(changes[0].source, SYSTEM_CONFIG_UNIT_DIR"/with-dropin-2.service")); +- assert_se(streq(changes[1].source, SYSTEM_CONFIG_UNIT_DIR"/with-dropin-2.service")); ++ assert_se(streq(changes[0].source, "../with-dropin-2.service")); ++ assert_se(streq(changes[1].source, "../with-dropin-2.service")); + p = strjoina(root, SYSTEM_CONFIG_UNIT_DIR"/multi-user.target.wants/with-dropin-2.service"); + assert_se(streq(changes[0].path, p)); + p = strjoina(root, SYSTEM_CONFIG_UNIT_DIR"/graphical.target.wants/with-dropin-2.service"); +@@ -894,8 +897,8 @@ TEST(with_dropin) { + assert_se(n_changes == 2); + assert_se(changes[0].type_or_errno == UNIT_FILE_SYMLINK); + assert_se(changes[1].type_or_errno == UNIT_FILE_SYMLINK); +- assert_se(streq(changes[0].source, "/usr/lib/systemd/system/with-dropin-3.service")); +- assert_se(streq(changes[1].source, "/usr/lib/systemd/system/with-dropin-3.service")); ++ assert_se(streq(changes[0].source, "../with-dropin-3.service")); ++ assert_se(streq(changes[1].source, "../with-dropin-3.service")); + p = strjoina(root, SYSTEM_CONFIG_UNIT_DIR"/multi-user.target.wants/with-dropin-3.service"); + assert_se(streq(changes[0].path, p)); + p = strjoina(root, SYSTEM_CONFIG_UNIT_DIR"/graphical.target.wants/with-dropin-3.service"); +@@ -908,8 +911,8 @@ TEST(with_dropin) { + assert_se(n_changes == 2); + assert_se(changes[0].type_or_errno == UNIT_FILE_SYMLINK); + assert_se(changes[1].type_or_errno == UNIT_FILE_SYMLINK); +- assert_se(streq(changes[0].source, "/usr/lib/systemd/system/with-dropin-4a.service")); +- assert_se(streq(changes[1].source, "/usr/lib/systemd/system/with-dropin-4b.service")); ++ assert_se(streq(changes[0].source, "../with-dropin-4a.service")); ++ assert_se(streq(changes[1].source, "../with-dropin-4b.service")); + p = strjoina(root, SYSTEM_CONFIG_UNIT_DIR"/multi-user.target.wants/with-dropin-4a.service"); + assert_se(streq(changes[0].path, p)); + p = strjoina(root, SYSTEM_CONFIG_UNIT_DIR"/multi-user.target.wants/with-dropin-4b.service"); +@@ -975,8 +978,8 @@ TEST(with_dropin_template) { + assert_se(n_changes == 2); + assert_se(changes[0].type_or_errno == UNIT_FILE_SYMLINK); + assert_se(changes[1].type_or_errno == UNIT_FILE_SYMLINK); +- assert_se(streq(changes[0].source, "/usr/lib/systemd/system/with-dropin-1@.service")); +- assert_se(streq(changes[1].source, "/usr/lib/systemd/system/with-dropin-1@.service")); ++ assert_se(streq(changes[0].source, "../with-dropin-1@instance-1.service")); ++ assert_se(streq(changes[1].source, "../with-dropin-1@instance-1.service")); + p = strjoina(root, SYSTEM_CONFIG_UNIT_DIR"/multi-user.target.wants/with-dropin-1@instance-1.service"); + assert_se(streq(changes[0].path, p)); + p = strjoina(root, SYSTEM_CONFIG_UNIT_DIR"/graphical.target.wants/with-dropin-1@instance-1.service"); +@@ -988,8 +991,8 @@ TEST(with_dropin_template) { + assert_se(n_changes == 2); + assert_se(changes[0].type_or_errno == UNIT_FILE_SYMLINK); + assert_se(changes[1].type_or_errno == UNIT_FILE_SYMLINK); +- assert_se(streq(changes[0].source, "/usr/lib/systemd/system/with-dropin-2@.service")); +- assert_se(streq(changes[1].source, "/usr/lib/systemd/system/with-dropin-2@.service")); ++ assert_se(streq(changes[0].source, "../with-dropin-2@instance-1.service")); ++ assert_se(streq(changes[1].source, "../with-dropin-2@instance-1.service")); + p = strjoina(root, SYSTEM_CONFIG_UNIT_DIR"/multi-user.target.wants/with-dropin-2@instance-1.service"); + assert_se(streq(changes[0].path, p)); + p = strjoina(root, SYSTEM_CONFIG_UNIT_DIR"/graphical.target.wants/with-dropin-2@instance-1.service"); +@@ -1000,7 +1003,7 @@ TEST(with_dropin_template) { + assert_se(unit_file_enable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("with-dropin-2@instance-2.service"), &changes, &n_changes) == 1); + assert_se(n_changes == 1); + assert_se(changes[0].type_or_errno == UNIT_FILE_SYMLINK); +- assert_se(streq(changes[0].source, "/usr/lib/systemd/system/with-dropin-2@.service")); ++ assert_se(streq(changes[0].source, "../with-dropin-2@instance-2.service")); + p = strjoina(root, SYSTEM_CONFIG_UNIT_DIR"/multi-user.target.wants/with-dropin-2@instance-2.service"); + assert_se(streq(changes[0].path, p)); + unit_file_changes_free(changes, n_changes); +@@ -1009,7 +1012,7 @@ TEST(with_dropin_template) { + assert_se(unit_file_enable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("with-dropin-3@.service"), &changes, &n_changes) == 1); + assert_se(n_changes == 1); + assert_se(changes[0].type_or_errno == UNIT_FILE_SYMLINK); +- assert_se(streq(changes[0].source, "/usr/lib/systemd/system/with-dropin-3@.service")); ++ assert_se(streq(changes[0].source, "../with-dropin-3@.service")); + p = strjoina(root, SYSTEM_CONFIG_UNIT_DIR"/multi-user.target.wants/with-dropin-3@instance-2.service"); + assert_se(streq(changes[0].path, p)); + unit_file_changes_free(changes, n_changes); +diff --git a/test/test-systemctl-enable.sh b/test/test-systemctl-enable.sh +index 4462fb386e..9463433c5b 100644 +--- a/test/test-systemctl-enable.sh ++++ b/test/test-systemctl-enable.sh +@@ -68,27 +68,27 @@ EOF + "$systemctl" --root="$root" enable test1 && { echo "Expected failure" >&2; exit 1; } + test -h "$root/etc/systemd/system/default.target.wants/test1.service" + test -h "$root/etc/systemd/system/special.target.requires/test1.service" +-test ! -e "$root/etc/systemd/system/test1-goodalias.service" ++test -e "$root/etc/systemd/system/test1-goodalias.service" + test -h "$root/etc/systemd/system/test1-goodalias.service" +-test ! -e "$root/etc/systemd/system/test1@badalias.service" +-test ! -e "$root/etc/systemd/system/test1-badalias.target" +-test ! -e "$root/etc/systemd/system/test1-badalias.socket" ++test ! -h "$root/etc/systemd/system/test1@badalias.service" ++test ! -h "$root/etc/systemd/system/test1-badalias.target" ++test ! -h "$root/etc/systemd/system/test1-badalias.socket" ++test -e "$root/etc/systemd/system/test1-goodalias2.service" + test -h "$root/etc/systemd/system/test1-goodalias2.service" + + : -------aliases in reeanble---------------------------------- + "$systemctl" --root="$root" reenable test1 && { echo "Expected failure" >&2; exit 1; } +-test -h "$root/etc/systemd/system/default.target.wants/test1.service" +-test ! -e "$root/etc/systemd/system/test1-goodalias.service" +-test -h "$root/etc/systemd/system/test1-goodalias.service" ++islink "$root/etc/systemd/system/default.target.wants/test1.service" "../test1.service" ++islink "$root/etc/systemd/system/test1-goodalias.service" "test1.service" + +-test ! -e "$root/etc/systemd/system/test1@badalias.service" +-test ! -e "$root/etc/systemd/system/test1-badalias.target" +-test ! -e "$root/etc/systemd/system/test1-badalias.socket" ++test ! -h "$root/etc/systemd/system/test1@badalias.service" ++test ! -h "$root/etc/systemd/system/test1-badalias.target" ++test ! -h "$root/etc/systemd/system/test1-badalias.socket" + + "$systemctl" --root="$root" disable test1 +-test ! -e "$root/etc/systemd/system/default.target.wants/test1.service" +-test ! -e "$root/etc/systemd/system/special.target.requires/test1.service" +-test ! -e "$root/etc/systemd/system/test1-goodalias.service" ++test ! -h "$root/etc/systemd/system/default.target.wants/test1.service" ++test ! -h "$root/etc/systemd/system/special.target.requires/test1.service" ++test ! -h "$root/etc/systemd/system/test1-goodalias.service" + + : -------also units------------------------------------------- + cat >"$root/etc/systemd/system/test2.socket" <&2; exit 1; } + islink "$root/etc/systemd/system/link1.path" "/link1.path" +-islink "$root/etc/systemd/system/paths.target.wants/link1.path" "/link1.path" ++islink "$root/etc/systemd/system/paths.target.wants/link1.path" "../link1.path" + + : -------enable bad suffix------------------------------------ + cp "$root/link1.path" "$root/subdir/link1.suffix" +@@ -204,11 +204,11 @@ test ! -h "$root/etc/systemd/system/paths.target.wants/link1.path" + + "$systemctl" --root="$root" enable 'link1.path' + islink "$root/etc/systemd/system/link1.path" "/link1.path" +-islink "$root/etc/systemd/system/paths.target.wants/link1.path" "/link1.path" ++islink "$root/etc/systemd/system/paths.target.wants/link1.path" "../link1.path" + + "$systemctl" --root="$root" reenable 'link1.path' + islink "$root/etc/systemd/system/link1.path" "/link1.path" +-islink "$root/etc/systemd/system/paths.target.wants/link1.path" "/link1.path" ++islink "$root/etc/systemd/system/paths.target.wants/link1.path" "../link1.path" + + : -------manual link------------------------------------------ + cat >"$root/link3.suffix" <"$root/etc/systemd/system/templ1@.service" < +Date: Wed, 16 Mar 2022 17:37:58 +0100 +Subject: [PATCH] shared/install: when looking for symlinks in + .wants/.requires, ignore symlink target +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +We'd say that file is enabled indirectly if we had a symlink like: + foo@.service ← bar.target.wants/foo@one.service +but not when we had + foo@one.service ← bar.target.wants/foo@one.service + +The effect of both link types is the same. In fact we don't care +about the symlink target. (We'll warn if it is mismatched, but we honour +it anyway.) + +So let's use the original match logic only for aliases. +For .wants/.requires we instead look for a matching source name, +or a source name that matches after stripping of instance. + +(cherry picked from commit 466f6979c90aaee62c33723392cc49c6638a3f46) + +Related: #2082131 +--- + src/shared/install.c | 93 ++++++++++++++++++++++++++++---------------- + 1 file changed, 60 insertions(+), 33 deletions(-) + +diff --git a/src/shared/install.c b/src/shared/install.c +index 1a2b0ccf24..a864039f44 100644 +--- a/src/shared/install.c ++++ b/src/shared/install.c +@@ -748,7 +748,8 @@ static int find_symlinks_in_directory( + const char *dir_path, + const char *root_dir, + const UnitFileInstallInfo *info, +- bool match_aliases, ++ bool ignore_destination, ++ bool match_name, + bool ignore_same_name, + const char *config_path, + bool *same_name_link) { +@@ -756,51 +757,67 @@ static int find_symlinks_in_directory( + int r = 0; + + FOREACH_DIRENT(de, dir, return -errno) { +- _cleanup_free_ char *dest = NULL; +- bool found_path = false, found_dest, b = false; ++ bool found_path = false, found_dest = false, b = false; + int q; + + if (de->d_type != DT_LNK) + continue; + +- /* Acquire symlink destination */ +- q = readlinkat_malloc(dirfd(dir), de->d_name, &dest); +- if (q == -ENOENT) +- continue; +- if (q < 0) { +- if (r == 0) +- r = q; +- continue; +- } ++ if (!ignore_destination) { ++ _cleanup_free_ char *dest = NULL; ++ ++ /* Acquire symlink destination */ ++ q = readlinkat_malloc(dirfd(dir), de->d_name, &dest); ++ if (q == -ENOENT) ++ continue; ++ if (q < 0) { ++ if (r == 0) ++ r = q; ++ continue; ++ } + +- /* Make absolute */ +- if (!path_is_absolute(dest)) { +- char *x; ++ /* Make absolute */ ++ if (!path_is_absolute(dest)) { ++ char *x; + +- x = path_join(dir_path, dest); +- if (!x) +- return -ENOMEM; ++ x = path_join(dir_path, dest); ++ if (!x) ++ return -ENOMEM; + +- free_and_replace(dest, x); ++ free_and_replace(dest, x); ++ } ++ ++ /* Check if what the symlink points to matches what we are looking for */ ++ found_dest = streq(basename(dest), info->name); + } + + assert(unit_name_is_valid(info->name, UNIT_NAME_ANY)); +- if (!ignore_same_name) +- /* Check if the symlink itself matches what we are looking for. +- * +- * If ignore_same_name is specified, we are in one of the directories which +- * have lower priority than the unit file, and even if a file or symlink with +- * this name was found, we should ignore it. */ +- found_path = streq(de->d_name, info->name); + +- /* Check if what the symlink points to matches what we are looking for */ +- found_dest = streq(basename(dest), info->name); ++ /* Check if the symlink itself matches what we are looking for. ++ * ++ * If ignore_destination is specified, we only look at the source name. ++ * ++ * If ignore_same_name is specified, we are in one of the directories which ++ * have lower priority than the unit file, and even if a file or symlink with ++ * this name was found, we should ignore it. */ ++ ++ if (ignore_destination || !ignore_same_name) ++ found_path = streq(de->d_name, info->name); ++ ++ if (!found_path && ignore_destination) { ++ _cleanup_free_ char *template = NULL; ++ ++ q = unit_name_template(de->d_name, &template); ++ if (q < 0 && q != -EINVAL) ++ return q; ++ if (q >= 0) ++ found_dest = streq(template, info->name); ++ } + + if (found_path && found_dest) { + _cleanup_free_ char *p = NULL, *t = NULL; + +- /* Filter out same name links in the main +- * config path */ ++ /* Filter out same name links in the main config path */ + p = path_make_absolute(de->d_name, dir_path); + t = path_make_absolute(info->name, config_path); + +@@ -813,7 +830,7 @@ static int find_symlinks_in_directory( + if (b) + *same_name_link = true; + else if (found_path || found_dest) { +- if (!match_aliases) ++ if (!match_name) + return 1; + + /* Check if symlink name is in the set of names used by [Install] */ +@@ -872,7 +889,12 @@ static int find_symlinks( + continue; + } + +- r = find_symlinks_in_directory(d, path, root_dir, i, match_name, ignore_same_name, config_path, same_name_link); ++ r = find_symlinks_in_directory(d, path, root_dir, i, ++ /* ignore_destination= */ true, ++ /* match_name= */ match_name, ++ /* ignore_same_name= */ ignore_same_name, ++ config_path, ++ same_name_link); + if (r > 0) + return 1; + else if (r < 0) +@@ -881,7 +903,12 @@ static int find_symlinks( + + /* We didn't find any suitable symlinks in .wants or .requires directories, let's look for linked unit files in this directory. */ + rewinddir(config_dir); +- return find_symlinks_in_directory(config_dir, config_path, root_dir, i, match_name, ignore_same_name, config_path, same_name_link); ++ return find_symlinks_in_directory(config_dir, config_path, root_dir, i, ++ /* ignore_destination= */ false, ++ /* match_name= */ match_name, ++ /* ignore_same_name= */ ignore_same_name, ++ config_path, ++ same_name_link); + } + + static int find_symlinks_in_scope( diff --git a/0195-shared-install-stop-passing-duplicate-root-argument-.patch b/0195-shared-install-stop-passing-duplicate-root-argument-.patch new file mode 100644 index 0000000..29bd4e3 --- /dev/null +++ b/0195-shared-install-stop-passing-duplicate-root-argument-.patch @@ -0,0 +1,111 @@ +From 0d19f19be9a93642f10b4c039aafd9e62f35e8fc Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Thu, 17 Mar 2022 10:16:30 +0100 +Subject: [PATCH] shared/install: stop passing duplicate root argument to + install_name_printf() + +All callers were just passing info + info->root, we can simplify this. + +(cherry picked from commit 38e8a6c7fdffd3389cb3596139b1309579193946) + +Related: #2082131 +--- + src/shared/install-printf.c | 7 +++---- + src/shared/install-printf.h | 3 +-- + src/shared/install.c | 8 ++++---- + src/test/test-load-fragment.c | 2 +- + 4 files changed, 9 insertions(+), 11 deletions(-) + +diff --git a/src/shared/install-printf.c b/src/shared/install-printf.c +index 963102674b..7aad1b7443 100644 +--- a/src/shared/install-printf.c ++++ b/src/shared/install-printf.c +@@ -105,9 +105,8 @@ static int specifier_last_component(char specifier, const void *data, const char + + int install_name_printf( + UnitFileScope scope, +- const UnitFileInstallInfo *i, ++ const UnitFileInstallInfo *info, + const char *format, +- const char *root, + char **ret) { + /* This is similar to unit_name_printf() */ + +@@ -124,9 +123,9 @@ int install_name_printf( + {} + }; + +- assert(i); ++ assert(info); + assert(format); + assert(ret); + +- return specifier_printf(format, UNIT_NAME_MAX, table, root, i, ret); ++ return specifier_printf(format, UNIT_NAME_MAX, table, info->root, info, ret); + } +diff --git a/src/shared/install-printf.h b/src/shared/install-printf.h +index d2cccdf66d..60d3a9fc55 100644 +--- a/src/shared/install-printf.h ++++ b/src/shared/install-printf.h +@@ -6,7 +6,6 @@ + + int install_name_printf( + UnitFileScope scope, +- const UnitFileInstallInfo *i, ++ const UnitFileInstallInfo *info, + const char *format, +- const char *root, + char **ret); +diff --git a/src/shared/install.c b/src/shared/install.c +index a864039f44..f911d527df 100644 +--- a/src/shared/install.c ++++ b/src/shared/install.c +@@ -1205,7 +1205,7 @@ static int config_parse_also( + if (r == 0) + break; + +- r = install_name_printf(ctx->scope, info, word, info->root, &printed); ++ r = install_name_printf(ctx->scope, info, word, &printed); + if (r < 0) + return log_syntax(unit, LOG_WARNING, filename, line, r, + "Failed to resolve unit name in Also=\"%s\": %m", word); +@@ -1254,7 +1254,7 @@ static int config_parse_default_instance( + return log_syntax(unit, LOG_WARNING, filename, line, 0, + "DefaultInstance= only makes sense for template units, ignoring."); + +- r = install_name_printf(ctx->scope, info, rvalue, info->root, &printed); ++ r = install_name_printf(ctx->scope, info, rvalue, &printed); + if (r < 0) + return log_syntax(unit, LOG_WARNING, filename, line, r, + "Failed to resolve instance name in DefaultInstance=\"%s\": %m", rvalue); +@@ -1850,7 +1850,7 @@ static int install_info_symlink_alias( + STRV_FOREACH(s, info->aliases) { + _cleanup_free_ char *alias_path = NULL, *dst = NULL, *dst_updated = NULL; + +- q = install_name_printf(scope, info, *s, info->root, &dst); ++ q = install_name_printf(scope, info, *s, &dst); + if (q < 0) { + unit_file_changes_add(changes, n_changes, q, *s, NULL); + r = r < 0 ? r : q; +@@ -1940,7 +1940,7 @@ static int install_info_symlink_wants( + STRV_FOREACH(s, list) { + _cleanup_free_ char *dst = NULL; + +- q = install_name_printf(scope, info, *s, info->root, &dst); ++ q = install_name_printf(scope, info, *s, &dst); + if (q < 0) { + unit_file_changes_add(changes, n_changes, q, *s, NULL); + return q; +diff --git a/src/test/test-load-fragment.c b/src/test/test-load-fragment.c +index 9df53cec2b..a87c654f4e 100644 +--- a/src/test/test-load-fragment.c ++++ b/src/test/test-load-fragment.c +@@ -531,7 +531,7 @@ TEST(install_printf, .sd_booted = true) { + _cleanup_free_ char *t = NULL, \ + *d1 = ASSERT_PTR(strdup(i.name)), \ + *d2 = ASSERT_PTR(strdup(i.path)); \ +- int r = install_name_printf(scope, &src, pattern, NULL, &t); \ ++ int r = install_name_printf(scope, &src, pattern, &t); \ + assert_se(result ? r >= 0 : r < 0); \ + memzero(i.name, strlen(i.name)); \ + memzero(i.path, strlen(i.path)); \ diff --git a/0196-basic-unit-file-reverse-negative-conditional.patch b/0196-basic-unit-file-reverse-negative-conditional.patch new file mode 100644 index 0000000..633fcd4 --- /dev/null +++ b/0196-basic-unit-file-reverse-negative-conditional.patch @@ -0,0 +1,70 @@ +From 4ac4cc6e4b17dea8f071e260cd8d3eae68ba883d Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Thu, 17 Mar 2022 11:46:03 +0100 +Subject: [PATCH] basic/unit-file: reverse negative conditional + +Having the reverse condition first makes changes that I want to do +later awkward, so reverse it as a separate step first. + +(cherry picked from commit bd177c62158df97785af0d360c4fc9c266311d88) + +Related: #2082131 +--- + src/basic/unit-file.c | 32 ++++++++++++++++---------------- + 1 file changed, 16 insertions(+), 16 deletions(-) + +diff --git a/src/basic/unit-file.c b/src/basic/unit-file.c +index 6cf66b45cf..2474648ceb 100644 +--- a/src/basic/unit-file.c ++++ b/src/basic/unit-file.c +@@ -326,27 +326,16 @@ int unit_file_resolve_symlink( + + assert(path_is_absolute(simplified)); + +- /* Check if the symlink goes outside of our search path. +- * If yes, it's a linked unit file or mask, and we don't care about the target name ++ /* Check if the symlink remain inside of of our search path. ++ * If yes, it is an alias. Verify that it is valid. ++ * ++ * If no, then this is a linked unit file or mask, and we don't care about the target name + * when loading units, and we return the link *source* (resolve_destination_target == false); + * When this is called for installation purposes, we want the final destination, + * so we return the *target*. +- * +- * Otherwise, let's verify that it's a good alias. + */ + const char *tail = path_startswith_strv(simplified, search_path); +- if (!tail) { +- log_debug("Linked unit file: %s/%s → %s", dir, filename, simplified); +- +- if (resolve_destination_target) +- dst = TAKE_PTR(simplified); +- else { +- dst = path_join(dir, filename); +- if (!dst) +- return log_oom(); +- } +- +- } else { ++ if (tail) { /* An alias */ + _cleanup_free_ char *target_name = NULL; + + r = path_extract_filename(simplified, &target_name); +@@ -361,6 +350,17 @@ int unit_file_resolve_symlink( + dir, filename, simplified); + + dst = resolve_destination_target ? TAKE_PTR(simplified) : TAKE_PTR(target_name); ++ ++ } else { ++ log_debug("Linked unit file: %s/%s → %s", dir, filename, simplified); ++ ++ if (resolve_destination_target) ++ dst = TAKE_PTR(simplified); ++ else { ++ dst = path_join(dir, filename); ++ if (!dst) ++ return log_oom(); ++ } + } + + *ret_destination = TAKE_PTR(dst); diff --git a/0197-shared-install-split-UNIT_FILE_SYMLINK-into-two-stat.patch b/0197-shared-install-split-UNIT_FILE_SYMLINK-into-two-stat.patch new file mode 100644 index 0000000..f5b972c --- /dev/null +++ b/0197-shared-install-split-UNIT_FILE_SYMLINK-into-two-stat.patch @@ -0,0 +1,109 @@ +From e2d699c92944c6251f9de161c9e3ae93d915c4e0 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Thu, 17 Mar 2022 15:50:16 +0100 +Subject: [PATCH] shared/install: split UNIT_FILE_SYMLINK into two states + +The two states are distinguished, but are treated everywhere identically, +so there is no difference in behaviour except for slighlty different log +output. + +(cherry picked from commit 48ed75adabef3427767038fa155e55b3b0d48f35) + +Related: #2082131 +--- + src/basic/unit-file.c | 6 ++++-- + src/shared/install.c | 14 +++++++++----- + src/shared/install.h | 3 ++- + 3 files changed, 15 insertions(+), 8 deletions(-) + +diff --git a/src/basic/unit-file.c b/src/basic/unit-file.c +index 2474648ceb..7c1ae515e1 100644 +--- a/src/basic/unit-file.c ++++ b/src/basic/unit-file.c +@@ -282,7 +282,9 @@ int unit_file_resolve_symlink( + * + * If resolve_destination_target is true, an absolute path will be returned. + * If not, an absolute path is returned for linked unit files, and a relative +- * path otherwise. */ ++ * path otherwise. ++ * ++ * Returns an error, false if this is an alias, true if it's a linked unit file. */ + + assert(filename); + assert(ret_destination); +@@ -364,7 +366,7 @@ int unit_file_resolve_symlink( + } + + *ret_destination = TAKE_PTR(dst); +- return 0; ++ return !tail; /* true if linked unit file */ + } + + int unit_file_build_name_map( +diff --git a/src/shared/install.c b/src/shared/install.c +index f911d527df..b33f7d4bc1 100644 +--- a/src/shared/install.c ++++ b/src/shared/install.c +@@ -93,8 +93,9 @@ void unit_file_presets_freep(UnitFilePresets *p) { + + static const char *const unit_file_type_table[_UNIT_FILE_TYPE_MAX] = { + [UNIT_FILE_TYPE_REGULAR] = "regular", +- [UNIT_FILE_TYPE_SYMLINK] = "symlink", +- [UNIT_FILE_TYPE_MASKED] = "masked", ++ [UNIT_FILE_TYPE_LINKED] = "linked", ++ [UNIT_FILE_TYPE_ALIAS] = "alias", ++ [UNIT_FILE_TYPE_MASKED] = "masked", + }; + + DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(unit_file_type, UnitFileType); +@@ -1404,14 +1405,17 @@ static int unit_file_load_or_readlink( + true, &info->symlink_target); + if (r < 0) + return r; ++ bool outside_search_path = r > 0; + + r = null_or_empty_path_with_root(info->symlink_target, lp->root_dir); + if (r < 0 && r != -ENOENT) + return log_debug_errno(r, "Failed to stat %s: %m", info->symlink_target); + if (r > 0) + info->type = UNIT_FILE_TYPE_MASKED; ++ else if (outside_search_path) ++ info->type = UNIT_FILE_TYPE_LINKED; + else +- info->type = UNIT_FILE_TYPE_SYMLINK; ++ info->type = UNIT_FILE_TYPE_ALIAS; + + return 0; + } +@@ -1550,7 +1554,7 @@ static int install_info_follow( + assert(ctx); + assert(info); + +- if (info->type != UNIT_FILE_TYPE_SYMLINK) ++ if (!IN_SET(info->type, UNIT_FILE_TYPE_ALIAS, UNIT_FILE_TYPE_LINKED)) + return -EINVAL; + if (!info->symlink_target) + return -EINVAL; +@@ -1591,7 +1595,7 @@ static int install_info_traverse( + return r; + + i = start; +- while (i->type == UNIT_FILE_TYPE_SYMLINK) { ++ while (IN_SET(i->type, UNIT_FILE_TYPE_ALIAS, UNIT_FILE_TYPE_LINKED)) { + /* Follow the symlink */ + + if (++k > UNIT_FILE_FOLLOW_SYMLINK_MAX) +diff --git a/src/shared/install.h b/src/shared/install.h +index dba6987406..95427537f2 100644 +--- a/src/shared/install.h ++++ b/src/shared/install.h +@@ -70,7 +70,8 @@ struct UnitFileList { + + enum UnitFileType { + UNIT_FILE_TYPE_REGULAR, +- UNIT_FILE_TYPE_SYMLINK, ++ UNIT_FILE_TYPE_LINKED, ++ UNIT_FILE_TYPE_ALIAS, + UNIT_FILE_TYPE_MASKED, + _UNIT_FILE_TYPE_MAX, + _UNIT_FILE_TYPE_INVALID = -EINVAL, diff --git a/0198-shared-install-fix-handling-of-a-linked-unit-file.patch b/0198-shared-install-fix-handling-of-a-linked-unit-file.patch new file mode 100644 index 0000000..b22a45a --- /dev/null +++ b/0198-shared-install-fix-handling-of-a-linked-unit-file.patch @@ -0,0 +1,57 @@ +From 13c099caa9ae0389423c403152952c3c548fd146 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Thu, 17 Mar 2022 16:02:10 +0100 +Subject: [PATCH] shared/install: fix handling of a linked unit file + +When we have a symlink that goes outside of our search path, we should just +ignore the target file name. But we were verifying it, and rejecting in +the case where a symlink was created manually. + +(cherry picked from commit 48eadb9d9b66f302cda09cdf6d35fead31aaa968) + +Related: #2082131 +--- + src/shared/install.c | 4 +++- + test/test-systemctl-enable.sh | 12 ++++++++---- + 2 files changed, 11 insertions(+), 5 deletions(-) + +diff --git a/src/shared/install.c b/src/shared/install.c +index b33f7d4bc1..d6951b805d 100644 +--- a/src/shared/install.c ++++ b/src/shared/install.c +@@ -1609,7 +1609,9 @@ static int install_info_traverse( + return -ELOOP; + } + +- r = install_info_follow(ctx, i, lp, flags, false); ++ r = install_info_follow(ctx, i, lp, flags, ++ /* If linked, don't look at the target name */ ++ /* ignore_different_name= */ i->type == UNIT_FILE_TYPE_LINKED); + if (r == -EXDEV) { + _cleanup_free_ char *buffer = NULL; + const char *bn; +diff --git a/test/test-systemctl-enable.sh b/test/test-systemctl-enable.sh +index 9463433c5b..45f3513de3 100644 +--- a/test/test-systemctl-enable.sh ++++ b/test/test-systemctl-enable.sh +@@ -216,12 +216,16 @@ cat >"$root/link3.suffix" < +Date: Thu, 24 Mar 2022 11:52:35 +0100 +Subject: [PATCH] test-systemctl-enable: make shellcheck happy + +Quoting is not necessary in many places, but I think it's nicer +to use it consistently. + +(cherry picked from commit 84fdced62c740a3b07656e84747dd721ad6a30c5) + +Related: #2082131 +--- + test/test-systemctl-enable.sh | 76 +++++++++++++++++------------------ + 1 file changed, 38 insertions(+), 38 deletions(-) + +diff --git a/test/test-systemctl-enable.sh b/test/test-systemctl-enable.sh +index 45f3513de3..3b30f090a5 100644 +--- a/test/test-systemctl-enable.sh ++++ b/test/test-systemctl-enable.sh +@@ -19,10 +19,10 @@ islink() { + test "$(readlink "$1")" = "$2" || return 2 + } + +-: ------enablement nonexistent-------------------------------- ++: '------enable nonexistent------------------------------------' + "$systemctl" --root="$root" enable test1.service && { echo "Expected failure" >&2; exit 1; } + +-: ------basic enablement-------------------------------------- ++: '------basic enablement--------------------------------------' + mkdir -p "$root/etc/systemd/system" + cat >"$root/etc/systemd/system/test1.service" <>"$root/etc/systemd/system/test1.service" <&2; exit 1; } + islink "$root/etc/systemd/system/default.target.wants/test1.service" "../test1.service" + islink "$root/etc/systemd/system/test1-goodalias.service" "test1.service" +@@ -90,7 +90,7 @@ test ! -h "$root/etc/systemd/system/default.target.wants/test1.service" + test ! -h "$root/etc/systemd/system/special.target.requires/test1.service" + test ! -h "$root/etc/systemd/system/test1-goodalias.service" + +-: -------also units------------------------------------------- ++: '-------also units-------------------------------------------' + cat >"$root/etc/systemd/system/test2.socket" <&2; exit 1; } +@@ -130,65 +130,65 @@ EOF + "$systemctl" --root="$root" link '/link1.path' + islink "$root/etc/systemd/system/link1.path" "/link1.path" + +-: -------link already linked same path------------------------ ++: '-------link already linked same path------------------------' + SYSTEMD_LOG_LEVEL=debug "$systemctl" --root="$root" link '/link1.path' # this passes + islink "$root/etc/systemd/system/link1.path" "/link1.path" + +-: -------link already linked different path------------------- ++: '-------link already linked different path-------------------' + mkdir "$root/subdir" + cp "$root/link1.path" "$root/subdir/" + "$systemctl" --root="$root" link '/subdir/link1.path' && { echo "Expected failure" >&2; exit 1; } + islink "$root/etc/systemd/system/link1.path" "/link1.path" + +-: -------link bad suffix-------------------------------------- ++: '-------link bad suffix--------------------------------------' + cp "$root/link1.path" "$root/subdir/link1.suffix" + "$systemctl" --root="$root" link '/subdir/link1.suffix' && { echo "Expected failure" >&2; exit 1; } + test ! -e "$root/etc/systemd/system/link1.suffix" + +-: -------unlink by unit name---------------------------------- ++: '-------unlink by unit name----------------------------------' + "$systemctl" --root="$root" disable 'link1.path' + test ! -e "$root/etc/systemd/system/link1.path" + +-: -------unlink by path--------------------------------------- ++: '-------unlink by path---------------------------------------' + "$systemctl" --root="$root" link '/link1.path' + test -h "$root/etc/systemd/system/link1.path" + "$systemctl" --root="$root" disable '/link1.path' + test ! -e "$root/etc/systemd/system/link1.path" + +-: -------unlink by wrong path--------------------------------- ++: '-------unlink by wrong path---------------------------------' + "$systemctl" --root="$root" link '/link1.path' + test -h "$root/etc/systemd/system/link1.path" + "$systemctl" --root="$root" disable '/subdir/link1.path' # we only care about the name + test ! -e "$root/etc/systemd/system/link1.path" + + +-: -------link and enable-------------------------------------- ++: '-------link and enable--------------------------------------' + "$systemctl" --root="$root" enable '/link1.path' + islink "$root/etc/systemd/system/link1.path" "/link1.path" + islink "$root/etc/systemd/system/paths.target.wants/link1.path" "../link1.path" + +-: -------enable already linked same path---------------------- ++: '-------enable already linked same path----------------------' + "$systemctl" --root="$root" enable '/link1.path' + islink "$root/etc/systemd/system/link1.path" "/link1.path" + islink "$root/etc/systemd/system/paths.target.wants/link1.path" "../link1.path" + +-: -------enable already linked different path----------------- ++: '-------enable already linked different path-----------------' + "$systemctl" --root="$root" enable '/subdir/link1.path' && { echo "Expected failure" >&2; exit 1; } + islink "$root/etc/systemd/system/link1.path" "/link1.path" + islink "$root/etc/systemd/system/paths.target.wants/link1.path" "../link1.path" + +-: -------enable bad suffix------------------------------------ ++: '-------enable bad suffix------------------------------------' + cp "$root/link1.path" "$root/subdir/link1.suffix" + "$systemctl" --root="$root" enable '/subdir/link1.suffix' && { echo "Expected failure" >&2; exit 1; } + test ! -e "$root/etc/systemd/system/link1.suffix" + test ! -e "$root/etc/systemd/system/paths.target.wants/link1.suffix" + +-: -------disable by unit name--------------------------------- ++: '-------disable by unit name---------------------------------' + "$systemctl" --root="$root" disable 'link1.path' + test ! -e "$root/etc/systemd/system/link1.path" + test ! -e "$root/etc/systemd/system/paths.target.wants/link1.path" + +-: -------disable by path-------------------------------------- ++: '-------disable by path--------------------------------------' + "$systemctl" --root="$root" enable '/link1.path' + test -h "$root/etc/systemd/system/link1.path" + test -h "$root/etc/systemd/system/paths.target.wants/link1.path" +@@ -197,7 +197,7 @@ test ! -e "$root/etc/systemd/system/link1.path" + test ! -e "$root/etc/systemd/system/paths.target.wants/link1.path" + + +-: -------link then enable------------------------------------- ++: '-------link and enable-------------------------------------' + "$systemctl" --root="$root" link '/link1.path' + islink "$root/etc/systemd/system/link1.path" "/link1.path" + test ! -h "$root/etc/systemd/system/paths.target.wants/link1.path" +@@ -210,7 +210,7 @@ islink "$root/etc/systemd/system/paths.target.wants/link1.path" "../link1.path" + islink "$root/etc/systemd/system/link1.path" "/link1.path" + islink "$root/etc/systemd/system/paths.target.wants/link1.path" "../link1.path" + +-: -------manual link------------------------------------------ ++: '-------manual link------------------------------------------' + cat >"$root/link3.suffix" <&2; exit 1; } + "$systemctl" --root="$root" enable '/etc/systemd/system/masked.service' && { echo "Expected failure" >&2; exit 1; } + +-: -------enable on masked alias------------------------------- ++: '-------enable on masked alias-------------------------------' + test -h "$root/etc/systemd/system/masked.service" + ln -s "masked.service" "$root/etc/systemd/system/masked-alias.service" + "$systemctl" --root="$root" enable 'masked-alias.service' && { echo "Expected failure" >&2; exit 1; } + "$systemctl" --root="$root" enable '/etc/systemd/system/masked-alias.service' && { echo "Expected failure" >&2; exit 1; } + +-: -------issue 22000: link in subdirectory-------------------- ++: '-------issue 22000: link in subdirectory--------------------' + mkdir -p "$root/etc/systemd/system/myown.d" + cat >"$root/etc/systemd/system/link5-also.service" <"$root/etc/systemd/system/templ1@.service" <"$root/etc/systemd/system/templ1@.service" <"$root/etc/systemd/system/templ2@.service" <"$root/etc/systemd/system/link4.service" <"$root/etc/systemd/system/link4.service" <"$root/etc/systemd/system/link5.service" <"$root/link5copy.service" <"$root/etc/systemd/system/link5@.path" <"$root/etc/systemd/system/multilink.mount" <"$root/etc/systemd/system/some-some-link6@.socket" <&2; exit 1; } + +-: -------specifiers in WantedBy------------------------------- ++: '-------specifiers in WantedBy-------------------------------' + # We don't need to repeat all the tests. Let's do a basic check that specifier + # expansion is performed. + +@@ -642,7 +642,7 @@ test ! -h "$root/etc/systemd/system/another-target2@.target.requires/some-some-l + + # TODO: repeat the tests above for presets + +-: -------SYSTEMD_OS_RELEASE relative to root------------------ ++: '-------SYSTEMD_OS_RELEASE relative to root-------------------' + # check that os-release overwriting works as expected with root + test -e "$root/etc/os-release" + diff --git a/0200-shared-install-when-creating-symlinks-accept-differe.patch b/0200-shared-install-when-creating-symlinks-accept-differe.patch new file mode 100644 index 0000000..ced8871 --- /dev/null +++ b/0200-shared-install-when-creating-symlinks-accept-differe.patch @@ -0,0 +1,176 @@ +From 56bc8e8eef5fcbfcf72dd1b3caa56b9186e1011d Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Fri, 25 Mar 2022 15:43:27 +0100 +Subject: [PATCH] shared/install: when creating symlinks, accept different but + equivalent symlinks +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +We would only accept "identical" links, but having e.g. a symlink +/usr/lib/systemd/system/foo-alias.service → /usr/lib/systemd/system/foo.service +when we're trying to create /usr/lib/systemd/system/foo-alias.service → +./foo.service is OK. This fixes an issue found in ubuntuautopkg package +installation, where we'd fail when enabling systemd-resolved.service, because +the existing alias was absolute, and (with the recent patches) we were trying +to create a relative one. + +A test is added. +(For .wants/.requires symlinks we were already doing OK. A test is also +added, to verify.) + +(cherry picked from commit 3fc53351dc8f37355f5a4ee8f922d3e13a5182c2) + +Related: #2082131 +--- + src/shared/install.c | 59 ++++++++++++++++++++++++++--------- + test/test-systemctl-enable.sh | 39 +++++++++++++++++++++-- + 2 files changed, 81 insertions(+), 17 deletions(-) + +diff --git a/src/shared/install.c b/src/shared/install.c +index d6951b805d..22b16ad453 100644 +--- a/src/shared/install.c ++++ b/src/shared/install.c +@@ -423,21 +423,54 @@ void unit_file_dump_changes(int r, const char *verb, const UnitFileChange *chang + } + + /** +- * Checks if two paths or symlinks from wd are the same, when root is the root of the filesystem. +- * wc should be the full path in the host file system. ++ * Checks if two symlink targets (starting from src) are equivalent as far as the unit enablement logic is ++ * concerned. If the target is in the unit search path, then anything with the same name is equivalent. ++ * If outside the unit search path, paths must be identical. + */ +-static bool chroot_symlinks_same(const char *root, const char *wd, const char *a, const char *b) { +- assert(path_is_absolute(wd)); ++static int chroot_unit_symlinks_equivalent( ++ const LookupPaths *lp, ++ const char *src, ++ const char *target_a, ++ const char *target_b) { ++ ++ assert(lp); ++ assert(src); ++ assert(target_a); ++ assert(target_b); + + /* This will give incorrect results if the paths are relative and go outside + * of the chroot. False negatives are possible. */ + +- if (!root) +- root = "/"; ++ const char *root = lp->root_dir ?: "/"; ++ _cleanup_free_ char *dirname = NULL; ++ int r; ++ ++ if (!path_is_absolute(target_a) || !path_is_absolute(target_b)) { ++ r = path_extract_directory(src, &dirname); ++ if (r < 0) ++ return r; ++ } + +- a = strjoina(path_is_absolute(a) ? root : wd, "/", a); +- b = strjoina(path_is_absolute(b) ? root : wd, "/", b); +- return path_equal_or_files_same(a, b, 0); ++ _cleanup_free_ char *a = path_join(path_is_absolute(target_a) ? root : dirname, target_a); ++ _cleanup_free_ char *b = path_join(path_is_absolute(target_b) ? root : dirname, target_b); ++ if (!a || !b) ++ return log_oom(); ++ ++ r = path_equal_or_files_same(a, b, 0); ++ if (r != 0) ++ return r; ++ ++ _cleanup_free_ char *a_name = NULL, *b_name = NULL; ++ r = path_extract_filename(a, &a_name); ++ if (r < 0) ++ return r; ++ r = path_extract_filename(b, &b_name); ++ if (r < 0) ++ return r; ++ ++ return streq(a_name, b_name) && ++ path_startswith_strv(a, lp->search_path) && ++ path_startswith_strv(b, lp->search_path); + } + + static int create_symlink( +@@ -448,7 +481,7 @@ static int create_symlink( + UnitFileChange **changes, + size_t *n_changes) { + +- _cleanup_free_ char *dest = NULL, *dirname = NULL; ++ _cleanup_free_ char *dest = NULL; + const char *rp; + int r; + +@@ -489,11 +522,7 @@ static int create_symlink( + return r; + } + +- dirname = dirname_malloc(new_path); +- if (!dirname) +- return -ENOMEM; +- +- if (chroot_symlinks_same(lp->root_dir, dirname, dest, old_path)) { ++ if (chroot_unit_symlinks_equivalent(lp, new_path, dest, old_path)) { + log_debug("Symlink %s → %s already exists", new_path, dest); + return 1; + } +diff --git a/test/test-systemctl-enable.sh b/test/test-systemctl-enable.sh +index 3b30f090a5..0f66af309a 100644 +--- a/test/test-systemctl-enable.sh ++++ b/test/test-systemctl-enable.sh +@@ -39,8 +39,29 @@ test -h "$root/etc/systemd/system/default.target.wants/test1.service" + test -h "$root/etc/systemd/system/special.target.requires/test1.service" + + "$systemctl" --root="$root" disable test1.service +-test ! -e "$root/etc/systemd/system/default.target.wants/test1.service" +-test ! -e "$root/etc/systemd/system/special.target.requires/test1.service" ++test ! -h "$root/etc/systemd/system/default.target.wants/test1.service" ++test ! -h "$root/etc/systemd/system/special.target.requires/test1.service" ++ ++: '------enable when link already exists-----------------------' ++# We don't read the symlink target, so it's OK for the symlink to point ++# to something else. We should just silently accept this. ++ ++mkdir -p "$root/etc/systemd/system/default.target.wants" ++mkdir -p "$root/etc/systemd/system/special.target.requires" ++ln -s /usr/lib/systemd/system/test1.service "$root/etc/systemd/system/default.target.wants/test1.service" ++ln -s /usr/lib/systemd/system/test1.service "$root/etc/systemd/system/special.target.requires/test1.service" ++ ++"$systemctl" --root="$root" enable test1.service ++test -h "$root/etc/systemd/system/default.target.wants/test1.service" ++test -h "$root/etc/systemd/system/special.target.requires/test1.service" ++ ++"$systemctl" --root="$root" reenable test1.service ++test -h "$root/etc/systemd/system/default.target.wants/test1.service" ++test -h "$root/etc/systemd/system/special.target.requires/test1.service" ++ ++"$systemctl" --root="$root" disable test1.service ++test ! -h "$root/etc/systemd/system/default.target.wants/test1.service" ++test ! -h "$root/etc/systemd/system/special.target.requires/test1.service" + + : '------suffix guessing---------------------------------------' + "$systemctl" --root="$root" enable test1 +@@ -90,6 +111,20 @@ test ! -h "$root/etc/systemd/system/default.target.wants/test1.service" + test ! -h "$root/etc/systemd/system/special.target.requires/test1.service" + test ! -h "$root/etc/systemd/system/test1-goodalias.service" + ++: '-------aliases when link already exists---------------------' ++cat >"$root/etc/systemd/system/test1a.service" <"$root/etc/systemd/system/test2.socket" < +Date: Fri, 25 Mar 2022 15:56:16 +0100 +Subject: [PATCH] test-systemctl-enable: use magic syntax to allow inverted + tests +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Inspired by 7910ec3bcde2ee0086b3e49f8aaa2a9f13f58d97. +'! true' passes, because it's a conditional expression. +But '( ! true )' fails, because '( … )' creates a subshell, i.e. a separate +program, and '! true' becomes the return value of that program, and the whole +thing apparently is not a conditional expression for the outer shell. + +This is shorter, so let's just do this. + +(cherry picked from commit d6c51c485abe0026a5da654fca5d6c1457c4587d) + +Related: #2082131 +--- + test/test-systemctl-enable.sh | 76 ++++++++++++++++++----------------- + 1 file changed, 39 insertions(+), 37 deletions(-) + +diff --git a/test/test-systemctl-enable.sh b/test/test-systemctl-enable.sh +index 0f66af309a..ecb433380e 100644 +--- a/test/test-systemctl-enable.sh ++++ b/test/test-systemctl-enable.sh +@@ -20,7 +20,7 @@ islink() { + } + + : '------enable nonexistent------------------------------------' +-"$systemctl" --root="$root" enable test1.service && { echo "Expected failure" >&2; exit 1; } ++( ! "$systemctl" --root="$root" enable test1.service ) + + : '------basic enablement--------------------------------------' + mkdir -p "$root/etc/systemd/system" +@@ -86,7 +86,7 @@ Alias=test1-badalias.socket + Alias=test1-goodalias2.service + EOF + +-"$systemctl" --root="$root" enable test1 && { echo "Expected failure" >&2; exit 1; } ++( ! "$systemctl" --root="$root" enable test1 ) + test -h "$root/etc/systemd/system/default.target.wants/test1.service" + test -h "$root/etc/systemd/system/special.target.requires/test1.service" + test -e "$root/etc/systemd/system/test1-goodalias.service" +@@ -98,7 +98,7 @@ test -e "$root/etc/systemd/system/test1-goodalias2.service" + test -h "$root/etc/systemd/system/test1-goodalias2.service" + + : '-------aliases in reeanble----------------------------------' +-"$systemctl" --root="$root" reenable test1 && { echo "Expected failure" >&2; exit 1; } ++( ! "$systemctl" --root="$root" reenable test1 ) + islink "$root/etc/systemd/system/default.target.wants/test1.service" "../test1.service" + islink "$root/etc/systemd/system/test1-goodalias.service" "test1.service" + +@@ -154,7 +154,7 @@ test ! -e "$root/etc/systemd/system/sockets.target.wants/test2.socket" + : '-------link-------------------------------------------------' + # File doesn't exist yet + test ! -e "$root/link1.path" +-"$systemctl" --root="$root" link '/link1.path' && { echo "Expected failure" >&2; exit 1; } ++( ! "$systemctl" --root="$root" link '/link1.path' ) + test ! -e "$root/etc/systemd/system/link1.path" + + cat >"$root/link1.path" <&2; exit 1; } ++( ! "$systemctl" --root="$root" link '/subdir/link1.path' ) + islink "$root/etc/systemd/system/link1.path" "/link1.path" + + : '-------link bad suffix--------------------------------------' + cp "$root/link1.path" "$root/subdir/link1.suffix" +-"$systemctl" --root="$root" link '/subdir/link1.suffix' && { echo "Expected failure" >&2; exit 1; } ++( ! "$systemctl" --root="$root" link '/subdir/link1.suffix' ) + test ! -e "$root/etc/systemd/system/link1.suffix" + + : '-------unlink by unit name----------------------------------' +@@ -208,13 +208,13 @@ islink "$root/etc/systemd/system/link1.path" "/link1.path" + islink "$root/etc/systemd/system/paths.target.wants/link1.path" "../link1.path" + + : '-------enable already linked different path-----------------' +-"$systemctl" --root="$root" enable '/subdir/link1.path' && { echo "Expected failure" >&2; exit 1; } ++( ! "$systemctl" --root="$root" enable '/subdir/link1.path' ) + islink "$root/etc/systemd/system/link1.path" "/link1.path" + islink "$root/etc/systemd/system/paths.target.wants/link1.path" "../link1.path" + + : '-------enable bad suffix------------------------------------' + cp "$root/link1.path" "$root/subdir/link1.suffix" +-"$systemctl" --root="$root" enable '/subdir/link1.suffix' && { echo "Expected failure" >&2; exit 1; } ++( ! "$systemctl" --root="$root" enable '/subdir/link1.suffix' ) + test ! -e "$root/etc/systemd/system/link1.suffix" + test ! -e "$root/etc/systemd/system/paths.target.wants/link1.suffix" + +@@ -264,14 +264,14 @@ test ! -h "$root/etc/systemd/system/services.target.wants/link3.service" + + : '-------enable on masked-------------------------------------' + ln -s "/dev/null" "$root/etc/systemd/system/masked.service" +-"$systemctl" --root="$root" enable 'masked.service' && { echo "Expected failure" >&2; exit 1; } +-"$systemctl" --root="$root" enable '/etc/systemd/system/masked.service' && { echo "Expected failure" >&2; exit 1; } ++( ! "$systemctl" --root="$root" enable 'masked.service' ) ++( ! "$systemctl" --root="$root" enable '/etc/systemd/system/masked.service' ) + + : '-------enable on masked alias-------------------------------' + test -h "$root/etc/systemd/system/masked.service" + ln -s "masked.service" "$root/etc/systemd/system/masked-alias.service" +-"$systemctl" --root="$root" enable 'masked-alias.service' && { echo "Expected failure" >&2; exit 1; } +-"$systemctl" --root="$root" enable '/etc/systemd/system/masked-alias.service' && { echo "Expected failure" >&2; exit 1; } ++( ! "$systemctl" --root="$root" enable 'masked-alias.service' ) ++( ! "$systemctl" --root="$root" enable '/etc/systemd/system/masked-alias.service' ) + + : '-------issue 22000: link in subdirectory--------------------' + mkdir -p "$root/etc/systemd/system/myown.d" +@@ -286,7 +286,7 @@ WantedBy=services.target + Also=link5-also.service + EOF + +-"$systemctl" --root="$root" enable 'link5.service' && { echo "Expected failure" >&2; exit 1; } ++( ! "$systemctl" --root="$root" enable 'link5.service' ) + test ! -h "$root/etc/systemd/system/services.target.wants/link5.service" + test ! -h "$root/etc/systemd/system/services.target.wants/link5-also.service" + +@@ -301,7 +301,7 @@ WantedBy=services.target + EOF + + # No instance here — this can't succeed. +-"$systemctl" --root="$root" enable 'templ1@.service' && { echo "Expected failure" >&2; exit 1; } ++( ! "$systemctl" --root="$root" enable 'templ1@.service' ) + test ! -h "$root/etc/systemd/system/services.target.wants/templ1@.service" + + "$systemctl" --root="$root" enable 'templ1@one.service' +@@ -428,7 +428,7 @@ Alias=link4alias.service + Alias=link4alias2.service + EOF + +-"$systemctl" --root="$root" enable 'link4.service' && { echo "Expected failure" >&2; exit 1; } ++( ! "$systemctl" --root="$root" enable 'link4.service' ) + test ! -h "$root/etc/systemd/system/link4.service" # this is our file + test ! -h "$root/etc/systemd/system/link4@.service" + test ! -h "$root/etc/systemd/system/link4@inst.service" +@@ -571,12 +571,12 @@ check_alias a "$(uname -m | tr '_' '-')" + test ! -e "$root/etc/os-release" + test ! -e "$root/usr/lib/os-release" + +-check_alias A '' && { echo "Expected failure" >&2; exit 1; } +-check_alias B '' && { echo "Expected failure" >&2; exit 1; } +-check_alias M '' && { echo "Expected failure" >&2; exit 1; } +-check_alias o '' && { echo "Expected failure" >&2; exit 1; } +-check_alias w '' && { echo "Expected failure" >&2; exit 1; } +-check_alias W '' && { echo "Expected failure" >&2; exit 1; } ++( ! check_alias A '' ) ++( ! check_alias B '' ) ++( ! check_alias M '' ) ++( ! check_alias o '' ) ++( ! check_alias w '' ) ++( ! check_alias W '' ) + + cat >"$root/etc/os-release" <&2; exit 1; } +-check_alias E '' && { echo "Expected failure" >&2; exit 1; } +-check_alias f '' && { echo "Expected failure" >&2; exit 1; } +-check_alias h '' && { echo "Expected failure" >&2; exit 1; } +-check_alias I '' && { echo "Expected failure" >&2; exit 1; } +-check_alias J '' && { echo "Expected failure" >&2; exit 1; } +-check_alias L '' && { echo "Expected failure" >&2; exit 1; } +-check_alias P '' && { echo "Expected failure" >&2; exit 1; } +-check_alias s '' && { echo "Expected failure" >&2; exit 1; } +-check_alias S '' && { echo "Expected failure" >&2; exit 1; } +-check_alias t '' && { echo "Expected failure" >&2; exit 1; } +-check_alias T '' && { echo "Expected failure" >&2; exit 1; } +-check_alias V '' && { echo "Expected failure" >&2; exit 1; } ++( ! check_alias C '' ) ++( ! check_alias E '' ) ++( ! check_alias f '' ) ++( ! check_alias h '' ) ++( ! check_alias I '' ) ++( ! check_alias J '' ) ++( ! check_alias L '' ) ++( ! check_alias P '' ) ++( ! check_alias s '' ) ++( ! check_alias S '' ) ++( ! check_alias t '' ) ++( ! check_alias T '' ) ++( ! check_alias V '' ) + + check_alias g root + check_alias G 0 +@@ -635,7 +635,7 @@ check_alias j 'link6' + check_alias l "$(uname -n | sed 's/\..*//')" + + test ! -e "$root/etc/machine-id" +-check_alias m '' && { echo "Expected failure" >&2; exit 1; } ++( ! check_alias m '' ) + + systemd-id128 new >"$root/etc/machine-id" + check_alias m "$(cat "$root/etc/machine-id")" +@@ -647,9 +647,11 @@ check_alias p 'some-some-link6' + + check_alias v "$(uname -r)" + +-check_alias % '%' && { echo "Expected failure because % is not legal in unit name" >&2; exit 1; } ++# % is not legal in unit name ++( ! check_alias % '%' ) + +-check_alias z 'z' && { echo "Expected failure because %z is not known" >&2; exit 1; } ++# %z is not defined ++( ! check_alias z 'z' ) + + : '-------specifiers in WantedBy-------------------------------' + # We don't need to repeat all the tests. Let's do a basic check that specifier diff --git a/0202-test-systemctl-enable-also-use-freshly-built-systemd.patch b/0202-test-systemctl-enable-also-use-freshly-built-systemd.patch new file mode 100644 index 0000000..369d9d3 --- /dev/null +++ b/0202-test-systemctl-enable-also-use-freshly-built-systemd.patch @@ -0,0 +1,97 @@ +From 90fb011c43410958e5bda6f470137522f536adb4 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Mon, 28 Mar 2022 20:03:37 +0200 +Subject: [PATCH] test-systemctl-enable: also use freshly-built systemd-id128 + +Tests were failing on centos7 because systemd-id128 is not in path. + +(cherry picked from commit 2a2d002fb0913fe931b4ac903ca425a725aa79c0) + +Related: #2082131 +--- + meson.build | 21 ++++++++++++--------- + test/test-systemctl-enable.sh | 5 +++-- + 2 files changed, 15 insertions(+), 11 deletions(-) + +diff --git a/meson.build b/meson.build +index 005af872cf..4fc3e64e54 100644 +--- a/meson.build ++++ b/meson.build +@@ -2371,7 +2371,7 @@ public_programs += executable( + install_rpath : rootlibexecdir, + install : true) + +-exe = executable( ++systemctl = executable( + 'systemctl', + systemctl_sources, + include_directories : includes, +@@ -2385,13 +2385,7 @@ exe = executable( + install_rpath : rootlibexecdir, + install : true, + install_dir : rootbindir) +-public_programs += exe +-if want_tests != 'false' +- test('test-systemctl-enable', +- test_systemctl_enable_sh, +- # https://github.com/mesonbuild/meson/issues/2681 +- args : exe.full_path()) +-endif ++public_programs += systemctl + + if conf.get('ENABLE_PORTABLED') == 1 + dbus_programs += executable( +@@ -3188,13 +3182,22 @@ executable( + install : true, + install_dir : rootlibexecdir) + +-public_programs += executable( ++systemd_id128 = executable( + 'systemd-id128', + 'src/id128/id128.c', + include_directories : includes, + link_with : [libshared], + install_rpath : rootlibexecdir, + install : true) ++public_programs += systemd_id128 ++ ++if want_tests != 'false' ++ test('test-systemctl-enable', ++ test_systemctl_enable_sh, ++ # https://github.com/mesonbuild/meson/issues/2681 ++ args : [systemctl.full_path(), ++ systemd_id128.full_path()]) ++endif + + public_programs += executable( + 'systemd-path', +diff --git a/test/test-systemctl-enable.sh b/test/test-systemctl-enable.sh +index ecb433380e..8eb2828e35 100644 +--- a/test/test-systemctl-enable.sh ++++ b/test/test-systemctl-enable.sh +@@ -6,6 +6,7 @@ set -ex + export SYSTEMD_IGNORE_CHROOT=1 + + systemctl=${1:-systemctl} ++systemd_id128=${2:-systemd-id128} + + unset root + cleanup() { +@@ -606,7 +607,7 @@ check_alias o 'the-id' + check_alias w '39a' + check_alias W 'right' + +-check_alias b "$(systemd-id128 boot-id)" ++check_alias b "$("$systemd_id128" boot-id)" + + # Specifiers not available for [Install] + ( ! check_alias C '' ) +@@ -637,7 +638,7 @@ check_alias l "$(uname -n | sed 's/\..*//')" + test ! -e "$root/etc/machine-id" + ( ! check_alias m '' ) + +-systemd-id128 new >"$root/etc/machine-id" ++"$systemd_id128" new >"$root/etc/machine-id" + check_alias m "$(cat "$root/etc/machine-id")" + + check_alias n 'some-some-link6@.socket' diff --git a/0203-test-systemctl-enable-disable-the-test-for-a-for-now.patch b/0203-test-systemctl-enable-disable-the-test-for-a-for-now.patch new file mode 100644 index 0000000..8c95ce6 --- /dev/null +++ b/0203-test-systemctl-enable-disable-the-test-for-a-for-now.patch @@ -0,0 +1,27 @@ +From 9b0a2632fd060e0c7b13eabb5ad87f623237eef9 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Mon, 28 Mar 2022 20:20:09 +0200 +Subject: [PATCH] test-systemctl-enable: disable the test for %a for now + +(cherry picked from commit 5c29de29b43829ba09967b05ae2f136356c8c0d2) + +Related: #2082131 +--- + test/test-systemctl-enable.sh | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/test/test-systemctl-enable.sh b/test/test-systemctl-enable.sh +index 8eb2828e35..ac1bcc1cc7 100644 +--- a/test/test-systemctl-enable.sh ++++ b/test/test-systemctl-enable.sh +@@ -567,7 +567,9 @@ EOF + islink "$root/etc/systemd/system/target@$1:$2.socket" "some-some-link6@.socket" || return 2 + } + +-check_alias a "$(uname -m | tr '_' '-')" ++# TODO: our architecture names are different than what uname -m returns. ++# Add something like 'systemd-detect-virt --print-architecture' and use it here. ++check_alias a "$(uname -m | tr '_' '-')" || : + + test ! -e "$root/etc/os-release" + test ! -e "$root/usr/lib/os-release" diff --git a/0204-Rename-UnitFileScope-to-LookupScope.patch b/0204-Rename-UnitFileScope-to-LookupScope.patch new file mode 100644 index 0000000..5088923 --- /dev/null +++ b/0204-Rename-UnitFileScope-to-LookupScope.patch @@ -0,0 +1,3454 @@ +From c499122cb7ba5fe2f76760844cbc2e34cc3a5626 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Tue, 29 Mar 2022 15:55:59 +0200 +Subject: [PATCH] Rename UnitFileScope to LookupScope + +As suggested in +https://github.com/systemd/systemd/pull/22649/commits/8b3ad3983f5440eef812b34e5ed862ca59fdf7f7#r837345892 + +The define is generalized and moved to path-lookup.h, where it seems to fit +better. This allows a recursive include to be removed and in general makes +things simpler. + +(cherry picked from commit b380b6438361e39ad5076bfa58d2021621a957af) + +Related: #2082131 +--- + src/analyze/analyze-condition.c | 2 +- + src/analyze/analyze-condition.h | 2 +- + src/analyze/analyze-security.c | 4 +- + src/analyze/analyze-security.h | 2 +- + src/analyze/analyze-verify.c | 2 +- + src/analyze/analyze-verify.h | 2 +- + src/analyze/analyze.c | 24 +- + src/basic/path-lookup.c | 64 ++-- + src/basic/path-lookup.h | 21 +- + src/basic/unit-file.h | 11 +- + src/core/dbus-manager.c | 8 +- + src/core/fuzz-unit-file.c | 2 +- + src/core/main.c | 2 +- + src/core/manager.c | 6 +- + src/core/manager.h | 8 +- + src/libsystemd/sd-path/sd-path.c | 8 +- + src/portable/portable.c | 14 +- + src/shared/install-printf.c | 2 +- + src/shared/install-printf.h | 2 +- + src/shared/install.c | 92 ++--- + src/shared/install.h | 35 +- + src/shared/specifier.c | 26 +- + src/systemctl/systemctl-edit.c | 6 +- + src/systemctl/systemctl-is-enabled.c | 2 +- + src/systemctl/systemctl-show.c | 2 +- + src/systemctl/systemctl-start-special.c | 4 +- + src/systemctl/systemctl-start-unit.c | 6 +- + src/systemctl/systemctl-sysv-compat.c | 2 +- + src/systemctl/systemctl-util.c | 10 +- + src/systemctl/systemctl.c | 12 +- + src/systemctl/systemctl.h | 2 +- + src/sysv-generator/sysv-generator.c | 4 +- + src/test/test-bpf-firewall.c | 2 +- + src/test/test-bpf-foreign-programs.c | 2 +- + src/test/test-bpf-lsm.c | 2 +- + src/test/test-cgroup-mask.c | 2 +- + src/test/test-cgroup-unit-default.c | 2 +- + src/test/test-engine.c | 2 +- + src/test/test-execute.c | 10 +- + src/test/test-install-root.c | 448 ++++++++++++------------ + src/test/test-install.c | 72 ++-- + src/test/test-load-fragment.c | 96 ++--- + src/test/test-path-lookup.c | 30 +- + src/test/test-path.c | 2 +- + src/test/test-sched-prio.c | 2 +- + src/test/test-socket-bind.c | 2 +- + src/test/test-specifier.c | 2 +- + src/test/test-unit-file.c | 2 +- + src/test/test-unit-name.c | 2 +- + src/test/test-unit-serialize.c | 2 +- + src/test/test-watch-pid.c | 2 +- + src/tmpfiles/tmpfiles.c | 2 +- + 52 files changed, 536 insertions(+), 539 deletions(-) + +diff --git a/src/analyze/analyze-condition.c b/src/analyze/analyze-condition.c +index a7ad085f46..248fe01448 100644 +--- a/src/analyze/analyze-condition.c ++++ b/src/analyze/analyze-condition.c +@@ -73,7 +73,7 @@ static int log_helper(void *userdata, int level, int error, const char *file, in + return r; + } + +-int verify_conditions(char **lines, UnitFileScope scope, const char *unit, const char *root) { ++int verify_conditions(char **lines, LookupScope scope, const char *unit, const char *root) { + _cleanup_(manager_freep) Manager *m = NULL; + Unit *u; + int r, q = 1; +diff --git a/src/analyze/analyze-condition.h b/src/analyze/analyze-condition.h +index 9ebd205b6d..04bd853c4f 100644 +--- a/src/analyze/analyze-condition.h ++++ b/src/analyze/analyze-condition.h +@@ -3,4 +3,4 @@ + + #include "install.h" + +-int verify_conditions(char **lines, UnitFileScope scope, const char *unit, const char *root); ++int verify_conditions(char **lines, LookupScope scope, const char *unit, const char *root); +diff --git a/src/analyze/analyze-security.c b/src/analyze/analyze-security.c +index d8ccbf8c54..e112922cbf 100644 +--- a/src/analyze/analyze-security.c ++++ b/src/analyze/analyze-security.c +@@ -2643,7 +2643,7 @@ static int offline_security_check(Unit *u, + + static int offline_security_checks(char **filenames, + JsonVariant *policy, +- UnitFileScope scope, ++ LookupScope scope, + bool check_man, + bool run_generators, + unsigned threshold, +@@ -2755,7 +2755,7 @@ static int offline_security_checks(char **filenames, + int analyze_security(sd_bus *bus, + char **units, + JsonVariant *policy, +- UnitFileScope scope, ++ LookupScope scope, + bool check_man, + bool run_generators, + bool offline, +diff --git a/src/analyze/analyze-security.h b/src/analyze/analyze-security.h +index 07483248ee..99bc1fabe4 100644 +--- a/src/analyze/analyze-security.h ++++ b/src/analyze/analyze-security.h +@@ -18,7 +18,7 @@ typedef enum AnalyzeSecurityFlags { + int analyze_security(sd_bus *bus, + char **units, + JsonVariant *policy, +- UnitFileScope scope, ++ LookupScope scope, + bool check_man, + bool run_generators, + bool offline, +diff --git a/src/analyze/analyze-verify.c b/src/analyze/analyze-verify.c +index 39eb5cf93b..6680b9768d 100644 +--- a/src/analyze/analyze-verify.c ++++ b/src/analyze/analyze-verify.c +@@ -243,7 +243,7 @@ static void set_destroy_ignore_pointer_max(Set** s) { + set_free_free(*s); + } + +-int verify_units(char **filenames, UnitFileScope scope, bool check_man, bool run_generators, RecursiveErrors recursive_errors, const char *root) { ++int verify_units(char **filenames, LookupScope scope, bool check_man, bool run_generators, RecursiveErrors recursive_errors, const char *root) { + const ManagerTestRunFlags flags = + MANAGER_TEST_RUN_MINIMAL | + MANAGER_TEST_RUN_ENV_GENERATORS | +diff --git a/src/analyze/analyze-verify.h b/src/analyze/analyze-verify.h +index 47b78a8158..385d635e33 100644 +--- a/src/analyze/analyze-verify.h ++++ b/src/analyze/analyze-verify.h +@@ -17,7 +17,7 @@ typedef enum RecursiveErrors { + int verify_generate_path(char **var, char **filenames); + int verify_prepare_filename(const char *filename, char **ret); + int verify_executable(Unit *u, const ExecCommand *exec, const char *root); +-int verify_units(char **filenames, UnitFileScope scope, bool check_man, bool run_generators, RecursiveErrors recursive_errors, const char *root); ++int verify_units(char **filenames, LookupScope scope, bool check_man, bool run_generators, RecursiveErrors recursive_errors, const char *root); + + const char* recursive_errors_to_string(RecursiveErrors i) _const_; + RecursiveErrors recursive_errors_from_string(const char *s) _pure_; +diff --git a/src/analyze/analyze.c b/src/analyze/analyze.c +index 846acf31d3..7520134880 100644 +--- a/src/analyze/analyze.c ++++ b/src/analyze/analyze.c +@@ -92,7 +92,7 @@ static usec_t arg_fuzz = 0; + static PagerFlags arg_pager_flags = 0; + static BusTransport arg_transport = BUS_TRANSPORT_LOCAL; + static const char *arg_host = NULL; +-static UnitFileScope arg_scope = UNIT_FILE_SYSTEM; ++static LookupScope arg_scope = LOOKUP_SCOPE_SYSTEM; + static RecursiveErrors arg_recursive_errors = RECURSIVE_ERRORS_YES; + static bool arg_man = true; + static bool arg_generators = false; +@@ -171,7 +171,7 @@ typedef struct HostInfo { + } HostInfo; + + static int acquire_bus(sd_bus **bus, bool *use_full_bus) { +- bool user = arg_scope != UNIT_FILE_SYSTEM; ++ bool user = arg_scope != LOOKUP_SCOPE_SYSTEM; + int r; + + if (use_full_bus && *use_full_bus) { +@@ -349,9 +349,9 @@ static int acquire_boot_times(sd_bus *bus, BootTimes **bt) { + "Please try again later.\n" + "Hint: Use 'systemctl%s list-jobs' to see active jobs", + times.finish_time, +- arg_scope == UNIT_FILE_SYSTEM ? "" : " --user"); ++ arg_scope == LOOKUP_SCOPE_SYSTEM ? "" : " --user"); + +- if (arg_scope == UNIT_FILE_SYSTEM && times.security_start_time > 0) { ++ if (arg_scope == LOOKUP_SCOPE_SYSTEM && times.security_start_time > 0) { + /* security_start_time is set when systemd is not running under container environment. */ + if (times.initrd_time > 0) + times.kernel_done_time = times.initrd_time; +@@ -506,7 +506,7 @@ static int acquire_host_info(sd_bus *bus, HostInfo **hi) { + if (!host) + return log_oom(); + +- if (arg_scope != UNIT_FILE_SYSTEM) { ++ if (arg_scope != LOOKUP_SCOPE_SYSTEM) { + r = bus_connect_transport(arg_transport, arg_host, false, &system_bus); + if (r < 0) { + log_debug_errno(r, "Failed to connect to system bus, ignoring: %m"); +@@ -684,7 +684,7 @@ static int analyze_plot(int argc, char *argv[], void *userdata) { + _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL; + _cleanup_(unit_times_free_arrayp) UnitTimes *times = NULL; + _cleanup_free_ char *pretty_times = NULL; +- bool use_full_bus = arg_scope == UNIT_FILE_SYSTEM; ++ bool use_full_bus = arg_scope == LOOKUP_SCOPE_SYSTEM; + BootTimes *boot; + UnitTimes *u; + int n, m = 1, y = 0, r; +@@ -702,7 +702,7 @@ static int analyze_plot(int argc, char *argv[], void *userdata) { + if (n < 0) + return n; + +- if (use_full_bus || arg_scope != UNIT_FILE_SYSTEM) { ++ if (use_full_bus || arg_scope != LOOKUP_SCOPE_SYSTEM) { + n = acquire_host_info(bus, &host); + if (n < 0) + return n; +@@ -2607,15 +2607,15 @@ static int parse_argv(int argc, char *argv[]) { + break; + + case ARG_SYSTEM: +- arg_scope = UNIT_FILE_SYSTEM; ++ arg_scope = LOOKUP_SCOPE_SYSTEM; + break; + + case ARG_USER: +- arg_scope = UNIT_FILE_USER; ++ arg_scope = LOOKUP_SCOPE_USER; + break; + + case ARG_GLOBAL: +- arg_scope = UNIT_FILE_GLOBAL; ++ arg_scope = LOOKUP_SCOPE_GLOBAL; + break; + + case ARG_ORDER: +@@ -2756,12 +2756,12 @@ static int parse_argv(int argc, char *argv[]) { + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), + "Option --threshold= is only supported for security right now."); + +- if (arg_scope == UNIT_FILE_GLOBAL && ++ if (arg_scope == LOOKUP_SCOPE_GLOBAL && + !STR_IN_SET(argv[optind] ?: "time", "dot", "unit-paths", "verify")) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), + "Option --global only makes sense with verbs dot, unit-paths, verify."); + +- if (streq_ptr(argv[optind], "cat-config") && arg_scope == UNIT_FILE_USER) ++ if (streq_ptr(argv[optind], "cat-config") && arg_scope == LOOKUP_SCOPE_USER) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), + "Option --user is not supported for cat-config right now."); + +diff --git a/src/basic/path-lookup.c b/src/basic/path-lookup.c +index b699756658..1f4331a8bf 100644 +--- a/src/basic/path-lookup.c ++++ b/src/basic/path-lookup.c +@@ -232,7 +232,7 @@ bool path_is_user_config_dir(const char *path) { + } + + static int acquire_generator_dirs( +- UnitFileScope scope, ++ LookupScope scope, + const char *tempdir, + char **generator, + char **generator_early, +@@ -244,17 +244,17 @@ static int acquire_generator_dirs( + assert(generator); + assert(generator_early); + assert(generator_late); +- assert(IN_SET(scope, UNIT_FILE_SYSTEM, UNIT_FILE_USER, UNIT_FILE_GLOBAL)); ++ assert(IN_SET(scope, LOOKUP_SCOPE_SYSTEM, LOOKUP_SCOPE_USER, LOOKUP_SCOPE_GLOBAL)); + +- if (scope == UNIT_FILE_GLOBAL) ++ if (scope == LOOKUP_SCOPE_GLOBAL) + return -EOPNOTSUPP; + + if (tempdir) + prefix = tempdir; +- else if (scope == UNIT_FILE_SYSTEM) ++ else if (scope == LOOKUP_SCOPE_SYSTEM) + prefix = "/run/systemd"; + else { +- /* UNIT_FILE_USER */ ++ /* LOOKUP_SCOPE_USER */ + const char *e; + + e = getenv("XDG_RUNTIME_DIR"); +@@ -288,21 +288,21 @@ static int acquire_generator_dirs( + } + + static int acquire_transient_dir( +- UnitFileScope scope, ++ LookupScope scope, + const char *tempdir, + char **ret) { + + char *transient; + + assert(ret); +- assert(IN_SET(scope, UNIT_FILE_SYSTEM, UNIT_FILE_USER, UNIT_FILE_GLOBAL)); ++ assert(IN_SET(scope, LOOKUP_SCOPE_SYSTEM, LOOKUP_SCOPE_USER, LOOKUP_SCOPE_GLOBAL)); + +- if (scope == UNIT_FILE_GLOBAL) ++ if (scope == LOOKUP_SCOPE_GLOBAL) + return -EOPNOTSUPP; + + if (tempdir) + transient = path_join(tempdir, "transient"); +- else if (scope == UNIT_FILE_SYSTEM) ++ else if (scope == LOOKUP_SCOPE_SYSTEM) + transient = strdup("/run/systemd/transient"); + else + return xdg_user_runtime_dir(ret, "/systemd/transient"); +@@ -313,7 +313,7 @@ static int acquire_transient_dir( + return 0; + } + +-static int acquire_config_dirs(UnitFileScope scope, char **persistent, char **runtime) { ++static int acquire_config_dirs(LookupScope scope, char **persistent, char **runtime) { + _cleanup_free_ char *a = NULL, *b = NULL; + int r; + +@@ -322,17 +322,17 @@ static int acquire_config_dirs(UnitFileScope scope, char **persistent, char **ru + + switch (scope) { + +- case UNIT_FILE_SYSTEM: ++ case LOOKUP_SCOPE_SYSTEM: + a = strdup(SYSTEM_CONFIG_UNIT_DIR); + b = strdup("/run/systemd/system"); + break; + +- case UNIT_FILE_GLOBAL: ++ case LOOKUP_SCOPE_GLOBAL: + a = strdup(USER_CONFIG_UNIT_DIR); + b = strdup("/run/systemd/user"); + break; + +- case UNIT_FILE_USER: ++ case LOOKUP_SCOPE_USER: + r = xdg_user_config_dir(&a, "/systemd/user"); + if (r < 0 && r != -ENXIO) + return r; +@@ -364,7 +364,7 @@ static int acquire_config_dirs(UnitFileScope scope, char **persistent, char **ru + return 0; + } + +-static int acquire_control_dirs(UnitFileScope scope, char **persistent, char **runtime) { ++static int acquire_control_dirs(LookupScope scope, char **persistent, char **runtime) { + _cleanup_free_ char *a = NULL; + int r; + +@@ -373,7 +373,7 @@ static int acquire_control_dirs(UnitFileScope scope, char **persistent, char **r + + switch (scope) { + +- case UNIT_FILE_SYSTEM: { ++ case LOOKUP_SCOPE_SYSTEM: { + _cleanup_free_ char *b = NULL; + + a = strdup("/etc/systemd/system.control"); +@@ -389,7 +389,7 @@ static int acquire_control_dirs(UnitFileScope scope, char **persistent, char **r + break; + } + +- case UNIT_FILE_USER: ++ case LOOKUP_SCOPE_USER: + r = xdg_user_config_dir(&a, "/systemd/user.control"); + if (r < 0 && r != -ENXIO) + return r; +@@ -406,7 +406,7 @@ static int acquire_control_dirs(UnitFileScope scope, char **persistent, char **r + + break; + +- case UNIT_FILE_GLOBAL: ++ case LOOKUP_SCOPE_GLOBAL: + return -EOPNOTSUPP; + + default: +@@ -419,7 +419,7 @@ static int acquire_control_dirs(UnitFileScope scope, char **persistent, char **r + } + + static int acquire_attached_dirs( +- UnitFileScope scope, ++ LookupScope scope, + char **ret_persistent, + char **ret_runtime) { + +@@ -429,7 +429,7 @@ static int acquire_attached_dirs( + assert(ret_runtime); + + /* Portable services are not available to regular users for now. */ +- if (scope != UNIT_FILE_SYSTEM) ++ if (scope != LOOKUP_SCOPE_SYSTEM) + return -EOPNOTSUPP; + + a = strdup("/etc/systemd/system.attached"); +@@ -509,7 +509,7 @@ static int get_paths_from_environ(const char *var, char ***paths, bool *append) + + int lookup_paths_init( + LookupPaths *lp, +- UnitFileScope scope, ++ LookupScope scope, + LookupPathsFlags flags, + const char *root_dir) { + +@@ -528,14 +528,14 @@ int lookup_paths_init( + + assert(lp); + assert(scope >= 0); +- assert(scope < _UNIT_FILE_SCOPE_MAX); ++ assert(scope < _LOOKUP_SCOPE_MAX); + + #if HAVE_SPLIT_USR + flags |= LOOKUP_PATHS_SPLIT_USR; + #endif + + if (!empty_or_root(root_dir)) { +- if (scope == UNIT_FILE_USER) ++ if (scope == LOOKUP_SCOPE_USER) + return -EINVAL; + + r = is_dir(root_dir, true); +@@ -560,8 +560,8 @@ int lookup_paths_init( + if (r < 0) + return r; + +- if (scope == UNIT_FILE_USER) { +- r = acquire_config_dirs(UNIT_FILE_GLOBAL, &global_persistent_config, &global_runtime_config); ++ if (scope == LOOKUP_SCOPE_USER) { ++ r = acquire_config_dirs(LOOKUP_SCOPE_GLOBAL, &global_persistent_config, &global_runtime_config); + if (r < 0) + return r; + } +@@ -606,7 +606,7 @@ int lookup_paths_init( + + switch (scope) { + +- case UNIT_FILE_SYSTEM: ++ case LOOKUP_SCOPE_SYSTEM: + add = strv_new( + /* If you modify this you also want to modify + * systemdsystemunitpath= in systemd.pc.in! */ +@@ -629,7 +629,7 @@ int lookup_paths_init( + STRV_IFNOTNULL(generator_late)); + break; + +- case UNIT_FILE_GLOBAL: ++ case LOOKUP_SCOPE_GLOBAL: + add = strv_new( + /* If you modify this you also want to modify + * systemduserunitpath= in systemd.pc.in, and +@@ -652,7 +652,7 @@ int lookup_paths_init( + STRV_IFNOTNULL(generator_late)); + break; + +- case UNIT_FILE_USER: ++ case LOOKUP_SCOPE_USER: + add = user_dirs(persistent_config, runtime_config, + global_persistent_config, global_runtime_config, + generator, generator_early, generator_late, +@@ -741,7 +741,7 @@ int lookup_paths_init( + return 0; + } + +-int lookup_paths_init_or_warn(LookupPaths *lp, UnitFileScope scope, LookupPathsFlags flags, const char *root_dir) { ++int lookup_paths_init_or_warn(LookupPaths *lp, LookupScope scope, LookupPathsFlags flags, const char *root_dir) { + int r; + + r = lookup_paths_init(lp, scope, flags, root_dir); +@@ -790,7 +790,7 @@ void lookup_paths_log(LookupPaths *lp) { + } + } + +-char **generator_binary_paths(UnitFileScope scope) { ++char **generator_binary_paths(LookupScope scope) { + bool append = false; /* Add items from SYSTEMD_GENERATOR_PATH before normal directories */ + _cleanup_strv_free_ char **paths = NULL; + int r; +@@ -805,15 +805,15 @@ char **generator_binary_paths(UnitFileScope scope) { + + switch (scope) { + +- case UNIT_FILE_SYSTEM: ++ case LOOKUP_SCOPE_SYSTEM: + add = strv_new("/run/systemd/system-generators", + "/etc/systemd/system-generators", + "/usr/local/lib/systemd/system-generators", + SYSTEM_GENERATOR_DIR); + break; + +- case UNIT_FILE_GLOBAL: +- case UNIT_FILE_USER: ++ case LOOKUP_SCOPE_GLOBAL: ++ case LOOKUP_SCOPE_USER: + add = strv_new("/run/systemd/user-generators", + "/etc/systemd/user-generators", + "/usr/local/lib/systemd/user-generators", +diff --git a/src/basic/path-lookup.h b/src/basic/path-lookup.h +index 1f0e5ea271..aed72defe7 100644 +--- a/src/basic/path-lookup.h ++++ b/src/basic/path-lookup.h +@@ -3,10 +3,7 @@ + + #include + +-typedef struct LookupPaths LookupPaths; +- + #include "def.h" +-#include "unit-file.h" + #include "macro.h" + + typedef enum LookupPathsFlags { +@@ -15,7 +12,15 @@ typedef enum LookupPathsFlags { + LOOKUP_PATHS_SPLIT_USR = 1 << 2, + } LookupPathsFlags; + +-struct LookupPaths { ++typedef enum LookupScope { ++ LOOKUP_SCOPE_SYSTEM, ++ LOOKUP_SCOPE_GLOBAL, ++ LOOKUP_SCOPE_USER, ++ _LOOKUP_SCOPE_MAX, ++ _LOOKUP_SCOPE_INVALID = -EINVAL, ++} LookupScope; ++ ++typedef struct LookupPaths { + /* Where we look for unit files. This includes the individual special paths below, but also any vendor + * supplied, static unit file paths. */ + char **search_path; +@@ -52,10 +57,10 @@ struct LookupPaths { + + /* A temporary directory when running in test mode, to be nuked */ + char *temporary_dir; +-}; ++} LookupPaths; + +-int lookup_paths_init(LookupPaths *lp, UnitFileScope scope, LookupPathsFlags flags, const char *root_dir); +-int lookup_paths_init_or_warn(LookupPaths *lp, UnitFileScope scope, LookupPathsFlags flags, const char *root_dir); ++int lookup_paths_init(LookupPaths *lp, LookupScope scope, LookupPathsFlags flags, const char *root_dir); ++int lookup_paths_init_or_warn(LookupPaths *lp, LookupScope scope, LookupPathsFlags flags, const char *root_dir); + + int xdg_user_dirs(char ***ret_config_dirs, char ***ret_data_dirs); + int xdg_user_runtime_dir(char **ret, const char *suffix); +@@ -68,7 +73,7 @@ bool path_is_user_config_dir(const char *path); + void lookup_paths_log(LookupPaths *p); + void lookup_paths_free(LookupPaths *p); + +-char **generator_binary_paths(UnitFileScope scope); ++char **generator_binary_paths(LookupScope scope); + char **env_generator_binary_paths(bool is_system); + + #define NETWORK_DIRS ((const char* const*) CONF_PATHS_STRV("systemd/network")) +diff --git a/src/basic/unit-file.h b/src/basic/unit-file.h +index b7c03e9c2c..1c43861f00 100644 +--- a/src/basic/unit-file.h ++++ b/src/basic/unit-file.h +@@ -4,12 +4,11 @@ + #include + + #include "hashmap.h" ++#include "path-lookup.h" + #include "time-util.h" + #include "unit-name.h" + + typedef enum UnitFileState UnitFileState; +-typedef enum UnitFileScope UnitFileScope; +-typedef struct LookupPaths LookupPaths; + + enum UnitFileState { + UNIT_FILE_ENABLED, +@@ -29,14 +28,6 @@ enum UnitFileState { + _UNIT_FILE_STATE_INVALID = -EINVAL, + }; + +-enum UnitFileScope { +- UNIT_FILE_SYSTEM, +- UNIT_FILE_GLOBAL, +- UNIT_FILE_USER, +- _UNIT_FILE_SCOPE_MAX, +- _UNIT_FILE_SCOPE_INVALID = -EINVAL, +-}; +- + bool unit_type_may_alias(UnitType type) _const_; + bool unit_type_may_template(UnitType type) _const_; + +diff --git a/src/core/dbus-manager.c b/src/core/dbus-manager.c +index 0e3590d1c9..efba6331b9 100644 +--- a/src/core/dbus-manager.c ++++ b/src/core/dbus-manager.c +@@ -2215,7 +2215,7 @@ fail: + static int method_enable_unit_files_generic( + sd_bus_message *message, + Manager *m, +- int (*call)(UnitFileScope scope, UnitFileFlags flags, const char *root_dir, char *files[], UnitFileChange **changes, size_t *n_changes), ++ int (*call)(LookupScope scope, UnitFileFlags flags, const char *root_dir, char *files[], UnitFileChange **changes, size_t *n_changes), + bool carries_install_info, + sd_bus_error *error) { + +@@ -2279,7 +2279,7 @@ static int method_link_unit_files(sd_bus_message *message, void *userdata, sd_bu + return method_enable_unit_files_generic(message, userdata, unit_file_link, false, error); + } + +-static int unit_file_preset_without_mode(UnitFileScope scope, UnitFileFlags flags, const char *root_dir, char **files, UnitFileChange **changes, size_t *n_changes) { ++static int unit_file_preset_without_mode(LookupScope scope, UnitFileFlags flags, const char *root_dir, char **files, UnitFileChange **changes, size_t *n_changes) { + return unit_file_preset(scope, flags, root_dir, files, UNIT_FILE_PRESET_FULL, changes, n_changes); + } + +@@ -2339,7 +2339,7 @@ static int method_preset_unit_files_with_mode(sd_bus_message *message, void *use + static int method_disable_unit_files_generic( + sd_bus_message *message, + Manager *m, +- int (*call)(UnitFileScope scope, UnitFileFlags flags, const char *root_dir, char *files[], UnitFileChange **changes, size_t *n_changes), ++ int (*call)(LookupScope scope, UnitFileFlags flags, const char *root_dir, char *files[], UnitFileChange **changes, size_t *n_changes), + sd_bus_error *error) { + + _cleanup_strv_free_ char **l = NULL; +@@ -2565,7 +2565,7 @@ static int method_get_unit_file_links(sd_bus_message *message, void *userdata, s + flags = UNIT_FILE_DRY_RUN | + (runtime ? UNIT_FILE_RUNTIME : 0); + +- r = unit_file_disable(UNIT_FILE_SYSTEM, flags, NULL, p, &changes, &n_changes); ++ r = unit_file_disable(LOOKUP_SCOPE_SYSTEM, flags, NULL, p, &changes, &n_changes); + if (r < 0) + return log_error_errno(r, "Failed to get file links for %s: %m", name); + +diff --git a/src/core/fuzz-unit-file.c b/src/core/fuzz-unit-file.c +index 780dd3988d..c12e874e2d 100644 +--- a/src/core/fuzz-unit-file.c ++++ b/src/core/fuzz-unit-file.c +@@ -62,7 +62,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { + if (!getenv("SYSTEMD_LOG_LEVEL")) + log_set_max_level(LOG_CRIT); + +- assert_se(manager_new(UNIT_FILE_SYSTEM, MANAGER_TEST_RUN_MINIMAL, &m) >= 0); ++ assert_se(manager_new(LOOKUP_SCOPE_SYSTEM, MANAGER_TEST_RUN_MINIMAL, &m) >= 0); + + name = strjoina("a.", unit_type_to_string(t)); + assert_se(unit_new_for_name(m, unit_vtable[t]->object_size, name, &u) >= 0); +diff --git a/src/core/main.c b/src/core/main.c +index 4bad2e84a0..667e972364 100644 +--- a/src/core/main.c ++++ b/src/core/main.c +@@ -2970,7 +2970,7 @@ int main(int argc, char *argv[]) { + if (r < 0) + goto finish; + +- r = manager_new(arg_system ? UNIT_FILE_SYSTEM : UNIT_FILE_USER, ++ r = manager_new(arg_system ? LOOKUP_SCOPE_SYSTEM : LOOKUP_SCOPE_USER, + arg_action == ACTION_TEST ? MANAGER_TEST_FULL : 0, + &m); + if (r < 0) { +diff --git a/src/core/manager.c b/src/core/manager.c +index 60846a66e6..c01128adb4 100644 +--- a/src/core/manager.c ++++ b/src/core/manager.c +@@ -781,13 +781,13 @@ static int manager_setup_sigchld_event_source(Manager *m) { + return 0; + } + +-int manager_new(UnitFileScope scope, ManagerTestRunFlags test_run_flags, Manager **_m) { ++int manager_new(LookupScope scope, ManagerTestRunFlags test_run_flags, Manager **_m) { + _cleanup_(manager_freep) Manager *m = NULL; + const char *e; + int r; + + assert(_m); +- assert(IN_SET(scope, UNIT_FILE_SYSTEM, UNIT_FILE_USER)); ++ assert(IN_SET(scope, LOOKUP_SCOPE_SYSTEM, LOOKUP_SCOPE_USER)); + + m = new(Manager, 1); + if (!m) +@@ -1705,7 +1705,7 @@ static void manager_preset_all(Manager *m) { + return; + + /* If this is the first boot, and we are in the host system, then preset everything */ +- r = unit_file_preset_all(UNIT_FILE_SYSTEM, 0, NULL, UNIT_FILE_PRESET_ENABLE_ONLY, NULL, 0); ++ r = unit_file_preset_all(LOOKUP_SCOPE_SYSTEM, 0, NULL, UNIT_FILE_PRESET_ENABLE_ONLY, NULL, 0); + if (r < 0) + log_full_errno(r == -EEXIST ? LOG_NOTICE : LOG_WARNING, r, + "Failed to populate /etc with preset unit settings, ignoring: %m"); +diff --git a/src/core/manager.h b/src/core/manager.h +index e445e4d751..281d2a2138 100644 +--- a/src/core/manager.h ++++ b/src/core/manager.h +@@ -235,7 +235,7 @@ struct Manager { + int user_lookup_fds[2]; + sd_event_source *user_lookup_event_source; + +- UnitFileScope unit_file_scope; ++ LookupScope unit_file_scope; + LookupPaths lookup_paths; + Hashmap *unit_id_map; + Hashmap *unit_name_map; +@@ -461,8 +461,8 @@ static inline usec_t manager_default_timeout_abort_usec(Manager *m) { + return m->default_timeout_abort_set ? m->default_timeout_abort_usec : m->default_timeout_stop_usec; + } + +-#define MANAGER_IS_SYSTEM(m) ((m)->unit_file_scope == UNIT_FILE_SYSTEM) +-#define MANAGER_IS_USER(m) ((m)->unit_file_scope != UNIT_FILE_SYSTEM) ++#define MANAGER_IS_SYSTEM(m) ((m)->unit_file_scope == LOOKUP_SCOPE_SYSTEM) ++#define MANAGER_IS_USER(m) ((m)->unit_file_scope != LOOKUP_SCOPE_SYSTEM) + + #define MANAGER_IS_RELOADING(m) ((m)->n_reloading > 0) + +@@ -473,7 +473,7 @@ static inline usec_t manager_default_timeout_abort_usec(Manager *m) { + + #define MANAGER_IS_TEST_RUN(m) ((m)->test_run_flags != 0) + +-int manager_new(UnitFileScope scope, ManagerTestRunFlags test_run_flags, Manager **m); ++int manager_new(LookupScope scope, ManagerTestRunFlags test_run_flags, Manager **m); + Manager* manager_free(Manager *m); + DEFINE_TRIVIAL_CLEANUP_FUNC(Manager*, manager_free); + +diff --git a/src/libsystemd/sd-path/sd-path.c b/src/libsystemd/sd-path/sd-path.c +index 8d9cfbc0af..385cfd3006 100644 +--- a/src/libsystemd/sd-path/sd-path.c ++++ b/src/libsystemd/sd-path/sd-path.c +@@ -601,8 +601,8 @@ static int get_search(uint64_t type, char ***list) { + case SD_PATH_SYSTEMD_SEARCH_SYSTEM_UNIT: + case SD_PATH_SYSTEMD_SEARCH_USER_UNIT: { + _cleanup_(lookup_paths_free) LookupPaths lp = {}; +- const UnitFileScope scope = type == SD_PATH_SYSTEMD_SEARCH_SYSTEM_UNIT ? +- UNIT_FILE_SYSTEM : UNIT_FILE_USER; ++ const LookupScope scope = type == SD_PATH_SYSTEMD_SEARCH_SYSTEM_UNIT ? ++ LOOKUP_SCOPE_SYSTEM : LOOKUP_SCOPE_USER; + + r = lookup_paths_init(&lp, scope, 0, NULL); + if (r < 0) +@@ -615,8 +615,8 @@ static int get_search(uint64_t type, char ***list) { + case SD_PATH_SYSTEMD_SEARCH_SYSTEM_GENERATOR: + case SD_PATH_SYSTEMD_SEARCH_USER_GENERATOR: { + char **t; +- const UnitFileScope scope = type == SD_PATH_SYSTEMD_SEARCH_SYSTEM_GENERATOR ? +- UNIT_FILE_SYSTEM : UNIT_FILE_USER; ++ const LookupScope scope = type == SD_PATH_SYSTEMD_SEARCH_SYSTEM_GENERATOR ? ++ LOOKUP_SCOPE_SYSTEM : LOOKUP_SCOPE_USER; + + t = generator_binary_paths(scope); + if (!t) +diff --git a/src/portable/portable.c b/src/portable/portable.c +index 5be7ea854d..4c75dc0e0c 100644 +--- a/src/portable/portable.c ++++ b/src/portable/portable.c +@@ -231,7 +231,7 @@ static int extract_now( + /* Then, send unit file data to the parent (or/and add it to the hashmap). For that we use our usual unit + * discovery logic. Note that we force looking inside of /lib/systemd/system/ for units too, as we mightbe + * compiled for a split-usr system but the image might be a legacy-usr one. */ +- r = lookup_paths_init(&paths, UNIT_FILE_SYSTEM, LOOKUP_PATHS_SPLIT_USR, where); ++ r = lookup_paths_init(&paths, LOOKUP_SCOPE_SYSTEM, LOOKUP_PATHS_SPLIT_USR, where); + if (r < 0) + return log_debug_errno(r, "Failed to acquire lookup paths: %m"); + +@@ -1302,12 +1302,12 @@ int portable_attach( + strempty(extensions_joined)); + } + +- r = lookup_paths_init(&paths, UNIT_FILE_SYSTEM, LOOKUP_PATHS_SPLIT_USR, NULL); ++ r = lookup_paths_init(&paths, LOOKUP_SCOPE_SYSTEM, LOOKUP_PATHS_SPLIT_USR, NULL); + if (r < 0) + return r; + + HASHMAP_FOREACH(item, unit_files) { +- r = unit_file_exists(UNIT_FILE_SYSTEM, &paths, item->name); ++ r = unit_file_exists(LOOKUP_SCOPE_SYSTEM, &paths, item->name); + if (r < 0) + return sd_bus_error_set_errnof(error, r, "Failed to determine whether unit '%s' exists on the host: %m", item->name); + if (!FLAGS_SET(flags, PORTABLE_REATTACH) && r > 0) +@@ -1489,7 +1489,7 @@ int portable_detach( + + assert(name_or_path); + +- r = lookup_paths_init(&paths, UNIT_FILE_SYSTEM, LOOKUP_PATHS_SPLIT_USR, NULL); ++ r = lookup_paths_init(&paths, LOOKUP_SCOPE_SYSTEM, LOOKUP_PATHS_SPLIT_USR, NULL); + if (r < 0) + return r; + +@@ -1523,7 +1523,7 @@ int portable_detach( + if (r == 0) + continue; + +- r = unit_file_lookup_state(UNIT_FILE_SYSTEM, &paths, de->d_name, &state); ++ r = unit_file_lookup_state(LOOKUP_SCOPE_SYSTEM, &paths, de->d_name, &state); + if (r < 0) + return log_debug_errno(r, "Failed to determine unit file state of '%s': %m", de->d_name); + if (!IN_SET(state, UNIT_FILE_STATIC, UNIT_FILE_DISABLED, UNIT_FILE_LINKED, UNIT_FILE_RUNTIME, UNIT_FILE_LINKED_RUNTIME)) +@@ -1657,7 +1657,7 @@ static int portable_get_state_internal( + assert(name_or_path); + assert(ret); + +- r = lookup_paths_init(&paths, UNIT_FILE_SYSTEM, LOOKUP_PATHS_SPLIT_USR, NULL); ++ r = lookup_paths_init(&paths, LOOKUP_SCOPE_SYSTEM, LOOKUP_PATHS_SPLIT_USR, NULL); + if (r < 0) + return r; + +@@ -1693,7 +1693,7 @@ static int portable_get_state_internal( + if (r == 0) + continue; + +- r = unit_file_lookup_state(UNIT_FILE_SYSTEM, &paths, de->d_name, &state); ++ r = unit_file_lookup_state(LOOKUP_SCOPE_SYSTEM, &paths, de->d_name, &state); + if (r < 0) + return log_debug_errno(r, "Failed to determine unit file state of '%s': %m", de->d_name); + if (!IN_SET(state, UNIT_FILE_STATIC, UNIT_FILE_DISABLED, UNIT_FILE_LINKED, UNIT_FILE_LINKED_RUNTIME)) +diff --git a/src/shared/install-printf.c b/src/shared/install-printf.c +index 7aad1b7443..fdb8e021ac 100644 +--- a/src/shared/install-printf.c ++++ b/src/shared/install-printf.c +@@ -104,7 +104,7 @@ static int specifier_last_component(char specifier, const void *data, const char + } + + int install_name_printf( +- UnitFileScope scope, ++ LookupScope scope, + const UnitFileInstallInfo *info, + const char *format, + char **ret) { +diff --git a/src/shared/install-printf.h b/src/shared/install-printf.h +index 60d3a9fc55..6a9ab24e15 100644 +--- a/src/shared/install-printf.h ++++ b/src/shared/install-printf.h +@@ -5,7 +5,7 @@ + #include "unit-name.h" + + int install_name_printf( +- UnitFileScope scope, ++ LookupScope scope, + const UnitFileInstallInfo *info, + const char *format, + char **ret); +diff --git a/src/shared/install.c b/src/shared/install.c +index 22b16ad453..fa7bbdd93a 100644 +--- a/src/shared/install.c ++++ b/src/shared/install.c +@@ -47,7 +47,7 @@ typedef enum SearchFlags { + } SearchFlags; + + typedef struct { +- UnitFileScope scope; ++ LookupScope scope; + OrderedHashmap *will_process; + OrderedHashmap *have_processed; + } InstallContext; +@@ -942,7 +942,7 @@ static int find_symlinks( + } + + static int find_symlinks_in_scope( +- UnitFileScope scope, ++ LookupScope scope, + const LookupPaths *lp, + const UnitFileInstallInfo *info, + bool match_name, +@@ -976,7 +976,7 @@ static int find_symlinks_in_scope( + } + + /* look for global enablement of user units */ +- if (scope == UNIT_FILE_USER && path_is_user_config_dir(*p)) { ++ if (scope == LOOKUP_SCOPE_USER && path_is_user_config_dir(*p)) { + *state = UNIT_FILE_ENABLED; + return 1; + } +@@ -1868,7 +1868,7 @@ int unit_file_verify_alias( + } + + static int install_info_symlink_alias( +- UnitFileScope scope, ++ LookupScope scope, + UnitFileInstallInfo *info, + const LookupPaths *lp, + const char *config_path, +@@ -1912,7 +1912,7 @@ static int install_info_symlink_alias( + } + + static int install_info_symlink_wants( +- UnitFileScope scope, ++ LookupScope scope, + UnitFileFlags file_flags, + UnitFileInstallInfo *info, + const LookupPaths *lp, +@@ -2052,7 +2052,7 @@ static int install_info_symlink_link( + } + + static int install_info_apply( +- UnitFileScope scope, ++ LookupScope scope, + UnitFileFlags file_flags, + UnitFileInstallInfo *info, + const LookupPaths *lp, +@@ -2225,7 +2225,7 @@ static int install_context_mark_for_removal( + } + + int unit_file_mask( +- UnitFileScope scope, ++ LookupScope scope, + UnitFileFlags flags, + const char *root_dir, + char **files, +@@ -2237,7 +2237,7 @@ int unit_file_mask( + int r; + + assert(scope >= 0); +- assert(scope < _UNIT_FILE_SCOPE_MAX); ++ assert(scope < _LOOKUP_SCOPE_MAX); + + r = lookup_paths_init(&lp, scope, 0, root_dir); + if (r < 0) +@@ -2270,7 +2270,7 @@ int unit_file_mask( + } + + int unit_file_unmask( +- UnitFileScope scope, ++ LookupScope scope, + UnitFileFlags flags, + const char *root_dir, + char **files, +@@ -2285,7 +2285,7 @@ int unit_file_unmask( + int r, q; + + assert(scope >= 0); +- assert(scope < _UNIT_FILE_SCOPE_MAX); ++ assert(scope < _LOOKUP_SCOPE_MAX); + + r = lookup_paths_init(&lp, scope, 0, root_dir); + if (r < 0) +@@ -2362,7 +2362,7 @@ int unit_file_unmask( + } + + int unit_file_link( +- UnitFileScope scope, ++ LookupScope scope, + UnitFileFlags flags, + const char *root_dir, + char **files, +@@ -2376,7 +2376,7 @@ int unit_file_link( + int r, q; + + assert(scope >= 0); +- assert(scope < _UNIT_FILE_SCOPE_MAX); ++ assert(scope < _LOOKUP_SCOPE_MAX); + + r = lookup_paths_init(&lp, scope, 0, root_dir); + if (r < 0) +@@ -2462,7 +2462,7 @@ static int path_shall_revert(const LookupPaths *lp, const char *path) { + } + + int unit_file_revert( +- UnitFileScope scope, ++ LookupScope scope, + const char *root_dir, + char **files, + UnitFileChange **changes, +@@ -2613,7 +2613,7 @@ int unit_file_revert( + } + + int unit_file_add_dependency( +- UnitFileScope scope, ++ LookupScope scope, + UnitFileFlags file_flags, + const char *root_dir, + char **files, +@@ -2629,7 +2629,7 @@ int unit_file_add_dependency( + int r; + + assert(scope >= 0); +- assert(scope < _UNIT_FILE_SCOPE_MAX); ++ assert(scope < _LOOKUP_SCOPE_MAX); + assert(target); + + if (!IN_SET(dep, UNIT_WANTS, UNIT_REQUIRES)) +@@ -2684,7 +2684,7 @@ int unit_file_add_dependency( + + static int do_unit_file_enable( + const LookupPaths *lp, +- UnitFileScope scope, ++ LookupScope scope, + UnitFileFlags flags, + const char *config_path, + char **files, +@@ -2714,7 +2714,7 @@ static int do_unit_file_enable( + } + + int unit_file_enable( +- UnitFileScope scope, ++ LookupScope scope, + UnitFileFlags flags, + const char *root_dir, + char **files, +@@ -2725,7 +2725,7 @@ int unit_file_enable( + int r; + + assert(scope >= 0); +- assert(scope < _UNIT_FILE_SCOPE_MAX); ++ assert(scope < _LOOKUP_SCOPE_MAX); + + r = lookup_paths_init(&lp, scope, 0, root_dir); + if (r < 0) +@@ -2740,7 +2740,7 @@ int unit_file_enable( + + static int do_unit_file_disable( + const LookupPaths *lp, +- UnitFileScope scope, ++ LookupScope scope, + UnitFileFlags flags, + const char *config_path, + char **files, +@@ -2769,7 +2769,7 @@ static int do_unit_file_disable( + + + int unit_file_disable( +- UnitFileScope scope, ++ LookupScope scope, + UnitFileFlags flags, + const char *root_dir, + char **files, +@@ -2780,7 +2780,7 @@ int unit_file_disable( + int r; + + assert(scope >= 0); +- assert(scope < _UNIT_FILE_SCOPE_MAX); ++ assert(scope < _LOOKUP_SCOPE_MAX); + + r = lookup_paths_init(&lp, scope, 0, root_dir); + if (r < 0) +@@ -2794,7 +2794,7 @@ int unit_file_disable( + } + + static int normalize_linked_files( +- UnitFileScope scope, ++ LookupScope scope, + const LookupPaths *lp, + char **names_or_paths, + char ***ret_names, +@@ -2852,7 +2852,7 @@ static int normalize_linked_files( + } + + int unit_file_reenable( +- UnitFileScope scope, ++ LookupScope scope, + UnitFileFlags flags, + const char *root_dir, + char **names_or_paths, +@@ -2864,7 +2864,7 @@ int unit_file_reenable( + int r; + + assert(scope >= 0); +- assert(scope < _UNIT_FILE_SCOPE_MAX); ++ assert(scope < _LOOKUP_SCOPE_MAX); + + r = lookup_paths_init(&lp, scope, 0, root_dir); + if (r < 0) +@@ -2888,7 +2888,7 @@ int unit_file_reenable( + } + + int unit_file_set_default( +- UnitFileScope scope, ++ LookupScope scope, + UnitFileFlags flags, + const char *root_dir, + const char *name, +@@ -2902,7 +2902,7 @@ int unit_file_set_default( + int r; + + assert(scope >= 0); +- assert(scope < _UNIT_FILE_SCOPE_MAX); ++ assert(scope < _LOOKUP_SCOPE_MAX); + assert(name); + + if (unit_name_to_type(name) != UNIT_TARGET) /* this also validates the name */ +@@ -2923,7 +2923,7 @@ int unit_file_set_default( + } + + int unit_file_get_default( +- UnitFileScope scope, ++ LookupScope scope, + const char *root_dir, + char **name) { + +@@ -2934,7 +2934,7 @@ int unit_file_get_default( + int r; + + assert(scope >= 0); +- assert(scope < _UNIT_FILE_SCOPE_MAX); ++ assert(scope < _LOOKUP_SCOPE_MAX); + assert(name); + + r = lookup_paths_init(&lp, scope, 0, root_dir); +@@ -2958,7 +2958,7 @@ int unit_file_get_default( + } + + int unit_file_lookup_state( +- UnitFileScope scope, ++ LookupScope scope, + const LookupPaths *lp, + const char *name, + UnitFileState *ret) { +@@ -3056,7 +3056,7 @@ int unit_file_lookup_state( + } + + int unit_file_get_state( +- UnitFileScope scope, ++ LookupScope scope, + const char *root_dir, + const char *name, + UnitFileState *ret) { +@@ -3065,7 +3065,7 @@ int unit_file_get_state( + int r; + + assert(scope >= 0); +- assert(scope < _UNIT_FILE_SCOPE_MAX); ++ assert(scope < _LOOKUP_SCOPE_MAX); + assert(name); + + r = lookup_paths_init(&lp, scope, 0, root_dir); +@@ -3075,7 +3075,7 @@ int unit_file_get_state( + return unit_file_lookup_state(scope, &lp, name, ret); + } + +-int unit_file_exists(UnitFileScope scope, const LookupPaths *lp, const char *name) { ++int unit_file_exists(LookupScope scope, const LookupPaths *lp, const char *name) { + _cleanup_(install_context_done) InstallContext c = { .scope = scope }; + int r; + +@@ -3127,17 +3127,17 @@ static int split_pattern_into_name_and_instances(const char *pattern, char **out + return 0; + } + +-static int presets_find_config(UnitFileScope scope, const char *root_dir, char ***files) { ++static int presets_find_config(LookupScope scope, const char *root_dir, char ***files) { + static const char* const system_dirs[] = {CONF_PATHS("systemd/system-preset"), NULL}; + static const char* const user_dirs[] = {CONF_PATHS_USR("systemd/user-preset"), NULL}; + const char* const* dirs; + + assert(scope >= 0); +- assert(scope < _UNIT_FILE_SCOPE_MAX); ++ assert(scope < _LOOKUP_SCOPE_MAX); + +- if (scope == UNIT_FILE_SYSTEM) ++ if (scope == LOOKUP_SCOPE_SYSTEM) + dirs = system_dirs; +- else if (IN_SET(scope, UNIT_FILE_GLOBAL, UNIT_FILE_USER)) ++ else if (IN_SET(scope, LOOKUP_SCOPE_GLOBAL, LOOKUP_SCOPE_USER)) + dirs = user_dirs; + else + assert_not_reached(); +@@ -3145,13 +3145,13 @@ static int presets_find_config(UnitFileScope scope, const char *root_dir, char * + return conf_files_list_strv(files, ".preset", root_dir, 0, dirs); + } + +-static int read_presets(UnitFileScope scope, const char *root_dir, UnitFilePresets *presets) { ++static int read_presets(LookupScope scope, const char *root_dir, UnitFilePresets *presets) { + _cleanup_(unit_file_presets_freep) UnitFilePresets ps = {}; + _cleanup_strv_free_ char **files = NULL; + int r; + + assert(scope >= 0); +- assert(scope < _UNIT_FILE_SCOPE_MAX); ++ assert(scope < _LOOKUP_SCOPE_MAX); + assert(presets); + + r = presets_find_config(scope, root_dir, &files); +@@ -3325,7 +3325,7 @@ static int query_presets(const char *name, const UnitFilePresets *presets, char + } + } + +-int unit_file_query_preset(UnitFileScope scope, const char *root_dir, const char *name, UnitFilePresets *cached) { ++int unit_file_query_preset(LookupScope scope, const char *root_dir, const char *name, UnitFilePresets *cached) { + _cleanup_(unit_file_presets_freep) UnitFilePresets tmp = {}; + int r; + +@@ -3389,7 +3389,7 @@ static int execute_preset( + } + + static int preset_prepare_one( +- UnitFileScope scope, ++ LookupScope scope, + InstallContext *plus, + InstallContext *minus, + LookupPaths *lp, +@@ -3442,7 +3442,7 @@ static int preset_prepare_one( + } + + int unit_file_preset( +- UnitFileScope scope, ++ LookupScope scope, + UnitFileFlags file_flags, + const char *root_dir, + char **files, +@@ -3457,7 +3457,7 @@ int unit_file_preset( + int r; + + assert(scope >= 0); +- assert(scope < _UNIT_FILE_SCOPE_MAX); ++ assert(scope < _LOOKUP_SCOPE_MAX); + assert(mode < _UNIT_FILE_PRESET_MAX); + + r = lookup_paths_init(&lp, scope, 0, root_dir); +@@ -3482,7 +3482,7 @@ int unit_file_preset( + } + + int unit_file_preset_all( +- UnitFileScope scope, ++ LookupScope scope, + UnitFileFlags file_flags, + const char *root_dir, + UnitFilePresetMode mode, +@@ -3496,7 +3496,7 @@ int unit_file_preset_all( + int r; + + assert(scope >= 0); +- assert(scope < _UNIT_FILE_SCOPE_MAX); ++ assert(scope < _LOOKUP_SCOPE_MAX); + assert(mode < _UNIT_FILE_PRESET_MAX); + + r = lookup_paths_init(&lp, scope, 0, root_dir); +@@ -3557,7 +3557,7 @@ Hashmap* unit_file_list_free(Hashmap *h) { + DEFINE_TRIVIAL_CLEANUP_FUNC(UnitFileList*, unit_file_list_free_one); + + int unit_file_get_list( +- UnitFileScope scope, ++ LookupScope scope, + const char *root_dir, + Hashmap *h, + char **states, +@@ -3567,7 +3567,7 @@ int unit_file_get_list( + int r; + + assert(scope >= 0); +- assert(scope < _UNIT_FILE_SCOPE_MAX); ++ assert(scope < _LOOKUP_SCOPE_MAX); + assert(h); + + r = lookup_paths_init(&lp, scope, 0, root_dir); +diff --git a/src/shared/install.h b/src/shared/install.h +index 95427537f2..2ba7e8aea0 100644 +--- a/src/shared/install.h ++++ b/src/shared/install.h +@@ -15,6 +15,7 @@ typedef struct UnitFileInstallInfo UnitFileInstallInfo; + #include "macro.h" + #include "path-lookup.h" + #include "strv.h" ++#include "unit-file.h" + #include "unit-name.h" + + enum UnitFilePresetMode { +@@ -95,28 +96,28 @@ struct UnitFileInstallInfo { + }; + + int unit_file_enable( +- UnitFileScope scope, ++ LookupScope scope, + UnitFileFlags flags, + const char *root_dir, + char **files, + UnitFileChange **changes, + size_t *n_changes); + int unit_file_disable( +- UnitFileScope scope, ++ LookupScope scope, + UnitFileFlags flags, + const char *root_dir, + char **files, + UnitFileChange **changes, + size_t *n_changes); + int unit_file_reenable( +- UnitFileScope scope, ++ LookupScope scope, + UnitFileFlags flags, + const char *root_dir, + char **names_or_paths, + UnitFileChange **changes, + size_t *n_changes); + int unit_file_preset( +- UnitFileScope scope, ++ LookupScope scope, + UnitFileFlags flags, + const char *root_dir, + char **files, +@@ -124,52 +125,52 @@ int unit_file_preset( + UnitFileChange **changes, + size_t *n_changes); + int unit_file_preset_all( +- UnitFileScope scope, ++ LookupScope scope, + UnitFileFlags flags, + const char *root_dir, + UnitFilePresetMode mode, + UnitFileChange **changes, + size_t *n_changes); + int unit_file_mask( +- UnitFileScope scope, ++ LookupScope scope, + UnitFileFlags flags, + const char *root_dir, + char **files, + UnitFileChange **changes, + size_t *n_changes); + int unit_file_unmask( +- UnitFileScope scope, ++ LookupScope scope, + UnitFileFlags flags, + const char *root_dir, + char **files, + UnitFileChange **changes, + size_t *n_changes); + int unit_file_link( +- UnitFileScope scope, ++ LookupScope scope, + UnitFileFlags flags, + const char *root_dir, + char **files, + UnitFileChange **changes, + size_t *n_changes); + int unit_file_revert( +- UnitFileScope scope, ++ LookupScope scope, + const char *root_dir, + char **files, + UnitFileChange **changes, + size_t *n_changes); + int unit_file_set_default( +- UnitFileScope scope, ++ LookupScope scope, + UnitFileFlags flags, + const char *root_dir, + const char *file, + UnitFileChange **changes, + size_t *n_changes); + int unit_file_get_default( +- UnitFileScope scope, ++ LookupScope scope, + const char *root_dir, + char **name); + int unit_file_add_dependency( +- UnitFileScope scope, ++ LookupScope scope, + UnitFileFlags flags, + const char *root_dir, + char **files, +@@ -179,15 +180,15 @@ int unit_file_add_dependency( + size_t *n_changes); + + int unit_file_lookup_state( +- UnitFileScope scope, ++ LookupScope scope, + const LookupPaths *paths, + const char *name, + UnitFileState *ret); + +-int unit_file_get_state(UnitFileScope scope, const char *root_dir, const char *filename, UnitFileState *ret); +-int unit_file_exists(UnitFileScope scope, const LookupPaths *paths, const char *name); ++int unit_file_get_state(LookupScope scope, const char *root_dir, const char *filename, UnitFileState *ret); ++int unit_file_exists(LookupScope scope, const LookupPaths *paths, const char *name); + +-int unit_file_get_list(UnitFileScope scope, const char *root_dir, Hashmap *h, char **states, char **patterns); ++int unit_file_get_list(LookupScope scope, const char *root_dir, Hashmap *h, char **states, char **patterns); + Hashmap* unit_file_list_free(Hashmap *h); + + int unit_file_changes_add(UnitFileChange **changes, size_t *n_changes, int type, const char *path, const char *source); +@@ -210,7 +211,7 @@ typedef struct { + } UnitFilePresets; + + void unit_file_presets_freep(UnitFilePresets *p); +-int unit_file_query_preset(UnitFileScope scope, const char *root_dir, const char *name, UnitFilePresets *cached); ++int unit_file_query_preset(LookupScope scope, const char *root_dir, const char *name, UnitFilePresets *cached); + + const char *unit_file_state_to_string(UnitFileState s) _const_; + UnitFileState unit_file_state_from_string(const char *s) _pure_; +diff --git a/src/shared/specifier.c b/src/shared/specifier.c +index ac353a651c..cfa60abc7b 100644 +--- a/src/shared/specifier.c ++++ b/src/shared/specifier.c +@@ -18,10 +18,10 @@ + #include "id128-util.h" + #include "macro.h" + #include "os-util.h" ++#include "path-lookup.h" + #include "specifier.h" + #include "string-util.h" + #include "strv.h" +-#include "unit-file.h" + #include "user-util.h" + + /* +@@ -254,15 +254,15 @@ int specifier_os_image_version(char specifier, const void *data, const char *roo + } + + int specifier_group_name(char specifier, const void *data, const char *root, const void *userdata, char **ret) { +- UnitFileScope scope = PTR_TO_INT(data); ++ LookupScope scope = PTR_TO_INT(data); + char *t; + + assert(ret); + +- if (scope == UNIT_FILE_GLOBAL) ++ if (scope == LOOKUP_SCOPE_GLOBAL) + return -EINVAL; + +- t = gid_to_name(scope == UNIT_FILE_USER ? getgid() : 0); ++ t = gid_to_name(scope == LOOKUP_SCOPE_USER ? getgid() : 0); + if (!t) + return -ENOMEM; + +@@ -271,15 +271,15 @@ int specifier_group_name(char specifier, const void *data, const char *root, con + } + + int specifier_group_id(char specifier, const void *data, const char *root, const void *userdata, char **ret) { +- UnitFileScope scope = PTR_TO_INT(data); ++ LookupScope scope = PTR_TO_INT(data); + gid_t gid; + + assert(ret); + +- if (scope == UNIT_FILE_GLOBAL) ++ if (scope == LOOKUP_SCOPE_GLOBAL) + return -EINVAL; + +- gid = scope == UNIT_FILE_USER ? getgid() : 0; ++ gid = scope == LOOKUP_SCOPE_USER ? getgid() : 0; + + if (asprintf(ret, UID_FMT, gid) < 0) + return -ENOMEM; +@@ -288,16 +288,16 @@ int specifier_group_id(char specifier, const void *data, const char *root, const + } + + int specifier_user_name(char specifier, const void *data, const char *root, const void *userdata, char **ret) { +- UnitFileScope scope = PTR_TO_INT(data); ++ LookupScope scope = PTR_TO_INT(data); + uid_t uid; + char *t; + + assert(ret); + +- if (scope == UNIT_FILE_GLOBAL) ++ if (scope == LOOKUP_SCOPE_GLOBAL) + return -EINVAL; + +- uid = scope == UNIT_FILE_USER ? getuid() : 0; ++ uid = scope == LOOKUP_SCOPE_USER ? getuid() : 0; + + /* If we are UID 0 (root), this will not result in NSS, otherwise it might. This is good, as we want + * to be able to run this in PID 1, where our user ID is 0, but where NSS lookups are not allowed. +@@ -315,15 +315,15 @@ int specifier_user_name(char specifier, const void *data, const char *root, cons + } + + int specifier_user_id(char specifier, const void *data, const char *root, const void *userdata, char **ret) { +- UnitFileScope scope = PTR_TO_INT(data); ++ LookupScope scope = PTR_TO_INT(data); + uid_t uid; + + assert(ret); + +- if (scope == UNIT_FILE_GLOBAL) ++ if (scope == LOOKUP_SCOPE_GLOBAL) + return -EINVAL; + +- uid = scope == UNIT_FILE_USER ? getuid() : 0; ++ uid = scope == LOOKUP_SCOPE_USER ? getuid() : 0; + + if (asprintf(ret, UID_FMT, uid) < 0) + return -ENOMEM; +diff --git a/src/systemctl/systemctl-edit.c b/src/systemctl/systemctl-edit.c +index 328168e4bb..1d9e8dc5d2 100644 +--- a/src/systemctl/systemctl-edit.c ++++ b/src/systemctl/systemctl-edit.c +@@ -99,7 +99,7 @@ int cat(int argc, char *argv[], void *userdata) { + ansi_highlight_red(), + ansi_highlight_red(), + ansi_highlight_red(), +- arg_scope == UNIT_FILE_SYSTEM ? "" : " --user", ++ arg_scope == LOOKUP_SCOPE_SYSTEM ? "" : " --user", + ansi_normal()); + + r = cat_files(fragment_path, dropin_paths, 0); +@@ -406,8 +406,8 @@ static int find_paths_to_edit(sd_bus *bus, char **names, char ***paths) { + if (!path) { + if (!arg_force) { + log_info("Run 'systemctl edit%s --force --full %s' to create a new unit.", +- arg_scope == UNIT_FILE_GLOBAL ? " --global" : +- arg_scope == UNIT_FILE_USER ? " --user" : "", ++ arg_scope == LOOKUP_SCOPE_GLOBAL ? " --global" : ++ arg_scope == LOOKUP_SCOPE_USER ? " --user" : "", + *name); + return -ENOENT; + } +diff --git a/src/systemctl/systemctl-is-enabled.c b/src/systemctl/systemctl-is-enabled.c +index eaf25217a8..db8f9e8cc4 100644 +--- a/src/systemctl/systemctl-is-enabled.c ++++ b/src/systemctl/systemctl-is-enabled.c +@@ -18,7 +18,7 @@ static int show_installation_targets_client_side(const char *name) { + flags = UNIT_FILE_DRY_RUN | + (arg_runtime ? UNIT_FILE_RUNTIME : 0); + +- r = unit_file_disable(UNIT_FILE_SYSTEM, flags, NULL, p, &changes, &n_changes); ++ r = unit_file_disable(LOOKUP_SCOPE_SYSTEM, flags, NULL, p, &changes, &n_changes); + if (r < 0) + return log_error_errno(r, "Failed to get file links for %s: %m", name); + +diff --git a/src/systemctl/systemctl-show.c b/src/systemctl/systemctl-show.c +index ee96dac457..d472e1759d 100644 +--- a/src/systemctl/systemctl-show.c ++++ b/src/systemctl/systemctl-show.c +@@ -764,7 +764,7 @@ static void print_status_info( + getuid(), + get_output_flags() | OUTPUT_BEGIN_NEWLINE, + SD_JOURNAL_LOCAL_ONLY, +- arg_scope == UNIT_FILE_SYSTEM, ++ arg_scope == LOOKUP_SCOPE_SYSTEM, + ellipsized); + + if (i->need_daemon_reload) +diff --git a/src/systemctl/systemctl-start-special.c b/src/systemctl/systemctl-start-special.c +index 6ece700a9b..9c88e7910c 100644 +--- a/src/systemctl/systemctl-start-special.c ++++ b/src/systemctl/systemctl-start-special.c +@@ -242,10 +242,10 @@ int start_special(int argc, char *argv[], void *userdata) { + int start_system_special(int argc, char *argv[], void *userdata) { + /* Like start_special above, but raises an error when running in user mode */ + +- if (arg_scope != UNIT_FILE_SYSTEM) ++ if (arg_scope != LOOKUP_SCOPE_SYSTEM) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), + "Bad action for %s mode.", +- arg_scope == UNIT_FILE_GLOBAL ? "--global" : "--user"); ++ arg_scope == LOOKUP_SCOPE_GLOBAL ? "--global" : "--user"); + + return start_special(argc, argv, userdata); + } +diff --git a/src/systemctl/systemctl-start-unit.c b/src/systemctl/systemctl-start-unit.c +index b45495d51d..88b2b7a53d 100644 +--- a/src/systemctl/systemctl-start-unit.c ++++ b/src/systemctl/systemctl-start-unit.c +@@ -168,8 +168,8 @@ fail: + BUS_ERROR_UNIT_MASKED, + BUS_ERROR_JOB_TYPE_NOT_APPLICABLE)) + log_error("See %s logs and 'systemctl%s status%s %s' for details.", +- arg_scope == UNIT_FILE_SYSTEM ? "system" : "user", +- arg_scope == UNIT_FILE_SYSTEM ? "" : " --user", ++ arg_scope == LOOKUP_SCOPE_SYSTEM ? "system" : "user", ++ arg_scope == LOOKUP_SCOPE_SYSTEM ? "" : " --user", + name[0] == '-' ? " --" : "", + name); + +@@ -242,7 +242,7 @@ static const char** make_extra_args(const char *extra_args[static 4]) { + + assert(extra_args); + +- if (arg_scope != UNIT_FILE_SYSTEM) ++ if (arg_scope != LOOKUP_SCOPE_SYSTEM) + extra_args[n++] = "--user"; + + if (arg_transport == BUS_TRANSPORT_REMOTE) { +diff --git a/src/systemctl/systemctl-sysv-compat.c b/src/systemctl/systemctl-sysv-compat.c +index c6e8defd1b..f6889993ed 100644 +--- a/src/systemctl/systemctl-sysv-compat.c ++++ b/src/systemctl/systemctl-sysv-compat.c +@@ -116,7 +116,7 @@ int enable_sysv_units(const char *verb, char **args) { + + /* Processes all SysV units, and reshuffles the array so that afterwards only the native units remain */ + +- if (arg_scope != UNIT_FILE_SYSTEM) ++ if (arg_scope != LOOKUP_SCOPE_SYSTEM) + return 0; + + if (getenv_bool("SYSTEMCTL_SKIP_SYSV") > 0) +diff --git a/src/systemctl/systemctl-util.c b/src/systemctl/systemctl-util.c +index db40154943..c39e0b7d5d 100644 +--- a/src/systemctl/systemctl-util.c ++++ b/src/systemctl/systemctl-util.c +@@ -46,7 +46,7 @@ int acquire_bus(BusFocus focus, sd_bus **ret) { + if (!buses[focus]) { + bool user; + +- user = arg_scope != UNIT_FILE_SYSTEM; ++ user = arg_scope != LOOKUP_SCOPE_SYSTEM; + + if (focus == BUS_MANAGER) + r = bus_connect_transport_systemd(arg_transport, arg_host, user, &buses[focus]); +@@ -73,7 +73,7 @@ void ask_password_agent_open_maybe(void) { + if (arg_dry_run) + return; + +- if (arg_scope != UNIT_FILE_SYSTEM) ++ if (arg_scope != LOOKUP_SCOPE_SYSTEM) + return; + + ask_password_agent_open_if_enabled(arg_transport, arg_ask_password); +@@ -82,7 +82,7 @@ void ask_password_agent_open_maybe(void) { + void polkit_agent_open_maybe(void) { + /* Open the polkit agent as a child process if necessary */ + +- if (arg_scope != UNIT_FILE_SYSTEM) ++ if (arg_scope != LOOKUP_SCOPE_SYSTEM) + return; + + polkit_agent_open_if_enabled(arg_transport, arg_ask_password); +@@ -380,7 +380,7 @@ void warn_unit_file_changed(const char *unit) { + ansi_highlight_red(), + ansi_normal(), + unit, +- arg_scope == UNIT_FILE_SYSTEM ? "" : " --user"); ++ arg_scope == LOOKUP_SCOPE_SYSTEM ? "" : " --user"); + } + + int unit_file_find_path(LookupPaths *lp, const char *unit_name, char **ret_unit_path) { +@@ -814,7 +814,7 @@ bool install_client_side(void) { + if (!isempty(arg_root)) + return true; + +- if (arg_scope == UNIT_FILE_GLOBAL) ++ if (arg_scope == LOOKUP_SCOPE_GLOBAL) + return true; + + /* Unsupported environment variable, mostly for debugging purposes */ +diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c +index 0489796a75..094cceebd6 100644 +--- a/src/systemctl/systemctl.c ++++ b/src/systemctl/systemctl.c +@@ -66,7 +66,7 @@ char **arg_properties = NULL; + bool arg_all = false; + enum dependency arg_dependency = DEPENDENCY_FORWARD; + const char *_arg_job_mode = NULL; +-UnitFileScope arg_scope = UNIT_FILE_SYSTEM; ++LookupScope arg_scope = LOOKUP_SCOPE_SYSTEM; + bool arg_wait = false; + bool arg_no_block = false; + int arg_legend = -1; /* -1: true, unless --quiet is passed, 1: true */ +@@ -616,15 +616,15 @@ static int systemctl_parse_argv(int argc, char *argv[]) { + break; + + case ARG_USER: +- arg_scope = UNIT_FILE_USER; ++ arg_scope = LOOKUP_SCOPE_USER; + break; + + case ARG_SYSTEM: +- arg_scope = UNIT_FILE_SYSTEM; ++ arg_scope = LOOKUP_SCOPE_SYSTEM; + break; + + case ARG_GLOBAL: +- arg_scope = UNIT_FILE_GLOBAL; ++ arg_scope = LOOKUP_SCOPE_GLOBAL; + break; + + case ARG_WAIT: +@@ -924,10 +924,10 @@ static int systemctl_parse_argv(int argc, char *argv[]) { + + /* If we are in --user mode, there's no point in talking to PolicyKit or the infra to query system + * passwords */ +- if (arg_scope != UNIT_FILE_SYSTEM) ++ if (arg_scope != LOOKUP_SCOPE_SYSTEM) + arg_ask_password = false; + +- if (arg_transport == BUS_TRANSPORT_REMOTE && arg_scope != UNIT_FILE_SYSTEM) ++ if (arg_transport == BUS_TRANSPORT_REMOTE && arg_scope != LOOKUP_SCOPE_SYSTEM) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), + "Cannot access user instance remotely."); + +diff --git a/src/systemctl/systemctl.h b/src/systemctl/systemctl.h +index d6b9d7495c..7507398c4a 100644 +--- a/src/systemctl/systemctl.h ++++ b/src/systemctl/systemctl.h +@@ -51,7 +51,7 @@ extern char **arg_properties; + extern bool arg_all; + extern enum dependency arg_dependency; + extern const char *_arg_job_mode; +-extern UnitFileScope arg_scope; ++extern LookupScope arg_scope; + extern bool arg_wait; + extern bool arg_no_block; + extern int arg_legend; +diff --git a/src/sysv-generator/sysv-generator.c b/src/sysv-generator/sysv-generator.c +index 428509f4ce..14ae873dc0 100644 +--- a/src/sysv-generator/sysv-generator.c ++++ b/src/sysv-generator/sysv-generator.c +@@ -747,7 +747,7 @@ static int enumerate_sysv(const LookupPaths *lp, Hashmap *all_services) { + if (hashmap_contains(all_services, name)) + continue; + +- r = unit_file_exists(UNIT_FILE_SYSTEM, lp, name); ++ r = unit_file_exists(LOOKUP_SCOPE_SYSTEM, lp, name); + if (r < 0 && !IN_SET(r, -ELOOP, -ERFKILL, -EADDRNOTAVAIL)) { + log_debug_errno(r, "Failed to detect whether %s exists, skipping: %m", name); + continue; +@@ -891,7 +891,7 @@ static int run(const char *dest, const char *dest_early, const char *dest_late) + + assert_se(arg_dest = dest_late); + +- r = lookup_paths_init_or_warn(&lp, UNIT_FILE_SYSTEM, LOOKUP_PATHS_EXCLUDE_GENERATED, NULL); ++ r = lookup_paths_init_or_warn(&lp, LOOKUP_SCOPE_SYSTEM, LOOKUP_PATHS_EXCLUDE_GENERATED, NULL); + if (r < 0) + return r; + +diff --git a/src/test/test-bpf-firewall.c b/src/test/test-bpf-firewall.c +index 2e19db600e..cebd7d8a8b 100644 +--- a/src/test/test-bpf-firewall.c ++++ b/src/test/test-bpf-firewall.c +@@ -97,7 +97,7 @@ int main(int argc, char *argv[]) { + + /* The simple tests succeeded. Now let's try full unit-based use-case. */ + +- assert_se(manager_new(UNIT_FILE_USER, MANAGER_TEST_RUN_BASIC, &m) >= 0); ++ assert_se(manager_new(LOOKUP_SCOPE_USER, MANAGER_TEST_RUN_BASIC, &m) >= 0); + assert_se(manager_startup(m, NULL, NULL, NULL) >= 0); + + assert_se(u = unit_new(m, sizeof(Service))); +diff --git a/src/test/test-bpf-foreign-programs.c b/src/test/test-bpf-foreign-programs.c +index 56933c87bf..45b685d219 100644 +--- a/src/test/test-bpf-foreign-programs.c ++++ b/src/test/test-bpf-foreign-programs.c +@@ -301,7 +301,7 @@ int main(int argc, char *argv[]) { + assert_se(set_unit_path(unit_dir) >= 0); + assert_se(runtime_dir = setup_fake_runtime_dir()); + +- assert_se(manager_new(UNIT_FILE_USER, MANAGER_TEST_RUN_BASIC, &m) >= 0); ++ assert_se(manager_new(LOOKUP_SCOPE_USER, MANAGER_TEST_RUN_BASIC, &m) >= 0); + assert_se(manager_startup(m, NULL, NULL, NULL) >= 0); + + assert_se(test_bpf_cgroup_programs(m, +diff --git a/src/test/test-bpf-lsm.c b/src/test/test-bpf-lsm.c +index 4a3b327a3f..812f7e99fb 100644 +--- a/src/test/test-bpf-lsm.c ++++ b/src/test/test-bpf-lsm.c +@@ -92,7 +92,7 @@ int main(int argc, char *argv[]) { + assert_se(set_unit_path(unit_dir) >= 0); + assert_se(runtime_dir = setup_fake_runtime_dir()); + +- assert_se(manager_new(UNIT_FILE_SYSTEM, MANAGER_TEST_RUN_BASIC, &m) >= 0); ++ assert_se(manager_new(LOOKUP_SCOPE_SYSTEM, MANAGER_TEST_RUN_BASIC, &m) >= 0); + assert_se(manager_startup(m, NULL, NULL, NULL) >= 0); + + /* We need to enable access to the filesystem where the binary is so we +diff --git a/src/test/test-cgroup-mask.c b/src/test/test-cgroup-mask.c +index 6058f32b0e..57483f72c2 100644 +--- a/src/test/test-cgroup-mask.c ++++ b/src/test/test-cgroup-mask.c +@@ -42,7 +42,7 @@ TEST_RET(cgroup_mask, .sd_booted = true) { + assert_se(get_testdata_dir("units", &unit_dir) >= 0); + assert_se(set_unit_path(unit_dir) >= 0); + assert_se(runtime_dir = setup_fake_runtime_dir()); +- r = manager_new(UNIT_FILE_USER, MANAGER_TEST_RUN_BASIC, &m); ++ r = manager_new(LOOKUP_SCOPE_USER, MANAGER_TEST_RUN_BASIC, &m); + if (IN_SET(r, -EPERM, -EACCES)) { + log_error_errno(r, "manager_new: %m"); + return log_tests_skipped("cannot create manager"); +diff --git a/src/test/test-cgroup-unit-default.c b/src/test/test-cgroup-unit-default.c +index 4c8de1e382..94201a3ccc 100644 +--- a/src/test/test-cgroup-unit-default.c ++++ b/src/test/test-cgroup-unit-default.c +@@ -26,7 +26,7 @@ TEST_RET(default_memory_low, .sd_booted = true) { + assert_se(get_testdata_dir("units", &unit_dir) >= 0); + assert_se(set_unit_path(unit_dir) >= 0); + assert_se(runtime_dir = setup_fake_runtime_dir()); +- r = manager_new(UNIT_FILE_USER, MANAGER_TEST_RUN_BASIC, &m); ++ r = manager_new(LOOKUP_SCOPE_USER, MANAGER_TEST_RUN_BASIC, &m); + if (IN_SET(r, -EPERM, -EACCES)) { + log_error_errno(r, "manager_new: %m"); + return log_tests_skipped("cannot create manager"); +diff --git a/src/test/test-engine.c b/src/test/test-engine.c +index 673c665612..70f727d91c 100644 +--- a/src/test/test-engine.c ++++ b/src/test/test-engine.c +@@ -93,7 +93,7 @@ int main(int argc, char *argv[]) { + assert_se(set_unit_path(unit_dir) >= 0); + assert_se(runtime_dir = setup_fake_runtime_dir()); + +- r = manager_new(UNIT_FILE_USER, MANAGER_TEST_RUN_BASIC, &m); ++ r = manager_new(LOOKUP_SCOPE_USER, MANAGER_TEST_RUN_BASIC, &m); + if (manager_errno_skip_test(r)) + return log_tests_skipped_errno(r, "manager_new"); + assert_se(r >= 0); +diff --git a/src/test/test-execute.c b/src/test/test-execute.c +index 3b4b02184c..3505e81a43 100644 +--- a/src/test/test-execute.c ++++ b/src/test/test-execute.c +@@ -1116,7 +1116,7 @@ typedef struct test_entry { + + #define entry(x) {x, #x} + +-static int run_tests(UnitFileScope scope, const test_entry tests[], char **patterns) { ++static int run_tests(LookupScope scope, const test_entry tests[], char **patterns) { + _cleanup_(manager_freep) Manager *m = NULL; + int r; + +@@ -1238,11 +1238,11 @@ int main(int argc, char *argv[]) { + assert_se(unsetenv("VAR2") == 0); + assert_se(unsetenv("VAR3") == 0); + +- r = run_tests(UNIT_FILE_USER, user_tests, argv + 1); ++ r = run_tests(LOOKUP_SCOPE_USER, user_tests, argv + 1); + if (r != 0) + return r; + +- r = run_tests(UNIT_FILE_SYSTEM, system_tests, argv + 1); ++ r = run_tests(LOOKUP_SCOPE_SYSTEM, system_tests, argv + 1); + if (r != 0) + return r; + +@@ -1264,11 +1264,11 @@ int main(int argc, char *argv[]) { + + can_unshare = false; + +- r = run_tests(UNIT_FILE_USER, user_tests, argv + 1); ++ r = run_tests(LOOKUP_SCOPE_USER, user_tests, argv + 1); + if (r != 0) + return r; + +- return run_tests(UNIT_FILE_SYSTEM, system_tests, argv + 1); ++ return run_tests(LOOKUP_SCOPE_SYSTEM, system_tests, argv + 1); + #else + return 0; + #endif +diff --git a/src/test/test-install-root.c b/src/test/test-install-root.c +index dca695d124..a36536b85b 100644 +--- a/src/test/test-install-root.c ++++ b/src/test/test-install-root.c +@@ -23,41 +23,41 @@ TEST(basic_mask_and_enable) { + UnitFileChange *changes = NULL; + size_t n_changes = 0; + +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "a.service", NULL) == -ENOENT); +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "b.service", NULL) == -ENOENT); +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "c.service", NULL) == -ENOENT); +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "d.service", NULL) == -ENOENT); +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "e.service", NULL) == -ENOENT); +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "f.service", NULL) == -ENOENT); ++ assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "a.service", NULL) == -ENOENT); ++ assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "b.service", NULL) == -ENOENT); ++ assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "c.service", NULL) == -ENOENT); ++ assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "d.service", NULL) == -ENOENT); ++ assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "e.service", NULL) == -ENOENT); ++ assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "f.service", NULL) == -ENOENT); + + p = strjoina(root, "/usr/lib/systemd/system/a.service"); + assert_se(write_string_file(p, + "[Install]\n" + "WantedBy=multi-user.target\n", WRITE_STRING_FILE_CREATE) >= 0); + +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "a.service", NULL) >= 0); +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "a.service", &state) >= 0 && state == UNIT_FILE_DISABLED); ++ assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "a.service", NULL) >= 0); ++ assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "a.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + + p = strjoina(root, "/usr/lib/systemd/system/b.service"); + assert_se(symlink("a.service", p) >= 0); + +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "b.service", NULL) >= 0); +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "b.service", &state) >= 0 && state == UNIT_FILE_ALIAS); ++ assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "b.service", NULL) >= 0); ++ assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "b.service", &state) >= 0 && state == UNIT_FILE_ALIAS); + + p = strjoina(root, "/usr/lib/systemd/system/c.service"); + assert_se(symlink("/usr/lib/systemd/system/a.service", p) >= 0); + +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "c.service", NULL) >= 0); +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "c.service", &state) >= 0 && state == UNIT_FILE_ALIAS); ++ assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "c.service", NULL) >= 0); ++ assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "c.service", &state) >= 0 && state == UNIT_FILE_ALIAS); + + p = strjoina(root, "/usr/lib/systemd/system/d.service"); + assert_se(symlink("c.service", p) >= 0); + + /* This one is interesting, as d follows a relative, then an absolute symlink */ +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "d.service", NULL) >= 0); +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "d.service", &state) >= 0 && state == UNIT_FILE_ALIAS); ++ assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "d.service", NULL) >= 0); ++ assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "d.service", &state) >= 0 && state == UNIT_FILE_ALIAS); + +- assert_se(unit_file_mask(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("a.service"), &changes, &n_changes) >= 0); ++ assert_se(unit_file_mask(LOOKUP_SCOPE_SYSTEM, 0, root, STRV_MAKE("a.service"), &changes, &n_changes) >= 0); + assert_se(n_changes == 1); + assert_se(changes[0].type_or_errno == UNIT_FILE_SYMLINK); + assert_se(streq(changes[0].source, "/dev/null")); +@@ -67,17 +67,17 @@ TEST(basic_mask_and_enable) { + unit_file_changes_free(changes, n_changes); + changes = NULL; n_changes = 0; + +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "a.service", &state) >= 0 && state == UNIT_FILE_MASKED); +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "b.service", &state) >= 0 && state == UNIT_FILE_MASKED); +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "c.service", &state) >= 0 && state == UNIT_FILE_MASKED); +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "d.service", &state) >= 0 && state == UNIT_FILE_MASKED); ++ assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "a.service", &state) >= 0 && state == UNIT_FILE_MASKED); ++ assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "b.service", &state) >= 0 && state == UNIT_FILE_MASKED); ++ assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "c.service", &state) >= 0 && state == UNIT_FILE_MASKED); ++ assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "d.service", &state) >= 0 && state == UNIT_FILE_MASKED); + + /* Enabling a masked unit should fail! */ +- assert_se(unit_file_enable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("a.service"), &changes, &n_changes) == -ERFKILL); ++ assert_se(unit_file_enable(LOOKUP_SCOPE_SYSTEM, 0, root, STRV_MAKE("a.service"), &changes, &n_changes) == -ERFKILL); + unit_file_changes_free(changes, n_changes); + changes = NULL; n_changes = 0; + +- assert_se(unit_file_unmask(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("a.service"), &changes, &n_changes) >= 0); ++ assert_se(unit_file_unmask(LOOKUP_SCOPE_SYSTEM, 0, root, STRV_MAKE("a.service"), &changes, &n_changes) >= 0); + assert_se(n_changes == 1); + assert_se(changes[0].type_or_errno == UNIT_FILE_UNLINK); + p = strjoina(root, SYSTEM_CONFIG_UNIT_DIR"/a.service"); +@@ -85,7 +85,7 @@ TEST(basic_mask_and_enable) { + unit_file_changes_free(changes, n_changes); + changes = NULL; n_changes = 0; + +- assert_se(unit_file_enable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("a.service"), &changes, &n_changes) == 1); ++ assert_se(unit_file_enable(LOOKUP_SCOPE_SYSTEM, 0, root, STRV_MAKE("a.service"), &changes, &n_changes) == 1); + assert_se(n_changes == 1); + assert_se(changes[0].type_or_errno == UNIT_FILE_SYMLINK); + assert_se(streq(changes[0].source, "../a.service")); +@@ -94,18 +94,18 @@ TEST(basic_mask_and_enable) { + unit_file_changes_free(changes, n_changes); + changes = NULL; n_changes = 0; + +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "a.service", &state) >= 0 && state == UNIT_FILE_ENABLED); +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "b.service", &state) >= 0 && state == UNIT_FILE_ALIAS); +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "c.service", &state) >= 0 && state == UNIT_FILE_ALIAS); +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "d.service", &state) >= 0 && state == UNIT_FILE_ALIAS); ++ assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "a.service", &state) >= 0 && state == UNIT_FILE_ENABLED); ++ assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "b.service", &state) >= 0 && state == UNIT_FILE_ALIAS); ++ assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "c.service", &state) >= 0 && state == UNIT_FILE_ALIAS); ++ assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "d.service", &state) >= 0 && state == UNIT_FILE_ALIAS); + + /* Enabling it again should succeed but be a NOP */ +- assert_se(unit_file_enable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("a.service"), &changes, &n_changes) >= 0); ++ assert_se(unit_file_enable(LOOKUP_SCOPE_SYSTEM, 0, root, STRV_MAKE("a.service"), &changes, &n_changes) >= 0); + assert_se(n_changes == 0); + unit_file_changes_free(changes, n_changes); + changes = NULL; n_changes = 0; + +- assert_se(unit_file_disable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("a.service"), &changes, &n_changes) >= 0); ++ assert_se(unit_file_disable(LOOKUP_SCOPE_SYSTEM, 0, root, STRV_MAKE("a.service"), &changes, &n_changes) >= 0); + assert_se(n_changes == 1); + assert_se(changes[0].type_or_errno == UNIT_FILE_UNLINK); + p = strjoina(root, SYSTEM_CONFIG_UNIT_DIR"/multi-user.target.wants/a.service"); +@@ -113,19 +113,19 @@ TEST(basic_mask_and_enable) { + unit_file_changes_free(changes, n_changes); + changes = NULL; n_changes = 0; + +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "a.service", &state) >= 0 && state == UNIT_FILE_DISABLED); +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "b.service", &state) >= 0 && state == UNIT_FILE_ALIAS); +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "c.service", &state) >= 0 && state == UNIT_FILE_ALIAS); +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "d.service", &state) >= 0 && state == UNIT_FILE_ALIAS); ++ assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "a.service", &state) >= 0 && state == UNIT_FILE_DISABLED); ++ assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "b.service", &state) >= 0 && state == UNIT_FILE_ALIAS); ++ assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "c.service", &state) >= 0 && state == UNIT_FILE_ALIAS); ++ assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "d.service", &state) >= 0 && state == UNIT_FILE_ALIAS); + + /* Disabling a disabled unit must succeed but be a NOP */ +- assert_se(unit_file_disable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("a.service"), &changes, &n_changes) >= 0); ++ assert_se(unit_file_disable(LOOKUP_SCOPE_SYSTEM, 0, root, STRV_MAKE("a.service"), &changes, &n_changes) >= 0); + assert_se(n_changes == 0); + unit_file_changes_free(changes, n_changes); + changes = NULL; n_changes = 0; + + /* Let's enable this indirectly via a symlink */ +- assert_se(unit_file_enable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("d.service"), &changes, &n_changes) >= 0); ++ assert_se(unit_file_enable(LOOKUP_SCOPE_SYSTEM, 0, root, STRV_MAKE("d.service"), &changes, &n_changes) >= 0); + assert_se(n_changes == 1); + assert_se(changes[0].type_or_errno == UNIT_FILE_SYMLINK); + assert_se(streq(changes[0].source, "../a.service")); +@@ -134,14 +134,14 @@ TEST(basic_mask_and_enable) { + unit_file_changes_free(changes, n_changes); + changes = NULL; n_changes = 0; + +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "a.service", &state) >= 0 && state == UNIT_FILE_ENABLED); +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "b.service", &state) >= 0 && state == UNIT_FILE_ALIAS); +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "c.service", &state) >= 0 && state == UNIT_FILE_ALIAS); +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "d.service", &state) >= 0 && state == UNIT_FILE_ALIAS); ++ assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "a.service", &state) >= 0 && state == UNIT_FILE_ENABLED); ++ assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "b.service", &state) >= 0 && state == UNIT_FILE_ALIAS); ++ assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "c.service", &state) >= 0 && state == UNIT_FILE_ALIAS); ++ assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "d.service", &state) >= 0 && state == UNIT_FILE_ALIAS); + + /* Let's try to reenable */ + +- assert_se(unit_file_reenable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("b.service"), &changes, &n_changes) >= 0); ++ assert_se(unit_file_reenable(LOOKUP_SCOPE_SYSTEM, 0, root, STRV_MAKE("b.service"), &changes, &n_changes) >= 0); + assert_se(n_changes == 2); + assert_se(changes[0].type_or_errno == UNIT_FILE_UNLINK); + p = strjoina(root, SYSTEM_CONFIG_UNIT_DIR"/multi-user.target.wants/a.service"); +@@ -152,24 +152,24 @@ TEST(basic_mask_and_enable) { + unit_file_changes_free(changes, n_changes); + changes = NULL; n_changes = 0; + +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "a.service", &state) >= 0 && state == UNIT_FILE_ENABLED); +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "b.service", &state) >= 0 && state == UNIT_FILE_ALIAS); +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "c.service", &state) >= 0 && state == UNIT_FILE_ALIAS); +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "d.service", &state) >= 0 && state == UNIT_FILE_ALIAS); ++ assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "a.service", &state) >= 0 && state == UNIT_FILE_ENABLED); ++ assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "b.service", &state) >= 0 && state == UNIT_FILE_ALIAS); ++ assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "c.service", &state) >= 0 && state == UNIT_FILE_ALIAS); ++ assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "d.service", &state) >= 0 && state == UNIT_FILE_ALIAS); + + /* Test masking with relative symlinks */ + + p = strjoina(root, "/usr/lib/systemd/system/e.service"); + assert_se(symlink("../../../../../../dev/null", p) >= 0); + +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "e.service", NULL) >= 0); +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "e.service", &state) >= 0 && state == UNIT_FILE_MASKED); ++ assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "e.service", NULL) >= 0); ++ assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "e.service", &state) >= 0 && state == UNIT_FILE_MASKED); + + assert_se(unlink(p) == 0); + assert_se(symlink("/usr/../dev/null", p) >= 0); + +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "e.service", NULL) >= 0); +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "e.service", &state) >= 0 && state == UNIT_FILE_MASKED); ++ assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "e.service", NULL) >= 0); ++ assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "e.service", &state) >= 0 && state == UNIT_FILE_MASKED); + + assert_se(unlink(p) == 0); + +@@ -180,10 +180,10 @@ TEST(basic_mask_and_enable) { + "[Install]\n" + "WantedBy=x.target\n", WRITE_STRING_FILE_CREATE) >= 0); + +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "f.service", NULL) >= 0); +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "f.service", &state) >= 0 && state == UNIT_FILE_DISABLED); ++ assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "f.service", NULL) >= 0); ++ assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "f.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + +- assert_se(unit_file_enable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("f.service"), &changes, &n_changes) == 1); ++ assert_se(unit_file_enable(LOOKUP_SCOPE_SYSTEM, 0, root, STRV_MAKE("f.service"), &changes, &n_changes) == 1); + assert_se(n_changes == 2); + assert_se(changes[0].type_or_errno == UNIT_FILE_SYMLINK); + assert_se(streq(changes[0].source, "../f.service")); +@@ -196,7 +196,7 @@ TEST(basic_mask_and_enable) { + unit_file_changes_free(changes, n_changes); + changes = NULL; n_changes = 0; + +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "f.service", &state) >= 0 && state == UNIT_FILE_ENABLED); ++ assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "f.service", &state) >= 0 && state == UNIT_FILE_ENABLED); + } + + TEST(linked_units) { +@@ -236,9 +236,9 @@ TEST(linked_units) { + "[Install]\n" + "WantedBy=multi-user.target\n", WRITE_STRING_FILE_CREATE) >= 0); + +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "linked.service", NULL) == -ENOENT); +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "linked2.service", NULL) == -ENOENT); +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "linked3.service", NULL) == -ENOENT); ++ assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "linked.service", NULL) == -ENOENT); ++ assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "linked2.service", NULL) == -ENOENT); ++ assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "linked3.service", NULL) == -ENOENT); + + p = strjoina(root, "/usr/lib/systemd/system/linked2.service"); + assert_se(symlink("/opt/linked2.service", p) >= 0); +@@ -246,12 +246,12 @@ TEST(linked_units) { + p = strjoina(root, SYSTEM_CONFIG_UNIT_DIR"/linked3.service"); + assert_se(symlink("/opt/linked3.service", p) >= 0); + +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "linked.service", &state) == -ENOENT); +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "linked2.service", &state) >= 0 && state == UNIT_FILE_DISABLED); +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "linked3.service", &state) >= 0 && state == UNIT_FILE_LINKED); ++ assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "linked.service", &state) == -ENOENT); ++ assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "linked2.service", &state) >= 0 && state == UNIT_FILE_DISABLED); ++ assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "linked3.service", &state) >= 0 && state == UNIT_FILE_LINKED); + + /* First, let's link the unit into the search path */ +- assert_se(unit_file_link(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("/opt/linked.service"), &changes, &n_changes) >= 0); ++ assert_se(unit_file_link(LOOKUP_SCOPE_SYSTEM, 0, root, STRV_MAKE("/opt/linked.service"), &changes, &n_changes) >= 0); + assert_se(n_changes == 1); + assert_se(changes[0].type_or_errno == UNIT_FILE_SYMLINK); + assert_se(streq(changes[0].source, "/opt/linked.service")); +@@ -260,10 +260,10 @@ TEST(linked_units) { + unit_file_changes_free(changes, n_changes); + changes = NULL; n_changes = 0; + +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "linked.service", &state) >= 0 && state == UNIT_FILE_LINKED); ++ assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "linked.service", &state) >= 0 && state == UNIT_FILE_LINKED); + + /* Let's unlink it from the search path again */ +- assert_se(unit_file_disable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("linked.service"), &changes, &n_changes) >= 0); ++ assert_se(unit_file_disable(LOOKUP_SCOPE_SYSTEM, 0, root, STRV_MAKE("linked.service"), &changes, &n_changes) >= 0); + assert_se(n_changes == 1); + assert_se(changes[0].type_or_errno == UNIT_FILE_UNLINK); + p = strjoina(root, SYSTEM_CONFIG_UNIT_DIR"/linked.service"); +@@ -271,10 +271,10 @@ TEST(linked_units) { + unit_file_changes_free(changes, n_changes); + changes = NULL; n_changes = 0; + +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "linked.service", NULL) == -ENOENT); ++ assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "linked.service", NULL) == -ENOENT); + + /* Now, let's not just link it, but also enable it */ +- assert_se(unit_file_enable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("/opt/linked.service"), &changes, &n_changes) >= 0); ++ assert_se(unit_file_enable(LOOKUP_SCOPE_SYSTEM, 0, root, STRV_MAKE("/opt/linked.service"), &changes, &n_changes) >= 0); + assert_se(n_changes == 2); + p = strjoina(root, SYSTEM_CONFIG_UNIT_DIR"/multi-user.target.wants/linked.service"); + q = strjoina(root, SYSTEM_CONFIG_UNIT_DIR"/linked.service"); +@@ -294,10 +294,10 @@ TEST(linked_units) { + unit_file_changes_free(changes, n_changes); + changes = NULL; n_changes = 0; + +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "linked.service", &state) >= 0 && state == UNIT_FILE_ENABLED); ++ assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "linked.service", &state) >= 0 && state == UNIT_FILE_ENABLED); + + /* And let's unlink it again */ +- assert_se(unit_file_disable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("linked.service"), &changes, &n_changes) >= 0); ++ assert_se(unit_file_disable(LOOKUP_SCOPE_SYSTEM, 0, root, STRV_MAKE("linked.service"), &changes, &n_changes) >= 0); + assert_se(n_changes == 2); + p = strjoina(root, SYSTEM_CONFIG_UNIT_DIR"/multi-user.target.wants/linked.service"); + q = strjoina(root, SYSTEM_CONFIG_UNIT_DIR"/linked.service"); +@@ -315,9 +315,9 @@ TEST(linked_units) { + unit_file_changes_free(changes, n_changes); + changes = NULL; n_changes = 0; + +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "linked.service", NULL) == -ENOENT); ++ assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "linked.service", NULL) == -ENOENT); + +- assert_se(unit_file_enable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("linked2.service"), &changes, &n_changes) >= 0); ++ assert_se(unit_file_enable(LOOKUP_SCOPE_SYSTEM, 0, root, STRV_MAKE("linked2.service"), &changes, &n_changes) >= 0); + assert_se(n_changes == 2); + p = strjoina(root, SYSTEM_CONFIG_UNIT_DIR"/multi-user.target.wants/linked2.service"); + q = strjoina(root, SYSTEM_CONFIG_UNIT_DIR"/linked2.service"); +@@ -337,7 +337,7 @@ TEST(linked_units) { + unit_file_changes_free(changes, n_changes); + changes = NULL; n_changes = 0; + +- assert_se(unit_file_enable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("linked3.service"), &changes, &n_changes) >= 0); ++ assert_se(unit_file_enable(LOOKUP_SCOPE_SYSTEM, 0, root, STRV_MAKE("linked3.service"), &changes, &n_changes) >= 0); + assert_se(n_changes == 1); + assert_se(changes[0].type_or_errno == UNIT_FILE_SYMLINK); + assert_se(startswith(changes[0].path, root)); +@@ -359,18 +359,18 @@ TEST(default) { + p = strjoina(root, "/usr/lib/systemd/system/test-default.target"); + assert_se(symlink("test-default-real.target", p) >= 0); + +- assert_se(unit_file_get_default(UNIT_FILE_SYSTEM, root, &def) == -ENOENT); ++ assert_se(unit_file_get_default(LOOKUP_SCOPE_SYSTEM, root, &def) == -ENOENT); + +- assert_se(unit_file_set_default(UNIT_FILE_SYSTEM, 0, root, "idontexist.target", &changes, &n_changes) == -ENOENT); ++ assert_se(unit_file_set_default(LOOKUP_SCOPE_SYSTEM, 0, root, "idontexist.target", &changes, &n_changes) == -ENOENT); + assert_se(n_changes == 1); + assert_se(changes[0].type_or_errno == -ENOENT); + assert_se(streq_ptr(changes[0].path, "idontexist.target")); + unit_file_changes_free(changes, n_changes); + changes = NULL; n_changes = 0; + +- assert_se(unit_file_get_default(UNIT_FILE_SYSTEM, root, &def) == -ENOENT); ++ assert_se(unit_file_get_default(LOOKUP_SCOPE_SYSTEM, root, &def) == -ENOENT); + +- assert_se(unit_file_set_default(UNIT_FILE_SYSTEM, 0, root, "test-default.target", &changes, &n_changes) >= 0); ++ assert_se(unit_file_set_default(LOOKUP_SCOPE_SYSTEM, 0, root, "test-default.target", &changes, &n_changes) >= 0); + assert_se(n_changes == 1); + assert_se(changes[0].type_or_errno == UNIT_FILE_SYMLINK); + assert_se(streq(changes[0].source, "test-default-real.target")); +@@ -379,7 +379,7 @@ TEST(default) { + unit_file_changes_free(changes, n_changes); + changes = NULL; n_changes = 0; + +- assert_se(unit_file_get_default(UNIT_FILE_SYSTEM, root, &def) >= 0); ++ assert_se(unit_file_get_default(LOOKUP_SCOPE_SYSTEM, root, &def) >= 0); + assert_se(streq_ptr(def, "test-default-real.target")); + } + +@@ -400,7 +400,7 @@ TEST(add_dependency) { + p = strjoina(root, "/usr/lib/systemd/system/add-dependency-test-service.service"); + assert_se(symlink("real-add-dependency-test-service.service", p) >= 0); + +- assert_se(unit_file_add_dependency(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("add-dependency-test-service.service"), "add-dependency-test-target.target", UNIT_WANTS, &changes, &n_changes) >= 0); ++ assert_se(unit_file_add_dependency(LOOKUP_SCOPE_SYSTEM, 0, root, STRV_MAKE("add-dependency-test-service.service"), "add-dependency-test-target.target", UNIT_WANTS, &changes, &n_changes) >= 0); + assert_se(n_changes == 1); + assert_se(changes[0].type_or_errno == UNIT_FILE_SYMLINK); + assert_se(streq(changes[0].source, "../real-add-dependency-test-service.service")); +@@ -418,10 +418,10 @@ TEST(template_enable) { + + log_info("== %s ==", __func__); + +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@.service", &state) == -ENOENT); +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@def.service", &state) == -ENOENT); +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@foo.service", &state) == -ENOENT); +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@foo.service", &state) == -ENOENT); ++ assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "template@.service", &state) == -ENOENT); ++ assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "template@def.service", &state) == -ENOENT); ++ assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "template@foo.service", &state) == -ENOENT); ++ assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "template-symlink@foo.service", &state) == -ENOENT); + + p = strjoina(root, "/usr/lib/systemd/system/template@.service"); + assert_se(write_string_file(p, +@@ -432,16 +432,16 @@ TEST(template_enable) { + p = strjoina(root, "/usr/lib/systemd/system/template-symlink@.service"); + assert_se(symlink("template@.service", p) >= 0); + +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@.service", &state) >= 0 && state == UNIT_FILE_DISABLED); +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@def.service", &state) >= 0 && state == UNIT_FILE_DISABLED); +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@foo.service", &state) >= 0 && state == UNIT_FILE_DISABLED); +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@.service", &state) >= 0 && state == UNIT_FILE_ALIAS); +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@def.service", &state) >= 0 && state == UNIT_FILE_DISABLED); +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@foo.service", &state) >= 0 && state == UNIT_FILE_DISABLED); ++ assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "template@.service", &state) >= 0 && state == UNIT_FILE_DISABLED); ++ assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "template@def.service", &state) >= 0 && state == UNIT_FILE_DISABLED); ++ assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "template@foo.service", &state) >= 0 && state == UNIT_FILE_DISABLED); ++ assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "template-symlink@.service", &state) >= 0 && state == UNIT_FILE_ALIAS); ++ assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "template-symlink@def.service", &state) >= 0 && state == UNIT_FILE_DISABLED); ++ assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "template-symlink@foo.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + + log_info("== %s with template@.service enabled ==", __func__); + +- assert_se(unit_file_enable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("template@.service"), &changes, &n_changes) >= 0); ++ assert_se(unit_file_enable(LOOKUP_SCOPE_SYSTEM, 0, root, STRV_MAKE("template@.service"), &changes, &n_changes) >= 0); + assert_se(n_changes == 1); + assert_se(changes[0].type_or_errno == UNIT_FILE_SYMLINK); + assert_se(streq(changes[0].source, "../template@.service")); +@@ -450,30 +450,30 @@ TEST(template_enable) { + unit_file_changes_free(changes, n_changes); + changes = NULL; n_changes = 0; + +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@.service", &state) >= 0 && state == UNIT_FILE_ENABLED); +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@def.service", &state) >= 0 && state == UNIT_FILE_ENABLED); +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@foo.service", &state) >= 0 && state == UNIT_FILE_DISABLED); +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@.service", &state) >= 0 && state == UNIT_FILE_ALIAS); +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@def.service", &state) >= 0 && state == UNIT_FILE_ENABLED); +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@foo.service", &state) >= 0 && state == UNIT_FILE_DISABLED); ++ assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "template@.service", &state) >= 0 && state == UNIT_FILE_ENABLED); ++ assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "template@def.service", &state) >= 0 && state == UNIT_FILE_ENABLED); ++ assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "template@foo.service", &state) >= 0 && state == UNIT_FILE_DISABLED); ++ assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "template-symlink@.service", &state) >= 0 && state == UNIT_FILE_ALIAS); ++ assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "template-symlink@def.service", &state) >= 0 && state == UNIT_FILE_ENABLED); ++ assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "template-symlink@foo.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + +- assert_se(unit_file_disable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("template@.service"), &changes, &n_changes) >= 0); ++ assert_se(unit_file_disable(LOOKUP_SCOPE_SYSTEM, 0, root, STRV_MAKE("template@.service"), &changes, &n_changes) >= 0); + assert_se(n_changes == 1); + assert_se(changes[0].type_or_errno == UNIT_FILE_UNLINK); + assert_se(streq(changes[0].path, p)); + unit_file_changes_free(changes, n_changes); + changes = NULL; n_changes = 0; + +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@.service", &state) >= 0 && state == UNIT_FILE_DISABLED); +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@def.service", &state) >= 0 && state == UNIT_FILE_DISABLED); +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@foo.service", &state) >= 0 && state == UNIT_FILE_DISABLED); +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@.service", &state) >= 0 && state == UNIT_FILE_ALIAS); +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@def.service", &state) >= 0 && state == UNIT_FILE_DISABLED); +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@foo.service", &state) >= 0 && state == UNIT_FILE_DISABLED); ++ assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "template@.service", &state) >= 0 && state == UNIT_FILE_DISABLED); ++ assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "template@def.service", &state) >= 0 && state == UNIT_FILE_DISABLED); ++ assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "template@foo.service", &state) >= 0 && state == UNIT_FILE_DISABLED); ++ assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "template-symlink@.service", &state) >= 0 && state == UNIT_FILE_ALIAS); ++ assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "template-symlink@def.service", &state) >= 0 && state == UNIT_FILE_DISABLED); ++ assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "template-symlink@foo.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + + log_info("== %s with template@foo.service enabled ==", __func__); + +- assert_se(unit_file_enable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("template@foo.service"), &changes, &n_changes) >= 0); ++ assert_se(unit_file_enable(LOOKUP_SCOPE_SYSTEM, 0, root, STRV_MAKE("template@foo.service"), &changes, &n_changes) >= 0); + assert_se(changes[0].type_or_errno == UNIT_FILE_SYMLINK); + assert_se(streq(changes[0].source, "../template@foo.service")); + p = strjoina(root, SYSTEM_CONFIG_UNIT_DIR"/multi-user.target.wants/template@foo.service"); +@@ -481,33 +481,33 @@ TEST(template_enable) { + unit_file_changes_free(changes, n_changes); + changes = NULL; n_changes = 0; + +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@.service", &state) >= 0); ++ assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "template@.service", &state) >= 0); + assert_se(state == UNIT_FILE_INDIRECT); +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@def.service", &state) >= 0 && state == UNIT_FILE_DISABLED); +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@foo.service", &state) >= 0 && state == UNIT_FILE_ENABLED); +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@foo.service", &state) >= 0 && state == UNIT_FILE_ENABLED); +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@def.service", &state) >= 0 && state == UNIT_FILE_DISABLED); +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@foo.service", &state) >= 0 && state == UNIT_FILE_ENABLED); ++ assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "template@def.service", &state) >= 0 && state == UNIT_FILE_DISABLED); ++ assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "template@foo.service", &state) >= 0 && state == UNIT_FILE_ENABLED); ++ assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "template-symlink@foo.service", &state) >= 0 && state == UNIT_FILE_ENABLED); ++ assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "template-symlink@def.service", &state) >= 0 && state == UNIT_FILE_DISABLED); ++ assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "template-symlink@foo.service", &state) >= 0 && state == UNIT_FILE_ENABLED); + +- assert_se(unit_file_disable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("template@foo.service"), &changes, &n_changes) >= 0); ++ assert_se(unit_file_disable(LOOKUP_SCOPE_SYSTEM, 0, root, STRV_MAKE("template@foo.service"), &changes, &n_changes) >= 0); + assert_se(n_changes == 1); + assert_se(changes[0].type_or_errno == UNIT_FILE_UNLINK); + assert_se(streq(changes[0].path, p)); + unit_file_changes_free(changes, n_changes); + changes = NULL; n_changes = 0; + +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@.service", &state) >= 0 && state == UNIT_FILE_DISABLED); +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@def.service", &state) >= 0 && state == UNIT_FILE_DISABLED); +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@foo.service", &state) >= 0 && state == UNIT_FILE_DISABLED); +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@quux.service", &state) >= 0 && state == UNIT_FILE_DISABLED); +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@.service", &state) >= 0 && state == UNIT_FILE_ALIAS); +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@def.service", &state) >= 0 && state == UNIT_FILE_DISABLED); +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@foo.service", &state) >= 0 && state == UNIT_FILE_DISABLED); +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@quux.service", &state) >= 0 && state == UNIT_FILE_DISABLED); ++ assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "template@.service", &state) >= 0 && state == UNIT_FILE_DISABLED); ++ assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "template@def.service", &state) >= 0 && state == UNIT_FILE_DISABLED); ++ assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "template@foo.service", &state) >= 0 && state == UNIT_FILE_DISABLED); ++ assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "template@quux.service", &state) >= 0 && state == UNIT_FILE_DISABLED); ++ assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "template-symlink@.service", &state) >= 0 && state == UNIT_FILE_ALIAS); ++ assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "template-symlink@def.service", &state) >= 0 && state == UNIT_FILE_DISABLED); ++ assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "template-symlink@foo.service", &state) >= 0 && state == UNIT_FILE_DISABLED); ++ assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "template-symlink@quux.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + + log_info("== %s with template-symlink@quux.service enabled ==", __func__); + +- assert_se(unit_file_enable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("template-symlink@quux.service"), &changes, &n_changes) >= 0); ++ assert_se(unit_file_enable(LOOKUP_SCOPE_SYSTEM, 0, root, STRV_MAKE("template-symlink@quux.service"), &changes, &n_changes) >= 0); + assert_se(changes[0].type_or_errno == UNIT_FILE_SYMLINK); + assert_se(streq(changes[0].source, "../template@quux.service")); + p = strjoina(root, SYSTEM_CONFIG_UNIT_DIR"/multi-user.target.wants/template@quux.service"); +@@ -515,14 +515,14 @@ TEST(template_enable) { + unit_file_changes_free(changes, n_changes); + changes = NULL; n_changes = 0; + +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@.service", &state) >= 0 && state == UNIT_FILE_INDIRECT); +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@def.service", &state) >= 0 && state == UNIT_FILE_DISABLED); +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@foo.service", &state) >= 0 && state == UNIT_FILE_DISABLED); +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@quux.service", &state) >= 0 && state == UNIT_FILE_ENABLED); +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@.service", &state) >= 0 && state == UNIT_FILE_ALIAS); +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@def.service", &state) >= 0 && state == UNIT_FILE_DISABLED); +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@foo.service", &state) >= 0 && state == UNIT_FILE_DISABLED); +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@quux.service", &state) >= 0 && state == UNIT_FILE_ENABLED); ++ assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "template@.service", &state) >= 0 && state == UNIT_FILE_INDIRECT); ++ assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "template@def.service", &state) >= 0 && state == UNIT_FILE_DISABLED); ++ assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "template@foo.service", &state) >= 0 && state == UNIT_FILE_DISABLED); ++ assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "template@quux.service", &state) >= 0 && state == UNIT_FILE_ENABLED); ++ assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "template-symlink@.service", &state) >= 0 && state == UNIT_FILE_ALIAS); ++ assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "template-symlink@def.service", &state) >= 0 && state == UNIT_FILE_DISABLED); ++ assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "template-symlink@foo.service", &state) >= 0 && state == UNIT_FILE_DISABLED); ++ assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "template-symlink@quux.service", &state) >= 0 && state == UNIT_FILE_ENABLED); + } + + TEST(indirect) { +@@ -531,9 +531,9 @@ TEST(indirect) { + UnitFileState state; + const char *p; + +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "indirecta.service", &state) == -ENOENT); +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "indirectb.service", &state) == -ENOENT); +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "indirectc.service", &state) == -ENOENT); ++ assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "indirecta.service", &state) == -ENOENT); ++ assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "indirectb.service", &state) == -ENOENT); ++ assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "indirectc.service", &state) == -ENOENT); + + p = strjoina(root, "/usr/lib/systemd/system/indirecta.service"); + assert_se(write_string_file(p, +@@ -548,11 +548,11 @@ TEST(indirect) { + p = strjoina(root, "/usr/lib/systemd/system/indirectc.service"); + assert_se(symlink("indirecta.service", p) >= 0); + +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "indirecta.service", &state) >= 0 && state == UNIT_FILE_INDIRECT); +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "indirectb.service", &state) >= 0 && state == UNIT_FILE_DISABLED); +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "indirectc.service", &state) >= 0 && state == UNIT_FILE_ALIAS); ++ assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "indirecta.service", &state) >= 0 && state == UNIT_FILE_INDIRECT); ++ assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "indirectb.service", &state) >= 0 && state == UNIT_FILE_DISABLED); ++ assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "indirectc.service", &state) >= 0 && state == UNIT_FILE_ALIAS); + +- assert_se(unit_file_enable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("indirectc.service"), &changes, &n_changes) >= 0); ++ assert_se(unit_file_enable(LOOKUP_SCOPE_SYSTEM, 0, root, STRV_MAKE("indirectc.service"), &changes, &n_changes) >= 0); + assert_se(n_changes == 1); + assert_se(changes[0].type_or_errno == UNIT_FILE_SYMLINK); + assert_se(streq(changes[0].source, "../indirectb.service")); +@@ -561,11 +561,11 @@ TEST(indirect) { + unit_file_changes_free(changes, n_changes); + changes = NULL; n_changes = 0; + +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "indirecta.service", &state) >= 0 && state == UNIT_FILE_INDIRECT); +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "indirectb.service", &state) >= 0 && state == UNIT_FILE_ENABLED); +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "indirectc.service", &state) >= 0 && state == UNIT_FILE_ALIAS); ++ assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "indirecta.service", &state) >= 0 && state == UNIT_FILE_INDIRECT); ++ assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "indirectb.service", &state) >= 0 && state == UNIT_FILE_ENABLED); ++ assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "indirectc.service", &state) >= 0 && state == UNIT_FILE_ALIAS); + +- assert_se(unit_file_disable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("indirectc.service"), &changes, &n_changes) >= 0); ++ assert_se(unit_file_disable(LOOKUP_SCOPE_SYSTEM, 0, root, STRV_MAKE("indirectc.service"), &changes, &n_changes) >= 0); + assert_se(n_changes == 1); + assert_se(changes[0].type_or_errno == UNIT_FILE_UNLINK); + p = strjoina(root, SYSTEM_CONFIG_UNIT_DIR"/multi-user.target.wants/indirectb.service"); +@@ -583,8 +583,8 @@ TEST(preset_and_list) { + UnitFileList *fl; + Hashmap *h; + +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "preset-yes.service", &state) == -ENOENT); +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "preset-no.service", &state) == -ENOENT); ++ assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "preset-yes.service", &state) == -ENOENT); ++ assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "preset-no.service", &state) == -ENOENT); + + p = strjoina(root, "/usr/lib/systemd/system/preset-yes.service"); + assert_se(write_string_file(p, +@@ -601,10 +601,10 @@ TEST(preset_and_list) { + "enable *-yes.*\n" + "disable *\n", WRITE_STRING_FILE_CREATE) >= 0); + +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "preset-yes.service", &state) >= 0 && state == UNIT_FILE_DISABLED); +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "preset-no.service", &state) >= 0 && state == UNIT_FILE_DISABLED); ++ assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "preset-yes.service", &state) >= 0 && state == UNIT_FILE_DISABLED); ++ assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "preset-no.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + +- assert_se(unit_file_preset(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("preset-yes.service"), UNIT_FILE_PRESET_FULL, &changes, &n_changes) >= 0); ++ assert_se(unit_file_preset(LOOKUP_SCOPE_SYSTEM, 0, root, STRV_MAKE("preset-yes.service"), UNIT_FILE_PRESET_FULL, &changes, &n_changes) >= 0); + assert_se(n_changes == 1); + assert_se(changes[0].type_or_errno == UNIT_FILE_SYMLINK); + assert_se(streq(changes[0].source, "../preset-yes.service")); +@@ -613,10 +613,10 @@ TEST(preset_and_list) { + unit_file_changes_free(changes, n_changes); + changes = NULL; n_changes = 0; + +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "preset-yes.service", &state) >= 0 && state == UNIT_FILE_ENABLED); +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "preset-no.service", &state) >= 0 && state == UNIT_FILE_DISABLED); ++ assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "preset-yes.service", &state) >= 0 && state == UNIT_FILE_ENABLED); ++ assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "preset-no.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + +- assert_se(unit_file_disable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("preset-yes.service"), &changes, &n_changes) >= 0); ++ assert_se(unit_file_disable(LOOKUP_SCOPE_SYSTEM, 0, root, STRV_MAKE("preset-yes.service"), &changes, &n_changes) >= 0); + assert_se(n_changes == 1); + assert_se(changes[0].type_or_errno == UNIT_FILE_UNLINK); + p = strjoina(root, SYSTEM_CONFIG_UNIT_DIR"/multi-user.target.wants/preset-yes.service"); +@@ -624,18 +624,18 @@ TEST(preset_and_list) { + unit_file_changes_free(changes, n_changes); + changes = NULL; n_changes = 0; + +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "preset-yes.service", &state) >= 0 && state == UNIT_FILE_DISABLED); +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "preset-no.service", &state) >= 0 && state == UNIT_FILE_DISABLED); ++ assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "preset-yes.service", &state) >= 0 && state == UNIT_FILE_DISABLED); ++ assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "preset-no.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + +- assert_se(unit_file_preset(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("preset-no.service"), UNIT_FILE_PRESET_FULL, &changes, &n_changes) >= 0); ++ assert_se(unit_file_preset(LOOKUP_SCOPE_SYSTEM, 0, root, STRV_MAKE("preset-no.service"), UNIT_FILE_PRESET_FULL, &changes, &n_changes) >= 0); + assert_se(n_changes == 0); + unit_file_changes_free(changes, n_changes); + changes = NULL; n_changes = 0; + +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "preset-yes.service", &state) >= 0 && state == UNIT_FILE_DISABLED); +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "preset-no.service", &state) >= 0 && state == UNIT_FILE_DISABLED); ++ assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "preset-yes.service", &state) >= 0 && state == UNIT_FILE_DISABLED); ++ assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "preset-no.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + +- assert_se(unit_file_preset_all(UNIT_FILE_SYSTEM, 0, root, UNIT_FILE_PRESET_FULL, &changes, &n_changes) >= 0); ++ assert_se(unit_file_preset_all(LOOKUP_SCOPE_SYSTEM, 0, root, UNIT_FILE_PRESET_FULL, &changes, &n_changes) >= 0); + + assert_se(n_changes > 0); + +@@ -653,17 +653,17 @@ TEST(preset_and_list) { + unit_file_changes_free(changes, n_changes); + changes = NULL; n_changes = 0; + +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "preset-yes.service", &state) >= 0 && state == UNIT_FILE_ENABLED); +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "preset-no.service", &state) >= 0 && state == UNIT_FILE_DISABLED); ++ assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "preset-yes.service", &state) >= 0 && state == UNIT_FILE_ENABLED); ++ assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "preset-no.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + + assert_se(h = hashmap_new(&string_hash_ops)); +- assert_se(unit_file_get_list(UNIT_FILE_SYSTEM, root, h, NULL, NULL) >= 0); ++ assert_se(unit_file_get_list(LOOKUP_SCOPE_SYSTEM, root, h, NULL, NULL) >= 0); + + p = strjoina(root, "/usr/lib/systemd/system/preset-yes.service"); + q = strjoina(root, "/usr/lib/systemd/system/preset-no.service"); + + HASHMAP_FOREACH(fl, h) { +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, basename(fl->path), &state) >= 0); ++ assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, basename(fl->path), &state) >= 0); + assert_se(fl->state == state); + + if (streq(fl->path, p)) { +@@ -687,17 +687,17 @@ TEST(revert) { + UnitFileChange *changes = NULL; + size_t n_changes = 0; + +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "xx.service", NULL) == -ENOENT); +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "yy.service", NULL) == -ENOENT); ++ assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "xx.service", NULL) == -ENOENT); ++ assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "yy.service", NULL) == -ENOENT); + + p = strjoina(root, "/usr/lib/systemd/system/xx.service"); + assert_se(write_string_file(p, "# Empty\n", WRITE_STRING_FILE_CREATE) >= 0); + +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "xx.service", NULL) >= 0); +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "xx.service", &state) >= 0 && state == UNIT_FILE_STATIC); ++ assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "xx.service", NULL) >= 0); ++ assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "xx.service", &state) >= 0 && state == UNIT_FILE_STATIC); + + /* Initially there's nothing to revert */ +- assert_se(unit_file_revert(UNIT_FILE_SYSTEM, root, STRV_MAKE("xx.service"), &changes, &n_changes) >= 0); ++ assert_se(unit_file_revert(LOOKUP_SCOPE_SYSTEM, root, STRV_MAKE("xx.service"), &changes, &n_changes) >= 0); + assert_se(n_changes == 0); + unit_file_changes_free(changes, n_changes); + changes = NULL; n_changes = 0; +@@ -706,7 +706,7 @@ TEST(revert) { + assert_se(write_string_file(p, "# Empty override\n", WRITE_STRING_FILE_CREATE) >= 0); + + /* Revert the override file */ +- assert_se(unit_file_revert(UNIT_FILE_SYSTEM, root, STRV_MAKE("xx.service"), &changes, &n_changes) >= 0); ++ assert_se(unit_file_revert(LOOKUP_SCOPE_SYSTEM, root, STRV_MAKE("xx.service"), &changes, &n_changes) >= 0); + assert_se(n_changes == 1); + assert_se(changes[0].type_or_errno == UNIT_FILE_UNLINK); + assert_se(streq(changes[0].path, p)); +@@ -717,7 +717,7 @@ TEST(revert) { + assert_se(write_string_file(p, "# Empty dropin\n", WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_MKDIR_0755) >= 0); + + /* Revert the dropin file */ +- assert_se(unit_file_revert(UNIT_FILE_SYSTEM, root, STRV_MAKE("xx.service"), &changes, &n_changes) >= 0); ++ assert_se(unit_file_revert(LOOKUP_SCOPE_SYSTEM, root, STRV_MAKE("xx.service"), &changes, &n_changes) >= 0); + assert_se(n_changes == 2); + assert_se(changes[0].type_or_errno == UNIT_FILE_UNLINK); + assert_se(streq(changes[0].path, p)); +@@ -735,8 +735,8 @@ TEST(preset_order) { + const char *p; + UnitFileState state; + +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "prefix-1.service", &state) == -ENOENT); +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "prefix-2.service", &state) == -ENOENT); ++ assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "prefix-1.service", &state) == -ENOENT); ++ assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "prefix-2.service", &state) == -ENOENT); + + p = strjoina(root, "/usr/lib/systemd/system/prefix-1.service"); + assert_se(write_string_file(p, +@@ -754,10 +754,10 @@ TEST(preset_order) { + "disable prefix-*.service\n" + "enable prefix-2.service\n", WRITE_STRING_FILE_CREATE) >= 0); + +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "prefix-1.service", &state) >= 0 && state == UNIT_FILE_DISABLED); +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "prefix-2.service", &state) >= 0 && state == UNIT_FILE_DISABLED); ++ assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "prefix-1.service", &state) >= 0 && state == UNIT_FILE_DISABLED); ++ assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "prefix-2.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + +- assert_se(unit_file_preset(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("prefix-1.service"), UNIT_FILE_PRESET_FULL, &changes, &n_changes) >= 0); ++ assert_se(unit_file_preset(LOOKUP_SCOPE_SYSTEM, 0, root, STRV_MAKE("prefix-1.service"), UNIT_FILE_PRESET_FULL, &changes, &n_changes) >= 0); + assert_se(n_changes == 1); + assert_se(changes[0].type_or_errno == UNIT_FILE_SYMLINK); + assert_se(streq(changes[0].source, "../prefix-1.service")); +@@ -766,36 +766,36 @@ TEST(preset_order) { + unit_file_changes_free(changes, n_changes); + changes = NULL; n_changes = 0; + +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "prefix-1.service", &state) >= 0 && state == UNIT_FILE_ENABLED); +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "prefix-2.service", &state) >= 0 && state == UNIT_FILE_DISABLED); ++ assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "prefix-1.service", &state) >= 0 && state == UNIT_FILE_ENABLED); ++ assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "prefix-2.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + +- assert_se(unit_file_preset(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("prefix-2.service"), UNIT_FILE_PRESET_FULL, &changes, &n_changes) >= 0); ++ assert_se(unit_file_preset(LOOKUP_SCOPE_SYSTEM, 0, root, STRV_MAKE("prefix-2.service"), UNIT_FILE_PRESET_FULL, &changes, &n_changes) >= 0); + assert_se(n_changes == 0); + +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "prefix-1.service", &state) >= 0 && state == UNIT_FILE_ENABLED); +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "prefix-2.service", &state) >= 0 && state == UNIT_FILE_DISABLED); ++ assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "prefix-1.service", &state) >= 0 && state == UNIT_FILE_ENABLED); ++ assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "prefix-2.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + } + + TEST(static_instance) { + UnitFileState state; + const char *p; + +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "static-instance@.service", &state) == -ENOENT); +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "static-instance@foo.service", &state) == -ENOENT); ++ assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "static-instance@.service", &state) == -ENOENT); ++ assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "static-instance@foo.service", &state) == -ENOENT); + + p = strjoina(root, "/usr/lib/systemd/system/static-instance@.service"); + assert_se(write_string_file(p, + "[Install]\n" + "WantedBy=multi-user.target\n", WRITE_STRING_FILE_CREATE) >= 0); + +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "static-instance@.service", &state) >= 0 && state == UNIT_FILE_DISABLED); +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "static-instance@foo.service", &state) >= 0 && state == UNIT_FILE_DISABLED); ++ assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "static-instance@.service", &state) >= 0 && state == UNIT_FILE_DISABLED); ++ assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "static-instance@foo.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + + p = strjoina(root, "/usr/lib/systemd/system/static-instance@foo.service"); + assert_se(symlink("static-instance@.service", p) >= 0); + +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "static-instance@.service", &state) >= 0 && state == UNIT_FILE_DISABLED); +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "static-instance@foo.service", &state) >= 0 && state == UNIT_FILE_STATIC); ++ assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "static-instance@.service", &state) >= 0 && state == UNIT_FILE_DISABLED); ++ assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "static-instance@foo.service", &state) >= 0 && state == UNIT_FILE_STATIC); + } + + TEST(with_dropin) { +@@ -804,11 +804,11 @@ TEST(with_dropin) { + UnitFileChange *changes = NULL; + size_t n_changes = 0; + +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "with-dropin-1.service", &state) == -ENOENT); +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "with-dropin-2.service", &state) == -ENOENT); +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "with-dropin-3.service", &state) == -ENOENT); +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "with-dropin-4a.service", &state) == -ENOENT); +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "with-dropin-4b.service", &state) == -ENOENT); ++ assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "with-dropin-1.service", &state) == -ENOENT); ++ assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "with-dropin-2.service", &state) == -ENOENT); ++ assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "with-dropin-3.service", &state) == -ENOENT); ++ assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "with-dropin-4a.service", &state) == -ENOENT); ++ assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "with-dropin-4b.service", &state) == -ENOENT); + + p = strjoina(root, "/usr/lib/systemd/system/with-dropin-1.service"); + assert_se(write_string_file(p, +@@ -820,7 +820,7 @@ TEST(with_dropin) { + "[Install]\n" + "WantedBy=graphical.target\n", WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_MKDIR_0755) >= 0); + +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "with-dropin-1.service", &state) >= 0 && state == UNIT_FILE_DISABLED); ++ assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "with-dropin-1.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + + p = strjoina(root, SYSTEM_CONFIG_UNIT_DIR"/with-dropin-2.service"); + assert_se(write_string_file(p, +@@ -832,7 +832,7 @@ TEST(with_dropin) { + "[Install]\n" + "WantedBy=graphical.target\n", WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_MKDIR_0755) >= 0); + +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "with-dropin-2.service", &state) >= 0 && state == UNIT_FILE_DISABLED); ++ assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "with-dropin-2.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + + p = strjoina(root, "/usr/lib/systemd/system/with-dropin-3.service"); + assert_se(write_string_file(p, +@@ -844,7 +844,7 @@ TEST(with_dropin) { + "[Install]\n" + "WantedBy=graphical.target\n", WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_MKDIR_0755) >= 0); + +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "with-dropin-3.service", &state) >= 0 && state == UNIT_FILE_DISABLED); ++ assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "with-dropin-3.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + + p = strjoina(root, "/usr/lib/systemd/system/with-dropin-4a.service"); + assert_se(write_string_file(p, +@@ -856,16 +856,16 @@ TEST(with_dropin) { + "[Install]\n" + "Also=with-dropin-4b.service\n", WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_MKDIR_0755) >= 0); + +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "with-dropin-4a.service", &state) >= 0 && state == UNIT_FILE_DISABLED); ++ assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "with-dropin-4a.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + + p = strjoina(root, "/usr/lib/systemd/system/with-dropin-4b.service"); + assert_se(write_string_file(p, + "[Install]\n" + "WantedBy=multi-user.target\n", WRITE_STRING_FILE_CREATE) >= 0); + +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "with-dropin-4b.service", &state) >= 0 && state == UNIT_FILE_DISABLED); ++ assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "with-dropin-4b.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + +- assert_se(unit_file_enable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("with-dropin-1.service"), &changes, &n_changes) == 1); ++ assert_se(unit_file_enable(LOOKUP_SCOPE_SYSTEM, 0, root, STRV_MAKE("with-dropin-1.service"), &changes, &n_changes) == 1); + assert_se(n_changes == 2); + assert_se(changes[0].type_or_errno == UNIT_FILE_SYMLINK); + assert_se(changes[1].type_or_errno == UNIT_FILE_SYMLINK); +@@ -878,8 +878,8 @@ TEST(with_dropin) { + unit_file_changes_free(changes, n_changes); + changes = NULL; n_changes = 0; + +- assert_se(unit_file_enable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("with-dropin-2.service"), &changes, &n_changes) == 1); +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "with-dropin-2.service", &state) >= 0 && state == UNIT_FILE_ENABLED); ++ assert_se(unit_file_enable(LOOKUP_SCOPE_SYSTEM, 0, root, STRV_MAKE("with-dropin-2.service"), &changes, &n_changes) == 1); ++ assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "with-dropin-2.service", &state) >= 0 && state == UNIT_FILE_ENABLED); + assert_se(n_changes == 2); + assert_se(changes[0].type_or_errno == UNIT_FILE_SYMLINK); + assert_se(changes[1].type_or_errno == UNIT_FILE_SYMLINK); +@@ -892,8 +892,8 @@ TEST(with_dropin) { + unit_file_changes_free(changes, n_changes); + changes = NULL; n_changes = 0; + +- assert_se(unit_file_enable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("with-dropin-3.service"), &changes, &n_changes) == 1); +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "with-dropin-3.service", &state) >= 0 && state == UNIT_FILE_ENABLED); ++ assert_se(unit_file_enable(LOOKUP_SCOPE_SYSTEM, 0, root, STRV_MAKE("with-dropin-3.service"), &changes, &n_changes) == 1); ++ assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "with-dropin-3.service", &state) >= 0 && state == UNIT_FILE_ENABLED); + assert_se(n_changes == 2); + assert_se(changes[0].type_or_errno == UNIT_FILE_SYMLINK); + assert_se(changes[1].type_or_errno == UNIT_FILE_SYMLINK); +@@ -906,8 +906,8 @@ TEST(with_dropin) { + unit_file_changes_free(changes, n_changes); + changes = NULL; n_changes = 0; + +- assert_se(unit_file_enable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("with-dropin-4a.service"), &changes, &n_changes) == 2); +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "with-dropin-3.service", &state) >= 0 && state == UNIT_FILE_ENABLED); ++ assert_se(unit_file_enable(LOOKUP_SCOPE_SYSTEM, 0, root, STRV_MAKE("with-dropin-4a.service"), &changes, &n_changes) == 2); ++ assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "with-dropin-3.service", &state) >= 0 && state == UNIT_FILE_ENABLED); + assert_se(n_changes == 2); + assert_se(changes[0].type_or_errno == UNIT_FILE_SYMLINK); + assert_se(changes[1].type_or_errno == UNIT_FILE_SYMLINK); +@@ -920,11 +920,11 @@ TEST(with_dropin) { + unit_file_changes_free(changes, n_changes); + changes = NULL; n_changes = 0; + +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "with-dropin-1.service", &state) >= 0 && state == UNIT_FILE_ENABLED); +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "with-dropin-2.service", &state) >= 0 && state == UNIT_FILE_ENABLED); +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "with-dropin-3.service", &state) >= 0 && state == UNIT_FILE_ENABLED); +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "with-dropin-4a.service", &state) >= 0 && state == UNIT_FILE_ENABLED); +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "with-dropin-4b.service", &state) >= 0 && state == UNIT_FILE_ENABLED); ++ assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "with-dropin-1.service", &state) >= 0 && state == UNIT_FILE_ENABLED); ++ assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "with-dropin-2.service", &state) >= 0 && state == UNIT_FILE_ENABLED); ++ assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "with-dropin-3.service", &state) >= 0 && state == UNIT_FILE_ENABLED); ++ assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "with-dropin-4a.service", &state) >= 0 && state == UNIT_FILE_ENABLED); ++ assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "with-dropin-4b.service", &state) >= 0 && state == UNIT_FILE_ENABLED); + } + + TEST(with_dropin_template) { +@@ -933,9 +933,9 @@ TEST(with_dropin_template) { + UnitFileChange *changes = NULL; + size_t n_changes = 0; + +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "with-dropin-1@.service", &state) == -ENOENT); +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "with-dropin-2@.service", &state) == -ENOENT); +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "with-dropin-3@.service", &state) == -ENOENT); ++ assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "with-dropin-1@.service", &state) == -ENOENT); ++ assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "with-dropin-2@.service", &state) == -ENOENT); ++ assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "with-dropin-3@.service", &state) == -ENOENT); + + p = strjoina(root, "/usr/lib/systemd/system/with-dropin-1@.service"); + assert_se(write_string_file(p, +@@ -947,7 +947,7 @@ TEST(with_dropin_template) { + "[Install]\n" + "WantedBy=graphical.target\n", WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_MKDIR_0755) >= 0); + +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "with-dropin-1@.service", &state) >= 0 && state == UNIT_FILE_DISABLED); ++ assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "with-dropin-1@.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + + p = strjoina(root, "/usr/lib/systemd/system/with-dropin-2@.service"); + assert_se(write_string_file(p, +@@ -959,7 +959,7 @@ TEST(with_dropin_template) { + "[Install]\n" + "WantedBy=graphical.target\n", WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_MKDIR_0755) >= 0); + +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "with-dropin-2@.service", &state) >= 0 && state == UNIT_FILE_DISABLED); ++ assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "with-dropin-2@.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + + p = strjoina(root, "/usr/lib/systemd/system/with-dropin-3@.service"); + assert_se(write_string_file(p, +@@ -972,9 +972,9 @@ TEST(with_dropin_template) { + "[Install]\n" + "DefaultInstance=instance-2\n", WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_MKDIR_0755) >= 0); + +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "with-dropin-3@.service", &state) >= 0 && state == UNIT_FILE_DISABLED); ++ assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "with-dropin-3@.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + +- assert_se(unit_file_enable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("with-dropin-1@instance-1.service"), &changes, &n_changes) == 1); ++ assert_se(unit_file_enable(LOOKUP_SCOPE_SYSTEM, 0, root, STRV_MAKE("with-dropin-1@instance-1.service"), &changes, &n_changes) == 1); + assert_se(n_changes == 2); + assert_se(changes[0].type_or_errno == UNIT_FILE_SYMLINK); + assert_se(changes[1].type_or_errno == UNIT_FILE_SYMLINK); +@@ -987,7 +987,7 @@ TEST(with_dropin_template) { + unit_file_changes_free(changes, n_changes); + changes = NULL; n_changes = 0; + +- assert_se(unit_file_enable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("with-dropin-2@instance-1.service"), &changes, &n_changes) == 1); ++ assert_se(unit_file_enable(LOOKUP_SCOPE_SYSTEM, 0, root, STRV_MAKE("with-dropin-2@instance-1.service"), &changes, &n_changes) == 1); + assert_se(n_changes == 2); + assert_se(changes[0].type_or_errno == UNIT_FILE_SYMLINK); + assert_se(changes[1].type_or_errno == UNIT_FILE_SYMLINK); +@@ -1000,7 +1000,7 @@ TEST(with_dropin_template) { + unit_file_changes_free(changes, n_changes); + changes = NULL; n_changes = 0; + +- assert_se(unit_file_enable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("with-dropin-2@instance-2.service"), &changes, &n_changes) == 1); ++ assert_se(unit_file_enable(LOOKUP_SCOPE_SYSTEM, 0, root, STRV_MAKE("with-dropin-2@instance-2.service"), &changes, &n_changes) == 1); + assert_se(n_changes == 1); + assert_se(changes[0].type_or_errno == UNIT_FILE_SYMLINK); + assert_se(streq(changes[0].source, "../with-dropin-2@instance-2.service")); +@@ -1009,7 +1009,7 @@ TEST(with_dropin_template) { + unit_file_changes_free(changes, n_changes); + changes = NULL; n_changes = 0; + +- assert_se(unit_file_enable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("with-dropin-3@.service"), &changes, &n_changes) == 1); ++ assert_se(unit_file_enable(LOOKUP_SCOPE_SYSTEM, 0, root, STRV_MAKE("with-dropin-3@.service"), &changes, &n_changes) == 1); + assert_se(n_changes == 1); + assert_se(changes[0].type_or_errno == UNIT_FILE_SYMLINK); + assert_se(streq(changes[0].source, "../with-dropin-3@.service")); +@@ -1018,11 +1018,11 @@ TEST(with_dropin_template) { + unit_file_changes_free(changes, n_changes); + changes = NULL; n_changes = 0; + +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "with-dropin-1@instance-1.service", &state) >= 0 && state == UNIT_FILE_ENABLED); +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "with-dropin-2@instance-1.service", &state) >= 0 && state == UNIT_FILE_ENABLED); +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "with-dropin-2@instance-2.service", &state) >= 0 && state == UNIT_FILE_ENABLED); +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "with-dropin-3@instance-1.service", &state) >= 0 && state == UNIT_FILE_DISABLED); +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "with-dropin-3@instance-2.service", &state) >= 0 && state == UNIT_FILE_ENABLED); ++ assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "with-dropin-1@instance-1.service", &state) >= 0 && state == UNIT_FILE_ENABLED); ++ assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "with-dropin-2@instance-1.service", &state) >= 0 && state == UNIT_FILE_ENABLED); ++ assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "with-dropin-2@instance-2.service", &state) >= 0 && state == UNIT_FILE_ENABLED); ++ assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "with-dropin-3@instance-1.service", &state) >= 0 && state == UNIT_FILE_DISABLED); ++ assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "with-dropin-3@instance-2.service", &state) >= 0 && state == UNIT_FILE_ENABLED); + } + + TEST(preset_multiple_instances) { +@@ -1038,7 +1038,7 @@ TEST(preset_multiple_instances) { + "DefaultInstance=def\n" + "WantedBy=multi-user.target\n", WRITE_STRING_FILE_CREATE) >= 0); + +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "foo@.service", &state) >= 0 && state == UNIT_FILE_DISABLED); ++ assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "foo@.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + + p = strjoina(root, "/usr/lib/systemd/system-preset/test.preset"); + assert_se(write_string_file(p, +@@ -1046,11 +1046,11 @@ TEST(preset_multiple_instances) { + "enable emptylist@.service\n" /* This line ensures the old functionality for templated unit still works */ + "disable *\n" , WRITE_STRING_FILE_CREATE) >= 0); + +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "foo@bar0.service", &state) >= 0 && state == UNIT_FILE_DISABLED); ++ assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "foo@bar0.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + + /* Preset a single instantiated unit specified in the list */ +- assert_se(unit_file_preset(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("foo@bar0.service"), UNIT_FILE_PRESET_FULL, &changes, &n_changes) >= 0); +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "foo@bar0.service", &state) >= 0 && state == UNIT_FILE_ENABLED); ++ assert_se(unit_file_preset(LOOKUP_SCOPE_SYSTEM, 0, root, STRV_MAKE("foo@bar0.service"), UNIT_FILE_PRESET_FULL, &changes, &n_changes) >= 0); ++ assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "foo@bar0.service", &state) >= 0 && state == UNIT_FILE_ENABLED); + assert_se(n_changes == 1); + assert_se(changes[0].type_or_errno == UNIT_FILE_SYMLINK); + p = strjoina(root, SYSTEM_CONFIG_UNIT_DIR"/multi-user.target.wants/foo@bar0.service"); +@@ -1058,7 +1058,7 @@ TEST(preset_multiple_instances) { + unit_file_changes_free(changes, n_changes); + changes = NULL; n_changes = 0; + +- assert_se(unit_file_disable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("foo@bar0.service"), &changes, &n_changes) >= 0); ++ assert_se(unit_file_disable(LOOKUP_SCOPE_SYSTEM, 0, root, STRV_MAKE("foo@bar0.service"), &changes, &n_changes) >= 0); + assert_se(n_changes == 1); + assert_se(changes[0].type_or_errno == UNIT_FILE_UNLINK); + p = strjoina(root, SYSTEM_CONFIG_UNIT_DIR"/multi-user.target.wants/foo@bar0.service"); +@@ -1067,17 +1067,17 @@ TEST(preset_multiple_instances) { + changes = NULL; n_changes = 0; + + /* Check for preset-all case, only instances on the list should be enabled, not including the default instance */ +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "foo@def.service", &state) >= 0 && state == UNIT_FILE_DISABLED); +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "foo@bar1.service", &state) >= 0 && state == UNIT_FILE_DISABLED); +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "foo@bartest.service", &state) >= 0 && state == UNIT_FILE_DISABLED); ++ assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "foo@def.service", &state) >= 0 && state == UNIT_FILE_DISABLED); ++ assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "foo@bar1.service", &state) >= 0 && state == UNIT_FILE_DISABLED); ++ assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "foo@bartest.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + +- assert_se(unit_file_preset_all(UNIT_FILE_SYSTEM, 0, root, UNIT_FILE_PRESET_FULL, &changes, &n_changes) >= 0); ++ assert_se(unit_file_preset_all(LOOKUP_SCOPE_SYSTEM, 0, root, UNIT_FILE_PRESET_FULL, &changes, &n_changes) >= 0); + assert_se(n_changes > 0); + +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "foo@def.service", &state) >= 0 && state == UNIT_FILE_DISABLED); +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "foo@bar0.service", &state) >= 0 && state == UNIT_FILE_ENABLED); +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "foo@bar1.service", &state) >= 0 && state == UNIT_FILE_ENABLED); +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "foo@bartest.service", &state) >= 0 && state == UNIT_FILE_ENABLED); ++ assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "foo@def.service", &state) >= 0 && state == UNIT_FILE_DISABLED); ++ assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "foo@bar0.service", &state) >= 0 && state == UNIT_FILE_ENABLED); ++ assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "foo@bar1.service", &state) >= 0 && state == UNIT_FILE_ENABLED); ++ assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "foo@bartest.service", &state) >= 0 && state == UNIT_FILE_ENABLED); + + unit_file_changes_free(changes, n_changes); + } +diff --git a/src/test/test-install.c b/src/test/test-install.c +index 7a0beb2d24..6c5a036465 100644 +--- a/src/test/test-install.c ++++ b/src/test/test-install.c +@@ -32,13 +32,13 @@ int main(int argc, char* argv[]) { + test_setup_logging(LOG_DEBUG); + + h = hashmap_new(&string_hash_ops); +- r = unit_file_get_list(UNIT_FILE_SYSTEM, NULL, h, NULL, NULL); ++ r = unit_file_get_list(LOOKUP_SCOPE_SYSTEM, NULL, h, NULL, NULL); + assert_se(r == 0); + + HASHMAP_FOREACH(p, h) { + UnitFileState s = _UNIT_FILE_STATE_INVALID; + +- r = unit_file_get_state(UNIT_FILE_SYSTEM, NULL, basename(p->path), &s); ++ r = unit_file_get_state(LOOKUP_SCOPE_SYSTEM, NULL, basename(p->path), &s); + + assert_se((r < 0 && p->state == UNIT_FILE_BAD) || + (p->state == s)); +@@ -52,18 +52,18 @@ int main(int argc, char* argv[]) { + + log_info("/*** enable **/"); + +- r = unit_file_enable(UNIT_FILE_SYSTEM, 0, NULL, (char**) files, &changes, &n_changes); ++ r = unit_file_enable(LOOKUP_SCOPE_SYSTEM, 0, NULL, (char**) files, &changes, &n_changes); + assert_se(r >= 0); + + log_info("/*** enable2 **/"); + +- r = unit_file_enable(UNIT_FILE_SYSTEM, 0, NULL, (char**) files, &changes, &n_changes); ++ r = unit_file_enable(LOOKUP_SCOPE_SYSTEM, 0, NULL, (char**) files, &changes, &n_changes); + assert_se(r >= 0); + + dump_changes(changes, n_changes); + unit_file_changes_free(changes, n_changes); + +- r = unit_file_get_state(UNIT_FILE_SYSTEM, NULL, files[0], &state); ++ r = unit_file_get_state(LOOKUP_SCOPE_SYSTEM, NULL, files[0], &state); + assert_se(r >= 0); + assert_se(state == UNIT_FILE_ENABLED); + +@@ -71,13 +71,13 @@ int main(int argc, char* argv[]) { + changes = NULL; + n_changes = 0; + +- r = unit_file_disable(UNIT_FILE_SYSTEM, 0, NULL, (char**) files, &changes, &n_changes); ++ r = unit_file_disable(LOOKUP_SCOPE_SYSTEM, 0, NULL, (char**) files, &changes, &n_changes); + assert_se(r >= 0); + + dump_changes(changes, n_changes); + unit_file_changes_free(changes, n_changes); + +- r = unit_file_get_state(UNIT_FILE_SYSTEM, NULL, files[0], &state); ++ r = unit_file_get_state(LOOKUP_SCOPE_SYSTEM, NULL, files[0], &state); + assert_se(r >= 0); + assert_se(state == UNIT_FILE_DISABLED); + +@@ -85,16 +85,16 @@ int main(int argc, char* argv[]) { + changes = NULL; + n_changes = 0; + +- r = unit_file_mask(UNIT_FILE_SYSTEM, 0, NULL, (char**) files, &changes, &n_changes); ++ r = unit_file_mask(LOOKUP_SCOPE_SYSTEM, 0, NULL, (char**) files, &changes, &n_changes); + assert_se(r >= 0); + log_info("/*** mask2 ***/"); +- r = unit_file_mask(UNIT_FILE_SYSTEM, 0, NULL, (char**) files, &changes, &n_changes); ++ r = unit_file_mask(LOOKUP_SCOPE_SYSTEM, 0, NULL, (char**) files, &changes, &n_changes); + assert_se(r >= 0); + + dump_changes(changes, n_changes); + unit_file_changes_free(changes, n_changes); + +- r = unit_file_get_state(UNIT_FILE_SYSTEM, NULL, files[0], &state); ++ r = unit_file_get_state(LOOKUP_SCOPE_SYSTEM, NULL, files[0], &state); + assert_se(r >= 0); + assert_se(state == UNIT_FILE_MASKED); + +@@ -102,16 +102,16 @@ int main(int argc, char* argv[]) { + changes = NULL; + n_changes = 0; + +- r = unit_file_unmask(UNIT_FILE_SYSTEM, 0, NULL, (char**) files, &changes, &n_changes); ++ r = unit_file_unmask(LOOKUP_SCOPE_SYSTEM, 0, NULL, (char**) files, &changes, &n_changes); + assert_se(r >= 0); + log_info("/*** unmask2 ***/"); +- r = unit_file_unmask(UNIT_FILE_SYSTEM, 0, NULL, (char**) files, &changes, &n_changes); ++ r = unit_file_unmask(LOOKUP_SCOPE_SYSTEM, 0, NULL, (char**) files, &changes, &n_changes); + assert_se(r >= 0); + + dump_changes(changes, n_changes); + unit_file_changes_free(changes, n_changes); + +- r = unit_file_get_state(UNIT_FILE_SYSTEM, NULL, files[0], &state); ++ r = unit_file_get_state(LOOKUP_SCOPE_SYSTEM, NULL, files[0], &state); + assert_se(r >= 0); + assert_se(state == UNIT_FILE_DISABLED); + +@@ -119,13 +119,13 @@ int main(int argc, char* argv[]) { + changes = NULL; + n_changes = 0; + +- r = unit_file_mask(UNIT_FILE_SYSTEM, 0, NULL, (char**) files, &changes, &n_changes); ++ r = unit_file_mask(LOOKUP_SCOPE_SYSTEM, 0, NULL, (char**) files, &changes, &n_changes); + assert_se(r >= 0); + + dump_changes(changes, n_changes); + unit_file_changes_free(changes, n_changes); + +- r = unit_file_get_state(UNIT_FILE_SYSTEM, NULL, files[0], &state); ++ r = unit_file_get_state(LOOKUP_SCOPE_SYSTEM, NULL, files[0], &state); + assert_se(r >= 0); + assert_se(state == UNIT_FILE_MASKED); + +@@ -133,16 +133,16 @@ int main(int argc, char* argv[]) { + changes = NULL; + n_changes = 0; + +- r = unit_file_disable(UNIT_FILE_SYSTEM, 0, NULL, (char**) files, &changes, &n_changes); ++ r = unit_file_disable(LOOKUP_SCOPE_SYSTEM, 0, NULL, (char**) files, &changes, &n_changes); + assert_se(r >= 0); + log_info("/*** disable2 ***/"); +- r = unit_file_disable(UNIT_FILE_SYSTEM, 0, NULL, (char**) files, &changes, &n_changes); ++ r = unit_file_disable(LOOKUP_SCOPE_SYSTEM, 0, NULL, (char**) files, &changes, &n_changes); + assert_se(r >= 0); + + dump_changes(changes, n_changes); + unit_file_changes_free(changes, n_changes); + +- r = unit_file_get_state(UNIT_FILE_SYSTEM, NULL, files[0], &state); ++ r = unit_file_get_state(LOOKUP_SCOPE_SYSTEM, NULL, files[0], &state); + assert_se(r >= 0); + assert_se(state == UNIT_FILE_MASKED); + +@@ -150,13 +150,13 @@ int main(int argc, char* argv[]) { + changes = NULL; + n_changes = 0; + +- r = unit_file_unmask(UNIT_FILE_SYSTEM, 0, NULL, (char**) files, &changes, &n_changes); ++ r = unit_file_unmask(LOOKUP_SCOPE_SYSTEM, 0, NULL, (char**) files, &changes, &n_changes); + assert_se(r >= 0); + + dump_changes(changes, n_changes); + unit_file_changes_free(changes, n_changes); + +- r = unit_file_get_state(UNIT_FILE_SYSTEM, NULL, files[0], &state); ++ r = unit_file_get_state(LOOKUP_SCOPE_SYSTEM, NULL, files[0], &state); + assert_se(r >= 0); + assert_se(state == UNIT_FILE_DISABLED); + +@@ -164,13 +164,13 @@ int main(int argc, char* argv[]) { + changes = NULL; + n_changes = 0; + +- r = unit_file_enable(UNIT_FILE_SYSTEM, 0, NULL, (char**) files2, &changes, &n_changes); ++ r = unit_file_enable(LOOKUP_SCOPE_SYSTEM, 0, NULL, (char**) files2, &changes, &n_changes); + assert_se(r >= 0); + + dump_changes(changes, n_changes); + unit_file_changes_free(changes, n_changes); + +- r = unit_file_get_state(UNIT_FILE_SYSTEM, NULL, basename(files2[0]), &state); ++ r = unit_file_get_state(LOOKUP_SCOPE_SYSTEM, NULL, basename(files2[0]), &state); + assert_se(r >= 0); + assert_se(state == UNIT_FILE_ENABLED); + +@@ -178,26 +178,26 @@ int main(int argc, char* argv[]) { + changes = NULL; + n_changes = 0; + +- r = unit_file_disable(UNIT_FILE_SYSTEM, 0, NULL, STRV_MAKE(basename(files2[0])), &changes, &n_changes); ++ r = unit_file_disable(LOOKUP_SCOPE_SYSTEM, 0, NULL, STRV_MAKE(basename(files2[0])), &changes, &n_changes); + assert_se(r >= 0); + + dump_changes(changes, n_changes); + unit_file_changes_free(changes, n_changes); + +- r = unit_file_get_state(UNIT_FILE_SYSTEM, NULL, basename(files2[0]), &state); ++ r = unit_file_get_state(LOOKUP_SCOPE_SYSTEM, NULL, basename(files2[0]), &state); + assert_se(r < 0); + + log_info("/*** link files2 ***/"); + changes = NULL; + n_changes = 0; + +- r = unit_file_link(UNIT_FILE_SYSTEM, 0, NULL, (char**) files2, &changes, &n_changes); ++ r = unit_file_link(LOOKUP_SCOPE_SYSTEM, 0, NULL, (char**) files2, &changes, &n_changes); + assert_se(r >= 0); + + dump_changes(changes, n_changes); + unit_file_changes_free(changes, n_changes); + +- r = unit_file_get_state(UNIT_FILE_SYSTEM, NULL, basename(files2[0]), &state); ++ r = unit_file_get_state(LOOKUP_SCOPE_SYSTEM, NULL, basename(files2[0]), &state); + assert_se(r >= 0); + assert_se(state == UNIT_FILE_LINKED); + +@@ -205,26 +205,26 @@ int main(int argc, char* argv[]) { + changes = NULL; + n_changes = 0; + +- r = unit_file_disable(UNIT_FILE_SYSTEM, 0, NULL, STRV_MAKE(basename(files2[0])), &changes, &n_changes); ++ r = unit_file_disable(LOOKUP_SCOPE_SYSTEM, 0, NULL, STRV_MAKE(basename(files2[0])), &changes, &n_changes); + assert_se(r >= 0); + + dump_changes(changes, n_changes); + unit_file_changes_free(changes, n_changes); + +- r = unit_file_get_state(UNIT_FILE_SYSTEM, NULL, basename(files2[0]), &state); ++ r = unit_file_get_state(LOOKUP_SCOPE_SYSTEM, NULL, basename(files2[0]), &state); + assert_se(r < 0); + + log_info("/*** link files2 ***/"); + changes = NULL; + n_changes = 0; + +- r = unit_file_link(UNIT_FILE_SYSTEM, 0, NULL, (char**) files2, &changes, &n_changes); ++ r = unit_file_link(LOOKUP_SCOPE_SYSTEM, 0, NULL, (char**) files2, &changes, &n_changes); + assert_se(r >= 0); + + dump_changes(changes, n_changes); + unit_file_changes_free(changes, n_changes); + +- r = unit_file_get_state(UNIT_FILE_SYSTEM, NULL, basename(files2[0]), &state); ++ r = unit_file_get_state(LOOKUP_SCOPE_SYSTEM, NULL, basename(files2[0]), &state); + assert_se(r >= 0); + assert_se(state == UNIT_FILE_LINKED); + +@@ -232,13 +232,13 @@ int main(int argc, char* argv[]) { + changes = NULL; + n_changes = 0; + +- r = unit_file_reenable(UNIT_FILE_SYSTEM, 0, NULL, (char**) files2, &changes, &n_changes); ++ r = unit_file_reenable(LOOKUP_SCOPE_SYSTEM, 0, NULL, (char**) files2, &changes, &n_changes); + assert_se(r >= 0); + + dump_changes(changes, n_changes); + unit_file_changes_free(changes, n_changes); + +- r = unit_file_get_state(UNIT_FILE_SYSTEM, NULL, basename(files2[0]), &state); ++ r = unit_file_get_state(LOOKUP_SCOPE_SYSTEM, NULL, basename(files2[0]), &state); + assert_se(r >= 0); + assert_se(state == UNIT_FILE_ENABLED); + +@@ -246,25 +246,25 @@ int main(int argc, char* argv[]) { + changes = NULL; + n_changes = 0; + +- r = unit_file_disable(UNIT_FILE_SYSTEM, 0, NULL, STRV_MAKE(basename(files2[0])), &changes, &n_changes); ++ r = unit_file_disable(LOOKUP_SCOPE_SYSTEM, 0, NULL, STRV_MAKE(basename(files2[0])), &changes, &n_changes); + assert_se(r >= 0); + + dump_changes(changes, n_changes); + unit_file_changes_free(changes, n_changes); + +- r = unit_file_get_state(UNIT_FILE_SYSTEM, NULL, basename(files2[0]), &state); ++ r = unit_file_get_state(LOOKUP_SCOPE_SYSTEM, NULL, basename(files2[0]), &state); + assert_se(r < 0); + log_info("/*** preset files ***/"); + changes = NULL; + n_changes = 0; + +- r = unit_file_preset(UNIT_FILE_SYSTEM, 0, NULL, (char**) files, UNIT_FILE_PRESET_FULL, &changes, &n_changes); ++ r = unit_file_preset(LOOKUP_SCOPE_SYSTEM, 0, NULL, (char**) files, UNIT_FILE_PRESET_FULL, &changes, &n_changes); + assert_se(r >= 0); + + dump_changes(changes, n_changes); + unit_file_changes_free(changes, n_changes); + +- r = unit_file_get_state(UNIT_FILE_SYSTEM, NULL, basename(files[0]), &state); ++ r = unit_file_get_state(LOOKUP_SCOPE_SYSTEM, NULL, basename(files[0]), &state); + assert_se(r >= 0); + assert_se(state == UNIT_FILE_ENABLED); + +diff --git a/src/test/test-load-fragment.c b/src/test/test-load-fragment.c +index a87c654f4e..46ba108266 100644 +--- a/src/test/test-load-fragment.c ++++ b/src/test/test-load-fragment.c +@@ -43,7 +43,7 @@ TEST_RET(unit_file_get_set) { + h = hashmap_new(&string_hash_ops); + assert_se(h); + +- r = unit_file_get_list(UNIT_FILE_SYSTEM, NULL, h, NULL, NULL); ++ r = unit_file_get_list(LOOKUP_SCOPE_SYSTEM, NULL, h, NULL, NULL); + if (IN_SET(r, -EPERM, -EACCES)) + return log_tests_skipped_errno(r, "unit_file_get_list"); + +@@ -102,7 +102,7 @@ TEST(config_parse_exec) { + _cleanup_(manager_freep) Manager *m = NULL; + _cleanup_(unit_freep) Unit *u = NULL; + +- r = manager_new(UNIT_FILE_USER, MANAGER_TEST_RUN_MINIMAL, &m); ++ r = manager_new(LOOKUP_SCOPE_USER, MANAGER_TEST_RUN_MINIMAL, &m); + if (manager_errno_skip_test(r)) { + log_notice_errno(r, "Skipping test: manager_new: %m"); + return; +@@ -461,7 +461,7 @@ TEST(config_parse_log_extra_fields) { + _cleanup_(unit_freep) Unit *u = NULL; + ExecContext c = {}; + +- r = manager_new(UNIT_FILE_USER, MANAGER_TEST_RUN_MINIMAL, &m); ++ r = manager_new(LOOKUP_SCOPE_USER, MANAGER_TEST_RUN_MINIMAL, &m); + if (manager_errno_skip_test(r)) { + log_notice_errno(r, "Skipping test: manager_new: %m"); + return; +@@ -544,56 +544,56 @@ TEST(install_printf, .sd_booted = true) { + strcpy(i.path, d2); \ + } while (false) + +- expect(UNIT_FILE_SYSTEM, i, "%n", "name.service"); +- expect(UNIT_FILE_SYSTEM, i, "%N", "name"); +- expect(UNIT_FILE_SYSTEM, i, "%p", "name"); +- expect(UNIT_FILE_SYSTEM, i, "%i", ""); +- expect(UNIT_FILE_SYSTEM, i, "%j", "name"); +- expect(UNIT_FILE_SYSTEM, i, "%g", "root"); +- expect(UNIT_FILE_SYSTEM, i, "%G", "0"); +- expect(UNIT_FILE_SYSTEM, i, "%u", "root"); +- expect(UNIT_FILE_SYSTEM, i, "%U", "0"); +- +- expect(UNIT_FILE_SYSTEM, i, "%m", mid); +- expect(UNIT_FILE_SYSTEM, i, "%b", bid); +- expect(UNIT_FILE_SYSTEM, i, "%H", host); +- +- expect(UNIT_FILE_SYSTEM, i2, "%g", "root"); +- expect(UNIT_FILE_SYSTEM, i2, "%G", "0"); +- expect(UNIT_FILE_SYSTEM, i2, "%u", "root"); +- expect(UNIT_FILE_SYSTEM, i2, "%U", "0"); +- +- expect(UNIT_FILE_USER, i2, "%g", group); +- expect(UNIT_FILE_USER, i2, "%G", gid); +- expect(UNIT_FILE_USER, i2, "%u", user); +- expect(UNIT_FILE_USER, i2, "%U", uid); ++ expect(LOOKUP_SCOPE_SYSTEM, i, "%n", "name.service"); ++ expect(LOOKUP_SCOPE_SYSTEM, i, "%N", "name"); ++ expect(LOOKUP_SCOPE_SYSTEM, i, "%p", "name"); ++ expect(LOOKUP_SCOPE_SYSTEM, i, "%i", ""); ++ expect(LOOKUP_SCOPE_SYSTEM, i, "%j", "name"); ++ expect(LOOKUP_SCOPE_SYSTEM, i, "%g", "root"); ++ expect(LOOKUP_SCOPE_SYSTEM, i, "%G", "0"); ++ expect(LOOKUP_SCOPE_SYSTEM, i, "%u", "root"); ++ expect(LOOKUP_SCOPE_SYSTEM, i, "%U", "0"); ++ ++ expect(LOOKUP_SCOPE_SYSTEM, i, "%m", mid); ++ expect(LOOKUP_SCOPE_SYSTEM, i, "%b", bid); ++ expect(LOOKUP_SCOPE_SYSTEM, i, "%H", host); ++ ++ expect(LOOKUP_SCOPE_SYSTEM, i2, "%g", "root"); ++ expect(LOOKUP_SCOPE_SYSTEM, i2, "%G", "0"); ++ expect(LOOKUP_SCOPE_SYSTEM, i2, "%u", "root"); ++ expect(LOOKUP_SCOPE_SYSTEM, i2, "%U", "0"); ++ ++ expect(LOOKUP_SCOPE_USER, i2, "%g", group); ++ expect(LOOKUP_SCOPE_USER, i2, "%G", gid); ++ expect(LOOKUP_SCOPE_USER, i2, "%u", user); ++ expect(LOOKUP_SCOPE_USER, i2, "%U", uid); + + /* gcc-12.0.1-0.9.fc36.x86_64 insist that streq(…, NULL) is called, + * even though the call is inside of a conditional where the pointer is checked. :( */ + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wnonnull" +- expect(UNIT_FILE_GLOBAL, i2, "%g", NULL); +- expect(UNIT_FILE_GLOBAL, i2, "%G", NULL); +- expect(UNIT_FILE_GLOBAL, i2, "%u", NULL); +- expect(UNIT_FILE_GLOBAL, i2, "%U", NULL); ++ expect(LOOKUP_SCOPE_GLOBAL, i2, "%g", NULL); ++ expect(LOOKUP_SCOPE_GLOBAL, i2, "%G", NULL); ++ expect(LOOKUP_SCOPE_GLOBAL, i2, "%u", NULL); ++ expect(LOOKUP_SCOPE_GLOBAL, i2, "%U", NULL); + #pragma GCC diagnostic pop + +- expect(UNIT_FILE_SYSTEM, i3, "%n", "name@inst.service"); +- expect(UNIT_FILE_SYSTEM, i3, "%N", "name@inst"); +- expect(UNIT_FILE_SYSTEM, i3, "%p", "name"); +- expect(UNIT_FILE_USER, i3, "%g", group); +- expect(UNIT_FILE_USER, i3, "%G", gid); +- expect(UNIT_FILE_USER, i3, "%u", user); +- expect(UNIT_FILE_USER, i3, "%U", uid); +- +- expect(UNIT_FILE_SYSTEM, i3, "%m", mid); +- expect(UNIT_FILE_SYSTEM, i3, "%b", bid); +- expect(UNIT_FILE_SYSTEM, i3, "%H", host); +- +- expect(UNIT_FILE_USER, i4, "%g", group); +- expect(UNIT_FILE_USER, i4, "%G", gid); +- expect(UNIT_FILE_USER, i4, "%u", user); +- expect(UNIT_FILE_USER, i4, "%U", uid); ++ expect(LOOKUP_SCOPE_SYSTEM, i3, "%n", "name@inst.service"); ++ expect(LOOKUP_SCOPE_SYSTEM, i3, "%N", "name@inst"); ++ expect(LOOKUP_SCOPE_SYSTEM, i3, "%p", "name"); ++ expect(LOOKUP_SCOPE_USER, i3, "%g", group); ++ expect(LOOKUP_SCOPE_USER, i3, "%G", gid); ++ expect(LOOKUP_SCOPE_USER, i3, "%u", user); ++ expect(LOOKUP_SCOPE_USER, i3, "%U", uid); ++ ++ expect(LOOKUP_SCOPE_SYSTEM, i3, "%m", mid); ++ expect(LOOKUP_SCOPE_SYSTEM, i3, "%b", bid); ++ expect(LOOKUP_SCOPE_SYSTEM, i3, "%H", host); ++ ++ expect(LOOKUP_SCOPE_USER, i4, "%g", group); ++ expect(LOOKUP_SCOPE_USER, i4, "%G", gid); ++ expect(LOOKUP_SCOPE_USER, i4, "%u", user); ++ expect(LOOKUP_SCOPE_USER, i4, "%U", uid); + } + + static uint64_t make_cap(int cap) { +@@ -822,7 +822,7 @@ TEST(config_parse_unit_env_file) { + _cleanup_strv_free_ char **files = NULL; + int r; + +- r = manager_new(UNIT_FILE_USER, MANAGER_TEST_RUN_MINIMAL, &m); ++ r = manager_new(LOOKUP_SCOPE_USER, MANAGER_TEST_RUN_MINIMAL, &m); + if (manager_errno_skip_test(r)) { + log_notice_errno(r, "Skipping test: manager_new: %m"); + return; +@@ -955,7 +955,7 @@ TEST(unit_is_recursive_template_dependency) { + Unit *u; + int r; + +- r = manager_new(UNIT_FILE_USER, MANAGER_TEST_RUN_MINIMAL, &m); ++ r = manager_new(LOOKUP_SCOPE_USER, MANAGER_TEST_RUN_MINIMAL, &m); + if (manager_errno_skip_test(r)) { + log_notice_errno(r, "Skipping test: manager_new: %m"); + return; +diff --git a/src/test/test-path-lookup.c b/src/test/test-path-lookup.c +index 2c30260f7b..8d25e5f7b7 100644 +--- a/src/test/test-path-lookup.c ++++ b/src/test/test-path-lookup.c +@@ -10,7 +10,7 @@ + #include "strv.h" + #include "tests.h" + +-static void test_paths_one(UnitFileScope scope) { ++static void test_paths_one(LookupScope scope) { + char template[] = "/tmp/test-path-lookup.XXXXXXX"; + + _cleanup_(lookup_paths_free) LookupPaths lp_without_env = {}; +@@ -36,9 +36,9 @@ static void test_paths_one(UnitFileScope scope) { + } + + TEST(paths) { +- test_paths_one(UNIT_FILE_SYSTEM); +- test_paths_one(UNIT_FILE_USER); +- test_paths_one(UNIT_FILE_GLOBAL); ++ test_paths_one(LOOKUP_SCOPE_SYSTEM); ++ test_paths_one(LOOKUP_SCOPE_USER); ++ test_paths_one(LOOKUP_SCOPE_GLOBAL); + } + + TEST(user_and_global_paths) { +@@ -50,8 +50,8 @@ TEST(user_and_global_paths) { + assert_se(unsetenv("XDG_DATA_DIRS") == 0); + assert_se(unsetenv("XDG_CONFIG_DIRS") == 0); + +- assert_se(lookup_paths_init(&lp_global, UNIT_FILE_GLOBAL, 0, NULL) == 0); +- assert_se(lookup_paths_init(&lp_user, UNIT_FILE_USER, 0, NULL) == 0); ++ assert_se(lookup_paths_init(&lp_global, LOOKUP_SCOPE_GLOBAL, 0, NULL) == 0); ++ assert_se(lookup_paths_init(&lp_user, LOOKUP_SCOPE_USER, 0, NULL) == 0); + g = lp_global.search_path; + u = lp_user.search_path; + +@@ -72,7 +72,7 @@ TEST(user_and_global_paths) { + log_info("+ %s", *p); + } + +-static void test_generator_binary_paths_one(UnitFileScope scope) { ++static void test_generator_binary_paths_one(LookupScope scope) { + char template[] = "/tmp/test-path-lookup.XXXXXXX"; + + _cleanup_strv_free_ char **gp_without_env = NULL; +@@ -88,13 +88,13 @@ static void test_generator_binary_paths_one(UnitFileScope scope) { + assert_se(unsetenv("SYSTEMD_ENVIRONMENT_GENERATOR_PATH") == 0); + + gp_without_env = generator_binary_paths(scope); +- env_gp_without_env = env_generator_binary_paths(scope == UNIT_FILE_SYSTEM ? true : false); ++ env_gp_without_env = env_generator_binary_paths(scope == LOOKUP_SCOPE_SYSTEM ? true : false); + +- log_info("Generators dirs (%s):", scope == UNIT_FILE_SYSTEM ? "system" : "user"); ++ log_info("Generators dirs (%s):", scope == LOOKUP_SCOPE_SYSTEM ? "system" : "user"); + STRV_FOREACH(dir, gp_without_env) + log_info(" %s", *dir); + +- log_info("Environment generators dirs (%s):", scope == UNIT_FILE_SYSTEM ? "system" : "user"); ++ log_info("Environment generators dirs (%s):", scope == LOOKUP_SCOPE_SYSTEM ? "system" : "user"); + STRV_FOREACH(dir, env_gp_without_env) + log_info(" %s", *dir); + +@@ -107,13 +107,13 @@ static void test_generator_binary_paths_one(UnitFileScope scope) { + assert_se(setenv("SYSTEMD_ENVIRONMENT_GENERATOR_PATH", systemd_env_generator_path, 1) == 0); + + gp_with_env = generator_binary_paths(scope); +- env_gp_with_env = env_generator_binary_paths(scope == UNIT_FILE_SYSTEM ? true : false); ++ env_gp_with_env = env_generator_binary_paths(scope == LOOKUP_SCOPE_SYSTEM ? true : false); + +- log_info("Generators dirs (%s):", scope == UNIT_FILE_SYSTEM ? "system" : "user"); ++ log_info("Generators dirs (%s):", scope == LOOKUP_SCOPE_SYSTEM ? "system" : "user"); + STRV_FOREACH(dir, gp_with_env) + log_info(" %s", *dir); + +- log_info("Environment generators dirs (%s):", scope == UNIT_FILE_SYSTEM ? "system" : "user"); ++ log_info("Environment generators dirs (%s):", scope == LOOKUP_SCOPE_SYSTEM ? "system" : "user"); + STRV_FOREACH(dir, env_gp_with_env) + log_info(" %s", *dir); + +@@ -122,8 +122,8 @@ static void test_generator_binary_paths_one(UnitFileScope scope) { + } + + TEST(generator_binary_paths) { +- test_generator_binary_paths_one(UNIT_FILE_SYSTEM); +- test_generator_binary_paths_one(UNIT_FILE_USER); ++ test_generator_binary_paths_one(LOOKUP_SCOPE_SYSTEM); ++ test_generator_binary_paths_one(LOOKUP_SCOPE_USER); + } + + DEFINE_TEST_MAIN(LOG_DEBUG); +diff --git a/src/test/test-path.c b/src/test/test-path.c +index 2690dc0aa4..7fb1f7363c 100644 +--- a/src/test/test-path.c ++++ b/src/test/test-path.c +@@ -33,7 +33,7 @@ static int setup_test(Manager **m) { + if (r == -ENOMEDIUM) + return log_tests_skipped("cgroupfs not available"); + +- r = manager_new(UNIT_FILE_USER, MANAGER_TEST_RUN_BASIC, &tmp); ++ r = manager_new(LOOKUP_SCOPE_USER, MANAGER_TEST_RUN_BASIC, &tmp); + if (manager_errno_skip_test(r)) + return log_tests_skipped_errno(r, "manager_new"); + assert_se(r >= 0); +diff --git a/src/test/test-sched-prio.c b/src/test/test-sched-prio.c +index 35f7be491a..721c4b61a1 100644 +--- a/src/test/test-sched-prio.c ++++ b/src/test/test-sched-prio.c +@@ -30,7 +30,7 @@ int main(int argc, char *argv[]) { + assert_se(set_unit_path(unit_dir) >= 0); + assert_se(runtime_dir = setup_fake_runtime_dir()); + +- r = manager_new(UNIT_FILE_USER, MANAGER_TEST_RUN_BASIC, &m); ++ r = manager_new(LOOKUP_SCOPE_USER, MANAGER_TEST_RUN_BASIC, &m); + if (manager_errno_skip_test(r)) + return log_tests_skipped_errno(r, "manager_new"); + assert_se(r >= 0); +diff --git a/src/test/test-socket-bind.c b/src/test/test-socket-bind.c +index c5c5477f69..b5f8eb9357 100644 +--- a/src/test/test-socket-bind.c ++++ b/src/test/test-socket-bind.c +@@ -136,7 +136,7 @@ int main(int argc, char *argv[]) { + assert_se(set_unit_path(unit_dir) >= 0); + assert_se(runtime_dir = setup_fake_runtime_dir()); + +- assert_se(manager_new(UNIT_FILE_USER, MANAGER_TEST_RUN_BASIC, &m) >= 0); ++ assert_se(manager_new(LOOKUP_SCOPE_USER, MANAGER_TEST_RUN_BASIC, &m) >= 0); + assert_se(manager_startup(m, NULL, NULL, NULL) >= 0); + + assert_se(test_socket_bind(m, "socket_bind_test.service", netcat_path, "2000", STRV_MAKE("2000"), STRV_MAKE("any")) >= 0); +diff --git a/src/test/test-specifier.c b/src/test/test-specifier.c +index dd47f0285e..71fb06963c 100644 +--- a/src/test/test-specifier.c ++++ b/src/test/test-specifier.c +@@ -46,7 +46,7 @@ TEST(specifier_escape_strv) { + static const Specifier specifier_table[] = { + COMMON_SYSTEM_SPECIFIERS, + +- COMMON_CREDS_SPECIFIERS(UNIT_FILE_USER), ++ COMMON_CREDS_SPECIFIERS(LOOKUP_SCOPE_USER), + { 'h', specifier_user_home, NULL }, + + COMMON_TMP_SPECIFIERS, +diff --git a/src/test/test-unit-file.c b/src/test/test-unit-file.c +index 261bd7412f..dffa2822e6 100644 +--- a/src/test/test-unit-file.c ++++ b/src/test/test-unit-file.c +@@ -35,7 +35,7 @@ TEST(unit_file_build_name_map) { + + ids = strv_skip(saved_argv, 1); + +- assert_se(lookup_paths_init(&lp, UNIT_FILE_SYSTEM, 0, NULL) >= 0); ++ assert_se(lookup_paths_init(&lp, LOOKUP_SCOPE_SYSTEM, 0, NULL) >= 0); + + assert_se(unit_file_build_name_map(&lp, &mtime, &unit_ids, &unit_names, NULL) == 1); + +diff --git a/src/test/test-unit-name.c b/src/test/test-unit-name.c +index b6137333aa..90539f108f 100644 +--- a/src/test/test-unit-name.c ++++ b/src/test/test-unit-name.c +@@ -248,7 +248,7 @@ TEST_RET(unit_printf, .sd_booted = true) { + assert_se(get_home_dir(&home) >= 0); + assert_se(get_shell(&shell) >= 0); + +- r = manager_new(UNIT_FILE_USER, MANAGER_TEST_RUN_MINIMAL, &m); ++ r = manager_new(LOOKUP_SCOPE_USER, MANAGER_TEST_RUN_MINIMAL, &m); + if (manager_errno_skip_test(r)) + return log_tests_skipped_errno(r, "manager_new"); + assert_se(r == 0); +diff --git a/src/test/test-unit-serialize.c b/src/test/test-unit-serialize.c +index 3ef15f3b1e..f84435f480 100644 +--- a/src/test/test-unit-serialize.c ++++ b/src/test/test-unit-serialize.c +@@ -31,7 +31,7 @@ TEST(deserialize_exec_command) { + _cleanup_(manager_freep) Manager *m = NULL; + int r; + +- r = manager_new(UNIT_FILE_USER, MANAGER_TEST_RUN_MINIMAL, &m); ++ r = manager_new(LOOKUP_SCOPE_USER, MANAGER_TEST_RUN_MINIMAL, &m); + if (manager_errno_skip_test(r)) { + log_notice_errno(r, "Skipping test: manager_new: %m"); + return; +diff --git a/src/test/test-watch-pid.c b/src/test/test-watch-pid.c +index 885ed802d4..8c355c1d5f 100644 +--- a/src/test/test-watch-pid.c ++++ b/src/test/test-watch-pid.c +@@ -26,7 +26,7 @@ int main(int argc, char *argv[]) { + + assert_se(runtime_dir = setup_fake_runtime_dir()); + +- assert_se(manager_new(UNIT_FILE_USER, MANAGER_TEST_RUN_BASIC, &m) >= 0); ++ assert_se(manager_new(LOOKUP_SCOPE_USER, MANAGER_TEST_RUN_BASIC, &m) >= 0); + assert_se(manager_startup(m, NULL, NULL, NULL) >= 0); + + assert_se(a = unit_new(m, sizeof(Service))); +diff --git a/src/tmpfiles/tmpfiles.c b/src/tmpfiles/tmpfiles.c +index 17b9c6ab9a..023207bc60 100644 +--- a/src/tmpfiles/tmpfiles.c ++++ b/src/tmpfiles/tmpfiles.c +@@ -2938,7 +2938,7 @@ static int parse_line( + { 'S', specifier_directory, UINT_TO_PTR(DIRECTORY_STATE) }, + { 't', specifier_directory, UINT_TO_PTR(DIRECTORY_RUNTIME) }, + +- COMMON_CREDS_SPECIFIERS(arg_user ? UNIT_FILE_USER : UNIT_FILE_SYSTEM), ++ COMMON_CREDS_SPECIFIERS(arg_user ? LOOKUP_SCOPE_USER : LOOKUP_SCOPE_SYSTEM), + COMMON_TMP_SPECIFIERS, + {} + }; diff --git a/0205-core-handle-lookup-paths-being-symlinks.patch b/0205-core-handle-lookup-paths-being-symlinks.patch new file mode 100644 index 0000000..295b41d --- /dev/null +++ b/0205-core-handle-lookup-paths-being-symlinks.patch @@ -0,0 +1,89 @@ +From dc017e5c51e61ddd96d2a94f35223ac7788c8454 Mon Sep 17 00:00:00 2001 +From: Andreas Rammhold +Date: Wed, 18 Aug 2021 19:10:08 +0200 +Subject: [PATCH] core: handle lookup paths being symlinks +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +With a recent change paths leaving the statically known lookup paths would be +treated differently then those that remained within those. That was done +(AFAIK) to consistently handle alias names. Unfortunately that means that on +some distributions, especially those where /etc/ consists mostly of symlinks, +would trigger that new detection for every single unit in /etc/systemd/system. +The reason for that is that the units directory itself is already a symlink. + +Rebased-by: Zbigniew Jędrzejewski-Szmek +(cherry picked from commit 66c38cd0536c50769eba6abccf383bbaceb268ca) + +Resolves: #2082131 +--- + src/basic/unit-file.c | 41 ++++++++++++++++++++++++++++++++++++++++- + 1 file changed, 40 insertions(+), 1 deletion(-) + +diff --git a/src/basic/unit-file.c b/src/basic/unit-file.c +index 7c1ae515e1..83c29bb25f 100644 +--- a/src/basic/unit-file.c ++++ b/src/basic/unit-file.c +@@ -388,6 +388,7 @@ int unit_file_build_name_map( + + _cleanup_hashmap_free_ Hashmap *ids = NULL, *names = NULL; + _cleanup_set_free_free_ Set *paths = NULL; ++ _cleanup_strv_free_ char **expanded_search_path = NULL; + uint64_t timestamp_hash; + int r; + +@@ -406,6 +407,44 @@ int unit_file_build_name_map( + return log_oom(); + } + ++ /* Go over all our search paths, chase their symlinks and store the result in the ++ * expanded_search_path list. ++ * ++ * This is important for cases where any of the unit directories itself are symlinks into other ++ * directories and would therefore cause all of the unit files to be recognized as linked units. ++ * ++ * This is important for distributions such as NixOS where most paths in /etc/ are symlinks to some ++ * other location on the filesystem (e.g. into /nix/store/). ++ * ++ * Search paths are ordered by priority (highest first), and we need to maintain this order. ++ * If a resolved path is already in the list, we don't need to include. ++ * ++ * Note that we build a list that contains both the original paths and the resolved symlinks: ++ * we need the latter for the case where the directory is symlinked, as described above, and ++ * the former for the case where some unit file alias is a dangling symlink that points to one ++ * of the "original" directories (and can't be followed). ++ */ ++ STRV_FOREACH(dir, lp->search_path) { ++ _cleanup_free_ char *resolved_dir = NULL; ++ ++ r = strv_extend(&expanded_search_path, *dir); ++ if (r < 0) ++ return log_oom(); ++ ++ r = chase_symlinks(*dir, NULL, 0, &resolved_dir, NULL); ++ if (r < 0) { ++ if (r != -ENOENT) ++ log_warning_errno(r, "Failed to resolve symlink %s, ignoring: %m", *dir); ++ continue; ++ } ++ ++ if (strv_contains(expanded_search_path, resolved_dir)) ++ continue; ++ ++ if (strv_consume(&expanded_search_path, TAKE_PTR(resolved_dir)) < 0) ++ return log_oom(); ++ } ++ + STRV_FOREACH(dir, lp->search_path) { + _cleanup_closedir_ DIR *d = NULL; + +@@ -504,7 +543,7 @@ int unit_file_build_name_map( + /* We don't explicitly check for alias loops here. unit_ids_map_get() which + * limits the number of hops should be used to access the map. */ + +- r = unit_file_resolve_symlink(lp->root_dir, lp->search_path, ++ r = unit_file_resolve_symlink(lp->root_dir, expanded_search_path, + *dir, dirfd(d), de->d_name, + /* resolve_destination_target= */ false, + &dst); diff --git a/0206-shared-install-use-correct-cleanup-function.patch b/0206-shared-install-use-correct-cleanup-function.patch new file mode 100644 index 0000000..5a0e3e3 --- /dev/null +++ b/0206-shared-install-use-correct-cleanup-function.patch @@ -0,0 +1,27 @@ +From dc7ddca892c329ef24b7e9098134f5cae50e09a0 Mon Sep 17 00:00:00 2001 +From: Yu Watanabe +Date: Tue, 3 May 2022 01:09:21 +0900 +Subject: [PATCH] shared/install: use correct cleanup function + +Fixes #23250. + +(cherry picked from commit 0b6bf4b674a63e9951dcffbd0b95de7377038690) + +Related: #2082131 +--- + src/shared/install.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/shared/install.c b/src/shared/install.c +index fa7bbdd93a..96d64d32bb 100644 +--- a/src/shared/install.c ++++ b/src/shared/install.c +@@ -2804,7 +2804,7 @@ static int normalize_linked_files( + * but operates on real unit names. For each argument we we look up the actual path + * where the unit is found. This way linked units can be reenabled successfully. */ + +- _cleanup_free_ char **files = NULL, **names = NULL; ++ _cleanup_strv_free_ char **files = NULL, **names = NULL; + int r; + + STRV_FOREACH(a, names_or_paths) { diff --git a/0207-udev-net_id-avoid-slot-based-names-only-for-single-f.patch b/0207-udev-net_id-avoid-slot-based-names-only-for-single-f.patch new file mode 100644 index 0000000..1714906 --- /dev/null +++ b/0207-udev-net_id-avoid-slot-based-names-only-for-single-f.patch @@ -0,0 +1,109 @@ +From 07a2159c8dc575745c967499b068209e8926ea79 Mon Sep 17 00:00:00 2001 +From: Michal Sekletar +Date: Wed, 23 Mar 2022 17:34:12 +0100 +Subject: [PATCH] udev/net_id: avoid slot based names only for single function + devices + +If we have two or more devices that share the same slot but they are +also multifunction then it is OK to use the slot information even if it +is the same for all of them. Name conflict will be avoided because we +will append function number and form names like, ens1f1, ens1f2... + +(cherry picked from commit 66425daf2c68793adf24a48a26d58add8662e83f) + +Resolves: #2073003 +--- + man/systemd.net-naming-scheme.xml | 7 ++++++- + src/shared/netif-naming-scheme.h | 31 ++++++++++++++++--------------- + src/udev/udev-builtin-net_id.c | 11 +++++++++-- + 3 files changed, 31 insertions(+), 18 deletions(-) + +diff --git a/man/systemd.net-naming-scheme.xml b/man/systemd.net-naming-scheme.xml +index 942ef572ff..73d08b681d 100644 +--- a/man/systemd.net-naming-scheme.xml ++++ b/man/systemd.net-naming-scheme.xml +@@ -406,7 +406,12 @@ + + rhel-9.0 + +- Same as naming scheme v250. ++ Since version v247 we no longer set ++ ID_NET_NAME_SLOT if we detect that a PCI device associated with a slot is a PCI ++ bridge as that would create naming conflict when there are more child devices on that bridge. Now, ++ this is relaxed and we will use slot information to generate the name based on it but only if ++ the PCI device has multiple functions. This is safe because distinct function number is a part of ++ the device name for multifunction devices. + + + +diff --git a/src/shared/netif-naming-scheme.h b/src/shared/netif-naming-scheme.h +index f765db6ef2..5c86cb4545 100644 +--- a/src/shared/netif-naming-scheme.h ++++ b/src/shared/netif-naming-scheme.h +@@ -22,20 +22,21 @@ + * OS versions, but not fully stabilize them. */ + typedef enum NamingSchemeFlags { + /* First, the individual features */ +- NAMING_SR_IOV_V = 1 << 0, /* Use "v" suffix for SR-IOV, see 609948c7043a */ +- NAMING_NPAR_ARI = 1 << 1, /* Use NPAR "ARI", see 6bc04997b6ea */ +- NAMING_INFINIBAND = 1 << 2, /* Use "ib" prefix for infiniband, see 938d30aa98df */ +- NAMING_ZERO_ACPI_INDEX = 1 << 3, /* Use zero acpi_index field, see d81186ef4f6a */ +- NAMING_ALLOW_RERENAMES = 1 << 4, /* Allow re-renaming of devices, see #9006 */ +- NAMING_STABLE_VIRTUAL_MACS = 1 << 5, /* Use device name to generate MAC, see 6d3646406560 */ +- NAMING_NETDEVSIM = 1 << 6, /* Generate names for netdevsim devices, see eaa9d507d855 */ +- NAMING_LABEL_NOPREFIX = 1 << 7, /* Don't prepend ID_NET_LABEL_ONBOARD with interface type prefix */ +- NAMING_NSPAWN_LONG_HASH = 1 << 8, /* Shorten nspawn interfaces by including 24bit hash, instead of simple truncation */ +- NAMING_BRIDGE_NO_SLOT = 1 << 9, /* Don't use PCI hotplug slot information if the corresponding device is a PCI bridge */ +- NAMING_SLOT_FUNCTION_ID = 1 << 10, /* Use function_id if present to identify PCI hotplug slots */ +- NAMING_16BIT_INDEX = 1 << 11, /* Allow full 16-bit for the onboard index */ +- NAMING_REPLACE_STRICTLY = 1 << 12, /* Use udev_replace_ifname() for NAME= rule */ +- NAMING_XEN_VIF = 1 << 13, /* GEnerate names for Xen netfront devices */ ++ NAMING_SR_IOV_V = 1 << 0, /* Use "v" suffix for SR-IOV, see 609948c7043a */ ++ NAMING_NPAR_ARI = 1 << 1, /* Use NPAR "ARI", see 6bc04997b6ea */ ++ NAMING_INFINIBAND = 1 << 2, /* Use "ib" prefix for infiniband, see 938d30aa98df */ ++ NAMING_ZERO_ACPI_INDEX = 1 << 3, /* Use zero acpi_index field, see d81186ef4f6a */ ++ NAMING_ALLOW_RERENAMES = 1 << 4, /* Allow re-renaming of devices, see #9006 */ ++ NAMING_STABLE_VIRTUAL_MACS = 1 << 5, /* Use device name to generate MAC, see 6d3646406560 */ ++ NAMING_NETDEVSIM = 1 << 6, /* Generate names for netdevsim devices, see eaa9d507d855 */ ++ NAMING_LABEL_NOPREFIX = 1 << 7, /* Don't prepend ID_NET_LABEL_ONBOARD with interface type prefix */ ++ NAMING_NSPAWN_LONG_HASH = 1 << 8, /* Shorten nspawn interfaces by including 24bit hash, instead of simple truncation */ ++ NAMING_BRIDGE_NO_SLOT = 1 << 9, /* Don't use PCI hotplug slot information if the corresponding device is a PCI bridge */ ++ NAMING_SLOT_FUNCTION_ID = 1 << 10, /* Use function_id if present to identify PCI hotplug slots */ ++ NAMING_16BIT_INDEX = 1 << 11, /* Allow full 16-bit for the onboard index */ ++ NAMING_REPLACE_STRICTLY = 1 << 12, /* Use udev_replace_ifname() for NAME= rule */ ++ NAMING_XEN_VIF = 1 << 13, /* Generate names for Xen netfront devices */ ++ NAMING_BRIDGE_MULTIFUNCTION_SLOT = 1 << 14, /* Use PCI hotplug slot information associated with bridge, but only if PCI device is multifunction */ + + /* And now the masks that combine the features above */ + NAMING_V238 = 0, +@@ -47,7 +48,7 @@ typedef enum NamingSchemeFlags { + NAMING_V247 = NAMING_V245 | NAMING_BRIDGE_NO_SLOT, + NAMING_V249 = NAMING_V247 | NAMING_SLOT_FUNCTION_ID | NAMING_16BIT_INDEX | NAMING_REPLACE_STRICTLY, + NAMING_V250 = NAMING_V249 | NAMING_XEN_VIF, +- NAMING_RHEL_9_0 = NAMING_V250, ++ NAMING_RHEL_9_0 = NAMING_V250 | NAMING_BRIDGE_MULTIFUNCTION_SLOT, + + EXTRA_NET_NAMING_SCHEMES + +diff --git a/src/udev/udev-builtin-net_id.c b/src/udev/udev-builtin-net_id.c +index 65e003eb15..673ed7a7ca 100644 +--- a/src/udev/udev-builtin-net_id.c ++++ b/src/udev/udev-builtin-net_id.c +@@ -451,8 +451,15 @@ static int dev_pci_slot(sd_device *dev, const LinkInfo *info, NetNames *names) { + * devices that will try to claim the same index and that would create name + * collision. */ + if (naming_scheme_has(NAMING_BRIDGE_NO_SLOT) && is_pci_bridge(hotplug_slot_dev)) { +- log_device_debug(dev, "Not using slot information because the PCI device is a bridge."); +- return 0; ++ if (naming_scheme_has(NAMING_BRIDGE_MULTIFUNCTION_SLOT) && !is_pci_multifunction(names->pcidev)) { ++ log_device_debug(dev, "Not using slot information because the PCI device associated with the hotplug slot is a bridge and the PCI device has single function."); ++ return 0; ++ } ++ ++ if (!naming_scheme_has(NAMING_BRIDGE_MULTIFUNCTION_SLOT)) { ++ log_device_debug(dev, "Not using slot information because the PCI device is a bridge."); ++ return 0; ++ } + } + + break; diff --git a/0208-test-import-logind-test-from-debian-ubuntu-test-suit.patch b/0208-test-import-logind-test-from-debian-ubuntu-test-suit.patch new file mode 100644 index 0000000..b406c4a --- /dev/null +++ b/0208-test-import-logind-test-from-debian-ubuntu-test-suit.patch @@ -0,0 +1,489 @@ +From 40806a5f552c8d223d1d7ff1878dcf57e4d817c5 Mon Sep 17 00:00:00 2001 +From: Yu Watanabe +Date: Wed, 1 Jun 2022 08:56:08 +0900 +Subject: [PATCH] test: import logind test from debian/ubuntu test suite + +(cherry picked from commit 9c94ab0f6ff22da4278a6e9a93ddc480607c55ac) + +Related: #2087652 +--- + test/TEST-35-LOGIN/Makefile | 1 + + test/TEST-35-LOGIN/test.sh | 10 + + test/test-functions | 8 + + test/units/testsuite-35.service | 10 + + test/units/testsuite-35.sh | 379 ++++++++++++++++++++++++++++++++ + 5 files changed, 408 insertions(+) + create mode 120000 test/TEST-35-LOGIN/Makefile + create mode 100755 test/TEST-35-LOGIN/test.sh + create mode 100644 test/units/testsuite-35.service + create mode 100755 test/units/testsuite-35.sh + +diff --git a/test/TEST-35-LOGIN/Makefile b/test/TEST-35-LOGIN/Makefile +new file mode 120000 +index 0000000000..e9f93b1104 +--- /dev/null ++++ b/test/TEST-35-LOGIN/Makefile +@@ -0,0 +1 @@ ++../TEST-01-BASIC/Makefile +\ No newline at end of file +diff --git a/test/TEST-35-LOGIN/test.sh b/test/TEST-35-LOGIN/test.sh +new file mode 100755 +index 0000000000..9762410fa3 +--- /dev/null ++++ b/test/TEST-35-LOGIN/test.sh +@@ -0,0 +1,10 @@ ++#!/usr/bin/env bash ++# SPDX-License-Identifier: LGPL-2.1-or-later ++set -e ++ ++TEST_DESCRIPTION="LOGIN" ++ ++# shellcheck source=test/test-functions ++. "${TEST_BASE_DIR:?}/test-functions" ++ ++do_test "$@" +diff --git a/test/test-functions b/test/test-functions +index 98efd047d7..d71e2a3328 100644 +--- a/test/test-functions ++++ b/test/test-functions +@@ -165,10 +165,12 @@ BASICTOOLS=( + mv + nc + nproc ++ pkill + readlink + rev + rm + rmdir ++ rmmod + sed + seq + setfattr +@@ -193,6 +195,8 @@ BASICTOOLS=( + umount + uname + unshare ++ useradd ++ userdel + wc + xargs + xzcat +@@ -921,6 +925,8 @@ install_modules() { + instmods vfat + instmods nls_ascii =nls + instmods dummy ++ # for TEST-35-LOGIN ++ instmods scsi_debug uinput + + if get_bool "$LOOKS_LIKE_SUSE"; then + instmods ext4 +@@ -1702,6 +1708,8 @@ install_basic_tools() { + image_install -o sushell + # in Debian ldconfig is just a shell script wrapper around ldconfig.real + image_install -o ldconfig.real ++ # for TEST-35-LOGIN ++ image_install -o evemu-device evemu-event + } + + install_debug_tools() { +diff --git a/test/units/testsuite-35.service b/test/units/testsuite-35.service +new file mode 100644 +index 0000000000..556a57a384 +--- /dev/null ++++ b/test/units/testsuite-35.service +@@ -0,0 +1,10 @@ ++# SPDX-License-Identifier: LGPL-2.1-or-later ++[Unit] ++Description=TEST-35-LOGIN ++ ++[Service] ++ExecStartPre=rm -f /failed /testok ++ExecStart=/usr/lib/systemd/tests/testdata/units/%N.sh ++StandardOutput=journal+console ++StandardError=journal+console ++Type=oneshot +diff --git a/test/units/testsuite-35.sh b/test/units/testsuite-35.sh +new file mode 100755 +index 0000000000..0a7198c3fe +--- /dev/null ++++ b/test/units/testsuite-35.sh +@@ -0,0 +1,379 @@ ++#!/usr/bin/env bash ++# SPDX-License-Identifier: LGPL-2.1-or-later ++set -eux ++set -o pipefail ++ ++test_enable_debug() { ++ mkdir -p /run/systemd/system/systemd-logind.service.d ++ cat >/run/systemd/system/systemd-logind.service.d/debug.conf </run/systemd/logind.conf.d/kill-user-processes.conf <&2 ++ exit 1 ++ fi ++ ++ cat >/run/systemd/logind.conf.d/kill-user-processes.conf <&2 ++ exit 1 ++ fi ++ ++ rm -rf /run/systemd/logind.conf.d ++} ++ ++test_started() { ++ systemctl restart systemd-logind.service ++ ++ # should start at boot, not with D-BUS activation ++ LOGINDPID=$(systemctl show systemd-logind.service -p ExecMainPID --value) ++ ++ # loginctl should succeed ++ loginctl --no-pager ++} ++ ++# args: ++wait_suspend() { ++ timeout="$1" ++ while [[ $timeout -gt 0 && ! -e /run/suspend.flag ]]; do ++ sleep 1 ++ timeout=$((timeout - 1)) ++ done ++ if [[ ! -e /run/suspend.flag ]]; then ++ echo "closing lid did not cause suspend" >&2 ++ exit 1 ++ fi ++ rm /run/suspend.flag ++} ++ ++test_suspend_tear_down() { ++ set +e ++ ++ kill "$KILL_PID" ++} ++ ++test_suspend_on_lid() { ++ if systemd-detect-virt --quiet --container; then ++ echo "Skipping suspend test in container" ++ return ++ fi ++ if ! grep -s -q mem /sys/power/state; then ++ echo "suspend not supported on this testbed, skipping" ++ return ++ fi ++ if ! command -v evemu-device &>/dev/null; then ++ echo "command evemu-device not found, skipping" ++ return ++ fi ++ if ! command -v evemu-event &>/dev/null; then ++ echo "command evemu-event not found, skipping" ++ return ++ fi ++ ++ KILL_PID= ++ trap test_suspend_tear_down EXIT ++ ++ # create fake suspend ++ mkdir -p /run/systemd/system/systemd-suspend.service.d ++ cat >/run/systemd/system/systemd-suspend.service.d/override.conf </run/udev/rules.d/70-logindtest-lid.rules </run/lidswitch.evemu <&2 ++ exit 1 ++ fi ++ INPUT_NAME=${INPUT_NAME%/device/name} ++ LID_DEV=/dev/${INPUT_NAME#/sys/class/} ++ udevadm info --wait-for-initialization=10s "$LID_DEV" ++ udevadm settle ++ ++ # close lid ++ evemu-event "$LID_DEV" --sync --type 5 --code 0 --value 1 ++ # need to wait for 30s suspend inhibition after boot ++ wait_suspend 31 ++ # open lid again ++ evemu-event "$LID_DEV" --sync --type 5 --code 0 --value 0 ++ ++ # waiting for 30s inhibition time between suspends ++ sleep 30 ++ ++ # now closing lid should cause instant suspend ++ evemu-event "$LID_DEV" --sync --type 5 --code 0 --value 1 ++ wait_suspend 2 ++ evemu-event "$LID_DEV" --sync --type 5 --code 0 --value 0 ++ ++ P=$(systemctl show systemd-logind.service -p ExecMainPID --value) ++ if [[ "$P" != "$LOGINDPID" ]]; then ++ echo "logind crashed" >&2 ++ exit 1 ++ fi ++ ++ test_suspend_tear_down ++ trap - EXIT ++} ++ ++test_shutdown() { ++ # scheduled shutdown with wall message ++ shutdown 2>&1 ++ sleep 5 ++ shutdown -c || : ++ # logind should still be running ++ P=$(systemctl show systemd-logind.service -p ExecMainPID --value) ++ if [[ "$P" != "$LOGINDPID" ]]; then ++ echo "logind crashed" >&2 ++ exit 1 ++ fi ++ ++ # scheduled shutdown without wall message ++ shutdown --no-wall 2>&1 ++ sleep 5 ++ shutdown -c --no-wall || true ++ P=$(systemctl show systemd-logind.service -p ExecMainPID --value) ++ if [[ "$P" != "$LOGINDPID" ]]; then ++ echo "logind crashed" >&2 ++ exit 1 ++ fi ++} ++ ++test_session_tear_down() { ++ set +e ++ ++ rm -f /run/udev/rules.d/70-logindtest-scsi_debug-user.rules ++ udevadm control --reload ++ ++ systemctl stop getty@tty2.service ++ rm -rf /run/systemd/system/getty@tty2.service.d ++ systemctl daemon-reload ++ ++ pkill -u logind-test-user ++ userdel logind-test-user ++ ++ rmmod scsi_debug ++} ++ ++check_session() { ++ loginctl ++ if [[ $(loginctl --no-legend | grep -c "logind-test-user") != 1 ]]; then ++ echo "no session or multile sessions for logind-test-user." >&2 ++ return 1 ++ fi ++ ++ SEAT=$(loginctl --no-legend | grep 'logind-test-user *seat' | awk '{ print $4 }') ++ if [[ -z "$SEAT" ]]; then ++ echo "no seat found for user logind-test-user" >&2 ++ return 1 ++ fi ++ ++ SESSION=$(loginctl --no-legend | grep "logind-test-user" | awk '{ print $1 }') ++ if [[ -z "$SESSION" ]]; then ++ echo "no session found for user logind-test-user" >&2 ++ return 1 ++ fi ++ ++ loginctl session-status "$SESSION" ++ loginctl session-status "$SESSION" | grep -q "Unit: session-${SESSION}\.scope" ++ LEADER_PID=$(loginctl session-status "$SESSION" | grep "Leader:" | awk '{ print $2 }') ++ if [[ -z "$LEADER_PID" ]]; then ++ echo "cannot found leader process for session $SESSION" >&2 ++ return 1 ++ fi ++ ++ # cgroup v1: "1:name=systemd:/user.slice/..."; unified hierarchy: "0::/user.slice" ++ if ! grep -q -E '(name=systemd|^0:):.*session.*scope' /proc/"$LEADER_PID"/cgroup; then ++ echo "FAIL: process $LEADER_PID is not in the session cgroup" >&2 ++ cat /proc/self/cgroup ++ return 1 ++ fi ++} ++ ++test_session() { ++ if systemd-detect-virt --quiet --container; then ++ echo " * Skipping ACL tests in container" ++ return ++ fi ++ ++ trap test_session_tear_down EXIT ++ ++ # add user ++ useradd -s /bin/bash logind-test-user ++ ++ # login with the test user to start a session ++ mkdir -p /run/systemd/system/getty@tty2.service.d ++ cat >/run/systemd/system/getty@tty2.service.d/override.conf <&2 ++ exit 1 ++ fi ++ ++ # we use scsi_debug to create new devices which we can put ACLs on ++ # tell udev about the tagging, so that logind can pick it up ++ mkdir -p /run/udev/rules.d ++ cat >/run/udev/rules.d/70-logindtest-scsi_debug-user.rules </dev/null); then ++ break ++ fi ++ done ++ if [[ ! -b "$dev" ]]; then ++ echo "cannot find suitable scsi block device" >&2 ++ exit 1 ++ fi ++ udevadm settle ++ udevadm info "$dev" ++ ++ # trigger logind and activate session ++ loginctl activate "$SESSION" ++ ++ # check ACL ++ sleep 1 ++ if ! getfacl -p "$dev" | grep -q "user:logind-test-user:rw-"; then ++ echo "$dev has no ACL for user logind-test-user" >&2 ++ getfacl -p "$dev" >&2 ++ exit 1 ++ fi ++ ++ # hotplug: new device appears while logind is running ++ rmmod scsi_debug ++ modprobe scsi_debug ++ for ((i=0;i<30;i++)); do ++ if (( i != 0)); then sleep 1; fi ++ if dev=/dev/$(ls /sys/bus/pseudo/drivers/scsi_debug/adapter*/host*/target*/*:*/block 2>/dev/null); then ++ break ++ fi ++ done ++ if [[ ! -b "$dev" ]]; then ++ echo "cannot find suitable scsi block device" >&2 ++ exit 1 ++ fi ++ udevadm settle ++ ++ # check ACL ++ sleep 1 ++ if ! getfacl -p "$dev" | grep -q "user:logind-test-user:rw-"; then ++ echo "$dev has no ACL for user logind-test-user" >&2 ++ getfacl -p "$dev" >&2 ++ exit 1 ++ fi ++ ++ test_session_tear_down ++ trap - EXIT ++} ++ ++: >/failed ++ ++test_enable_debug ++test_properties ++test_started ++test_suspend_on_lid ++test_shutdown ++test_session ++ ++touch /testok ++rm /failed diff --git a/0209-test-drop-redundant-IMAGE_NAME.patch b/0209-test-drop-redundant-IMAGE_NAME.patch new file mode 100644 index 0000000..0e46999 --- /dev/null +++ b/0209-test-drop-redundant-IMAGE_NAME.patch @@ -0,0 +1,52 @@ +From 41f1f6e87bd9bed458e5391587f1e1b671d383bd Mon Sep 17 00:00:00 2001 +From: Yu Watanabe +Date: Fri, 10 Jun 2022 12:31:10 +0900 +Subject: [PATCH] test: drop redundant IMAGE_NAME= + +If it is not specified, then "default" will be used. + +(cherry picked from commit 3d52219390fa2d87938d99ec3bf71e10e101ded6) + +Related: #2087652 +--- + test/TEST-03-JOBS/test.sh | 1 - + test/TEST-17-UDEV/test.sh | 1 - + test/TEST-64-UDEV-STORAGE/test.sh | 1 - + 3 files changed, 3 deletions(-) + +diff --git a/test/TEST-03-JOBS/test.sh b/test/TEST-03-JOBS/test.sh +index f827f90865..6a8d3a8a11 100755 +--- a/test/TEST-03-JOBS/test.sh ++++ b/test/TEST-03-JOBS/test.sh +@@ -4,7 +4,6 @@ set -e + + TEST_DESCRIPTION="Job-related tests" + TEST_NO_QEMU=1 +-IMAGE_NAME="default" + + # shellcheck source=test/test-functions + . "${TEST_BASE_DIR:?}/test-functions" +diff --git a/test/TEST-17-UDEV/test.sh b/test/TEST-17-UDEV/test.sh +index 079ecfd629..9d91eee204 100755 +--- a/test/TEST-17-UDEV/test.sh ++++ b/test/TEST-17-UDEV/test.sh +@@ -3,7 +3,6 @@ + set -e + + TEST_DESCRIPTION="UDEV" +-IMAGE_NAME="default" + TEST_NO_NSPAWN=1 + + # shellcheck source=test/test-functions +diff --git a/test/TEST-64-UDEV-STORAGE/test.sh b/test/TEST-64-UDEV-STORAGE/test.sh +index c360c8b661..2a5b5b2dd3 100755 +--- a/test/TEST-64-UDEV-STORAGE/test.sh ++++ b/test/TEST-64-UDEV-STORAGE/test.sh +@@ -9,7 +9,6 @@ + set -e + + TEST_DESCRIPTION="systemd-udev storage tests" +-IMAGE_NAME="default" + TEST_NO_NSPAWN=1 + # Save only journals of failing test cases by default (to conserve space) + TEST_SAVE_JOURNAL="${TEST_SAVE_JOURNAL:-fail}" diff --git a/0210-test-import-timedated-test-from-debian-ubuntu-test-s.patch b/0210-test-import-timedated-test-from-debian-ubuntu-test-s.patch new file mode 100644 index 0000000..5e6fad5 --- /dev/null +++ b/0210-test-import-timedated-test-from-debian-ubuntu-test-s.patch @@ -0,0 +1,363 @@ +From 014a660c937c1c5ebfc05667466a16b44e446c60 Mon Sep 17 00:00:00 2001 +From: Yu Watanabe +Date: Fri, 10 Jun 2022 13:55:54 +0900 +Subject: [PATCH] test: import timedated test from debian/ubuntu test suite + +(cherry picked from commit 759ed0a2533da8840dea315d07f92e6bb0272cdd) + +Related: #2087652 +--- + test/TEST-45-TIMEDATE/Makefile | 1 + + test/TEST-45-TIMEDATE/test.sh | 10 ++ + test/units/assert.sh | 44 ++++++ + test/units/testsuite-45.service | 10 ++ + test/units/testsuite-45.sh | 246 ++++++++++++++++++++++++++++++++ + 5 files changed, 311 insertions(+) + create mode 120000 test/TEST-45-TIMEDATE/Makefile + create mode 100755 test/TEST-45-TIMEDATE/test.sh + create mode 100644 test/units/assert.sh + create mode 100644 test/units/testsuite-45.service + create mode 100755 test/units/testsuite-45.sh + +diff --git a/test/TEST-45-TIMEDATE/Makefile b/test/TEST-45-TIMEDATE/Makefile +new file mode 120000 +index 0000000000..e9f93b1104 +--- /dev/null ++++ b/test/TEST-45-TIMEDATE/Makefile +@@ -0,0 +1 @@ ++../TEST-01-BASIC/Makefile +\ No newline at end of file +diff --git a/test/TEST-45-TIMEDATE/test.sh b/test/TEST-45-TIMEDATE/test.sh +new file mode 100755 +index 0000000000..27edf4a3b9 +--- /dev/null ++++ b/test/TEST-45-TIMEDATE/test.sh +@@ -0,0 +1,10 @@ ++#!/usr/bin/env bash ++# SPDX-License-Identifier: LGPL-2.1-or-later ++set -e ++ ++TEST_DESCRIPTION="test timedated" ++ ++# shellcheck source=test/test-functions ++. "${TEST_BASE_DIR:?}/test-functions" ++ ++do_test "$@" +diff --git a/test/units/assert.sh b/test/units/assert.sh +new file mode 100644 +index 0000000000..db67dad268 +--- /dev/null ++++ b/test/units/assert.sh +@@ -0,0 +1,44 @@ ++#!/usr/bin/env bash ++# SPDX-License-Identifier: LGPL-2.1-or-later ++ ++# utility functions for shell tests ++ ++assert_true() { ++ local rc ++ ++ set +e ++ "$@" ++ rc=$? ++ set -e ++ if [[ "$rc" != "0" ]]; then ++ echo "FAIL: command '$*' failed with exit code $rc" >&2 ++ exit 1 ++ fi ++} ++ ++ ++assert_eq() { ++ if [[ "$1" != "$2" ]]; then ++ echo "FAIL: expected: '$2' actual: '$1'" >&2 ++ exit 1 ++ fi ++} ++ ++assert_in() { ++ if ! echo "$2" | grep -q "$1"; then ++ echo "FAIL: '$1' not found in:" >&2 ++ echo "$2" >&2 ++ exit 1 ++ fi ++} ++ ++assert_rc() { ++ local exp=$1 ++ local rc ++ shift ++ set +e ++ "$@" ++ rc=$? ++ set -e ++ assert_eq "$rc" "$exp" ++} +diff --git a/test/units/testsuite-45.service b/test/units/testsuite-45.service +new file mode 100644 +index 0000000000..79c0a6f117 +--- /dev/null ++++ b/test/units/testsuite-45.service +@@ -0,0 +1,10 @@ ++# SPDX-License-Identifier: LGPL-2.1-or-later ++[Unit] ++Description=TEST-45-TIMEDATE ++ ++[Service] ++ExecStartPre=rm -f /failed /testok ++ExecStart=/usr/lib/systemd/tests/testdata/units/%N.sh ++StandardOutput=journal+console ++StandardError=journal+console ++Type=oneshot +diff --git a/test/units/testsuite-45.sh b/test/units/testsuite-45.sh +new file mode 100755 +index 0000000000..ac7860dccd +--- /dev/null ++++ b/test/units/testsuite-45.sh +@@ -0,0 +1,246 @@ ++#!/usr/bin/env bash ++# SPDX-License-Identifier: LGPL-2.1-or-later ++ ++set -eux ++set -o pipefail ++ ++# shellcheck source=test/units/assert.sh ++. "$(dirname "$0")"/assert.sh ++ ++test_timezone() { ++ local ORIG_TZ= ++ ++ if [[ -L /etc/localtime ]]; then ++ ORIG_TZ=$(readlink /etc/localtime | sed 's#^.*zoneinfo/##') ++ echo "original tz: $ORIG_TZ" ++ fi ++ ++ echo 'timedatectl works' ++ assert_in "Local time:" "$(timedatectl --no-pager)" ++ ++ echo 'change timezone' ++ assert_eq "$(timedatectl --no-pager set-timezone Europe/Kiev 2>&1)" "" ++ assert_eq "$(readlink /etc/localtime | sed 's#^.*zoneinfo/##')" "Europe/Kiev" ++ assert_in "Time.*zone: Europe/Kiev (EEST, +" "$(timedatectl --no-pager)" ++ ++ if [[ -n "$ORIG_TZ" ]]; then ++ echo 'reset timezone to original' ++ assert_eq "$(timedatectl --no-pager set-timezone "$ORIG_TZ" 2>&1)" "" ++ assert_eq "$(readlink /etc/localtime | sed 's#^.*zoneinfo/##')" "$ORIG_TZ" ++ fi ++} ++ ++restore_adjtime() { ++ if [[ -e /etc/adjtime.bak ]]; then ++ mv /etc/adjtime.bak /etc/adjtime ++ else ++ rm /etc/adjtime ++ fi ++} ++ ++check_adjtime_not_exist() { ++ if [[ -e /etc/adjtime ]]; then ++ echo "/etc/adjtime unexpectedly exists." >&2 ++ exit 1 ++ fi ++} ++ ++test_adjtime() { ++ # test setting UTC vs. LOCAL in /etc/adjtime ++ if [[ -e /etc/adjtime ]]; then ++ mv /etc/adjtime /etc/adjtime.bak ++ fi ++ ++ trap restore_adjtime EXIT ++ ++ echo 'no adjtime file' ++ rm -f /etc/adjtime ++ timedatectl set-local-rtc 0 ++ check_adjtime_not_exist ++ timedatectl set-local-rtc 1 ++ assert_eq "$(cat /etc/adjtime)" "0.0 0 0 ++0 ++LOCAL" ++ timedatectl set-local-rtc 0 ++ check_adjtime_not_exist ++ ++ echo 'UTC set in adjtime file' ++ printf '0.0 0 0\n0\nUTC\n' > /etc/adjtime ++ timedatectl set-local-rtc 0 ++ assert_eq "$(cat /etc/adjtime)" "0.0 0 0 ++0 ++UTC" ++ timedatectl set-local-rtc 1 ++ assert_eq "$(cat /etc/adjtime)" "0.0 0 0 ++0 ++LOCAL" ++ ++ echo 'non-zero values in adjtime file' ++ printf '0.1 123 0\n0\nLOCAL\n' > /etc/adjtime ++ timedatectl set-local-rtc 0 ++ assert_eq "$(cat /etc/adjtime)" "0.1 123 0 ++0 ++UTC" ++ timedatectl set-local-rtc 1 ++ assert_eq "$(cat /etc/adjtime)" "0.1 123 0 ++0 ++LOCAL" ++ ++ echo 'fourth line adjtime file' ++ printf '0.0 0 0\n0\nLOCAL\nsomethingelse\n' > /etc/adjtime ++ timedatectl set-local-rtc 0 ++ assert_eq "$(cat /etc/adjtime)" "0.0 0 0 ++0 ++UTC ++somethingelse" ++ timedatectl set-local-rtc 1 ++ assert_eq "$(cat /etc/adjtime)" "0.0 0 0 ++0 ++LOCAL ++somethingelse" ++ ++ echo 'no final newline in adjtime file' ++ printf '0.0 0 0\n0\nUTC' > /etc/adjtime ++ timedatectl set-local-rtc 0 ++ check_adjtime_not_exist ++ printf '0.0 0 0\n0\nUTC' > /etc/adjtime ++ timedatectl set-local-rtc 1 ++ assert_eq "$(cat /etc/adjtime)" "0.0 0 0 ++0 ++LOCAL" ++ ++ echo 'only one line in adjtime file' ++ printf '0.0 0 0\n' > /etc/adjtime ++ timedatectl set-local-rtc 0 ++ check_adjtime_not_exist ++ printf '0.0 0 0\n' > /etc/adjtime ++ timedatectl set-local-rtc 1 ++ assert_eq "$(cat /etc/adjtime)" "0.0 0 0 ++0 ++LOCAL" ++ ++ echo 'only one line in adjtime file, no final newline' ++ printf '0.0 0 0' > /etc/adjtime ++ timedatectl set-local-rtc 0 ++ check_adjtime_not_exist ++ printf '0.0 0 0' > /etc/adjtime ++ timedatectl set-local-rtc 1 ++ assert_eq "$(cat /etc/adjtime)" "0.0 0 0 ++0 ++LOCAL" ++ ++ echo 'only two lines in adjtime file' ++ printf '0.0 0 0\n0\n' > /etc/adjtime ++ timedatectl set-local-rtc 0 ++ check_adjtime_not_exist ++ printf '0.0 0 0\n0\n' > /etc/adjtime ++ timedatectl set-local-rtc 1 ++ assert_eq "$(cat /etc/adjtime)" "0.0 0 0 ++0 ++LOCAL" ++ ++ echo 'only two lines in adjtime file, no final newline' ++ printf '0.0 0 0\n0' > /etc/adjtime ++ timedatectl set-local-rtc 0 ++ check_adjtime_not_exist ++ printf '0.0 0 0\n0' > /etc/adjtime ++ timedatectl set-local-rtc 1 ++ assert_eq "$(cat /etc/adjtime)" "0.0 0 0 ++0 ++LOCAL" ++ ++ echo 'unknown value in 3rd line of adjtime file' ++ printf '0.0 0 0\n0\nFOO\n' > /etc/adjtime ++ timedatectl set-local-rtc 0 ++ check_adjtime_not_exist ++ printf '0.0 0 0\n0\nFOO\n' > /etc/adjtime ++ timedatectl set-local-rtc 1 ++ assert_eq "$(cat /etc/adjtime)" "0.0 0 0 ++0 ++LOCAL" ++ ++ restore_adjtime ++ trap - EXIT ++} ++ ++assert_ntp() { ++ assert_eq "$(busctl get-property org.freedesktop.timedate1 /org/freedesktop/timedate1 org.freedesktop.timedate1 NTP)" "b $1" ++} ++ ++start_mon() { ++ busctl monitor --match="type='signal',sender=org.freedesktop.timedate1,member='PropertiesChanged',path=/org/freedesktop/timedate1" >"$mon" & ++ MONPID=$! ++} ++ ++wait_mon() { ++ for ((i=0;i<10;i++)); do ++ if (( i != 0 )); then sleep 1; fi ++ if grep -q "$1" "$mon"; then break; fi ++ done ++ assert_in "$2" "$(cat "$mon")" ++ kill "$MONPID" ++ wait "$MONPID" 2>/dev/null || true ++} ++ ++test_ntp() { ++ # timesyncd has ConditionVirtualization=!container by default; drop/mock that for testing ++ if systemd-detect-virt --container --quiet; then ++ systemctl disable --quiet --now systemd-timesyncd ++ mkdir -p /run/systemd/system/systemd-timesyncd.service.d ++ cat >/run/systemd/system/systemd-timesyncd.service.d/container.conf </failed ++ ++test_timezone ++test_adjtime ++test_ntp ++ ++touch /testok ++rm /failed diff --git a/0211-test-introduce-assert_not_in-helper-function.patch b/0211-test-introduce-assert_not_in-helper-function.patch new file mode 100644 index 0000000..e712fb8 --- /dev/null +++ b/0211-test-introduce-assert_not_in-helper-function.patch @@ -0,0 +1,107 @@ +From e7b657694adbd03403f2ebbe089a6d5baa58d7d5 Mon Sep 17 00:00:00 2001 +From: Yu Watanabe +Date: Tue, 14 Jun 2022 09:00:00 +0900 +Subject: [PATCH] test: introduce assert_not_in() helper function + +This also silence assertions, and replace grep with bash's regular +expression match. + +(cherry picked from commit d170b47535e2acc8abd1af85ff8685107fdd490f) + +Related: #2087652 +--- + test/units/assert.sh | 48 ++++++++++++++++++++++++-------------- + test/units/testsuite-45.sh | 2 +- + 2 files changed, 32 insertions(+), 18 deletions(-) + +diff --git a/test/units/assert.sh b/test/units/assert.sh +index db67dad268..66357ab688 100644 +--- a/test/units/assert.sh ++++ b/test/units/assert.sh +@@ -3,42 +3,56 @@ + + # utility functions for shell tests + +-assert_true() { ++assert_true() {( + local rc + +- set +e ++ set +ex ++ + "$@" + rc=$? +- set -e +- if [[ "$rc" != "0" ]]; then ++ if [[ $rc -ne 0 ]]; then + echo "FAIL: command '$*' failed with exit code $rc" >&2 + exit 1 + fi +-} ++)} ++ + ++assert_eq() {( ++ set +ex + +-assert_eq() { +- if [[ "$1" != "$2" ]]; then ++ if [[ "${1?}" != "${2?}" ]]; then + echo "FAIL: expected: '$2' actual: '$1'" >&2 + exit 1 + fi +-} ++)} ++ ++assert_in() {( ++ set +ex + +-assert_in() { +- if ! echo "$2" | grep -q "$1"; then ++ if ! [[ "${2?}" =~ ${1?} ]]; then + echo "FAIL: '$1' not found in:" >&2 + echo "$2" >&2 + exit 1 + fi +-} ++)} ++ ++assert_not_in() {( ++ set +ex ++ ++ if [[ "${2?}" =~ ${1?} ]]; then ++ echo "FAIL: '$1' found in:" >&2 ++ echo "$2" >&2 ++ exit 1 ++ fi ++)} ++ ++assert_rc() {( ++ local rc exp="${1?}" ++ ++ set +ex + +-assert_rc() { +- local exp=$1 +- local rc + shift +- set +e + "$@" + rc=$? +- set -e + assert_eq "$rc" "$exp" +-} ++)} +diff --git a/test/units/testsuite-45.sh b/test/units/testsuite-45.sh +index ac7860dccd..d0d1ef2eb4 100755 +--- a/test/units/testsuite-45.sh ++++ b/test/units/testsuite-45.sh +@@ -21,7 +21,7 @@ test_timezone() { + echo 'change timezone' + assert_eq "$(timedatectl --no-pager set-timezone Europe/Kiev 2>&1)" "" + assert_eq "$(readlink /etc/localtime | sed 's#^.*zoneinfo/##')" "Europe/Kiev" +- assert_in "Time.*zone: Europe/Kiev (EEST, +" "$(timedatectl --no-pager)" ++ assert_in "Time zone: Europe/Kiev \(EEST, \+0[0-9]00\)" "$(timedatectl)" + + if [[ -n "$ORIG_TZ" ]]; then + echo 'reset timezone to original' diff --git a/0212-test-drop-unnecessary-no-pager-option.patch b/0212-test-drop-unnecessary-no-pager-option.patch new file mode 100644 index 0000000..fc75c97 --- /dev/null +++ b/0212-test-drop-unnecessary-no-pager-option.patch @@ -0,0 +1,53 @@ +From 740dd8e0a0c503980894968006a43fa05039e299 Mon Sep 17 00:00:00 2001 +From: Yu Watanabe +Date: Tue, 14 Jun 2022 09:01:00 +0900 +Subject: [PATCH] test: drop unnecessary --no-pager option + +(cherry picked from commit 8ed2103306fa6b3dcaf8d810e65e8957553ef752) + +Related: #2087652 +--- + test/units/testsuite-45.sh | 10 +++++----- + 1 file changed, 5 insertions(+), 5 deletions(-) + +diff --git a/test/units/testsuite-45.sh b/test/units/testsuite-45.sh +index d0d1ef2eb4..2069d2437f 100755 +--- a/test/units/testsuite-45.sh ++++ b/test/units/testsuite-45.sh +@@ -25,7 +25,7 @@ test_timezone() { + + if [[ -n "$ORIG_TZ" ]]; then + echo 'reset timezone to original' +- assert_eq "$(timedatectl --no-pager set-timezone "$ORIG_TZ" 2>&1)" "" ++ assert_eq "$(timedatectl set-timezone "$ORIG_TZ" 2>&1)" "" + assert_eq "$(readlink /etc/localtime | sed 's#^.*zoneinfo/##')" "$ORIG_TZ" + fi + } +@@ -206,11 +206,11 @@ EOF + timedatectl set-ntp false + for ((i=0;i<10;i++)); do + if (( i != 0 )); then sleep 1; fi +- if [[ "$(systemctl --no-pager show systemd-timesyncd --property ActiveState)" == "ActiveState=inactive" ]]; then ++ if [[ "$(systemctl show systemd-timesyncd --property ActiveState)" == "ActiveState=inactive" ]]; then + break; + fi + done +- assert_eq "$(systemctl --no-pager show systemd-timesyncd --property ActiveState)" "ActiveState=inactive" ++ assert_eq "$(systemctl show systemd-timesyncd --property ActiveState)" "ActiveState=inactive" + assert_ntp "false" + assert_rc 3 systemctl is-active --quiet systemd-timesyncd + +@@ -221,11 +221,11 @@ EOF + assert_ntp "true" + for ((i=0;i<10;i++)); do + if (( i != 0 )); then sleep 1; fi +- if [[ "$(systemctl --no-pager show systemd-timesyncd --property ActiveState)" == "ActiveState=active" ]]; then ++ if [[ "$(systemctl show systemd-timesyncd --property ActiveState)" == "ActiveState=active" ]]; then + break; + fi + done +- assert_eq "$(systemctl --no-pager show systemd-timesyncd --property ActiveState)" "ActiveState=active" ++ assert_eq "$(systemctl show systemd-timesyncd --property ActiveState)" "ActiveState=active" + assert_rc 0 systemctl is-active --quiet systemd-timesyncd + + echo 're-disable NTP' diff --git a/0213-test-support-debian-ubuntu-specific-timezone-config-.patch b/0213-test-support-debian-ubuntu-specific-timezone-config-.patch new file mode 100644 index 0000000..a82f54a --- /dev/null +++ b/0213-test-support-debian-ubuntu-specific-timezone-config-.patch @@ -0,0 +1,64 @@ +From ce027f67d29066f188891c94447e50c12168a693 Mon Sep 17 00:00:00 2001 +From: Yu Watanabe +Date: Tue, 14 Jun 2022 09:02:00 +0900 +Subject: [PATCH] test: support debian/ubuntu specific timezone config file + +(cherry picked from commit aab61a8c990a54703ae70ca951d0502860010267) + +Related: #2087652 +--- + test/units/testsuite-45.sh | 24 ++++++++++++++++++++++++ + 1 file changed, 24 insertions(+) + +diff --git a/test/units/testsuite-45.sh b/test/units/testsuite-45.sh +index 2069d2437f..d0f9dd9461 100755 +--- a/test/units/testsuite-45.sh ++++ b/test/units/testsuite-45.sh +@@ -7,9 +7,24 @@ set -o pipefail + # shellcheck source=test/units/assert.sh + . "$(dirname "$0")"/assert.sh + ++restore_timezone() { ++ if [[ -f /tmp/timezone.bak ]]; then ++ mv /tmp/timezone.bak /etc/timezone ++ else ++ rm -f /etc/timezone ++ fi ++} ++ + test_timezone() { + local ORIG_TZ= + ++ # Debian/Ubuntu specific file ++ if [[ -f /etc/timezone ]]; then ++ mv /etc/timezone /tmp/timezone.bak ++ fi ++ ++ trap restore_timezone EXIT ++ + if [[ -L /etc/localtime ]]; then + ORIG_TZ=$(readlink /etc/localtime | sed 's#^.*zoneinfo/##') + echo "original tz: $ORIG_TZ" +@@ -21,13 +36,22 @@ test_timezone() { + echo 'change timezone' + assert_eq "$(timedatectl --no-pager set-timezone Europe/Kiev 2>&1)" "" + assert_eq "$(readlink /etc/localtime | sed 's#^.*zoneinfo/##')" "Europe/Kiev" ++ if [[ -f /etc/timezone ]]; then ++ assert_eq "$(cat /etc/timezone)" "Europe/Kiev" ++ fi + assert_in "Time zone: Europe/Kiev \(EEST, \+0[0-9]00\)" "$(timedatectl)" + + if [[ -n "$ORIG_TZ" ]]; then + echo 'reset timezone to original' + assert_eq "$(timedatectl set-timezone "$ORIG_TZ" 2>&1)" "" + assert_eq "$(readlink /etc/localtime | sed 's#^.*zoneinfo/##')" "$ORIG_TZ" ++ if [[ -f /etc/timezone ]]; then ++ assert_eq "$(cat /etc/timezone)" "$ORIG_TZ" ++ fi + fi ++ ++ restore_timezone ++ trap - EXIT + } + + restore_adjtime() { diff --git a/0214-test-import-hostnamed-tests-from-debian-ubuntu-test-.patch b/0214-test-import-hostnamed-tests-from-debian-ubuntu-test-.patch new file mode 100644 index 0000000..86206a1 --- /dev/null +++ b/0214-test-import-hostnamed-tests-from-debian-ubuntu-test-.patch @@ -0,0 +1,117 @@ +From b9724ced388bef0a53be49c4ce45db2c8352f186 Mon Sep 17 00:00:00 2001 +From: Yu Watanabe +Date: Tue, 14 Jun 2022 09:03:00 +0900 +Subject: [PATCH] test: import hostnamed tests from debian/ubuntu test suite + +(cherry picked from commit 39f4546199d6394014cf79b76b9ff22d3c149c54) + +Related: #2087652 +--- + test/TEST-71-HOSTNAME/Makefile | 1 + + test/TEST-71-HOSTNAME/test.sh | 10 +++++++ + test/units/testsuite-71.service | 10 +++++++ + test/units/testsuite-71.sh | 52 +++++++++++++++++++++++++++++++++ + 4 files changed, 73 insertions(+) + create mode 120000 test/TEST-71-HOSTNAME/Makefile + create mode 100755 test/TEST-71-HOSTNAME/test.sh + create mode 100644 test/units/testsuite-71.service + create mode 100755 test/units/testsuite-71.sh + +diff --git a/test/TEST-71-HOSTNAME/Makefile b/test/TEST-71-HOSTNAME/Makefile +new file mode 120000 +index 0000000000..e9f93b1104 +--- /dev/null ++++ b/test/TEST-71-HOSTNAME/Makefile +@@ -0,0 +1 @@ ++../TEST-01-BASIC/Makefile +\ No newline at end of file +diff --git a/test/TEST-71-HOSTNAME/test.sh b/test/TEST-71-HOSTNAME/test.sh +new file mode 100755 +index 0000000000..7b3d2d12d4 +--- /dev/null ++++ b/test/TEST-71-HOSTNAME/test.sh +@@ -0,0 +1,10 @@ ++#!/usr/bin/env bash ++# SPDX-License-Identifier: LGPL-2.1-or-later ++set -e ++ ++TEST_DESCRIPTION="test hostnamed" ++ ++# shellcheck source=test/test-functions ++. "${TEST_BASE_DIR:?}/test-functions" ++ ++do_test "$@" +diff --git a/test/units/testsuite-71.service b/test/units/testsuite-71.service +new file mode 100644 +index 0000000000..019e8bff24 +--- /dev/null ++++ b/test/units/testsuite-71.service +@@ -0,0 +1,10 @@ ++# SPDX-License-Identifier: LGPL-2.1-or-later ++[Unit] ++Description=TEST-71-HOSTNAME ++ ++[Service] ++ExecStartPre=rm -f /failed /testok ++ExecStart=/usr/lib/systemd/tests/testdata/units/%N.sh ++StandardOutput=journal+console ++StandardError=journal+console ++Type=oneshot +diff --git a/test/units/testsuite-71.sh b/test/units/testsuite-71.sh +new file mode 100755 +index 0000000000..34fcaad961 +--- /dev/null ++++ b/test/units/testsuite-71.sh +@@ -0,0 +1,52 @@ ++#!/usr/bin/env bash ++# SPDX-License-Identifier: LGPL-2.1-or-later ++ ++set -eux ++set -o pipefail ++ ++# shellcheck source=test/units/assert.sh ++. "$(dirname "$0")"/assert.sh ++ ++restore_hostname() { ++ if [[ -e /tmp/hostname.bak ]]; then ++ mv /tmp/hostname.bak /etc/hostname ++ else ++ rm -f /etc/hostname ++ fi ++} ++ ++test_hostname() { ++ local orig= ++ ++ if [[ -f /etc/hostname ]]; then ++ cp /etc/hostname /tmp/hostname.bak ++ orig=$(cat /etc/hostname) ++ fi ++ ++ trap restore_hostname RETURN ++ ++ # should activate daemon and work ++ if [[ -n "$orig" ]]; then ++ assert_in "Static hostname: $orig" "$(hostnamectl)" ++ fi ++ assert_in "Kernel: $(uname -s) $(uname -r)" "$(hostnamectl)" ++ ++ # change hostname ++ assert_rc 0 hostnamectl set-hostname testhost ++ assert_eq "$(cat /etc/hostname)" "testhost" ++ assert_in "Static hostname: testhost" "$(hostnamectl)" ++ ++ if [[ -n "$orig" ]]; then ++ # reset to original ++ assert_rc 0 hostnamectl set-hostname "$orig" ++ assert_eq "$(cat /etc/hostname)" "$orig" ++ assert_in "Static hostname: $orig" "$(hostnamectl)" ++ fi ++} ++ ++: >/failed ++ ++test_hostname ++ ++touch /testok ++rm /failed diff --git a/0215-locale-util-fix-memleak-on-failure.patch b/0215-locale-util-fix-memleak-on-failure.patch new file mode 100644 index 0000000..13a03f5 --- /dev/null +++ b/0215-locale-util-fix-memleak-on-failure.patch @@ -0,0 +1,44 @@ +From 97c96647418ffbadf3d964d76a5f54a9c54535c1 Mon Sep 17 00:00:00 2001 +From: Yu Watanabe +Date: Tue, 14 Jun 2022 09:04:00 +0900 +Subject: [PATCH] locale-util: fix memleak on failure + +(cherry picked from commit 065058e63b566e21af737150ecd12bff57b97124) + +Related: #2087652 +--- + src/basic/locale-util.c | 7 +++++-- + 1 file changed, 5 insertions(+), 2 deletions(-) + +diff --git a/src/basic/locale-util.c b/src/basic/locale-util.c +index 7f1a2f15f7..abbebc7666 100644 +--- a/src/basic/locale-util.c ++++ b/src/basic/locale-util.c +@@ -156,7 +156,7 @@ static int add_locales_from_archive(Set *locales) { + return r; + } + +-static int add_locales_from_libdir (Set *locales) { ++static int add_locales_from_libdir(Set *locales) { + _cleanup_closedir_ DIR *dir = NULL; + int r; + +@@ -183,7 +183,7 @@ static int add_locales_from_libdir (Set *locales) { + } + + int get_locales(char ***ret) { +- _cleanup_set_free_ Set *locales = NULL; ++ _cleanup_set_free_free_ Set *locales = NULL; + _cleanup_strv_free_ char **l = NULL; + int r; + +@@ -203,6 +203,9 @@ int get_locales(char ***ret) { + if (!l) + return -ENOMEM; + ++ /* Now, all elements are owned by strv 'l'. Hence, do not call set_free_free(). */ ++ locales = set_free(locales); ++ + r = getenv_bool("SYSTEMD_LIST_NON_UTF8_LOCALES"); + if (r == -ENXIO || r == 0) { + char **a, **b; diff --git a/0216-locale-util-check-if-enumerated-locales-are-valid.patch b/0216-locale-util-check-if-enumerated-locales-are-valid.patch new file mode 100644 index 0000000..039d97c --- /dev/null +++ b/0216-locale-util-check-if-enumerated-locales-are-valid.patch @@ -0,0 +1,32 @@ +From c10efc8164dcdf8596315ce98f60405f8c2e17c0 Mon Sep 17 00:00:00 2001 +From: Yu Watanabe +Date: Tue, 14 Jun 2022 09:05:00 +0900 +Subject: [PATCH] locale-util: check if enumerated locales are valid + +(cherry picked from commit a2f7937747f12634d93049f645cdae88f89ff233) + +Related: #2087652 +--- + src/basic/locale-util.c | 9 +++++++++ + 1 file changed, 9 insertions(+) + +diff --git a/src/basic/locale-util.c b/src/basic/locale-util.c +index abbebc7666..bd36cdd1cd 100644 +--- a/src/basic/locale-util.c ++++ b/src/basic/locale-util.c +@@ -199,6 +199,15 @@ int get_locales(char ***ret) { + if (r < 0) + return r; + ++ char *locale; ++ SET_FOREACH(locale, locales) { ++ r = locale_is_installed(locale); ++ if (r < 0) ++ return r; ++ if (r == 0) ++ free(set_remove(locales, locale)); ++ } ++ + l = set_get_strv(locales); + if (!l) + return -ENOMEM; diff --git a/0217-locale-util-align-locale-entries.patch b/0217-locale-util-align-locale-entries.patch new file mode 100644 index 0000000..4e167dd --- /dev/null +++ b/0217-locale-util-align-locale-entries.patch @@ -0,0 +1,49 @@ +From 1fb9fa1c16f46ce830324173dd0920eddf13c9d6 Mon Sep 17 00:00:00 2001 +From: Yu Watanabe +Date: Tue, 14 Jun 2022 09:06:00 +0900 +Subject: [PATCH] locale-util: align locale entries + +(cherry picked from commit d2e96a4f87f814f3d5c8be986a4d4f616bfd67f4) + +Related: #2087652 +--- + src/basic/locale-util.c | 26 +++++++++++++------------- + 1 file changed, 13 insertions(+), 13 deletions(-) + +diff --git a/src/basic/locale-util.c b/src/basic/locale-util.c +index bd36cdd1cd..8098369db5 100644 +--- a/src/basic/locale-util.c ++++ b/src/basic/locale-util.c +@@ -336,19 +336,19 @@ void locale_variables_free(char *l[_VARIABLE_LC_MAX]) { + } + + static const char * const locale_variable_table[_VARIABLE_LC_MAX] = { +- [VARIABLE_LANG] = "LANG", +- [VARIABLE_LANGUAGE] = "LANGUAGE", +- [VARIABLE_LC_CTYPE] = "LC_CTYPE", +- [VARIABLE_LC_NUMERIC] = "LC_NUMERIC", +- [VARIABLE_LC_TIME] = "LC_TIME", +- [VARIABLE_LC_COLLATE] = "LC_COLLATE", +- [VARIABLE_LC_MONETARY] = "LC_MONETARY", +- [VARIABLE_LC_MESSAGES] = "LC_MESSAGES", +- [VARIABLE_LC_PAPER] = "LC_PAPER", +- [VARIABLE_LC_NAME] = "LC_NAME", +- [VARIABLE_LC_ADDRESS] = "LC_ADDRESS", +- [VARIABLE_LC_TELEPHONE] = "LC_TELEPHONE", +- [VARIABLE_LC_MEASUREMENT] = "LC_MEASUREMENT", ++ [VARIABLE_LANG] = "LANG", ++ [VARIABLE_LANGUAGE] = "LANGUAGE", ++ [VARIABLE_LC_CTYPE] = "LC_CTYPE", ++ [VARIABLE_LC_NUMERIC] = "LC_NUMERIC", ++ [VARIABLE_LC_TIME] = "LC_TIME", ++ [VARIABLE_LC_COLLATE] = "LC_COLLATE", ++ [VARIABLE_LC_MONETARY] = "LC_MONETARY", ++ [VARIABLE_LC_MESSAGES] = "LC_MESSAGES", ++ [VARIABLE_LC_PAPER] = "LC_PAPER", ++ [VARIABLE_LC_NAME] = "LC_NAME", ++ [VARIABLE_LC_ADDRESS] = "LC_ADDRESS", ++ [VARIABLE_LC_TELEPHONE] = "LC_TELEPHONE", ++ [VARIABLE_LC_MEASUREMENT] = "LC_MEASUREMENT", + [VARIABLE_LC_IDENTIFICATION] = "LC_IDENTIFICATION" + }; + diff --git a/0218-core-inline-an-iterator-variable.patch b/0218-core-inline-an-iterator-variable.patch new file mode 100644 index 0000000..ec4a4cd --- /dev/null +++ b/0218-core-inline-an-iterator-variable.patch @@ -0,0 +1,33 @@ +From bc5efb385f238fc7b9cbf552c61269fd680e2c94 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Thu, 7 Apr 2022 11:22:08 +0200 +Subject: [PATCH] core: inline an iterator variable + +(cherry picked from commit 32adc3a7cab85ce543d6895d644a52c6965a274c) + +Related: #2087652 +--- + src/core/locale-setup.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/src/core/locale-setup.c b/src/core/locale-setup.c +index 59ddb9c487..716febbefa 100644 +--- a/src/core/locale-setup.c ++++ b/src/core/locale-setup.c +@@ -16,7 +16,6 @@ + int locale_setup(char ***environment) { + _cleanup_(locale_variables_freep) char *variables[_VARIABLE_LC_MAX] = {}; + _cleanup_strv_free_ char **add = NULL; +- LocaleVariable i; + int r; + + r = proc_cmdline_get_key_many(PROC_CMDLINE_STRIP_RD_PREFIX, +@@ -58,7 +57,7 @@ int locale_setup(char ***environment) { + log_warning_errno(r, "Failed to read /etc/locale.conf: %m"); + } + +- for (i = 0; i < _VARIABLE_LC_MAX; i++) { ++ for (LocaleVariable i = 0; i < _VARIABLE_LC_MAX; i++) { + char *s; + + if (!variables[i]) diff --git a/0219-locale-setup-merge-locale-handling-in-PID1-and-local.patch b/0219-locale-setup-merge-locale-handling-in-PID1-and-local.patch new file mode 100644 index 0000000..b303053 --- /dev/null +++ b/0219-locale-setup-merge-locale-handling-in-PID1-and-local.patch @@ -0,0 +1,884 @@ +From cdcbd56d4eacba3b3ee4d8b0c38d6509a307a2b7 Mon Sep 17 00:00:00 2001 +From: Yu Watanabe +Date: Tue, 14 Jun 2022 09:07:00 +0900 +Subject: [PATCH] locale-setup: merge locale handling in PID1 and localed + +Related: #2087652 +--- + src/basic/locale-util.c | 11 ++ + src/basic/locale-util.h | 1 + + src/core/locale-setup.c | 95 -------------- + src/core/locale-setup.h | 4 - + src/core/meson.build | 2 - + src/locale/keymap-util.c | 102 +-------------- + src/locale/keymap-util.h | 7 +- + src/locale/localectl.c | 47 +++---- + src/locale/localed.c | 87 +++---------- + src/shared/locale-setup.c | 256 ++++++++++++++++++++++++++++++++++++++ + src/shared/locale-setup.h | 28 +++++ + src/shared/meson.build | 2 + + 12 files changed, 333 insertions(+), 309 deletions(-) + delete mode 100644 src/core/locale-setup.c + delete mode 100644 src/core/locale-setup.h + create mode 100644 src/shared/locale-setup.c + create mode 100644 src/shared/locale-setup.h + +diff --git a/src/basic/locale-util.c b/src/basic/locale-util.c +index 8098369db5..21f0982bb5 100644 +--- a/src/basic/locale-util.c ++++ b/src/basic/locale-util.c +@@ -335,6 +335,17 @@ void locale_variables_free(char *l[_VARIABLE_LC_MAX]) { + l[i] = mfree(l[i]); + } + ++void locale_variables_simplify(char *l[_VARIABLE_LC_MAX]) { ++ assert(l); ++ ++ for (LocaleVariable p = 0; p < _VARIABLE_LC_MAX; p++) { ++ if (p == VARIABLE_LANG) ++ continue; ++ if (isempty(l[p]) || streq_ptr(l[VARIABLE_LANG], l[p])) ++ l[p] = mfree(l[p]); ++ } ++} ++ + static const char * const locale_variable_table[_VARIABLE_LC_MAX] = { + [VARIABLE_LANG] = "LANG", + [VARIABLE_LANGUAGE] = "LANGUAGE", +diff --git a/src/basic/locale-util.h b/src/basic/locale-util.h +index bab927146b..8990cb6a75 100644 +--- a/src/basic/locale-util.h ++++ b/src/basic/locale-util.h +@@ -53,3 +53,4 @@ void locale_variables_free(char* l[_VARIABLE_LC_MAX]); + static inline void locale_variables_freep(char*(*l)[_VARIABLE_LC_MAX]) { + locale_variables_free(*l); + } ++void locale_variables_simplify(char *l[_VARIABLE_LC_MAX]); +diff --git a/src/core/locale-setup.c b/src/core/locale-setup.c +deleted file mode 100644 +index 716febbefa..0000000000 +--- a/src/core/locale-setup.c ++++ /dev/null +@@ -1,95 +0,0 @@ +-/* SPDX-License-Identifier: LGPL-2.1-or-later */ +- +-#include +-#include +- +-#include "env-file.h" +-#include "env-util.h" +-#include "locale-setup.h" +-#include "locale-util.h" +-#include "proc-cmdline.h" +-#include "string-util.h" +-#include "strv.h" +-#include "util.h" +-#include "virt.h" +- +-int locale_setup(char ***environment) { +- _cleanup_(locale_variables_freep) char *variables[_VARIABLE_LC_MAX] = {}; +- _cleanup_strv_free_ char **add = NULL; +- int r; +- +- r = proc_cmdline_get_key_many(PROC_CMDLINE_STRIP_RD_PREFIX, +- "locale.LANG", &variables[VARIABLE_LANG], +- "locale.LANGUAGE", &variables[VARIABLE_LANGUAGE], +- "locale.LC_CTYPE", &variables[VARIABLE_LC_CTYPE], +- "locale.LC_NUMERIC", &variables[VARIABLE_LC_NUMERIC], +- "locale.LC_TIME", &variables[VARIABLE_LC_TIME], +- "locale.LC_COLLATE", &variables[VARIABLE_LC_COLLATE], +- "locale.LC_MONETARY", &variables[VARIABLE_LC_MONETARY], +- "locale.LC_MESSAGES", &variables[VARIABLE_LC_MESSAGES], +- "locale.LC_PAPER", &variables[VARIABLE_LC_PAPER], +- "locale.LC_NAME", &variables[VARIABLE_LC_NAME], +- "locale.LC_ADDRESS", &variables[VARIABLE_LC_ADDRESS], +- "locale.LC_TELEPHONE", &variables[VARIABLE_LC_TELEPHONE], +- "locale.LC_MEASUREMENT", &variables[VARIABLE_LC_MEASUREMENT], +- "locale.LC_IDENTIFICATION", &variables[VARIABLE_LC_IDENTIFICATION]); +- if (r < 0 && r != -ENOENT) +- log_warning_errno(r, "Failed to read /proc/cmdline: %m"); +- +- /* Hmm, nothing set on the kernel cmd line? Then let's try /etc/locale.conf */ +- if (r <= 0) { +- r = parse_env_file(NULL, "/etc/locale.conf", +- "LANG", &variables[VARIABLE_LANG], +- "LANGUAGE", &variables[VARIABLE_LANGUAGE], +- "LC_CTYPE", &variables[VARIABLE_LC_CTYPE], +- "LC_NUMERIC", &variables[VARIABLE_LC_NUMERIC], +- "LC_TIME", &variables[VARIABLE_LC_TIME], +- "LC_COLLATE", &variables[VARIABLE_LC_COLLATE], +- "LC_MONETARY", &variables[VARIABLE_LC_MONETARY], +- "LC_MESSAGES", &variables[VARIABLE_LC_MESSAGES], +- "LC_PAPER", &variables[VARIABLE_LC_PAPER], +- "LC_NAME", &variables[VARIABLE_LC_NAME], +- "LC_ADDRESS", &variables[VARIABLE_LC_ADDRESS], +- "LC_TELEPHONE", &variables[VARIABLE_LC_TELEPHONE], +- "LC_MEASUREMENT", &variables[VARIABLE_LC_MEASUREMENT], +- "LC_IDENTIFICATION", &variables[VARIABLE_LC_IDENTIFICATION]); +- if (r < 0 && r != -ENOENT) +- log_warning_errno(r, "Failed to read /etc/locale.conf: %m"); +- } +- +- for (LocaleVariable i = 0; i < _VARIABLE_LC_MAX; i++) { +- char *s; +- +- if (!variables[i]) +- continue; +- +- s = strjoin(locale_variable_to_string(i), "=", variables[i]); +- if (!s) +- return -ENOMEM; +- +- if (strv_consume(&add, s) < 0) +- return -ENOMEM; +- } +- +- if (strv_isempty(add)) { +- /* If no locale is configured then default to compile-time default. */ +- +- add = strv_new("LANG=" SYSTEMD_DEFAULT_LOCALE); +- if (!add) +- return -ENOMEM; +- } +- +- if (strv_isempty(*environment)) +- strv_free_and_replace(*environment, add); +- else { +- char **merged; +- +- merged = strv_env_merge(*environment, add); +- if (!merged) +- return -ENOMEM; +- +- strv_free_and_replace(*environment, merged); +- } +- +- return 0; +-} +diff --git a/src/core/locale-setup.h b/src/core/locale-setup.h +deleted file mode 100644 +index d554ad3060..0000000000 +--- a/src/core/locale-setup.h ++++ /dev/null +@@ -1,4 +0,0 @@ +-/* SPDX-License-Identifier: LGPL-2.1-or-later */ +-#pragma once +- +-int locale_setup(char ***environment); +diff --git a/src/core/meson.build b/src/core/meson.build +index 97ac431763..7704478d43 100644 +--- a/src/core/meson.build ++++ b/src/core/meson.build +@@ -83,8 +83,6 @@ libcore_sources = ''' + load-dropin.h + load-fragment.c + load-fragment.h +- locale-setup.c +- locale-setup.h + manager-dump.c + manager-dump.h + manager-serialize.c +diff --git a/src/locale/keymap-util.c b/src/locale/keymap-util.c +index 10d2ed7aec..a3af396ebe 100644 +--- a/src/locale/keymap-util.c ++++ b/src/locale/keymap-util.c +@@ -65,13 +65,8 @@ static void context_free_vconsole(Context *c) { + c->vc_keymap_toggle = mfree(c->vc_keymap_toggle); + } + +-static void context_free_locale(Context *c) { +- for (LocaleVariable p = 0; p < _VARIABLE_LC_MAX; p++) +- c->locale[p] = mfree(c->locale[p]); +-} +- + void context_clear(Context *c) { +- context_free_locale(c); ++ locale_context_clear(&c->locale_context); + context_free_x11(c); + context_free_vconsole(c); + +@@ -82,15 +77,8 @@ void context_clear(Context *c) { + bus_verify_polkit_async_registry_free(c->polkit_registry); + }; + +-void locale_simplify(char *locale[_VARIABLE_LC_MAX]) { +- for (LocaleVariable p = VARIABLE_LANG+1; p < _VARIABLE_LC_MAX; p++) +- if (isempty(locale[p]) || streq_ptr(locale[VARIABLE_LANG], locale[p])) +- locale[p] = mfree(locale[p]); +-} +- + int locale_read_data(Context *c, sd_bus_message *m) { +- struct stat st; +- int r; ++ assert(c); + + /* Do not try to re-read the file within single bus operation. */ + if (m) { +@@ -101,57 +89,7 @@ int locale_read_data(Context *c, sd_bus_message *m) { + c->locale_cache = sd_bus_message_ref(m); + } + +- r = stat("/etc/locale.conf", &st); +- if (r < 0 && errno != ENOENT) +- return -errno; +- +- if (r >= 0) { +- usec_t t; +- +- /* If mtime is not changed, then we do not need to re-read the file. */ +- t = timespec_load(&st.st_mtim); +- if (c->locale_mtime != USEC_INFINITY && t == c->locale_mtime) +- return 0; +- +- c->locale_mtime = t; +- context_free_locale(c); +- +- r = parse_env_file(NULL, "/etc/locale.conf", +- "LANG", &c->locale[VARIABLE_LANG], +- "LANGUAGE", &c->locale[VARIABLE_LANGUAGE], +- "LC_CTYPE", &c->locale[VARIABLE_LC_CTYPE], +- "LC_NUMERIC", &c->locale[VARIABLE_LC_NUMERIC], +- "LC_TIME", &c->locale[VARIABLE_LC_TIME], +- "LC_COLLATE", &c->locale[VARIABLE_LC_COLLATE], +- "LC_MONETARY", &c->locale[VARIABLE_LC_MONETARY], +- "LC_MESSAGES", &c->locale[VARIABLE_LC_MESSAGES], +- "LC_PAPER", &c->locale[VARIABLE_LC_PAPER], +- "LC_NAME", &c->locale[VARIABLE_LC_NAME], +- "LC_ADDRESS", &c->locale[VARIABLE_LC_ADDRESS], +- "LC_TELEPHONE", &c->locale[VARIABLE_LC_TELEPHONE], +- "LC_MEASUREMENT", &c->locale[VARIABLE_LC_MEASUREMENT], +- "LC_IDENTIFICATION", &c->locale[VARIABLE_LC_IDENTIFICATION]); +- if (r < 0) +- return r; +- } else { +- c->locale_mtime = USEC_INFINITY; +- context_free_locale(c); +- +- /* Fill in what we got passed from systemd. */ +- for (LocaleVariable p = 0; p < _VARIABLE_LC_MAX; p++) { +- const char *name; +- +- name = locale_variable_to_string(p); +- assert(name); +- +- r = free_and_strdup(&c->locale[p], empty_to_null(getenv(name))); +- if (r < 0) +- return r; +- } +- } +- +- locale_simplify(c->locale); +- return 0; ++ return locale_context_load(&c->locale_context, LOCALE_LOAD_LOCALE_CONF | LOCALE_LOAD_ENVIRONMENT | LOCALE_LOAD_SIMPLIFY); + } + + int vconsole_read_data(Context *c, sd_bus_message *m) { +@@ -285,40 +223,6 @@ int x11_read_data(Context *c, sd_bus_message *m) { + return 0; + } + +-int locale_write_data(Context *c, char ***settings) { +- _cleanup_strv_free_ char **l = NULL; +- struct stat st; +- int r; +- +- /* Set values will be returned as strv in *settings on success. */ +- +- for (LocaleVariable p = 0; p < _VARIABLE_LC_MAX; p++) +- if (!isempty(c->locale[p])) { +- r = strv_env_assign(&l, locale_variable_to_string(p), c->locale[p]); +- if (r < 0) +- return r; +- } +- +- if (strv_isempty(l)) { +- if (unlink("/etc/locale.conf") < 0) +- return errno == ENOENT ? 0 : -errno; +- +- c->locale_mtime = USEC_INFINITY; +- return 0; +- } +- +- r = write_env_file_label("/etc/locale.conf", l); +- if (r < 0) +- return r; +- +- *settings = TAKE_PTR(l); +- +- if (stat("/etc/locale.conf", &st) >= 0) +- c->locale_mtime = timespec_load(&st.st_mtim); +- +- return 0; +-} +- + int vconsole_write_data(Context *c) { + _cleanup_strv_free_ char **l = NULL; + struct stat st; +diff --git a/src/locale/keymap-util.h b/src/locale/keymap-util.h +index c087dbcbbe..5470d1bb9b 100644 +--- a/src/locale/keymap-util.h ++++ b/src/locale/keymap-util.h +@@ -4,13 +4,12 @@ + #include "sd-bus.h" + + #include "hashmap.h" +-#include "locale-util.h" ++#include "locale-setup.h" + #include "time-util.h" + + typedef struct Context { + sd_bus_message *locale_cache; +- usec_t locale_mtime; +- char *locale[_VARIABLE_LC_MAX]; ++ LocaleContext locale_context; + + sd_bus_message *x11_cache; + usec_t x11_mtime; +@@ -40,8 +39,6 @@ int vconsole_convert_to_x11(Context *c); + int vconsole_write_data(Context *c); + int x11_convert_to_vconsole(Context *c); + int x11_write_data(Context *c); +-void locale_simplify(char *locale[_VARIABLE_LC_MAX]); +-int locale_write_data(Context *c, char ***settings); + + bool locale_gen_check_available(void); + int locale_gen_enable_locale(const char *locale); +diff --git a/src/locale/localectl.c b/src/locale/localectl.c +index 661d54c27d..6bfb564f97 100644 +--- a/src/locale/localectl.c ++++ b/src/locale/localectl.c +@@ -12,7 +12,7 @@ + #include "fd-util.h" + #include "fileio.h" + #include "kbd-util.h" +-#include "locale-util.h" ++#include "locale-setup.h" + #include "main-func.h" + #include "memory-util.h" + #include "pager.h" +@@ -52,44 +52,25 @@ static void status_info_clear(StatusInfo *info) { + } + + static void print_overridden_variables(void) { +- _cleanup_(locale_variables_freep) char *variables[_VARIABLE_LC_MAX] = {}; +- bool print_warning = true; ++ _cleanup_(locale_context_clear) LocaleContext c = { .mtime = USEC_INFINITY }; ++ _cleanup_strv_free_ char **env = NULL; + int r; + + if (arg_transport != BUS_TRANSPORT_LOCAL) + return; + +- r = proc_cmdline_get_key_many( +- PROC_CMDLINE_STRIP_RD_PREFIX, +- "locale.LANG", &variables[VARIABLE_LANG], +- "locale.LANGUAGE", &variables[VARIABLE_LANGUAGE], +- "locale.LC_CTYPE", &variables[VARIABLE_LC_CTYPE], +- "locale.LC_NUMERIC", &variables[VARIABLE_LC_NUMERIC], +- "locale.LC_TIME", &variables[VARIABLE_LC_TIME], +- "locale.LC_COLLATE", &variables[VARIABLE_LC_COLLATE], +- "locale.LC_MONETARY", &variables[VARIABLE_LC_MONETARY], +- "locale.LC_MESSAGES", &variables[VARIABLE_LC_MESSAGES], +- "locale.LC_PAPER", &variables[VARIABLE_LC_PAPER], +- "locale.LC_NAME", &variables[VARIABLE_LC_NAME], +- "locale.LC_ADDRESS", &variables[VARIABLE_LC_ADDRESS], +- "locale.LC_TELEPHONE", &variables[VARIABLE_LC_TELEPHONE], +- "locale.LC_MEASUREMENT", &variables[VARIABLE_LC_MEASUREMENT], +- "locale.LC_IDENTIFICATION", &variables[VARIABLE_LC_IDENTIFICATION]); +- if (r < 0 && r != -ENOENT) { +- log_warning_errno(r, "Failed to read /proc/cmdline: %m"); +- return; +- } +- +- for (LocaleVariable j = 0; j < _VARIABLE_LC_MAX; j++) +- if (variables[j]) { +- if (print_warning) { +- log_warning("Warning: Settings on kernel command line override system locale settings in /etc/locale.conf.\n" +- " Command Line: %s=%s", locale_variable_to_string(j), variables[j]); ++ (void) locale_context_load(&c, LOCALE_LOAD_PROC_CMDLINE); + +- print_warning = false; +- } else +- log_warning(" %s=%s", locale_variable_to_string(j), variables[j]); +- } ++ r = locale_context_build_env(&c, &env, NULL); ++ if (r < 0) ++ return (void) log_warning_errno(r, "Failed to build locale settings from kernel command line, ignoring: %m"); ++ ++ STRV_FOREACH(p, env) ++ if (p == env) ++ log_warning("Warning: Settings on kernel command line override system locale settings in /etc/locale.conf.\n" ++ " Command Line: %s", *p); ++ else ++ log_warning(" %s", *p); + } + + static void print_status_info(StatusInfo *i) { +diff --git a/src/locale/localed.c b/src/locale/localed.c +index 89bf9c6fba..9718c5b95f 100644 +--- a/src/locale/localed.c ++++ b/src/locale/localed.c +@@ -21,7 +21,6 @@ + #include "dlfcn-util.h" + #include "kbd-util.h" + #include "keymap-util.h" +-#include "locale-util.h" + #include "macro.h" + #include "main-func.h" + #include "missing_capability.h" +@@ -33,44 +32,13 @@ + #include "strv.h" + #include "user-util.h" + +-static int locale_update_system_manager(Context *c, sd_bus *bus) { +- _cleanup_free_ char **l_unset = NULL; +- _cleanup_strv_free_ char **l_set = NULL; ++static int locale_update_system_manager(sd_bus *bus, char **l_set, char **l_unset) { + _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; +- size_t c_set = 0, c_unset = 0; + int r; + + assert(bus); + +- l_unset = new0(char*, _VARIABLE_LC_MAX); +- if (!l_unset) +- return log_oom(); +- +- l_set = new0(char*, _VARIABLE_LC_MAX); +- if (!l_set) +- return log_oom(); +- +- for (LocaleVariable p = 0; p < _VARIABLE_LC_MAX; p++) { +- const char *name; +- +- name = locale_variable_to_string(p); +- assert(name); +- +- if (isempty(c->locale[p])) +- l_unset[c_set++] = (char*) name; +- else { +- char *s; +- +- s = strjoin(name, "=", c->locale[p]); +- if (!s) +- return log_oom(); +- +- l_set[c_unset++] = s; +- } +- } +- +- assert(c_set + c_unset == _VARIABLE_LC_MAX); + r = sd_bus_message_new_method_call(bus, &m, + "org.freedesktop.systemd1", + "/org/freedesktop/systemd1", +@@ -188,21 +156,9 @@ static int property_get_locale( + if (!l) + return -ENOMEM; + +- for (LocaleVariable p = 0, q = 0; p < _VARIABLE_LC_MAX; p++) { +- char *t; +- const char *name; +- +- name = locale_variable_to_string(p); +- assert(name); +- +- if (isempty(c->locale[p])) +- continue; +- +- if (asprintf(&t, "%s=%s", name, c->locale[p]) < 0) +- return -ENOMEM; +- +- l[q++] = t; +- } ++ r = locale_context_build_env(&c->locale_context, &l, NULL); ++ if (r < 0) ++ return r; + + return sd_bus_message_append_strv(reply, l); + } +@@ -342,9 +298,8 @@ static int locale_gen_process_locale(char *new_locale[static _VARIABLE_LC_MAX], + + static int method_set_locale(sd_bus_message *m, void *userdata, sd_bus_error *error) { + _cleanup_(locale_variables_freep) char *new_locale[_VARIABLE_LC_MAX] = {}; +- _cleanup_strv_free_ char **settings = NULL, **l = NULL; ++ _cleanup_strv_free_ char **l = NULL, **l_set = NULL, **l_unset = NULL; + Context *c = userdata; +- bool modified = false; + int interactive, r; + bool use_localegen; + +@@ -402,22 +357,13 @@ static int method_set_locale(sd_bus_message *m, void *userdata, sd_bus_error *er + } + + /* Merge with the current settings */ +- for (LocaleVariable p = 0; p < _VARIABLE_LC_MAX; p++) +- if (!isempty(c->locale[p]) && isempty(new_locale[p])) { +- new_locale[p] = strdup(c->locale[p]); +- if (!new_locale[p]) +- return -ENOMEM; +- } +- +- locale_simplify(new_locale); ++ r = locale_context_merge(&c->locale_context, new_locale); ++ if (r < 0) ++ return r; + +- for (LocaleVariable p = 0; p < _VARIABLE_LC_MAX; p++) +- if (!streq_ptr(c->locale[p], new_locale[p])) { +- modified = true; +- break; +- } ++ locale_variables_simplify(new_locale); + +- if (!modified) { ++ if (locale_context_equal(&c->locale_context, new_locale)) { + log_debug("Locale settings were not modified."); + return sd_bus_reply_method_return(m, NULL); + } +@@ -443,22 +389,21 @@ static int method_set_locale(sd_bus_message *m, void *userdata, sd_bus_error *er + return r; + } + +- for (LocaleVariable p = 0; p < _VARIABLE_LC_MAX; p++) +- free_and_replace(c->locale[p], new_locale[p]); ++ locale_context_take(&c->locale_context, new_locale); + + /* Write locale configuration */ +- r = locale_write_data(c, &settings); ++ r = locale_context_save(&c->locale_context, &l_set, &l_unset); + if (r < 0) { + log_error_errno(r, "Failed to set locale: %m"); + return sd_bus_error_set_errnof(error, r, "Failed to set locale: %m"); + } + +- (void) locale_update_system_manager(c, sd_bus_message_get_bus(m)); ++ (void) locale_update_system_manager(sd_bus_message_get_bus(m), l_set, l_unset); + +- if (settings) { ++ if (!strv_isempty(l_set)) { + _cleanup_free_ char *line = NULL; + +- line = strv_join(settings, ", "); ++ line = strv_join(l_set, ", "); + log_info("Changed locale to %s.", strnull(line)); + } else + log_info("Changed locale to unset."); +@@ -827,7 +772,7 @@ static int connect_bus(Context *c, sd_event *event, sd_bus **_bus) { + + static int run(int argc, char *argv[]) { + _cleanup_(context_clear) Context context = { +- .locale_mtime = USEC_INFINITY, ++ .locale_context.mtime = USEC_INFINITY, + .vc_mtime = USEC_INFINITY, + .x11_mtime = USEC_INFINITY, + }; +diff --git a/src/shared/locale-setup.c b/src/shared/locale-setup.c +new file mode 100644 +index 0000000000..b8c6647e7c +--- /dev/null ++++ b/src/shared/locale-setup.c +@@ -0,0 +1,256 @@ ++/* SPDX-License-Identifier: LGPL-2.1-or-later */ ++ ++#include ++#include ++ ++#include "env-file-label.h" ++#include "env-file.h" ++#include "env-util.h" ++#include "locale-setup.h" ++#include "proc-cmdline.h" ++#include "strv.h" ++ ++void locale_context_clear(LocaleContext *c) { ++ assert(c); ++ ++ c->mtime = USEC_INFINITY; ++ ++ for (LocaleVariable i = 0; i < _VARIABLE_LC_MAX; i++) ++ c->locale[i] = mfree(c->locale[i]); ++} ++ ++int locale_context_load(LocaleContext *c, LocaleLoadFlag flag) { ++ int r; ++ ++ assert(c); ++ ++ if (FLAGS_SET(flag, LOCALE_LOAD_PROC_CMDLINE)) { ++ locale_context_clear(c); ++ ++ r = proc_cmdline_get_key_many(PROC_CMDLINE_STRIP_RD_PREFIX, ++ "locale.LANG", &c->locale[VARIABLE_LANG], ++ "locale.LANGUAGE", &c->locale[VARIABLE_LANGUAGE], ++ "locale.LC_CTYPE", &c->locale[VARIABLE_LC_CTYPE], ++ "locale.LC_NUMERIC", &c->locale[VARIABLE_LC_NUMERIC], ++ "locale.LC_TIME", &c->locale[VARIABLE_LC_TIME], ++ "locale.LC_COLLATE", &c->locale[VARIABLE_LC_COLLATE], ++ "locale.LC_MONETARY", &c->locale[VARIABLE_LC_MONETARY], ++ "locale.LC_MESSAGES", &c->locale[VARIABLE_LC_MESSAGES], ++ "locale.LC_PAPER", &c->locale[VARIABLE_LC_PAPER], ++ "locale.LC_NAME", &c->locale[VARIABLE_LC_NAME], ++ "locale.LC_ADDRESS", &c->locale[VARIABLE_LC_ADDRESS], ++ "locale.LC_TELEPHONE", &c->locale[VARIABLE_LC_TELEPHONE], ++ "locale.LC_MEASUREMENT", &c->locale[VARIABLE_LC_MEASUREMENT], ++ "locale.LC_IDENTIFICATION", &c->locale[VARIABLE_LC_IDENTIFICATION]); ++ if (r < 0 && r != -ENOENT) ++ log_debug_errno(r, "Failed to read /proc/cmdline, ignoring: %m"); ++ if (r > 0) ++ goto finalize; ++ } ++ ++ if (FLAGS_SET(flag, LOCALE_LOAD_LOCALE_CONF)) { ++ struct stat st; ++ usec_t t; ++ ++ r = stat("/etc/locale.conf", &st); ++ if (r < 0 && errno != ENOENT) ++ return log_debug_errno(errno, "Failed to stat /etc/locale.conf: %m"); ++ ++ if (r >= 0) { ++ /* If mtime is not changed, then we do not need to re-read the file. */ ++ t = timespec_load(&st.st_mtim); ++ if (c->mtime != USEC_INFINITY && t == c->mtime) ++ return 0; ++ ++ locale_context_clear(c); ++ c->mtime = t; ++ ++ r = parse_env_file(NULL, "/etc/locale.conf", ++ "LANG", &c->locale[VARIABLE_LANG], ++ "LANGUAGE", &c->locale[VARIABLE_LANGUAGE], ++ "LC_CTYPE", &c->locale[VARIABLE_LC_CTYPE], ++ "LC_NUMERIC", &c->locale[VARIABLE_LC_NUMERIC], ++ "LC_TIME", &c->locale[VARIABLE_LC_TIME], ++ "LC_COLLATE", &c->locale[VARIABLE_LC_COLLATE], ++ "LC_MONETARY", &c->locale[VARIABLE_LC_MONETARY], ++ "LC_MESSAGES", &c->locale[VARIABLE_LC_MESSAGES], ++ "LC_PAPER", &c->locale[VARIABLE_LC_PAPER], ++ "LC_NAME", &c->locale[VARIABLE_LC_NAME], ++ "LC_ADDRESS", &c->locale[VARIABLE_LC_ADDRESS], ++ "LC_TELEPHONE", &c->locale[VARIABLE_LC_TELEPHONE], ++ "LC_MEASUREMENT", &c->locale[VARIABLE_LC_MEASUREMENT], ++ "LC_IDENTIFICATION", &c->locale[VARIABLE_LC_IDENTIFICATION]); ++ if (r < 0) ++ return log_debug_errno(r, "Failed to read /etc/locale.conf: %m"); ++ ++ goto finalize; ++ } ++ } ++ ++ if (FLAGS_SET(flag, LOCALE_LOAD_ENVIRONMENT)) { ++ locale_context_clear(c); ++ ++ /* Fill in what we got passed from systemd. */ ++ for (LocaleVariable p = 0; p < _VARIABLE_LC_MAX; p++) { ++ const char *name = ASSERT_PTR(locale_variable_to_string(p)); ++ ++ r = free_and_strdup(&c->locale[p], empty_to_null(getenv(name))); ++ if (r < 0) ++ return log_oom_debug(); ++ } ++ ++ goto finalize; ++ } ++ ++ /* Nothing loaded. */ ++ locale_context_clear(c); ++ return 0; ++ ++finalize: ++ if (FLAGS_SET(flag, LOCALE_LOAD_SIMPLIFY)) ++ locale_variables_simplify(c->locale); ++ ++ return 0; ++} ++ ++int locale_context_build_env(const LocaleContext *c, char ***ret_set, char ***ret_unset) { ++ _cleanup_strv_free_ char **set = NULL, **unset = NULL; ++ int r; ++ ++ assert(c); ++ ++ if (!ret_set && !ret_unset) ++ return 0; ++ ++ for (LocaleVariable p = 0; p < _VARIABLE_LC_MAX; p++) { ++ const char *name = ASSERT_PTR(locale_variable_to_string(p)); ++ ++ if (isempty(c->locale[p])) { ++ if (!ret_unset) ++ continue; ++ r = strv_extend(&unset, name); ++ } else { ++ if (!ret_set) ++ continue; ++ r = strv_env_assign(&set, name, c->locale[p]); ++ } ++ if (r < 0) ++ return r; ++ } ++ ++ if (ret_set) ++ *ret_set = TAKE_PTR(set); ++ if (ret_unset) ++ *ret_unset = TAKE_PTR(unset); ++ return 0; ++} ++ ++int locale_context_save(LocaleContext *c, char ***ret_set, char ***ret_unset) { ++ _cleanup_strv_free_ char **set = NULL, **unset = NULL; ++ struct stat st; ++ int r; ++ ++ assert(c); ++ ++ /* Set values will be returned as strv in *ret on success. */ ++ ++ r = locale_context_build_env(c, &set, ret_unset ? &unset : NULL); ++ if (r < 0) ++ return r; ++ ++ if (strv_isempty(set)) { ++ if (unlink("/etc/locale.conf") < 0) ++ return errno == ENOENT ? 0 : -errno; ++ ++ c->mtime = USEC_INFINITY; ++ if (ret_set) ++ *ret_set = NULL; ++ if (ret_unset) ++ *ret_unset = NULL; ++ return 0; ++ } ++ ++ r = write_env_file_label("/etc/locale.conf", set); ++ if (r < 0) ++ return r; ++ ++ if (stat("/etc/locale.conf", &st) >= 0) ++ c->mtime = timespec_load(&st.st_mtim); ++ ++ if (ret_set) ++ *ret_set = TAKE_PTR(set); ++ if (ret_unset) ++ *ret_unset = TAKE_PTR(unset); ++ return 0; ++} ++ ++int locale_context_merge(const LocaleContext *c, char *l[_VARIABLE_LC_MAX]) { ++ assert(c); ++ assert(l); ++ ++ for (LocaleVariable p = 0; p < _VARIABLE_LC_MAX; p++) ++ if (!isempty(c->locale[p]) && isempty(l[p])) { ++ l[p] = strdup(c->locale[p]); ++ if (!l[p]) ++ return -ENOMEM; ++ } ++ ++ return 0; ++} ++ ++void locale_context_take(LocaleContext *c, char *l[_VARIABLE_LC_MAX]) { ++ assert(c); ++ assert(l); ++ ++ for (LocaleVariable p = 0; p < _VARIABLE_LC_MAX; p++) ++ free_and_replace(c->locale[p], l[p]); ++} ++ ++bool locale_context_equal(const LocaleContext *c, char *l[_VARIABLE_LC_MAX]) { ++ assert(c); ++ assert(l); ++ ++ for (LocaleVariable p = 0; p < _VARIABLE_LC_MAX; p++) ++ if (!streq_ptr(c->locale[p], l[p])) ++ return false; ++ ++ return true; ++} ++ ++int locale_setup(char ***environment) { ++ _cleanup_(locale_context_clear) LocaleContext c = { .mtime = USEC_INFINITY }; ++ _cleanup_strv_free_ char **add = NULL; ++ int r; ++ ++ assert(environment); ++ ++ r = locale_context_load(&c, LOCALE_LOAD_PROC_CMDLINE | LOCALE_LOAD_LOCALE_CONF); ++ if (r < 0) ++ return r; ++ ++ r = locale_context_build_env(&c, &add, NULL); ++ if (r < 0) ++ return r; ++ ++ if (strv_isempty(add)) { ++ /* If no locale is configured then default to compile-time default. */ ++ ++ add = strv_new("LANG=" SYSTEMD_DEFAULT_LOCALE); ++ if (!add) ++ return -ENOMEM; ++ } ++ ++ if (strv_isempty(*environment)) ++ strv_free_and_replace(*environment, add); ++ else { ++ char **merged; ++ ++ merged = strv_env_merge(*environment, add); ++ if (!merged) ++ return -ENOMEM; ++ ++ strv_free_and_replace(*environment, merged); ++ } ++ ++ return 0; ++} +diff --git a/src/shared/locale-setup.h b/src/shared/locale-setup.h +new file mode 100644 +index 0000000000..ec3fc8c364 +--- /dev/null ++++ b/src/shared/locale-setup.h +@@ -0,0 +1,28 @@ ++/* SPDX-License-Identifier: LGPL-2.1-or-later */ ++#pragma once ++ ++#include "locale-util.h" ++#include "time-util.h" ++ ++typedef struct LocaleContext { ++ usec_t mtime; ++ char *locale[_VARIABLE_LC_MAX]; ++} LocaleContext; ++ ++typedef enum LocaleLoadFlag { ++ LOCALE_LOAD_PROC_CMDLINE = 1 << 0, ++ LOCALE_LOAD_LOCALE_CONF = 1 << 1, ++ LOCALE_LOAD_ENVIRONMENT = 1 << 2, ++ LOCALE_LOAD_SIMPLIFY = 1 << 3, ++} LocaleLoadFlag; ++ ++void locale_context_clear(LocaleContext *c); ++int locale_context_load(LocaleContext *c, LocaleLoadFlag flag); ++int locale_context_build_env(const LocaleContext *c, char ***ret_set, char ***ret_unset); ++int locale_context_save(LocaleContext *c, char ***ret_set, char ***ret_unset); ++ ++int locale_context_merge(const LocaleContext *c, char *l[_VARIABLE_LC_MAX]); ++void locale_context_take(LocaleContext *c, char *l[_VARIABLE_LC_MAX]); ++bool locale_context_equal(const LocaleContext *c, char *l[_VARIABLE_LC_MAX]); ++ ++int locale_setup(char ***environment); +diff --git a/src/shared/meson.build b/src/shared/meson.build +index 006310a917..62365682cf 100644 +--- a/src/shared/meson.build ++++ b/src/shared/meson.build +@@ -195,6 +195,8 @@ shared_sources = files(''' + linux/ethtool.h + local-addresses.c + local-addresses.h ++ locale-setup.c ++ locale-setup.h + lockfile-util.c + lockfile-util.h + log-link.h diff --git a/0220-locale-rename-keymap-util.-ch-localed-util.-ch.patch b/0220-locale-rename-keymap-util.-ch-localed-util.-ch.patch new file mode 100644 index 0000000..10a8057 --- /dev/null +++ b/0220-locale-rename-keymap-util.-ch-localed-util.-ch.patch @@ -0,0 +1,98 @@ +From 8cfe7b6243660a5f1b43fe7217a678317284c430 Mon Sep 17 00:00:00 2001 +From: Yu Watanabe +Date: Tue, 14 Jun 2022 09:08:00 +0900 +Subject: [PATCH] locale: rename keymap-util.[ch] -> localed-util.[ch] + +As the file contains not only keymap related functions. + +(cherry picked from commit 3e5203b3eb2b06ef346eef13d64430542bbfb5c4) + +Related: #2087652 +--- + src/locale/{keymap-util.c => localed-util.c} | 3 +-- + src/locale/{keymap-util.h => localed-util.h} | 0 + src/locale/localed.c | 2 +- + src/locale/meson.build | 10 +++++----- + src/locale/{test-keymap-util.c => test-localed-util.c} | 2 +- + 5 files changed, 8 insertions(+), 9 deletions(-) + rename src/locale/{keymap-util.c => localed-util.c} (99%) + rename src/locale/{keymap-util.h => localed-util.h} (100%) + rename src/locale/{test-keymap-util.c => test-localed-util.c} (99%) + +diff --git a/src/locale/keymap-util.c b/src/locale/localed-util.c +similarity index 99% +rename from src/locale/keymap-util.c +rename to src/locale/localed-util.c +index a3af396ebe..f4f8e5d168 100644 +--- a/src/locale/keymap-util.c ++++ b/src/locale/localed-util.c +@@ -15,8 +15,7 @@ + #include "fileio.h" + #include "fs-util.h" + #include "kbd-util.h" +-#include "keymap-util.h" +-#include "locale-util.h" ++#include "localed-util.h" + #include "macro.h" + #include "mkdir-label.h" + #include "nulstr-util.h" +diff --git a/src/locale/keymap-util.h b/src/locale/localed-util.h +similarity index 100% +rename from src/locale/keymap-util.h +rename to src/locale/localed-util.h +diff --git a/src/locale/localed.c b/src/locale/localed.c +index 9718c5b95f..2c324efb14 100644 +--- a/src/locale/localed.c ++++ b/src/locale/localed.c +@@ -20,7 +20,7 @@ + #include "def.h" + #include "dlfcn-util.h" + #include "kbd-util.h" +-#include "keymap-util.h" ++#include "localed-util.h" + #include "macro.h" + #include "main-func.h" + #include "missing_capability.h" +diff --git a/src/locale/meson.build b/src/locale/meson.build +index 0ccf71583d..2d8c48cf3a 100644 +--- a/src/locale/meson.build ++++ b/src/locale/meson.build +@@ -1,9 +1,9 @@ + # SPDX-License-Identifier: LGPL-2.1-or-later + + systemd_localed_sources = files(''' ++ localed-util.c ++ localed-util.h + localed.c +- keymap-util.c +- keymap-util.h + '''.split()) + + localectl_sources = files('localectl.c') +@@ -30,7 +30,7 @@ if conf.get('ENABLE_LOCALED') == 1 + endif + + tests += [ +- [files('test-keymap-util.c', +- 'keymap-util.c', +- 'keymap-util.h')], ++ [files('test-localed-util.c', ++ 'localed-util.c', ++ 'localed-util.h')], + ] +diff --git a/src/locale/test-keymap-util.c b/src/locale/test-localed-util.c +similarity index 99% +rename from src/locale/test-keymap-util.c +rename to src/locale/test-localed-util.c +index f726e8e524..f658d271dc 100644 +--- a/src/locale/test-keymap-util.c ++++ b/src/locale/test-localed-util.c +@@ -1,7 +1,7 @@ + /* SPDX-License-Identifier: LGPL-2.1-or-later */ + + #include "alloc-util.h" +-#include "keymap-util.h" ++#include "localed-util.h" + #include "log.h" + #include "string-util.h" + #include "tests.h" diff --git a/0221-test-add-one-more-path-to-search-keymaps.patch b/0221-test-add-one-more-path-to-search-keymaps.patch new file mode 100644 index 0000000..a0d36d0 --- /dev/null +++ b/0221-test-add-one-more-path-to-search-keymaps.patch @@ -0,0 +1,85 @@ +From 380a3b2b2d38f08ac84d3ac521b205960059d99c Mon Sep 17 00:00:00 2001 +From: Yu Watanabe +Date: Tue, 14 Jun 2022 09:10:00 +0900 +Subject: [PATCH] test: add one more path to search keymaps + +Now it also supports split-usr. + +(cherry picked from commit 569c6fd1b7c7946fa853d558fcbb23e4a45f957f) + +Related: #2087652 +--- + test/test-functions | 59 ++++++++++++++++++++++++++++++--------------- + 1 file changed, 40 insertions(+), 19 deletions(-) + +diff --git a/test/test-functions b/test/test-functions +index d71e2a3328..01fc90fbf5 100644 +--- a/test/test-functions ++++ b/test/test-functions +@@ -1844,26 +1844,47 @@ install_pam() { + + # shellcheck disable=SC2120 + install_keymaps() { +- dinfo "Install keymaps" +- # The first three paths may be deprecated. +- # It seems now the last two paths are used by many distributions. +- for i in \ +- /usr/lib/kbd/keymaps/include/* \ +- /usr/lib/kbd/keymaps/i386/include/* \ +- /usr/lib/kbd/keymaps/i386/qwerty/us.* \ +- /usr/lib/kbd/keymaps/legacy/include/* \ +- /usr/lib/kbd/keymaps/legacy/i386/qwerty/us.*; do +- [[ -f "$i" ]] || continue +- inst "$i" +- done ++ local i p ++ local -a prefix=( ++ "/usr" ++ ) + +- # When it takes any argument, then install more keymaps. +- if [[ $# -gt 1 ]]; then +- for i in \ +- /usr/lib/kbd/keymaps/i386/*/* \ +- /usr/lib/kbd/keymaps/legacy/i386/*/*; do +- [[ -f "$i" ]] || continue +- inst "$i" ++ dinfo "Install console keymaps" ++ ++ if command -v meson >/dev/null \ ++ && [[ "$(meson configure "${BUILD_DIR:?}" | grep 'split-usr' | awk '{ print $2 }')" == "true" ]] \ ++ || [[ ! -L /lib ]]; then ++ prefix+=( ++ "" ++ ) ++ fi ++ ++ if (( $# == 0 )); then ++ for p in "${prefix[@]}"; do ++ # The first three paths may be deprecated. ++ # It seems now the last three paths are used by many distributions. ++ for i in \ ++ "$p"/lib/kbd/keymaps/include/* \ ++ "$p"/lib/kbd/keymaps/i386/include/* \ ++ "$p"/lib/kbd/keymaps/i386/qwerty/us.* \ ++ "$p"/lib/kbd/keymaps/legacy/include/* \ ++ "$p"/lib/kbd/keymaps/legacy/i386/qwerty/us.* \ ++ "$p"/lib/kbd/keymaps/xkb/us*; do ++ [[ -f "$i" ]] || continue ++ inst "$i" ++ done ++ done ++ else ++ # When it takes any argument, then install more keymaps. ++ for p in "${prefix[@]}"; do ++ for i in \ ++ "$p"/lib/kbd/keymaps/include/* \ ++ "$p"/lib/kbd/keymaps/i386/*/* \ ++ "$p"/lib/kbd/keymaps/legacy/i386/*/* \ ++ "$p"/lib/kbd/keymaps/xkb/*; do ++ [[ -f "$i" ]] || continue ++ inst "$i" ++ done + done + fi + } diff --git a/0222-test-introduce-inst_recursive-helper-function.patch b/0222-test-introduce-inst_recursive-helper-function.patch new file mode 100644 index 0000000..54cd4fb --- /dev/null +++ b/0222-test-introduce-inst_recursive-helper-function.patch @@ -0,0 +1,37 @@ +From a8e7b3e863bc34f4b6aa0a61be1706dcc65392bc Mon Sep 17 00:00:00 2001 +From: Yu Watanabe +Date: Tue, 14 Jun 2022 09:11:00 +0900 +Subject: [PATCH] test: introduce inst_recursive() helper function + +(cherry picked from commit da0465dc95388afc15598357452afef85035c639) + +Related: #2087652 +--- + test/test-functions | 14 ++++++++++++++ + 1 file changed, 14 insertions(+) + +diff --git a/test/test-functions b/test/test-functions +index 01fc90fbf5..4a6436a74b 100644 +--- a/test/test-functions ++++ b/test/test-functions +@@ -2555,6 +2555,20 @@ inst_any() { + return 1 + } + ++inst_recursive() { ++ local p item ++ ++ for p in "$@"; do ++ while read -r item; do ++ if [[ -d "$item" ]]; then ++ inst_dir "$item" ++ elif [[ -f "$item" ]]; then ++ inst_simple "$item" ++ fi ++ done < <(find "$p" 2>/dev/null) ++ done ++} ++ + # image_install [-o ] [ ... ] + # Install to the test image + # -o optionally install the and don't fail, if it is not there diff --git a/0223-hmac-sha256-move-size-define-to-sha256.h.patch b/0223-hmac-sha256-move-size-define-to-sha256.h.patch new file mode 100644 index 0000000..5bfe290 --- /dev/null +++ b/0223-hmac-sha256-move-size-define-to-sha256.h.patch @@ -0,0 +1,39 @@ +From f7b73ede98fe971ba28def1af4f3e4ab1fc20c6c Mon Sep 17 00:00:00 2001 +From: Grigori Goronzy +Date: Sat, 12 Mar 2022 00:51:21 +0100 +Subject: [PATCH] hmac/sha256: move size define to sha256.h + +(cherry picked from commit e560cf4f71bf237019d982603af3d6be86394788) + +Related: #2087652 +--- + src/basic/hmac.h | 2 +- + src/fundamental/sha256.h | 2 ++ + 2 files changed, 3 insertions(+), 1 deletion(-) + +diff --git a/src/basic/hmac.h b/src/basic/hmac.h +index a5682c439f..e58c1838a3 100644 +--- a/src/basic/hmac.h ++++ b/src/basic/hmac.h +@@ -4,7 +4,7 @@ + #include + #include + +-#define SHA256_DIGEST_SIZE 32 ++#include "sha256.h" + + /* Unoptimized implementation based on FIPS 198. 'res' has to be allocated by + * the caller. Prefer external OpenSSL functions, and use this only when +diff --git a/src/fundamental/sha256.h b/src/fundamental/sha256.h +index abc4167628..e53197f2ef 100644 +--- a/src/fundamental/sha256.h ++++ b/src/fundamental/sha256.h +@@ -8,6 +8,8 @@ + + #include "types-fundamental.h" + ++#define SHA256_DIGEST_SIZE 32 ++ + struct sha256_ctx { + uint32_t H[8]; + diff --git a/0224-tpm2-support-policies-with-PIN.patch b/0224-tpm2-support-policies-with-PIN.patch new file mode 100644 index 0000000..9f56c08 --- /dev/null +++ b/0224-tpm2-support-policies-with-PIN.patch @@ -0,0 +1,322 @@ +From 98997b288819f4dac7b2ca19c199d71e733bfa92 Mon Sep 17 00:00:00 2001 +From: Grigori Goronzy +Date: Wed, 16 Feb 2022 22:13:42 +0100 +Subject: [PATCH] tpm2: support policies with PIN + +Modify TPM2 authentication policy to optionally include an authValue, i.e. +a password/PIN. We use the "PIN" terminology since it's used by other +systems such as Windows, even though the PIN is not necessarily numeric. + +The pin is hashed via SHA256 to allow for arbitrary length PINs. + +v2: fix tpm2_seal in sd-repart +v3: applied review feedback +(cherry picked from commit 2f5a892aa0d70aa4f1f10c8dba495ad52bc02bc3) + +Related: #2087652 +--- + src/cryptenroll/cryptenroll-tpm2.c | 4 +- + src/cryptsetup/cryptsetup-tokens/luks2-tpm2.c | 2 +- + src/cryptsetup/cryptsetup-tpm2.c | 2 +- + src/partition/repart.c | 2 +- + src/shared/creds-util.c | 2 + + src/shared/tpm2-util.c | 76 ++++++++++++++++++- + src/shared/tpm2-util.h | 8 +- + 7 files changed, 85 insertions(+), 11 deletions(-) + +diff --git a/src/cryptenroll/cryptenroll-tpm2.c b/src/cryptenroll/cryptenroll-tpm2.c +index 801014af11..f5f6b87d0f 100644 +--- a/src/cryptenroll/cryptenroll-tpm2.c ++++ b/src/cryptenroll/cryptenroll-tpm2.c +@@ -80,7 +80,7 @@ int enroll_tpm2(struct crypt_device *cd, + + assert_se(node = crypt_get_device_name(cd)); + +- r = tpm2_seal(device, pcr_mask, &secret, &secret_size, &blob, &blob_size, &hash, &hash_size, &pcr_bank, &primary_alg); ++ r = tpm2_seal(device, pcr_mask, NULL, &secret, &secret_size, &blob, &blob_size, &hash, &hash_size, &pcr_bank, &primary_alg); + if (r < 0) + return r; + +@@ -97,7 +97,7 @@ int enroll_tpm2(struct crypt_device *cd, + + /* Quick verification that everything is in order, we are not in a hurry after all. */ + log_debug("Unsealing for verification..."); +- r = tpm2_unseal(device, pcr_mask, pcr_bank, primary_alg, blob, blob_size, hash, hash_size, &secret2, &secret2_size); ++ r = tpm2_unseal(device, pcr_mask, pcr_bank, primary_alg, blob, blob_size, hash, hash_size, NULL, &secret2, &secret2_size); + if (r < 0) + return r; + +diff --git a/src/cryptsetup/cryptsetup-tokens/luks2-tpm2.c b/src/cryptsetup/cryptsetup-tokens/luks2-tpm2.c +index 3d39dfa884..de189c7bed 100644 +--- a/src/cryptsetup/cryptsetup-tokens/luks2-tpm2.c ++++ b/src/cryptsetup/cryptsetup-tokens/luks2-tpm2.c +@@ -41,7 +41,7 @@ int acquire_luks2_key( + pcr_mask, pcr_bank, + primary_alg, + key_data, key_data_size, +- policy_hash, policy_hash_size, ++ policy_hash, policy_hash_size, NULL, + ret_decrypted_key, ret_decrypted_key_size); + } + +diff --git a/src/cryptsetup/cryptsetup-tpm2.c b/src/cryptsetup/cryptsetup-tpm2.c +index cb139518a7..05d76a684d 100644 +--- a/src/cryptsetup/cryptsetup-tpm2.c ++++ b/src/cryptsetup/cryptsetup-tpm2.c +@@ -64,7 +64,7 @@ int acquire_tpm2_key( + blob = loaded_blob; + } + +- return tpm2_unseal(device, pcr_mask, pcr_bank, primary_alg, blob, blob_size, policy_hash, policy_hash_size, ret_decrypted_key, ret_decrypted_key_size); ++ return tpm2_unseal(device, pcr_mask, pcr_bank, primary_alg, blob, blob_size, policy_hash, policy_hash_size, NULL, ret_decrypted_key, ret_decrypted_key_size); + } + + int find_tpm2_auto_data( +diff --git a/src/partition/repart.c b/src/partition/repart.c +index 2f70796e58..adfec0b9f3 100644 +--- a/src/partition/repart.c ++++ b/src/partition/repart.c +@@ -2655,7 +2655,7 @@ static int partition_encrypt( + uint16_t pcr_bank, primary_alg; + int keyslot; + +- r = tpm2_seal(arg_tpm2_device, arg_tpm2_pcr_mask, &secret, &secret_size, &blob, &blob_size, &hash, &hash_size, &pcr_bank, &primary_alg); ++ r = tpm2_seal(arg_tpm2_device, arg_tpm2_pcr_mask, NULL, &secret, &secret_size, &blob, &blob_size, &hash, &hash_size, &pcr_bank, &primary_alg); + if (r < 0) + return log_error_errno(r, "Failed to seal to TPM2: %m"); + +diff --git a/src/shared/creds-util.c b/src/shared/creds-util.c +index 4d0681bc10..c4dcc396ac 100644 +--- a/src/shared/creds-util.c ++++ b/src/shared/creds-util.c +@@ -534,6 +534,7 @@ int encrypt_credential_and_warn( + + r = tpm2_seal(tpm2_device, + tpm2_pcr_mask, ++ NULL, + &tpm2_key, + &tpm2_key_size, + &tpm2_blob, +@@ -803,6 +804,7 @@ int decrypt_credential_and_warn( + le32toh(t->blob_size), + t->policy_hash_and_blob + le32toh(t->blob_size), + le32toh(t->policy_hash_size), ++ NULL, + &tpm2_key, + &tpm2_key_size); + if (r < 0) +diff --git a/src/shared/tpm2-util.c b/src/shared/tpm2-util.c +index 70a2929432..aca7b69ab5 100644 +--- a/src/shared/tpm2-util.c ++++ b/src/shared/tpm2-util.c +@@ -14,6 +14,7 @@ + #include "hexdecoct.h" + #include "memory-util.h" + #include "random-util.h" ++#include "sha256.h" + #include "time-util.h" + + static void *libtss2_esys_dl = NULL; +@@ -30,10 +31,12 @@ TSS2_RC (*sym_Esys_GetRandom)(ESYS_CONTEXT *esysContext, ESYS_TR shandle1, ESYS_ + TSS2_RC (*sym_Esys_Initialize)(ESYS_CONTEXT **esys_context, TSS2_TCTI_CONTEXT *tcti, TSS2_ABI_VERSION *abiVersion) = NULL; + TSS2_RC (*sym_Esys_Load)(ESYS_CONTEXT *esysContext, ESYS_TR parentHandle, ESYS_TR shandle1, ESYS_TR shandle2, ESYS_TR shandle3, const TPM2B_PRIVATE *inPrivate, const TPM2B_PUBLIC *inPublic, ESYS_TR *objectHandle) = NULL; + TSS2_RC (*sym_Esys_PCR_Read)(ESYS_CONTEXT *esysContext, ESYS_TR shandle1,ESYS_TR shandle2, ESYS_TR shandle3, const TPML_PCR_SELECTION *pcrSelectionIn, UINT32 *pcrUpdateCounter, TPML_PCR_SELECTION **pcrSelectionOut, TPML_DIGEST **pcrValues); ++TSS2_RC (*sym_Esys_PolicyAuthValue)(ESYS_CONTEXT *esysContext, ESYS_TR policySession, ESYS_TR shandle1, ESYS_TR shandle2, ESYS_TR shandle3) = NULL; + TSS2_RC (*sym_Esys_PolicyGetDigest)(ESYS_CONTEXT *esysContext, ESYS_TR policySession, ESYS_TR shandle1, ESYS_TR shandle2, ESYS_TR shandle3, TPM2B_DIGEST **policyDigest) = NULL; + TSS2_RC (*sym_Esys_PolicyPCR)(ESYS_CONTEXT *esysContext, ESYS_TR policySession, ESYS_TR shandle1, ESYS_TR shandle2, ESYS_TR shandle3, const TPM2B_DIGEST *pcrDigest, const TPML_PCR_SELECTION *pcrs) = NULL; + TSS2_RC (*sym_Esys_StartAuthSession)(ESYS_CONTEXT *esysContext, ESYS_TR tpmKey, ESYS_TR bind, ESYS_TR shandle1, ESYS_TR shandle2, ESYS_TR shandle3, const TPM2B_NONCE *nonceCaller, TPM2_SE sessionType, const TPMT_SYM_DEF *symmetric, TPMI_ALG_HASH authHash, ESYS_TR *sessionHandle) = NULL; + TSS2_RC (*sym_Esys_Startup)(ESYS_CONTEXT *esysContext, TPM2_SU startupType) = NULL; ++TSS2_RC (*sym_Esys_TR_SetAuth)(ESYS_CONTEXT *esysContext, ESYS_TR handle, TPM2B_AUTH const *authValue) = NULL; + TSS2_RC (*sym_Esys_Unseal)(ESYS_CONTEXT *esysContext, ESYS_TR itemHandle, ESYS_TR shandle1, ESYS_TR shandle2, ESYS_TR shandle3, TPM2B_SENSITIVE_DATA **outData) = NULL; + + const char* (*sym_Tss2_RC_Decode)(TSS2_RC rc) = NULL; +@@ -58,10 +61,12 @@ int dlopen_tpm2(void) { + DLSYM_ARG(Esys_Initialize), + DLSYM_ARG(Esys_Load), + DLSYM_ARG(Esys_PCR_Read), ++ DLSYM_ARG(Esys_PolicyAuthValue), + DLSYM_ARG(Esys_PolicyGetDigest), + DLSYM_ARG(Esys_PolicyPCR), + DLSYM_ARG(Esys_StartAuthSession), + DLSYM_ARG(Esys_Startup), ++ DLSYM_ARG(Esys_TR_SetAuth), + DLSYM_ARG(Esys_Unseal)); + if (r < 0) + return r; +@@ -594,6 +599,7 @@ static int tpm2_make_pcr_session( + ESYS_CONTEXT *c, + uint32_t pcr_mask, + uint16_t pcr_bank, /* If UINT16_MAX, pick best bank automatically, otherwise specify bank explicitly. */ ++ bool use_pin, + ESYS_TR *ret_session, + TPM2B_DIGEST **ret_policy_digest, + TPMI_ALG_HASH *ret_pcr_bank) { +@@ -669,6 +675,21 @@ static int tpm2_make_pcr_session( + goto finish; + } + ++ if (use_pin) { ++ rc = sym_Esys_PolicyAuthValue( ++ c, ++ session, ++ ESYS_TR_NONE, ++ ESYS_TR_NONE, ++ ESYS_TR_NONE); ++ if (rc != TSS2_RC_SUCCESS) { ++ r = log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), ++ "Failed to add authValue policy to TPM: %s", ++ sym_Tss2_RC_Decode(rc)); ++ goto finish; ++ } ++ } ++ + if (DEBUG_LOGGING || ret_policy_digest) { + log_debug("Acquiring policy digest."); + +@@ -717,9 +738,22 @@ finish: + return r; + } + ++static void hash_pin(const char *pin, size_t len, uint8_t ret_digest[static SHA256_DIGEST_SIZE]) { ++ struct sha256_ctx hash; ++ ++ assert(pin); ++ ++ sha256_init_ctx(&hash); ++ sha256_process_bytes(pin, len, &hash); ++ sha256_finish_ctx(&hash, ret_digest); ++ ++ explicit_bzero_safe(&hash, sizeof(hash)); ++} ++ + int tpm2_seal( + const char *device, + uint32_t pcr_mask, ++ const char *pin, + void **ret_secret, + size_t *ret_secret_size, + void **ret_blob, +@@ -782,7 +816,8 @@ int tpm2_seal( + if (r < 0) + return r; + +- r = tpm2_make_pcr_session(c.esys_context, pcr_mask, UINT16_MAX, NULL, &policy_digest, &pcr_bank); ++ r = tpm2_make_pcr_session(c.esys_context, pcr_mask, UINT16_MAX, !!pin, NULL, &policy_digest, ++ &pcr_bank); + if (r < 0) + goto finish; + +@@ -813,6 +848,10 @@ int tpm2_seal( + .size = sizeof(hmac_sensitive.sensitive), + .sensitive.data.size = 32, + }; ++ if (pin) { ++ hash_pin(pin, strlen(pin), hmac_sensitive.sensitive.userAuth.buffer); ++ hmac_sensitive.sensitive.userAuth.size = SHA256_DIGEST_SIZE; ++ } + assert(sizeof(hmac_sensitive.sensitive.data.buffer) >= hmac_sensitive.sensitive.data.size); + + (void) tpm2_credit_random(c.esys_context); +@@ -910,6 +949,7 @@ int tpm2_seal( + r = 0; + + finish: ++ explicit_bzero_safe(&hmac_sensitive, sizeof(hmac_sensitive)); + primary = flush_context_verbose(c.esys_context, primary); + return r; + } +@@ -923,6 +963,7 @@ int tpm2_unseal( + size_t blob_size, + const void *known_policy_hash, + size_t known_policy_hash_size, ++ const char *pin, + void **ret_secret, + size_t *ret_secret_size) { + +@@ -978,7 +1019,7 @@ int tpm2_unseal( + if (r < 0) + return r; + +- r = tpm2_make_pcr_session(c.esys_context, pcr_mask, pcr_bank, &session, &policy_digest, NULL); ++ r = tpm2_make_pcr_session(c.esys_context, pcr_mask, pcr_bank, !!pin, &session, &policy_digest, NULL); + if (r < 0) + goto finish; + +@@ -1005,11 +1046,38 @@ int tpm2_unseal( + &public, + &hmac_key); + if (rc != TSS2_RC_SUCCESS) { +- r = log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), +- "Failed to load HMAC key in TPM: %s", sym_Tss2_RC_Decode(rc)); ++ /* If we're in dictionary attack lockout mode, we should see a lockout error here, which we ++ * need to translate for the caller. */ ++ if (rc == TPM2_RC_LOCKOUT) ++ r = log_error_errno( ++ SYNTHETIC_ERRNO(ENOLCK), ++ "TPM2 device is in dictionary attack lockout mode."); ++ else ++ r = log_error_errno( ++ SYNTHETIC_ERRNO(ENOTRECOVERABLE), ++ "Failed to load HMAC key in TPM: %s", ++ sym_Tss2_RC_Decode(rc)); + goto finish; + } + ++ if (pin) { ++ TPM2B_AUTH auth = { ++ .size = SHA256_DIGEST_SIZE ++ }; ++ ++ hash_pin(pin, strlen(pin), auth.buffer); ++ ++ rc = sym_Esys_TR_SetAuth(c.esys_context, hmac_key, &auth); ++ explicit_bzero_safe(&auth, sizeof(auth)); ++ if (rc != TSS2_RC_SUCCESS) { ++ r = log_error_errno( ++ SYNTHETIC_ERRNO(ENOTRECOVERABLE), ++ "Failed to load PIN in TPM: %s", ++ sym_Tss2_RC_Decode(rc)); ++ goto finish; ++ } ++ } ++ + log_debug("Unsealing HMAC key."); + + rc = sym_Esys_Unseal( +diff --git a/src/shared/tpm2-util.h b/src/shared/tpm2-util.h +index cb57a847e2..784e9fd11e 100644 +--- a/src/shared/tpm2-util.h ++++ b/src/shared/tpm2-util.h +@@ -1,6 +1,8 @@ + /* SPDX-License-Identifier: LGPL-2.1-or-later */ + #pragma once + ++#include ++ + #include "json.h" + #include "macro.h" + +@@ -20,10 +22,12 @@ extern TSS2_RC (*sym_Esys_GetRandom)(ESYS_CONTEXT *esysContext, ESYS_TR shandle1 + extern TSS2_RC (*sym_Esys_Initialize)(ESYS_CONTEXT **esys_context, TSS2_TCTI_CONTEXT *tcti, TSS2_ABI_VERSION *abiVersion); + extern TSS2_RC (*sym_Esys_Load)(ESYS_CONTEXT *esysContext, ESYS_TR parentHandle, ESYS_TR shandle1, ESYS_TR shandle2, ESYS_TR shandle3, const TPM2B_PRIVATE *inPrivate, const TPM2B_PUBLIC *inPublic, ESYS_TR *objectHandle); + extern TSS2_RC (*sym_Esys_PCR_Read)(ESYS_CONTEXT *esysContext, ESYS_TR shandle1,ESYS_TR shandle2, ESYS_TR shandle3, const TPML_PCR_SELECTION *pcrSelectionIn, UINT32 *pcrUpdateCounter, TPML_PCR_SELECTION **pcrSelectionOut, TPML_DIGEST **pcrValues); ++extern TSS2_RC (*sym_Esys_PolicyAuthValue)(ESYS_CONTEXT *esysContext, ESYS_TR policySession, ESYS_TR shandle1, ESYS_TR shandle2, ESYS_TR shandle3); + extern TSS2_RC (*sym_Esys_PolicyGetDigest)(ESYS_CONTEXT *esysContext, ESYS_TR policySession, ESYS_TR shandle1, ESYS_TR shandle2, ESYS_TR shandle3, TPM2B_DIGEST **policyDigest); + extern TSS2_RC (*sym_Esys_PolicyPCR)(ESYS_CONTEXT *esysContext, ESYS_TR policySession, ESYS_TR shandle1, ESYS_TR shandle2, ESYS_TR shandle3, const TPM2B_DIGEST *pcrDigest, const TPML_PCR_SELECTION *pcrs); + extern TSS2_RC (*sym_Esys_StartAuthSession)(ESYS_CONTEXT *esysContext, ESYS_TR tpmKey, ESYS_TR bind, ESYS_TR shandle1, ESYS_TR shandle2, ESYS_TR shandle3, const TPM2B_NONCE *nonceCaller, TPM2_SE sessionType, const TPMT_SYM_DEF *symmetric, TPMI_ALG_HASH authHash, ESYS_TR *sessionHandle); + extern TSS2_RC (*sym_Esys_Startup)(ESYS_CONTEXT *esysContext, TPM2_SU startupType); ++extern TSS2_RC (*sym_Esys_TR_SetAuth)(ESYS_CONTEXT *esysContext, ESYS_TR handle, TPM2B_AUTH const *authValue); + extern TSS2_RC (*sym_Esys_Unseal)(ESYS_CONTEXT *esysContext, ESYS_TR itemHandle, ESYS_TR shandle1, ESYS_TR shandle2, ESYS_TR shandle3, TPM2B_SENSITIVE_DATA **outData); + + extern const char* (*sym_Tss2_RC_Decode)(TSS2_RC rc); +@@ -35,8 +39,8 @@ extern TSS2_RC (*sym_Tss2_MU_TPM2B_PUBLIC_Unmarshal)(uint8_t const buffer[], siz + + int dlopen_tpm2(void); + +-int tpm2_seal(const char *device, uint32_t pcr_mask, void **ret_secret, size_t *ret_secret_size, void **ret_blob, size_t *ret_blob_size, void **ret_pcr_hash, size_t *ret_pcr_hash_size, uint16_t *ret_pcr_bank, uint16_t *ret_primary_alg); +-int tpm2_unseal(const char *device, uint32_t pcr_mask, uint16_t pcr_bank, uint16_t primary_alg, const void *blob, size_t blob_size, const void *pcr_hash, size_t pcr_hash_size, void **ret_secret, size_t *ret_secret_size); ++int tpm2_seal(const char *device, uint32_t pcr_mask, const char *pin, void **ret_secret, size_t *ret_secret_size, void **ret_blob, size_t *ret_blob_size, void **ret_pcr_hash, size_t *ret_pcr_hash_size, uint16_t *ret_pcr_bank, uint16_t *ret_primary_alg); ++int tpm2_unseal(const char *device, uint32_t pcr_mask, uint16_t pcr_bank, uint16_t primary_alg, const void *blob, size_t blob_size, const void *pcr_hash, size_t pcr_hash_size, const char *pin, void **ret_secret, size_t *ret_secret_size); + + #endif + diff --git a/0225-cryptenroll-add-support-for-TPM2-pin.patch b/0225-cryptenroll-add-support-for-TPM2-pin.patch new file mode 100644 index 0000000..4115ec9 --- /dev/null +++ b/0225-cryptenroll-add-support-for-TPM2-pin.patch @@ -0,0 +1,296 @@ +From 9aecba3db5d381dd915e90931c63513141988d92 Mon Sep 17 00:00:00 2001 +From: Grigori Goronzy +Date: Fri, 18 Feb 2022 11:51:25 +0100 +Subject: [PATCH] cryptenroll: add support for TPM2 pin + +Add support for PIN enrollment with TPM2. A new "tpm2-pin" field is +introduced into metadata to signal that the policy needs to include a +PIN. + +v2: fix tpm2_make_luks2_json in sd-repart +(cherry picked from commit 6c7a1681052c37ef354a000355c4c0d676113a1a) + +Related: #2087652 +--- + src/cryptenroll/cryptenroll-tpm2.c | 85 ++++++++++++++++++++++++++++-- + src/cryptenroll/cryptenroll-tpm2.h | 4 +- + src/cryptenroll/cryptenroll.c | 15 +++++- + src/partition/repart.c | 2 +- + src/shared/tpm2-util.c | 5 +- + src/shared/tpm2-util.h | 6 ++- + 6 files changed, 107 insertions(+), 10 deletions(-) + +diff --git a/src/cryptenroll/cryptenroll-tpm2.c b/src/cryptenroll/cryptenroll-tpm2.c +index f5f6b87d0f..e8c64dd753 100644 +--- a/src/cryptenroll/cryptenroll-tpm2.c ++++ b/src/cryptenroll/cryptenroll-tpm2.c +@@ -1,7 +1,9 @@ + /* SPDX-License-Identifier: LGPL-2.1-or-later */ + + #include "alloc-util.h" ++#include "ask-password-api.h" + #include "cryptenroll-tpm2.h" ++#include "env-util.h" + #include "hexdecoct.h" + #include "json.h" + #include "memory-util.h" +@@ -58,11 +60,78 @@ static int search_policy_hash( + return -ENOENT; /* Not found */ + } + ++static int get_pin(char **ret_pin_str, TPM2Flags *ret_flags) { ++ _cleanup_free_ char *pin_str = NULL; ++ int r; ++ TPM2Flags flags = 0; ++ ++ assert(ret_pin_str); ++ assert(ret_flags); ++ ++ r = getenv_steal_erase("NEWPIN", &pin_str); ++ if (r < 0) ++ return log_error_errno(r, "Failed to acquire PIN from environment: %m"); ++ if (r > 0) ++ flags |= TPM2_FLAGS_USE_PIN; ++ else { ++ for (size_t i = 5;; i--) { ++ _cleanup_strv_free_erase_ char **pin = NULL, **pin2 = NULL; ++ ++ if (i <= 0) ++ return log_error_errno( ++ SYNTHETIC_ERRNO(ENOKEY), "Too many attempts, giving up."); ++ ++ pin = strv_free_erase(pin); ++ r = ask_password_auto( ++ "Please enter TPM2 PIN:", ++ "drive-harddisk", ++ NULL, ++ "tpm2-pin", ++ "cryptenroll.tpm2-pin", ++ USEC_INFINITY, ++ 0, ++ &pin); ++ if (r < 0) ++ return log_error_errno(r, "Failed to ask for user pin: %m"); ++ assert(strv_length(pin) == 1); ++ ++ r = ask_password_auto( ++ "Please enter TPM2 PIN (repeat):", ++ "drive-harddisk", ++ NULL, ++ "tpm2-pin", ++ "cryptenroll.tpm2-pin", ++ USEC_INFINITY, ++ 0, ++ &pin2); ++ if (r < 0) ++ return log_error_errno(r, "Failed to ask for user pin: %m"); ++ assert(strv_length(pin) == 1); ++ ++ if (strv_equal(pin, pin2)) { ++ pin_str = strdup(*pin); ++ if (!pin_str) ++ return log_oom(); ++ flags |= TPM2_FLAGS_USE_PIN; ++ break; ++ } ++ ++ log_error("PINs didn't match, please try again!"); ++ } ++ } ++ ++ *ret_flags = flags; ++ *ret_pin_str = TAKE_PTR(pin_str); ++ ++ return 0; ++} ++ + int enroll_tpm2(struct crypt_device *cd, + const void *volume_key, + size_t volume_key_size, + const char *device, +- uint32_t pcr_mask) { ++ uint32_t pcr_mask, ++ bool use_pin) { + + _cleanup_(erase_and_freep) void *secret = NULL, *secret2 = NULL; + _cleanup_(json_variant_unrefp) JsonVariant *v = NULL; +@@ -71,7 +140,9 @@ int enroll_tpm2(struct crypt_device *cd, + _cleanup_free_ void *blob = NULL, *hash = NULL; + uint16_t pcr_bank, primary_alg; + const char *node; ++ _cleanup_(erase_and_freep) char *pin_str = NULL; + int r, keyslot; ++ TPM2Flags flags = 0; + + assert(cd); + assert(volume_key); +@@ -80,7 +151,13 @@ int enroll_tpm2(struct crypt_device *cd, + + assert_se(node = crypt_get_device_name(cd)); + +- r = tpm2_seal(device, pcr_mask, NULL, &secret, &secret_size, &blob, &blob_size, &hash, &hash_size, &pcr_bank, &primary_alg); ++ if (use_pin) { ++ r = get_pin(&pin_str, &flags); ++ if (r < 0) ++ return r; ++ } ++ ++ r = tpm2_seal(device, pcr_mask, pin_str, &secret, &secret_size, &blob, &blob_size, &hash, &hash_size, &pcr_bank, &primary_alg); + if (r < 0) + return r; + +@@ -97,7 +174,7 @@ int enroll_tpm2(struct crypt_device *cd, + + /* Quick verification that everything is in order, we are not in a hurry after all. */ + log_debug("Unsealing for verification..."); +- r = tpm2_unseal(device, pcr_mask, pcr_bank, primary_alg, blob, blob_size, hash, hash_size, NULL, &secret2, &secret2_size); ++ r = tpm2_unseal(device, pcr_mask, pcr_bank, primary_alg, blob, blob_size, hash, hash_size, pin_str, &secret2, &secret2_size); + if (r < 0) + return r; + +@@ -123,7 +200,7 @@ int enroll_tpm2(struct crypt_device *cd, + if (keyslot < 0) + return log_error_errno(keyslot, "Failed to add new TPM2 key to %s: %m", node); + +- r = tpm2_make_luks2_json(keyslot, pcr_mask, pcr_bank, primary_alg, blob, blob_size, hash, hash_size, &v); ++ r = tpm2_make_luks2_json(keyslot, pcr_mask, pcr_bank, primary_alg, blob, blob_size, hash, hash_size, flags, &v); + if (r < 0) + return log_error_errno(r, "Failed to prepare TPM2 JSON token object: %m"); + +diff --git a/src/cryptenroll/cryptenroll-tpm2.h b/src/cryptenroll/cryptenroll-tpm2.h +index d5dd1b0003..742f49b8d5 100644 +--- a/src/cryptenroll/cryptenroll-tpm2.h ++++ b/src/cryptenroll/cryptenroll-tpm2.h +@@ -7,9 +7,9 @@ + #include "log.h" + + #if HAVE_TPM2 +-int enroll_tpm2(struct crypt_device *cd, const void *volume_key, size_t volume_key_size, const char *device, uint32_t pcr_mask); ++int enroll_tpm2(struct crypt_device *cd, const void *volume_key, size_t volume_key_size, const char *device, uint32_t pcr_mask, bool use_pin); + #else +-static inline int enroll_tpm2(struct crypt_device *cd, const void *volume_key, size_t volume_key_size, const char *device, uint32_t pcr_mask) { ++static inline int enroll_tpm2(struct crypt_device *cd, const void *volume_key, size_t volume_key_size, const char *device, uint32_t pcr_mask, bool use_pin) { + return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), + "TPM2 key enrollment not supported."); + } +diff --git a/src/cryptenroll/cryptenroll.c b/src/cryptenroll/cryptenroll.c +index 7f397f197f..ed19f3f8f4 100644 +--- a/src/cryptenroll/cryptenroll.c ++++ b/src/cryptenroll/cryptenroll.c +@@ -32,6 +32,7 @@ static char *arg_pkcs11_token_uri = NULL; + static char *arg_fido2_device = NULL; + static char *arg_tpm2_device = NULL; + static uint32_t arg_tpm2_pcr_mask = UINT32_MAX; ++static bool arg_tpm2_pin = false; + static char *arg_node = NULL; + static int *arg_wipe_slots = NULL; + static size_t arg_n_wipe_slots = 0; +@@ -100,6 +101,8 @@ static int help(void) { + " Enroll a TPM2 device\n" + " --tpm2-pcrs=PCR1+PCR2+PCR3+…\n" + " Specify TPM2 PCRs to seal against\n" ++ " --tpm2-with-pin=BOOL\n" ++ " Whether to require entering a PIN to unlock the volume\n" + " --wipe-slot=SLOT1,SLOT2,…\n" + " Wipe specified slots\n" + "\nSee the %s for details.\n", +@@ -121,6 +124,7 @@ static int parse_argv(int argc, char *argv[]) { + ARG_FIDO2_DEVICE, + ARG_TPM2_DEVICE, + ARG_TPM2_PCRS, ++ ARG_TPM2_PIN, + ARG_WIPE_SLOT, + ARG_FIDO2_WITH_PIN, + ARG_FIDO2_WITH_UP, +@@ -139,6 +143,7 @@ static int parse_argv(int argc, char *argv[]) { + { "fido2-with-user-verification", required_argument, NULL, ARG_FIDO2_WITH_UV }, + { "tpm2-device", required_argument, NULL, ARG_TPM2_DEVICE }, + { "tpm2-pcrs", required_argument, NULL, ARG_TPM2_PCRS }, ++ { "tpm2-with-pin", required_argument, NULL, ARG_TPM2_PIN }, + { "wipe-slot", required_argument, NULL, ARG_WIPE_SLOT }, + {} + }; +@@ -301,6 +306,14 @@ static int parse_argv(int argc, char *argv[]) { + break; + } + ++ case ARG_TPM2_PIN: { ++ r = parse_boolean_argument("--tpm2-with-pin=", optarg, &arg_tpm2_pin); ++ if (r < 0) ++ return r; ++ ++ break; ++ } ++ + case ARG_WIPE_SLOT: { + const char *p = optarg; + +@@ -563,7 +576,7 @@ static int run(int argc, char *argv[]) { + break; + + case ENROLL_TPM2: +- slot = enroll_tpm2(cd, vk, vks, arg_tpm2_device, arg_tpm2_pcr_mask); ++ slot = enroll_tpm2(cd, vk, vks, arg_tpm2_device, arg_tpm2_pcr_mask, arg_tpm2_pin); + break; + + case _ENROLL_TYPE_INVALID: +diff --git a/src/partition/repart.c b/src/partition/repart.c +index adfec0b9f3..67e379be55 100644 +--- a/src/partition/repart.c ++++ b/src/partition/repart.c +@@ -2677,7 +2677,7 @@ static int partition_encrypt( + if (keyslot < 0) + return log_error_errno(keyslot, "Failed to add new TPM2 key to %s: %m", node); + +- r = tpm2_make_luks2_json(keyslot, arg_tpm2_pcr_mask, pcr_bank, primary_alg, blob, blob_size, hash, hash_size, &v); ++ r = tpm2_make_luks2_json(keyslot, arg_tpm2_pcr_mask, pcr_bank, primary_alg, blob, blob_size, hash, hash_size, 0, &v); + if (r < 0) + return log_error_errno(r, "Failed to prepare TPM2 JSON token object: %m"); + +diff --git a/src/shared/tpm2-util.c b/src/shared/tpm2-util.c +index aca7b69ab5..44fe899acd 100644 +--- a/src/shared/tpm2-util.c ++++ b/src/shared/tpm2-util.c +@@ -1291,6 +1291,7 @@ int tpm2_make_luks2_json( + size_t blob_size, + const void *policy_hash, + size_t policy_hash_size, ++ TPM2Flags flags, + JsonVariant **ret) { + + _cleanup_(json_variant_unrefp) JsonVariant *v = NULL, *a = NULL; +@@ -1331,7 +1332,9 @@ int tpm2_make_luks2_json( + JSON_BUILD_PAIR("tpm2-pcrs", JSON_BUILD_VARIANT(a)), + JSON_BUILD_PAIR_CONDITION(!!tpm2_pcr_bank_to_string(pcr_bank), "tpm2-pcr-bank", JSON_BUILD_STRING(tpm2_pcr_bank_to_string(pcr_bank))), + JSON_BUILD_PAIR_CONDITION(!!tpm2_primary_alg_to_string(primary_alg), "tpm2-primary-alg", JSON_BUILD_STRING(tpm2_primary_alg_to_string(primary_alg))), +- JSON_BUILD_PAIR("tpm2-policy-hash", JSON_BUILD_HEX(policy_hash, policy_hash_size)))); ++ JSON_BUILD_PAIR("tpm2-policy-hash", JSON_BUILD_HEX(policy_hash, policy_hash_size)), ++ JSON_BUILD_PAIR("tpm2-pin", JSON_BUILD_BOOLEAN(flags & TPM2_FLAGS_USE_PIN))) ++ ); + if (r < 0) + return r; + +diff --git a/src/shared/tpm2-util.h b/src/shared/tpm2-util.h +index 784e9fd11e..5a9bcf8c24 100644 +--- a/src/shared/tpm2-util.h ++++ b/src/shared/tpm2-util.h +@@ -6,6 +6,10 @@ + #include "json.h" + #include "macro.h" + ++typedef enum TPM2Flags { ++ TPM2_FLAGS_USE_PIN = 1 << 0, ++} TPM2Flags; ++ + #if HAVE_TPM2 + + #include +@@ -49,7 +53,7 @@ int tpm2_find_device_auto(int log_level, char **ret); + + int tpm2_parse_pcrs(const char *s, uint32_t *ret); + +-int tpm2_make_luks2_json(int keyslot, uint32_t pcr_mask, uint16_t pcr_bank, uint16_t primary_alg, const void *blob, size_t blob_size, const void *policy_hash, size_t policy_hash_size, JsonVariant **ret); ++int tpm2_make_luks2_json(int keyslot, uint32_t pcr_mask, uint16_t pcr_bank, uint16_t primary_alg, const void *blob, size_t blob_size, const void *policy_hash, size_t policy_hash_size, TPM2Flags flags, JsonVariant **ret); + + #define TPM2_PCRS_MAX 24 + diff --git a/0226-cryptsetup-add-support-for-TPM2-pin.patch b/0226-cryptsetup-add-support-for-TPM2-pin.patch new file mode 100644 index 0000000..94a7c3c --- /dev/null +++ b/0226-cryptsetup-add-support-for-TPM2-pin.patch @@ -0,0 +1,292 @@ +From 2418e9c1409ba04ddff516a83d83b2daa3417832 Mon Sep 17 00:00:00 2001 +From: Grigori Goronzy +Date: Fri, 18 Feb 2022 11:56:02 +0100 +Subject: [PATCH] cryptsetup: add support for TPM2 pin + +Extend cryptsetup for TPM2 pin entry, similar to FIDO2. + +(cherry picked from commit bea344a1a426e615ba87b66b6d3ff4b265c57a95) + +Related: #2087652 +--- + src/cryptsetup/cryptsetup-tpm2.c | 108 ++++++++++++++++++++++++++++++- + src/cryptsetup/cryptsetup-tpm2.h | 16 ++++- + src/cryptsetup/cryptsetup.c | 16 ++++- + 3 files changed, 135 insertions(+), 5 deletions(-) + +diff --git a/src/cryptsetup/cryptsetup-tpm2.c b/src/cryptsetup/cryptsetup-tpm2.c +index 05d76a684d..b84d64def8 100644 +--- a/src/cryptsetup/cryptsetup-tpm2.c ++++ b/src/cryptsetup/cryptsetup-tpm2.c +@@ -1,7 +1,9 @@ + /* SPDX-License-Identifier: LGPL-2.1-or-later */ + + #include "alloc-util.h" ++#include "ask-password-api.h" + #include "cryptsetup-tpm2.h" ++#include "env-util.h" + #include "fileio.h" + #include "hexdecoct.h" + #include "json.h" +@@ -9,6 +11,47 @@ + #include "random-util.h" + #include "tpm2-util.h" + ++static int get_pin(usec_t until, AskPasswordFlags ask_password_flags, bool headless, char **ret_pin_str) { ++ _cleanup_free_ char *pin_str = NULL; ++ _cleanup_strv_free_erase_ char **pin = NULL; ++ int r; ++ ++ assert(ret_pin_str); ++ ++ r = getenv_steal_erase("PIN", &pin_str); ++ if (r < 0) ++ return log_error_errno(r, "Failed to acquire PIN from environment: %m"); ++ if (!r) { ++ if (headless) ++ return log_error_errno( ++ SYNTHETIC_ERRNO(ENOPKG), ++ "PIN querying disabled via 'headless' option. " ++ "Use the '$PIN' environment variable."); ++ ++ pin = strv_free_erase(pin); ++ r = ask_password_auto( ++ "Please enter TPM2 PIN:", ++ "drive-harddisk", ++ NULL, ++ "tpm2-pin", ++ "cryptsetup.tpm2-pin", ++ until, ++ ask_password_flags, ++ &pin); ++ if (r < 0) ++ return log_error_errno(r, "Failed to ask for user pin: %m"); ++ assert(strv_length(pin) == 1); ++ ++ pin_str = strdup(pin[0]); ++ if (!pin_str) ++ return log_oom(); ++ } ++ ++ *ret_pin_str = TAKE_PTR(pin_str); ++ ++ return r; ++} ++ + int acquire_tpm2_key( + const char *volume_name, + const char *device, +@@ -22,6 +65,10 @@ int acquire_tpm2_key( + size_t key_data_size, + const void *policy_hash, + size_t policy_hash_size, ++ TPM2Flags flags, ++ usec_t until, ++ bool headless, ++ AskPasswordFlags ask_password_flags, + void **ret_decrypted_key, + size_t *ret_decrypted_key_size) { + +@@ -64,7 +111,51 @@ int acquire_tpm2_key( + blob = loaded_blob; + } + +- return tpm2_unseal(device, pcr_mask, pcr_bank, primary_alg, blob, blob_size, policy_hash, policy_hash_size, NULL, ret_decrypted_key, ret_decrypted_key_size); ++ if (!(flags & TPM2_FLAGS_USE_PIN)) ++ return tpm2_unseal( ++ device, ++ pcr_mask, ++ pcr_bank, ++ primary_alg, ++ blob, ++ blob_size, ++ policy_hash, ++ policy_hash_size, ++ NULL, ++ ret_decrypted_key, ++ ret_decrypted_key_size); ++ ++ for (int i = 5;; i--) { ++ _cleanup_(erase_and_freep) char *pin_str = NULL; ++ ++ if (i <= 0) ++ return -EACCES; ++ ++ r = get_pin(until, ask_password_flags, headless, &pin_str); ++ if (r < 0) ++ return r; ++ ++ r = tpm2_unseal( ++ device, ++ pcr_mask, ++ pcr_bank, ++ primary_alg, ++ blob, ++ blob_size, ++ policy_hash, ++ policy_hash_size, ++ pin_str, ++ ret_decrypted_key, ++ ret_decrypted_key_size); ++ /* We get this error in case there is an authentication policy mismatch. This should ++ * not happen, but this avoids confusing behavior, just in case. */ ++ if (IN_SET(r, -EPERM, -ENOLCK)) ++ return r; ++ if (r < 0) ++ continue; ++ ++ return r; ++ } + } + + int find_tpm2_auto_data( +@@ -79,11 +170,13 @@ int find_tpm2_auto_data( + void **ret_policy_hash, + size_t *ret_policy_hash_size, + int *ret_keyslot, +- int *ret_token) { ++ int *ret_token, ++ TPM2Flags *ret_flags) { + + _cleanup_free_ void *blob = NULL, *policy_hash = NULL; + size_t blob_size = 0, policy_hash_size = 0; + int r, keyslot = -1, token = -1; ++ TPM2Flags flags = 0; + uint32_t pcr_mask = 0; + uint16_t pcr_bank = UINT16_MAX; /* default: pick automatically */ + uint16_t primary_alg = TPM2_ALG_ECC; /* ECC was the only supported algorithm in systemd < 250, use that as implied default, for compatibility */ +@@ -196,6 +289,16 @@ int find_tpm2_auto_data( + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), + "Invalid base64 data in 'tpm2-policy-hash' field."); + ++ w = json_variant_by_key(v, "tpm2-pin"); ++ if (w) { ++ if (!json_variant_is_boolean(w)) ++ return log_error_errno(SYNTHETIC_ERRNO(EINVAL), ++ "TPM2 PIN policy is not a boolean."); ++ ++ if (json_variant_boolean(w)) ++ flags |= TPM2_FLAGS_USE_PIN; ++ } ++ + break; + } + +@@ -215,6 +318,7 @@ int find_tpm2_auto_data( + *ret_token = token; + *ret_pcr_bank = pcr_bank; + *ret_primary_alg = primary_alg; ++ *ret_flags = flags; + + return 0; + } +diff --git a/src/cryptsetup/cryptsetup-tpm2.h b/src/cryptsetup/cryptsetup-tpm2.h +index bd04620462..ab16d0a18f 100644 +--- a/src/cryptsetup/cryptsetup-tpm2.h ++++ b/src/cryptsetup/cryptsetup-tpm2.h +@@ -3,9 +3,11 @@ + + #include + ++#include "ask-password-api.h" + #include "cryptsetup-util.h" + #include "log.h" + #include "time-util.h" ++#include "tpm2-util.h" + + #if HAVE_TPM2 + +@@ -22,6 +24,10 @@ int acquire_tpm2_key( + size_t key_data_size, + const void *policy_hash, + size_t policy_hash_size, ++ TPM2Flags flags, ++ usec_t until, ++ bool headless, ++ AskPasswordFlags ask_password_flags, + void **ret_decrypted_key, + size_t *ret_decrypted_key_size); + +@@ -37,7 +43,8 @@ int find_tpm2_auto_data( + void **ret_policy_hash, + size_t *ret_policy_hash_size, + int *ret_keyslot, +- int *ret_token); ++ int *ret_token, ++ TPM2Flags *ret_flags); + + #else + +@@ -54,6 +61,10 @@ static inline int acquire_tpm2_key( + size_t key_data_size, + const void *policy_hash, + size_t policy_hash_size, ++ TPM2Flags flags, ++ usec_t until, ++ bool headless, ++ AskPasswordFlags ask_password_flags, + void **ret_decrypted_key, + size_t *ret_decrypted_key_size) { + +@@ -73,7 +84,8 @@ static inline int find_tpm2_auto_data( + void **ret_policy_hash, + size_t *ret_policy_hash_size, + int *ret_keyslot, +- int *ret_token) { ++ int *ret_token, ++ TPM2Flags *ret_flags) { + + return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), + "TPM2 support not available."); +diff --git a/src/cryptsetup/cryptsetup.c b/src/cryptsetup/cryptsetup.c +index dddd976dc8..ede0f7ed0b 100644 +--- a/src/cryptsetup/cryptsetup.c ++++ b/src/cryptsetup/cryptsetup.c +@@ -1301,9 +1301,15 @@ static int attach_luks_or_plain_or_bitlk_by_tpm2( + key_file, arg_keyfile_size, arg_keyfile_offset, + key_data, key_data_size, + NULL, 0, /* we don't know the policy hash */ ++ 0, /* PIN is currently unhandled in this case */ ++ until, ++ arg_headless, ++ arg_ask_password_flags, + &decrypted_key, &decrypted_key_size); + if (r >= 0) + break; ++ if (IN_SET(r, -EACCES, -ENOLCK)) ++ return log_error_errno(SYNTHETIC_ERRNO(EAGAIN), "TPM2 PIN unlock failed, falling back to traditional unlocking."); + if (ERRNO_IS_NOT_SUPPORTED(r)) /* TPM2 support not compiled in? */ + return log_debug_errno(SYNTHETIC_ERRNO(EAGAIN), "TPM2 support not available, falling back to traditional unlocking."); + if (r != -EAGAIN) /* EAGAIN means: no tpm2 chip found */ +@@ -1335,6 +1341,7 @@ static int attach_luks_or_plain_or_bitlk_by_tpm2( + for (;;) { + uint32_t pcr_mask; + uint16_t pcr_bank, primary_alg; ++ TPM2Flags tpm2_flags; + + r = find_tpm2_auto_data( + cd, +@@ -1346,7 +1353,8 @@ static int attach_luks_or_plain_or_bitlk_by_tpm2( + &blob, &blob_size, + &policy_hash, &policy_hash_size, + &keyslot, +- &token); ++ &token, ++ &tpm2_flags); + if (r == -ENXIO) + /* No further TPM2 tokens found in the LUKS2 header. */ + return log_debug_errno(SYNTHETIC_ERRNO(EAGAIN), +@@ -1369,7 +1377,13 @@ static int attach_luks_or_plain_or_bitlk_by_tpm2( + NULL, 0, 0, /* no key file */ + blob, blob_size, + policy_hash, policy_hash_size, ++ tpm2_flags, ++ until, ++ arg_headless, ++ arg_ask_password_flags, + &decrypted_key, &decrypted_key_size); ++ if (IN_SET(r, -EACCES, -ENOLCK)) ++ return log_error_errno(SYNTHETIC_ERRNO(EAGAIN), "TPM2 PIN unlock failed, falling back to traditional unlocking."); + if (r != -EPERM) + break; + diff --git a/0227-cryptsetup-add-libcryptsetup-TPM2-PIN-support.patch b/0227-cryptsetup-add-libcryptsetup-TPM2-PIN-support.patch new file mode 100644 index 0000000..4ac80fe --- /dev/null +++ b/0227-cryptsetup-add-libcryptsetup-TPM2-PIN-support.patch @@ -0,0 +1,218 @@ +From 1b7d251ab836ba703913eda149f05bd03559c483 Mon Sep 17 00:00:00 2001 +From: Grigori Goronzy +Date: Fri, 18 Feb 2022 12:00:12 +0100 +Subject: [PATCH] cryptsetup: add libcryptsetup TPM2 PIN support + +This is unfinished: we don't have any way to actually query for PINs +interactively this way. It is similar to FIDO2 and PKCS#11 in this +regard. + +Nonetheless, this code is capable of validating and dumping tokens, so +it is already useful as-is. + +(cherry picked from commit 1f895adac287b5f1b6b854caa586093616ccc172) + +Related: #2087652 +--- + .../cryptsetup-token-systemd-tpm2.c | 18 +++++++++-- + src/cryptsetup/cryptsetup-tokens/luks2-tpm2.c | 32 +++++++++++++++++-- + src/cryptsetup/cryptsetup-tokens/luks2-tpm2.h | 6 +++- + 3 files changed, 51 insertions(+), 5 deletions(-) + +diff --git a/src/cryptsetup/cryptsetup-tokens/cryptsetup-token-systemd-tpm2.c b/src/cryptsetup/cryptsetup-tokens/cryptsetup-token-systemd-tpm2.c +index e2d28a5dda..23df974999 100644 +--- a/src/cryptsetup/cryptsetup-tokens/cryptsetup-token-systemd-tpm2.c ++++ b/src/cryptsetup/cryptsetup-tokens/cryptsetup-token-systemd-tpm2.c +@@ -6,8 +6,10 @@ + #include "cryptsetup-token.h" + #include "cryptsetup-token-util.h" + #include "hexdecoct.h" ++#include "json.h" + #include "luks2-tpm2.h" + #include "memory-util.h" ++#include "strv.h" + #include "tpm2-util.h" + #include "version.h" + +@@ -78,7 +80,8 @@ _public_ int cryptsetup_token_open( + if (usrptr) + params = *(systemd_tpm2_plugin_params *)usrptr; + +- r = parse_luks2_tpm2_data(json, params.search_pcr_mask, &pcr_mask, &pcr_bank, &primary_alg, &base64_blob, &hex_policy_hash); ++ TPM2Flags flags = 0; ++ r = parse_luks2_tpm2_data(json, params.search_pcr_mask, &pcr_mask, &pcr_bank, &primary_alg, &base64_blob, &hex_policy_hash, &flags); + if (r < 0) + return log_debug_open_error(cd, r); + +@@ -101,6 +104,7 @@ _public_ int cryptsetup_token_open( + blob_size, + policy_hash, + policy_hash_size, ++ flags, + &decrypted_key, + &decrypted_key_size); + if (r < 0) +@@ -135,6 +139,7 @@ _public_ void cryptsetup_token_dump( + const char *json /* validated 'systemd-tpm2' token if cryptsetup_token_validate is defined */) { + + int r; ++ TPM2Flags flags = 0; + uint32_t pcr_mask; + uint16_t pcr_bank, primary_alg; + size_t decoded_blob_size; +@@ -144,7 +149,7 @@ _public_ void cryptsetup_token_dump( + + assert(json); + +- r = parse_luks2_tpm2_data(json, UINT32_MAX, &pcr_mask, &pcr_bank, &primary_alg, &base64_blob, &hex_policy_hash); ++ r = parse_luks2_tpm2_data(json, UINT32_MAX, &pcr_mask, &pcr_bank, &primary_alg, &base64_blob, &hex_policy_hash, &flags); + if (r < 0) + return (void) crypt_log_debug_errno(cd, r, "Failed to parse " TOKEN_NAME " metadata: %m."); + +@@ -171,6 +176,7 @@ _public_ void cryptsetup_token_dump( + crypt_log(cd, "\ttpm2-primary-alg: %s\n", strna(tpm2_primary_alg_to_string(primary_alg))); + crypt_log(cd, "\ttpm2-blob: %s\n", blob_str); + crypt_log(cd, "\ttpm2-policy-hash:" CRYPT_DUMP_LINE_SEP "%s\n", policy_hash_str); ++ crypt_log(cd, "\ttpm2-pin: %s\n", true_false(flags & TPM2_FLAGS_USE_PIN)); + } + + /* +@@ -268,5 +274,13 @@ _public_ int cryptsetup_token_validate( + if (r < 0) + return crypt_log_debug_errno(cd, r, "Invalid base64 data in 'tpm2-policy-hash' field: %m"); + ++ w = json_variant_by_key(v, "tpm2-pin"); ++ if (w) { ++ if (!json_variant_is_boolean(w)) { ++ crypt_log_debug(cd, "TPM2 PIN policy is not a boolean."); ++ return 1; ++ } ++ } ++ + return 0; + } +diff --git a/src/cryptsetup/cryptsetup-tokens/luks2-tpm2.c b/src/cryptsetup/cryptsetup-tokens/luks2-tpm2.c +index de189c7bed..0d6e4bc0f8 100644 +--- a/src/cryptsetup/cryptsetup-tokens/luks2-tpm2.c ++++ b/src/cryptsetup/cryptsetup-tokens/luks2-tpm2.c +@@ -1,11 +1,15 @@ + /* SPDX-License-Identifier: LGPL-2.1-or-later */ + + #include "alloc-util.h" ++#include "ask-password-api.h" ++#include "env-util.h" + #include "hexdecoct.h" + #include "json.h" ++#include "log.h" + #include "luks2-tpm2.h" + #include "parse-util.h" + #include "random-util.h" ++#include "strv.h" + #include "tpm2-util.h" + + int acquire_luks2_key( +@@ -17,10 +21,12 @@ int acquire_luks2_key( + size_t key_data_size, + const void *policy_hash, + size_t policy_hash_size, ++ TPM2Flags flags, + void **ret_decrypted_key, + size_t *ret_decrypted_key_size) { + + _cleanup_free_ char *auto_device = NULL; ++ _cleanup_(erase_and_freep) char *pin_str = NULL; + int r; + + assert(ret_decrypted_key); +@@ -36,12 +42,22 @@ int acquire_luks2_key( + device = auto_device; + } + ++ r = getenv_steal_erase("PIN", &pin_str); ++ if (r < 0) ++ return log_error_errno(r, "Failed to acquire PIN from environment: %m"); ++ if (!r) { ++ /* PIN entry is not supported by plugin, let it fallback, possibly to sd-cryptsetup's ++ * internal handling. */ ++ if (flags & TPM2_FLAGS_USE_PIN) ++ return -EOPNOTSUPP; ++ } ++ + return tpm2_unseal( + device, + pcr_mask, pcr_bank, + primary_alg, + key_data, key_data_size, +- policy_hash, policy_hash_size, NULL, ++ policy_hash, policy_hash_size, pin_str, + ret_decrypted_key, ret_decrypted_key_size); + } + +@@ -53,7 +69,8 @@ int parse_luks2_tpm2_data( + uint16_t *ret_pcr_bank, + uint16_t *ret_primary_alg, + char **ret_base64_blob, +- char **ret_hex_policy_hash) { ++ char **ret_hex_policy_hash, ++ TPM2Flags *ret_flags) { + + int r; + JsonVariant *w, *e; +@@ -61,6 +78,7 @@ int parse_luks2_tpm2_data( + uint16_t pcr_bank = UINT16_MAX, primary_alg = TPM2_ALG_ECC; + _cleanup_free_ char *base64_blob = NULL, *hex_policy_hash = NULL; + _cleanup_(json_variant_unrefp) JsonVariant *v = NULL; ++ TPM2Flags flags = 0; + + assert(json); + assert(ret_pcr_mask); +@@ -138,11 +156,21 @@ int parse_luks2_tpm2_data( + if (!hex_policy_hash) + return -ENOMEM; + ++ w = json_variant_by_key(v, "tpm2-pin"); ++ if (w) { ++ if (!json_variant_is_boolean(w)) ++ return -EINVAL; ++ ++ if (json_variant_boolean(w)) ++ flags |= TPM2_FLAGS_USE_PIN; ++ } ++ + *ret_pcr_mask = pcr_mask; + *ret_pcr_bank = pcr_bank; + *ret_primary_alg = primary_alg; + *ret_base64_blob = TAKE_PTR(base64_blob); + *ret_hex_policy_hash = TAKE_PTR(hex_policy_hash); ++ *ret_flags = flags; + + return 0; + } +diff --git a/src/cryptsetup/cryptsetup-tokens/luks2-tpm2.h b/src/cryptsetup/cryptsetup-tokens/luks2-tpm2.h +index 0c93ea82cc..34c93216ee 100644 +--- a/src/cryptsetup/cryptsetup-tokens/luks2-tpm2.h ++++ b/src/cryptsetup/cryptsetup-tokens/luks2-tpm2.h +@@ -2,6 +2,8 @@ + + #pragma once + ++#include "tpm2-util.h" ++ + struct crypt_device; + + int acquire_luks2_key( +@@ -13,6 +15,7 @@ int acquire_luks2_key( + size_t key_data_size, + const void *policy_hash, + size_t policy_hash_size, ++ TPM2Flags flags, + void **ret_decrypted_key, + size_t *ret_decrypted_key_size); + +@@ -23,4 +26,5 @@ int parse_luks2_tpm2_data( + uint16_t *ret_pcr_bank, + uint16_t *ret_primary_alg, + char **ret_base64_blob, +- char **ret_hex_policy_hash); ++ char **ret_hex_policy_hash, ++ TPM2Flags *ret_flags); diff --git a/0228-cryptenroll-add-TPM2-PIN-documentation.patch b/0228-cryptenroll-add-TPM2-PIN-documentation.patch new file mode 100644 index 0000000..6490007 --- /dev/null +++ b/0228-cryptenroll-add-TPM2-PIN-documentation.patch @@ -0,0 +1,41 @@ +From ae4da9f80eb84469b0fbb3e02bfe95751d4513dd Mon Sep 17 00:00:00 2001 +From: Grigori Goronzy +Date: Fri, 18 Feb 2022 12:51:00 +0100 +Subject: [PATCH] cryptenroll: add TPM2 PIN documentation + +(cherry picked from commit caeb5604f9fd8e7aa43c7a1c853f8a7597240b17) + +Related: #2087652 +--- + man/systemd-cryptenroll.xml | 18 ++++++++++++++++++ + 1 file changed, 18 insertions(+) + +diff --git a/man/systemd-cryptenroll.xml b/man/systemd-cryptenroll.xml +index d5fdb54cdd..58a4626768 100644 +--- a/man/systemd-cryptenroll.xml ++++ b/man/systemd-cryptenroll.xml +@@ -299,6 +299,24 @@ + signatures likely will validate against pre-existing certificates. + + ++ ++ BOOL ++ ++ When enrolling a TPM2 device, controls whether to require the user to enter a PIN ++ when unlocking the volume in addition to PCR binding, based on TPM2 policy authentication. Defaults ++ to no. Despite being called PIN, any character can be used, not just numbers. ++ ++ ++ Note that incorrect PIN entry when unlocking increments the ++ TPM dictionary attack lockout mechanism, and may lock out users for a prolonged time, depending on ++ its configuration. The lockout mechanism is a global property of the TPM, ++ systemd-cryptenroll does not control or configure the lockout mechanism. You may ++ use tpm2-tss tools to inspect or configure the dictionary attack lockout, with ++ tpm2_getcap1 and ++ tpm2_dictionarylockout1 ++ commands, respectively. ++ ++ + + SLOT + diff --git a/0229-cryptsetup-add-manual-TPM2-PIN-configuration.patch b/0229-cryptsetup-add-manual-TPM2-PIN-configuration.patch new file mode 100644 index 0000000..536fbc8 --- /dev/null +++ b/0229-cryptsetup-add-manual-TPM2-PIN-configuration.patch @@ -0,0 +1,74 @@ +From d3615420322bf3c9666fe5580317ed0aec20fe62 Mon Sep 17 00:00:00 2001 +From: Grigori Goronzy +Date: Fri, 18 Feb 2022 21:13:41 +0100 +Subject: [PATCH] cryptsetup: add manual TPM2 PIN configuration + +Handle the case where TPM2 metadata is not available and explicitly +provided in crypttab. This adds a new "tpm2-pin" option to crypttab +options for this purpose. + +(cherry picked from commit 4005d41ef0d007021deb0536800fc782ff670420) + +Related: #2087652 +--- + man/crypttab.xml | 8 ++++++++ + src/cryptsetup/cryptsetup.c | 13 ++++++++++++- + 2 files changed, 20 insertions(+), 1 deletion(-) + +diff --git a/man/crypttab.xml b/man/crypttab.xml +index ac5c6ef666..22411166a8 100644 +--- a/man/crypttab.xml ++++ b/man/crypttab.xml +@@ -677,6 +677,14 @@ + of the current PCR state. + + ++ ++ ++ ++ Takes a boolean argument, defaults to false. Controls whether ++ TPM2 volume unlocking is bound to a PIN in addition to PCRs. Similarly, this option is only useful ++ when TPM2 enrollment metadata is not available. ++ ++ + + + +diff --git a/src/cryptsetup/cryptsetup.c b/src/cryptsetup/cryptsetup.c +index ede0f7ed0b..fc1f37730f 100644 +--- a/src/cryptsetup/cryptsetup.c ++++ b/src/cryptsetup/cryptsetup.c +@@ -82,6 +82,7 @@ static char *arg_fido2_rp_id = NULL; + static char *arg_tpm2_device = NULL; + static bool arg_tpm2_device_auto = false; + static uint32_t arg_tpm2_pcr_mask = UINT32_MAX; ++static bool arg_tpm2_pin = false; + static bool arg_headless = false; + static usec_t arg_token_timeout_usec = 30*USEC_PER_SEC; + +@@ -387,6 +388,16 @@ static int parse_one_option(const char *option) { + arg_tpm2_pcr_mask |= mask; + } + ++ } else if ((val = startswith(option, "tpm2-pin="))) { ++ ++ r = parse_boolean(val); ++ if (r < 0) { ++ log_error_errno(r, "Failed to parse %s, ignoring: %m", option); ++ return 0; ++ } ++ ++ arg_tpm2_pin = r; ++ + } else if ((val = startswith(option, "try-empty-password="))) { + + r = parse_boolean(val); +@@ -1301,7 +1312,7 @@ static int attach_luks_or_plain_or_bitlk_by_tpm2( + key_file, arg_keyfile_size, arg_keyfile_offset, + key_data, key_data_size, + NULL, 0, /* we don't know the policy hash */ +- 0, /* PIN is currently unhandled in this case */ ++ arg_tpm2_pin, + until, + arg_headless, + arg_ask_password_flags, diff --git a/0230-cryptenroll-add-tests-for-TPM2-unlocking.patch b/0230-cryptenroll-add-tests-for-TPM2-unlocking.patch new file mode 100644 index 0000000..9e73f69 --- /dev/null +++ b/0230-cryptenroll-add-tests-for-TPM2-unlocking.patch @@ -0,0 +1,166 @@ +From 6a31abd9fdfe9b08c169b315dd3bc18abbe200b0 Mon Sep 17 00:00:00 2001 +From: Grigori Goronzy +Date: Thu, 24 Feb 2022 01:28:29 +0100 +Subject: [PATCH] cryptenroll: add tests for TPM2 unlocking + +Add tests for enrolling and unlocking. Various cases are tested: + +- Default PCR 7 policy w/o PIN, good and bad cases (wrong PCR) +- PCR 7 + PIN policy, good and bad cases (wrong PCR, wrong PIN) +- Non-default PCR 0+7 policy w/o PIN, good and bad cases (wrong PCR 0) + +v2: rename test, fix tss2 library installation, fix CI failures +v3: fix ppc64, load module +(cherry picked from commit fd8b9248206734b655de503f8bb16c2d154934ed)Q + +Related: #2087652 +--- + test/TEST-70-TPM2/Makefile | 6 +++++ + test/TEST-70-TPM2/test.sh | 40 +++++++++++++++++++++++++++ + test/test-functions | 2 +- + test/units/testsuite-70.service | 7 +++++ + test/units/testsuite-70.sh | 48 +++++++++++++++++++++++++++++++++ + 5 files changed, 102 insertions(+), 1 deletion(-) + create mode 100644 test/TEST-70-TPM2/Makefile + create mode 100755 test/TEST-70-TPM2/test.sh + create mode 100644 test/units/testsuite-70.service + create mode 100755 test/units/testsuite-70.sh + +diff --git a/test/TEST-70-TPM2/Makefile b/test/TEST-70-TPM2/Makefile +new file mode 100644 +index 0000000000..9f65d4ca4f +--- /dev/null ++++ b/test/TEST-70-TPM2/Makefile +@@ -0,0 +1,6 @@ ++# SPDX-License-Identifier: LGPL-2.1-or-later ++ ++all setup run clean clean-again: ++ @TEST_BASE_DIR=../ ./test.sh --$@ ++ ++.PHONY: all setup run clean clean-again +diff --git a/test/TEST-70-TPM2/test.sh b/test/TEST-70-TPM2/test.sh +new file mode 100755 +index 0000000000..d716614bcf +--- /dev/null ++++ b/test/TEST-70-TPM2/test.sh +@@ -0,0 +1,40 @@ ++#!/usr/bin/env bash ++# SPDX-License-Identifier: LGPL-2.1-or-later ++set -e ++ ++TEST_DESCRIPTION="cryptenroll/cryptsetup with TPM2 devices" ++IMAGE_NAME="tpm2" ++TEST_NO_NSPAWN=1 ++TEST_REQUIRE_INSTALL_TESTS=0 ++ ++# shellcheck source=test/test-functions ++. "${TEST_BASE_DIR:?}/test-functions" ++ ++command -v swtpm >/dev/null 2>&1 || exit 0 ++command -v tpm2_pcrextend >/dev/null 2>&1 || exit 0 ++ ++test_append_files() { ++ ( ++ local workspace="${1:?}" ++ ++ instmods tpm tpm_tis tpm_ibmvtpm ++ install_dmevent ++ generate_module_dependencies ++ inst_binary tpm2_pcrextend ++ ) ++} ++ ++machine="$(uname -m)" ++tpmdevice="tpm-tis" ++if [ "$machine" = "ppc64le" ]; then ++ # tpm-spapr support was introduced in qemu 5.0.0. Skip test for old qemu versions. ++ qemu_min_version "5.0.0" || exit 0 ++ tpmdevice="tpm-spapr" ++fi ++ ++tpmstate=$(mktemp -d) ++swtpm socket --tpm2 --tpmstate dir="$tpmstate" --ctrl type=unixio,path="$tpmstate/sock" & ++trap 'kill %%; rm -rf $tpmstate' SIGINT EXIT ++QEMU_OPTIONS="-chardev socket,id=chrtpm,path=$tpmstate/sock -tpmdev emulator,id=tpm0,chardev=chrtpm -device $tpmdevice,tpmdev=tpm0" ++ ++do_test "$@" +diff --git a/test/test-functions b/test/test-functions +index 4a6436a74b..050fefaf1b 100644 +--- a/test/test-functions ++++ b/test/test-functions +@@ -1198,7 +1198,7 @@ install_missing_libraries() { + local lib path + # A number of dependencies is now optional via dlopen, so the install + # script will not pick them up, since it looks at linkage. +- for lib in libcryptsetup libidn libidn2 pwquality libqrencode tss2-esys tss2-rc tss2-mu libfido2 libbpf libelf libdw; do ++ for lib in libcryptsetup libidn libidn2 pwquality libqrencode tss2-esys tss2-rc tss2-mu tss2-tcti-device libfido2 libbpf libelf libdw; do + ddebug "Searching for $lib via pkg-config" + if pkg-config --exists "$lib"; then + path="$(pkg-config --variable=libdir "$lib")" +diff --git a/test/units/testsuite-70.service b/test/units/testsuite-70.service +new file mode 100644 +index 0000000000..c13c2d51a3 +--- /dev/null ++++ b/test/units/testsuite-70.service +@@ -0,0 +1,7 @@ ++# SPDX-License-Identifier: LGPL-2.1-or-later ++[Unit] ++Description=TEST-70-TPM2 ++ ++[Service] ++Type=oneshot ++ExecStart=/usr/lib/systemd/tests/testdata/units/%N.sh +diff --git a/test/units/testsuite-70.sh b/test/units/testsuite-70.sh +new file mode 100755 +index 0000000000..f395ef4e5e +--- /dev/null ++++ b/test/units/testsuite-70.sh +@@ -0,0 +1,48 @@ ++#!/usr/bin/env bash ++# SPDX-License-Identifier: LGPL-2.1-or-later ++set -ex ++ ++export SYSTEMD_LOG_LEVEL=debug ++ ++ ++# Prepare fresh disk image ++img="/var/tmp/test.img" ++dd if=/dev/zero of=$img bs=1024k count=20 status=none ++echo -n passphrase >/tmp/passphrase ++cryptsetup luksFormat -q --use-urandom $img /tmp/passphrase ++ ++# Enroll unlock with default PCR policy ++env PASSWORD=passphrase systemd-cryptenroll --tpm2-device=auto $img ++/usr/lib/systemd/systemd-cryptsetup attach test-volume $img - tpm2-device=auto,headless=1 ++/usr/lib/systemd/systemd-cryptsetup detach test-volume ++ ++# Check with wrong PCR ++tpm2_pcrextend 7:sha256=0000000000000000000000000000000000000000000000000000000000000000 ++/usr/lib/systemd/systemd-cryptsetup attach test-volume $img - tpm2-device=auto,headless=1 && { echo 'unexpected success'; exit 1; } ++ ++# Enroll unlock with PCR+PIN policy ++systemd-cryptenroll --wipe-slot=tpm2 $img ++env PASSWORD=passphrase NEWPIN=123456 systemd-cryptenroll --tpm2-device=auto --tpm2-with-pin=true $img ++env PIN=123456 /usr/lib/systemd/systemd-cryptsetup attach test-volume $img - tpm2-device=auto,headless=1 ++/usr/lib/systemd/systemd-cryptsetup detach test-volume ++ ++# Check failure with wrong PIN ++env PIN=123457 /usr/lib/systemd/systemd-cryptsetup attach test-volume $img - tpm2-device=auto,headless=1 && { echo 'unexpected success'; exit 1; } ++ ++# Check failure with wrong PCR (and correct PIN) ++tpm2_pcrextend 7:sha256=0000000000000000000000000000000000000000000000000000000000000000 ++env PIN=123456 /usr/lib/systemd/systemd-cryptsetup attach test-volume $img - tpm2-device=auto,headless=1 && { echo 'unexpected success'; exit 1; } ++ ++# Enroll unlock with PCR 0+7 ++systemd-cryptenroll --wipe-slot=tpm2 $img ++env PASSWORD=passphrase systemd-cryptenroll --tpm2-device=auto --tpm2-pcrs=0+7 $img ++/usr/lib/systemd/systemd-cryptsetup attach test-volume $img - tpm2-device=auto,headless=1 ++/usr/lib/systemd/systemd-cryptsetup detach test-volume ++ ++# Check with wrong PCR 0 ++tpm2_pcrextend 0:sha256=0000000000000000000000000000000000000000000000000000000000000000 ++/usr/lib/systemd/systemd-cryptsetup attach test-volume $img - tpm2-device=auto,headless=1 && exit 1 ++ ++echo OK >/testok ++ ++exit 0 diff --git a/0231-env-util-replace-unsetenv_erase-by-new-getenv_steal_.patch b/0231-env-util-replace-unsetenv_erase-by-new-getenv_steal_.patch new file mode 100644 index 0000000..d748e40 --- /dev/null +++ b/0231-env-util-replace-unsetenv_erase-by-new-getenv_steal_.patch @@ -0,0 +1,434 @@ +From 75e45d84d9391e29d49f6ec05272c3fb9a92bbd8 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Sat, 19 Feb 2022 00:08:39 +0100 +Subject: [PATCH] env-util: replace unsetenv_erase() by new + getenv_steal_erase() helper + +The new helper combines a bunch of steps every invocation of +unsetenv_erase() did so far: getenv() + strdup() + unsetenv_erase(). +Let's unify this into one helper that is harder to use incorrectly. It's +in inspired by TAKE_PTR() in a way: get the env var out and invalidate +where it was before. + +(cherry picked from commit e99ca1474145f7fad38bb0255d344f4ad7717ef5) + +Related: #2087652 +--- + src/basic/env-util.c | 27 ++++++++++--- + src/basic/env-util.h | 2 + + src/cryptenroll/cryptenroll-password.c | 15 ++----- + src/cryptenroll/cryptenroll.c | 20 ++++------ + src/cryptsetup/cryptsetup-fido2.c | 12 +++--- + src/cryptsetup/cryptsetup.c | 15 ++++--- + src/home/homectl.c | 55 ++++++++++++-------------- + src/shared/pkcs11-util.c | 11 +++--- + src/test/test-env-util.c | 16 +++++--- + 9 files changed, 89 insertions(+), 84 deletions(-) + +diff --git a/src/basic/env-util.c b/src/basic/env-util.c +index 455f5d76f5..b60c9f9fdc 100644 +--- a/src/basic/env-util.c ++++ b/src/basic/env-util.c +@@ -857,19 +857,36 @@ int getenv_path_list(const char *name, char ***ret_paths) { + return 1; + } + +-int unsetenv_erase(const char *name) { +- char *p; ++int getenv_steal_erase(const char *name, char **ret) { ++ _cleanup_(erase_and_freep) char *a = NULL; ++ char *e; + + assert(name); + +- p = getenv(name); +- if (!p) ++ /* Reads an environment variable, makes a copy of it, erases its memory in the environment block and removes ++ * it from there. Usecase: reading passwords from the env block (which is a bad idea, but useful for ++ * testing, and given that people are likely going to misuse this, be thorough) */ ++ ++ e = getenv(name); ++ if (!e) { ++ if (ret) ++ *ret = NULL; + return 0; ++ } + +- string_erase(p); ++ if (ret) { ++ a = strdup(e); ++ if (!a) ++ return -ENOMEM; ++ } ++ ++ string_erase(e); + + if (unsetenv(name) < 0) + return -errno; + ++ if (ret) ++ *ret = TAKE_PTR(a); ++ + return 1; + } +diff --git a/src/basic/env-util.h b/src/basic/env-util.h +index 38bfc8a3f2..e4084af9a5 100644 +--- a/src/basic/env-util.h ++++ b/src/basic/env-util.h +@@ -70,3 +70,5 @@ int setenv_systemd_exec_pid(bool update_only); + int getenv_path_list(const char *name, char ***ret_paths); + + int unsetenv_erase(const char *name); ++ ++int getenv_steal_erase(const char *name, char **ret); +diff --git a/src/cryptenroll/cryptenroll-password.c b/src/cryptenroll/cryptenroll-password.c +index 1775912d8e..9b7c8b5400 100644 +--- a/src/cryptenroll/cryptenroll-password.c ++++ b/src/cryptenroll/cryptenroll-password.c +@@ -17,20 +17,13 @@ int enroll_password( + _cleanup_free_ char *error = NULL; + const char *node; + int r, keyslot; +- char *e; + + assert_se(node = crypt_get_device_name(cd)); + +- e = getenv("NEWPASSWORD"); +- if (e) { +- +- new_password = strdup(e); +- if (!new_password) +- return log_oom(); +- +- assert_se(unsetenv_erase("NEWPASSWORD") >= 0); +- +- } else { ++ r = getenv_steal_erase("NEWPASSWORD", &new_password); ++ if (r < 0) ++ return log_error_errno(r, "Failed to acquire password from environment: %m"); ++ if (r == 0) { + _cleanup_free_ char *disk_path = NULL; + unsigned i = 5; + const char *id; +diff --git a/src/cryptenroll/cryptenroll.c b/src/cryptenroll/cryptenroll.c +index ed19f3f8f4..2e11ffe291 100644 +--- a/src/cryptenroll/cryptenroll.c ++++ b/src/cryptenroll/cryptenroll.c +@@ -422,8 +422,8 @@ static int prepare_luks( + size_t *ret_volume_key_size) { + + _cleanup_(crypt_freep) struct crypt_device *cd = NULL; ++ _cleanup_(erase_and_freep) char *envpw = NULL; + _cleanup_(erase_and_freep) void *vk = NULL; +- char *e = NULL; + size_t vks; + int r; + +@@ -458,23 +458,17 @@ static int prepare_luks( + if (!vk) + return log_oom(); + +- e = getenv("PASSWORD"); +- if (e) { +- _cleanup_(erase_and_freep) char *password = NULL; +- +- password = strdup(e); +- if (!password) +- return log_oom(); +- +- assert_se(unsetenv_erase("PASSWORD") >= 0); +- ++ r = getenv_steal_erase("PASSWORD", &envpw); ++ if (r < 0) ++ return log_error_errno(r, "Failed to acquire password from environment: %m"); ++ if (r > 0) { + r = crypt_volume_key_get( + cd, + CRYPT_ANY_SLOT, + vk, + &vks, +- password, +- strlen(password)); ++ envpw, ++ strlen(envpw)); + if (r < 0) + return log_error_errno(r, "Password from environment variable $PASSWORD did not work."); + } else { +diff --git a/src/cryptsetup/cryptsetup-fido2.c b/src/cryptsetup/cryptsetup-fido2.c +index 35d5dbe007..74053b8ce3 100644 +--- a/src/cryptsetup/cryptsetup-fido2.c ++++ b/src/cryptsetup/cryptsetup-fido2.c +@@ -30,12 +30,12 @@ int acquire_fido2_key( + size_t *ret_decrypted_key_size, + AskPasswordFlags ask_password_flags) { + ++ _cleanup_(erase_and_freep) char *envpw = NULL; + _cleanup_strv_free_erase_ char **pins = NULL; + _cleanup_free_ void *loaded_salt = NULL; + bool device_exists = false; + const char *salt; + size_t salt_size; +- char *e; + int r; + + ask_password_flags |= ASK_PASSWORD_PUSH_CACHE | ASK_PASSWORD_ACCEPT_CACHED; +@@ -66,13 +66,13 @@ int acquire_fido2_key( + salt = loaded_salt; + } + +- e = getenv("PIN"); +- if (e) { +- pins = strv_new(e); ++ r = getenv_steal_erase("PIN", &envpw); ++ if (r < 0) ++ return log_error_errno(r, "Failed to acquire password from environment: %m"); ++ if (r > 0) { ++ pins = strv_new(envpw); + if (!pins) + return log_oom(); +- +- assert_se(unsetenv_erase("PIN") >= 0); + } + + for (;;) { +diff --git a/src/cryptsetup/cryptsetup.c b/src/cryptsetup/cryptsetup.c +index fc1f37730f..692e1d137b 100644 +--- a/src/cryptsetup/cryptsetup.c ++++ b/src/cryptsetup/cryptsetup.c +@@ -829,20 +829,19 @@ static bool libcryptsetup_plugins_support(void) { + + #if HAVE_LIBCRYPTSETUP_PLUGINS + static int acquire_pins_from_env_variable(char ***ret_pins) { +- char *e; ++ _cleanup_(erase_and_freep) char *envpin = NULL; + _cleanup_strv_free_erase_ char **pins = NULL; ++ int r; + + assert(ret_pins); + +- e = getenv("PIN"); +- if (e) { +- pins = strv_new(e); ++ r = getenv_steal_erase("PIN", &envpin); ++ if (r < 0) ++ return log_error_errno(r, "Failed to acquire PIN from environment: %m"); ++ if (r > 0) { ++ pins = strv_new(envpin); + if (!pins) + return log_oom(); +- +- string_erase(e); +- if (unsetenv("PIN") < 0) +- return log_error_errno(errno, "Failed to unset $PIN: %m"); + } + + *ret_pins = TAKE_PTR(pins); +diff --git a/src/home/homectl.c b/src/home/homectl.c +index 4aeaaf6b9a..f0d1dac6ab 100644 +--- a/src/home/homectl.c ++++ b/src/home/homectl.c +@@ -201,24 +201,25 @@ static int acquire_existing_password( + AskPasswordFlags flags) { + + _cleanup_(strv_free_erasep) char **password = NULL; ++ _cleanup_(erase_and_freep) char *envpw = NULL; + _cleanup_free_ char *question = NULL; +- char *e; + int r; + + assert(user_name); + assert(hr); + +- e = getenv("PASSWORD"); +- if (e) { ++ r = getenv_steal_erase("PASSWORD", &envpw); ++ if (r < 0) ++ return log_error_errno(r, "Failed to acquire password from environment: %m"); ++ if (r > 0) { + /* People really shouldn't use environment variables for passing passwords. We support this + * only for testing purposes, and do not document the behaviour, so that people won't + * actually use this outside of testing. */ + +- r = user_record_set_password(hr, STRV_MAKE(e), true); ++ r = user_record_set_password(hr, STRV_MAKE(envpw), true); + if (r < 0) + return log_error_errno(r, "Failed to store password: %m"); + +- assert_se(unsetenv_erase("PASSWORD") >= 0); + return 1; + } + +@@ -261,24 +262,25 @@ static int acquire_recovery_key( + AskPasswordFlags flags) { + + _cleanup_(strv_free_erasep) char **recovery_key = NULL; ++ _cleanup_(erase_and_freep) char *envpw = NULL; + _cleanup_free_ char *question = NULL; +- char *e; + int r; + + assert(user_name); + assert(hr); + +- e = getenv("RECOVERY_KEY"); +- if (e) { ++ r = getenv_steal_erase("PASSWORD", &envpw); ++ if (r < 0) ++ return log_error_errno(r, "Failed to acquire password from environment: %m"); ++ if (r > 0) { + /* People really shouldn't use environment variables for passing secrets. We support this + * only for testing purposes, and do not document the behaviour, so that people won't + * actually use this outside of testing. */ + +- r = user_record_set_password(hr, STRV_MAKE(e), true); /* recovery keys are stored in the record exactly like regular passwords! */ ++ r = user_record_set_password(hr, STRV_MAKE(envpw), true); /* recovery keys are stored in the record exactly like regular passwords! */ + if (r < 0) + return log_error_errno(r, "Failed to store recovery key: %m"); + +- assert_se(unsetenv_erase("RECOVERY_KEY") >= 0); + return 1; + } + +@@ -318,20 +320,21 @@ static int acquire_token_pin( + AskPasswordFlags flags) { + + _cleanup_(strv_free_erasep) char **pin = NULL; ++ _cleanup_(erase_and_freep) char *envpin = NULL; + _cleanup_free_ char *question = NULL; +- char *e; + int r; + + assert(user_name); + assert(hr); + +- e = getenv("PIN"); +- if (e) { +- r = user_record_set_token_pin(hr, STRV_MAKE(e), false); ++ r = getenv_steal_erase("PIN", &envpin); ++ if (r < 0) ++ return log_error_errno(r, "Failed to acquire PIN from environment: %m"); ++ if (r > 0) { ++ r = user_record_set_token_pin(hr, STRV_MAKE(envpin), false); + if (r < 0) + return log_error_errno(r, "Failed to store token PIN: %m"); + +- assert_se(unsetenv_erase("PIN") >= 0); + return 1; + } + +@@ -1147,33 +1150,25 @@ static int acquire_new_password( + bool suggest, + char **ret) { + ++ _cleanup_(erase_and_freep) char *envpw = NULL; + unsigned i = 5; +- char *e; + int r; + + assert(user_name); + assert(hr); + +- e = getenv("NEWPASSWORD"); +- if (e) { +- _cleanup_(erase_and_freep) char *copy = NULL; +- ++ r = getenv_steal_erase("NEWPASSWORD", &envpw); ++ if (r < 0) ++ return log_error_errno(r, "Failed to acquire password from environment: %m"); ++ if (r > 0) { + /* As above, this is not for use, just for testing */ + +- if (ret) { +- copy = strdup(e); +- if (!copy) +- return log_oom(); +- } +- +- r = user_record_set_password(hr, STRV_MAKE(e), /* prepend = */ true); ++ r = user_record_set_password(hr, STRV_MAKE(envpw), /* prepend = */ true); + if (r < 0) + return log_error_errno(r, "Failed to store password: %m"); + +- assert_se(unsetenv_erase("NEWPASSWORD") >= 0); +- + if (ret) +- *ret = TAKE_PTR(copy); ++ *ret = TAKE_PTR(envpw); + + return 0; + } +diff --git a/src/shared/pkcs11-util.c b/src/shared/pkcs11-util.c +index 4f9ec1fbd6..80feeb1fae 100644 +--- a/src/shared/pkcs11-util.c ++++ b/src/shared/pkcs11-util.c +@@ -275,15 +275,16 @@ int pkcs11_token_login( + + for (unsigned tries = 0; tries < 3; tries++) { + _cleanup_strv_free_erase_ char **passwords = NULL; +- char *e; ++ _cleanup_(erase_and_freep) char *envpin = NULL; + +- e = getenv("PIN"); +- if (e) { +- passwords = strv_new(e); ++ r = getenv_steal_erase("PIN", &envpin); ++ if (r < 0) ++ return log_error_errno(r, "Failed to acquire PIN from environment: %m"); ++ if (r > 0) { ++ passwords = strv_new(envpin); + if (!passwords) + return log_oom(); + +- assert_se(unsetenv_erase("PIN") >= 0); + } else if (headless) + return log_error_errno(SYNTHETIC_ERRNO(ENOPKG), "PIN querying disabled via 'headless' option. Use the 'PIN' environment variable."); + else { +diff --git a/src/test/test-env-util.c b/src/test/test-env-util.c +index 4d5f39b5b7..cc37d96327 100644 +--- a/src/test/test-env-util.c ++++ b/src/test/test-env-util.c +@@ -406,16 +406,16 @@ TEST(setenv_systemd_exec_pid) { + assert_se(set_unset_env("SYSTEMD_EXEC_PID", saved, 1) >= 0); + } + +-TEST(unsetenv_erase) { ++TEST(getenv_steal_erase) { + int r; + +- r = safe_fork("(sd-unsetenverase)", FORK_DEATHSIG|FORK_LOG|FORK_WAIT, NULL); ++ r = safe_fork("(sd-getenvstealerase)", FORK_DEATHSIG|FORK_LOG|FORK_WAIT, NULL); + if (r == 0) { + _cleanup_strv_free_ char **l = NULL; + + /* child */ + +- assert_se(unsetenv_erase("thisenvvardefinitelywontexist") == 0); ++ assert_se(getenv_steal_erase("thisenvvardefinitelywontexist", NULL) == 0); + + l = strv_new("FOO=BAR", "QUUX=PIFF", "ONE=TWO", "A=B"); + assert_se(strv_length(l) == 4); +@@ -423,7 +423,7 @@ TEST(unsetenv_erase) { + environ = l; + + STRV_FOREACH(e, environ) { +- _cleanup_free_ char *n = NULL; ++ _cleanup_free_ char *n = NULL, *copy1 = NULL, *copy2 = NULL; + char *eq; + + eq = strchr(*e, '='); +@@ -433,9 +433,13 @@ TEST(unsetenv_erase) { + n = strndup(*e, eq - *e); + assert_se(n); + +- assert_se(streq_ptr(getenv(n), eq + 1)); ++ copy1 = strdup(eq + 1); ++ assert_se(copy1); ++ ++ assert_se(streq_ptr(getenv(n), copy1)); + assert_se(getenv(n) == eq + 1); +- assert_se(unsetenv_erase(n) > 0); ++ assert_se(getenv_steal_erase(n, ©2) > 0); ++ assert_se(streq_ptr(copy1, copy2)); + assert_se(isempty(eq + 1)); + assert_se(!getenv(n)); + } diff --git a/0232-test-install-libxkbcommon-and-x11-keymaps.patch b/0232-test-install-libxkbcommon-and-x11-keymaps.patch new file mode 100644 index 0000000..c6dea04 --- /dev/null +++ b/0232-test-install-libxkbcommon-and-x11-keymaps.patch @@ -0,0 +1,63 @@ +From 6bf4cd485735ecff5c0ccfb6b36bf1b2f310997a Mon Sep 17 00:00:00 2001 +From: Yu Watanabe +Date: Tue, 14 Jun 2022 09:12:00 +0900 +Subject: [PATCH] test: install libxkbcommon and x11 keymaps + +(cherry picked from commit 1136175c7fd4898c6fdc59c1f729386cf994265c) + +Related: #2087652 +--- + test/test-functions | 19 ++++++++++++++++++- + 1 file changed, 18 insertions(+), 1 deletion(-) + +diff --git a/test/test-functions b/test/test-functions +index 050fefaf1b..644c3a8613 100644 +--- a/test/test-functions ++++ b/test/test-functions +@@ -685,6 +685,7 @@ setup_basic_environment() { + install_dbus + install_fonts + install_keymaps ++ install_x11_keymaps + install_terminfo + install_execs + install_fs_tools +@@ -1198,7 +1199,7 @@ install_missing_libraries() { + local lib path + # A number of dependencies is now optional via dlopen, so the install + # script will not pick them up, since it looks at linkage. +- for lib in libcryptsetup libidn libidn2 pwquality libqrencode tss2-esys tss2-rc tss2-mu tss2-tcti-device libfido2 libbpf libelf libdw; do ++ for lib in libcryptsetup libidn libidn2 pwquality libqrencode tss2-esys tss2-rc tss2-mu tss2-tcti-device libfido2 libbpf libelf libdw xkbcommon; do + ddebug "Searching for $lib via pkg-config" + if pkg-config --exists "$lib"; then + path="$(pkg-config --variable=libdir "$lib")" +@@ -1214,6 +1215,10 @@ install_missing_libraries() { + # (eg: libcryptsetup), so just ignore them + inst_libs "${path}/${lib}.so" || true + inst_library "${path}/${lib}.so" || true ++ ++ if [[ "$lib" == "libxkbcommon" ]]; then ++ install_x11_keymaps full ++ fi + else + ddebug "$lib.pc not found, skipping" + continue +@@ -1889,6 +1894,18 @@ install_keymaps() { + fi + } + ++install_x11_keymaps() { ++ dinfo "Install x11 keymaps" ++ ++ if (( $# == 0 )); then ++ # Install only keymap list. ++ inst /usr/share/X11/xkb/rules/base.lst ++ else ++ # When it takes any argument, then install all keymaps. ++ inst_recursive /usr/share/X11/xkb ++ fi ++} ++ + install_zoneinfo() { + dinfo "Install time zones" + inst_any /usr/share/zoneinfo/Asia/Seoul diff --git a/0233-test-install-C.UTF-8-and-English-locales.patch b/0233-test-install-C.UTF-8-and-English-locales.patch new file mode 100644 index 0000000..c9c6064 --- /dev/null +++ b/0233-test-install-C.UTF-8-and-English-locales.patch @@ -0,0 +1,54 @@ +From 9e35f5e32eeacdeeb0d2b520320b08daafc11c72 Mon Sep 17 00:00:00 2001 +From: Yu Watanabe +Date: Tue, 14 Jun 2022 09:13:00 +0900 +Subject: [PATCH] test: install C.UTF-8 and English locales + +(cherry picked from commit 4ce68ea9b3707fde8c4be20e164fc2a41197fdda) + +Related: #2087652 +--- + test/test-functions | 24 ++++++++++++++++++++++++ + 1 file changed, 24 insertions(+) + +diff --git a/test/test-functions b/test/test-functions +index 644c3a8613..cab3e3c015 100644 +--- a/test/test-functions ++++ b/test/test-functions +@@ -684,6 +684,7 @@ setup_basic_environment() { + install_pam + install_dbus + install_fonts ++ install_locales + install_keymaps + install_x11_keymaps + install_terminfo +@@ -1847,6 +1848,29 @@ install_pam() { + done + } + ++install_locales() { ++ # install only C.UTF-8 and English locales ++ dinfo "Install locales" ++ ++ if command -v meson >/dev/null \ ++ && (meson configure "${BUILD_DIR:?}" | grep 'localegen-path */') \ ++ || get_bool "$LOOKS_LIKE_DEBIAN"; then ++ # locale-gen support ++ image_install -o locale-gen localedef ++ inst /etc/locale.gen || : ++ inst /usr/share/i18n/SUPPORTED || : ++ inst_recursive /usr/share/i18n/charmaps ++ inst_recursive /usr/share/i18n/locales ++ inst_recursive /usr/share/locale/en ++ inst_recursive /usr/share/locale/en_* ++ fi ++ ++ inst_recursive /usr/lib/locale/C.utf8 ++ inst_recursive /usr/lib/locale/C.UTF-8 ++ inst_recursive /usr/lib/locale/en_*.utf8 ++ inst_recursive /usr/lib/locale/en_*.UTF-8 ++} ++ + # shellcheck disable=SC2120 + install_keymaps() { + local i p diff --git a/0234-test-import-localed-tests-from-debian-ubuntu-test-su.patch b/0234-test-import-localed-tests-from-debian-ubuntu-test-su.patch new file mode 100644 index 0000000..a74682a --- /dev/null +++ b/0234-test-import-localed-tests-from-debian-ubuntu-test-su.patch @@ -0,0 +1,456 @@ +From 85e06430f03fe3078d5443d80ce53721fa88b285 Mon Sep 17 00:00:00 2001 +From: Yu Watanabe +Date: Tue, 14 Jun 2022 09:14:00 +0900 +Subject: [PATCH] test: import localed tests from debian/ubuntu test suite + +(cherry picked from commit 47ba157cc083dcc5e5d7dcbdc1e27db0d6dced3e) + +Related: #2087652 +--- + test/TEST-73-LOCALE/Makefile | 1 + + test/TEST-73-LOCALE/test.sh | 10 + + test/units/testsuite-73.service | 10 + + test/units/testsuite-73.sh | 391 ++++++++++++++++++++++++++++++++ + 4 files changed, 412 insertions(+) + create mode 120000 test/TEST-73-LOCALE/Makefile + create mode 100755 test/TEST-73-LOCALE/test.sh + create mode 100644 test/units/testsuite-73.service + create mode 100755 test/units/testsuite-73.sh + +diff --git a/test/TEST-73-LOCALE/Makefile b/test/TEST-73-LOCALE/Makefile +new file mode 120000 +index 0000000000..e9f93b1104 +--- /dev/null ++++ b/test/TEST-73-LOCALE/Makefile +@@ -0,0 +1 @@ ++../TEST-01-BASIC/Makefile +\ No newline at end of file +diff --git a/test/TEST-73-LOCALE/test.sh b/test/TEST-73-LOCALE/test.sh +new file mode 100755 +index 0000000000..a33ddaba86 +--- /dev/null ++++ b/test/TEST-73-LOCALE/test.sh +@@ -0,0 +1,10 @@ ++#!/usr/bin/env bash ++# SPDX-License-Identifier: LGPL-2.1-or-later ++set -e ++ ++TEST_DESCRIPTION="test localed" ++ ++# shellcheck source=test/test-functions ++. "${TEST_BASE_DIR:?}/test-functions" ++ ++do_test "$@" +diff --git a/test/units/testsuite-73.service b/test/units/testsuite-73.service +new file mode 100644 +index 0000000000..bee8c4215d +--- /dev/null ++++ b/test/units/testsuite-73.service +@@ -0,0 +1,10 @@ ++# SPDX-License-Identifier: LGPL-2.1-or-later ++[Unit] ++Description=TEST-73-LOCALE ++ ++[Service] ++ExecStartPre=rm -f /failed /testok ++ExecStart=/usr/lib/systemd/tests/testdata/units/%N.sh ++StandardOutput=journal+console ++StandardError=journal+console ++Type=oneshot +diff --git a/test/units/testsuite-73.sh b/test/units/testsuite-73.sh +new file mode 100755 +index 0000000000..d96e9f4151 +--- /dev/null ++++ b/test/units/testsuite-73.sh +@@ -0,0 +1,391 @@ ++#!/usr/bin/env bash ++# SPDX-License-Identifier: LGPL-2.1-or-later ++ ++set -eux ++set -o pipefail ++ ++# shellcheck source=test/units/assert.sh ++. "$(dirname "$0")"/assert.sh ++ ++enable_debug() { ++ mkdir -p /run/systemd/system/systemd-localed.service.d ++ cat >>/run/systemd/system/systemd-localed.service.d/override.conf <>/run/systemd/system/systemd-vconsole-setup.service.d/override.conf </dev/null 2>&1 && ++ ! localectl list-locales | grep -F "en_US.UTF-8"; then ++ # ensure at least one utf8 locale exist ++ echo "en_US.UTF-8 UTF-8" > /etc/locale.gen ++ locale-gen en_US.UTF-8 ++ fi ++ ++ # create invalid locale ++ mkdir -p /usr/lib/locale/xx_XX.UTF-8 ++ assert_not_in "xx_XX.UTF-8" "$(localectl list-locales)" ++ ++ if [[ -z "$(localectl list-locales)" ]]; then ++ echo "No locale installed, skipping test." ++ return ++ fi ++ ++ # warn when kernel command line has locale settings ++ output=$(SYSTEMD_PROC_CMDLINE="locale.LANG=C.UTF-8 locale.LC_CTYPE=ja_JP.UTF-8" localectl 2>&1) ++ assert_in "Warning:" "$output" ++ assert_in "Command Line: LANG=C.UTF-8" "$output" ++ assert_in "LC_CTYPE=ja_JP.UTF-8" "$output" ++ assert_in "System Locale:" "$output" ++ ++ # change locale ++ for i in $(localectl list-locales); do ++ assert_rc 0 localectl set-locale "LANG=C" "LC_CTYPE=$i" ++ if [[ -f /etc/default/locale ]]; then ++ assert_eq "$(cat /etc/default/locale)" "LANG=C ++LC_CTYPE=$i" ++ else ++ assert_eq "$(cat /etc/locale.conf)" "LANG=C ++LC_CTYPE=$i" ++ fi ++ output=$(localectl) ++ assert_in "System Locale: LANG=C" "$output" ++ assert_in "LC_CTYPE=$i" "$output" ++ output=$(systemctl show-environment) ++ assert_in "LANG=C" "$output" ++ assert_in "LC_CTYPE=$i" "$output" ++ ++ assert_rc 0 localectl set-locale "$i" ++ if [[ -f /etc/default/locale ]]; then ++ # Debian/Ubuntu patch is buggy, and LC_CTYPE= still exists. ++ assert_eq "$(cat /etc/default/locale)" "LANG=$i ++LC_CTYPE=$i" ++ else ++ assert_eq "$(cat /etc/locale.conf)" "LANG=$i" ++ fi ++ output=$(localectl) ++ assert_in "System Locale: LANG=$i" "$output" ++ assert_not_in "LC_CTYPE=" "$output" ++ output=$(systemctl show-environment) ++ assert_in "LANG=$i" "$output" ++ assert_not_in "LC_CTYPE=" "$output" ++ done ++ ++ # test if localed auto-runs locale-gen ++ if command -v locale-gen >/dev/null 2>&1 && ++ ! localectl list-locales | grep -F "de_DE.UTF-8"; then ++ ++ # clear previous locale ++ systemctl stop systemd-localed.service ++ rm -f /etc/locale.conf /etc/default/locale ++ ++ # change locale ++ assert_rc 0 localectl set-locale de_DE.UTF-8 ++ if [[ -f /etc/default/locale ]]; then ++ assert_eq "$(cat /etc/default/locale)" "LANG=de_DE.UTF-8" ++ else ++ assert_eq "$(cat /etc/locale.conf)" "LANG=de_DE.UTF-8" ++ fi ++ assert_in "System Locale: LANG=de_DE.UTF-8" "$(localectl)" ++ assert_in "LANG=de_DE.UTF-8" "$(systemctl show-environment)" ++ ++ # ensure tested locale exists and works now ++ assert_in "de_DE.UTF-8" "$(localectl list-locales)" ++ fi ++} ++ ++backup_keymap() { ++ if [[ -f /etc/vconsole.conf ]]; then ++ cp /etc/vconsole.conf /tmp/vconsole.conf.bak ++ fi ++ ++ if [[ -f /etc/X11/xorg.conf.d/00-keyboard.conf ]]; then ++ cp /etc/X11/xorg.conf.d/00-keyboard.conf /tmp/00-keyboard.conf.bak ++ fi ++ ++ # Debian/Ubuntu specific file ++ if [[ -f /etc/default/keyboard ]]; then ++ cp /etc/default/keyboard /tmp/default-keyboard.bak ++ fi ++ ++ mkdir -p /etc/default ++} ++ ++restore_keymap() { ++ if [[ -f /tmp/vconsole.conf.bak ]]; then ++ mv /tmp/vconsole.conf.bak /etc/vconsole.conf ++ else ++ rm -f /etc/vconsole.conf ++ fi ++ ++ if [[ -f /tmp/00-keyboard.conf.bak ]]; then ++ mv /tmp/00-keyboard.conf.bak /etc/X11/xorg.conf.d/00-keyboard.conf ++ else ++ rm -f /etc/X11/xorg.conf.d/00-keyboard.conf ++ fi ++ ++ if [[ -f /tmp/default-keyboard.bak ]]; then ++ mv /tmp/default-keyboard.bak /etc/default/keyboard ++ else ++ rm -f /etc/default/keyboard ++ rmdir --ignore-fail-on-non-empty /etc/default ++ fi ++} ++ ++wait_vconsole_setup() { ++ local i ss ++ for ((i = 0; i < 20; i++)); do ++ if (( i != 0 )); then sleep .5; fi ++ ss="$(systemctl --property SubState --value show systemd-vconsole-setup.service)" ++ if [[ "$ss" == "exited" || "$ss" == "dead" || "$ss" == "condition" ]]; then ++ return 0 ++ elif [[ "$ss" == "failed" ]]; then ++ echo "WARNING: systemd-vconsole-setup.service failed, ignoring." >&2 ++ systemctl reset-failed systemd-vconsole-setup.service ++ return 0 ++ fi ++ done ++ ++ systemctl status systemd-vconsole-setup.service ++ return 1 ++} ++ ++test_vc_keymap() { ++ local i output ++ ++ if [[ -z "$(localectl list-keymaps)" ]]; then ++ echo "No vconsole keymap installed, skipping test." ++ return ++ fi ++ ++ backup_keymap ++ trap restore_keymap RETURN ++ ++ # should activate daemon and work ++ assert_in "VC Keymap:" "$(localectl)" ++ ++ for i in $(localectl list-keymaps); do ++ # clear previous conversion from VC -> X11 keymap ++ systemctl stop systemd-localed.service ++ wait_vconsole_setup ++ rm -f /etc/X11/xorg.conf.d/00-keyboard.conf /etc/default/keyboard ++ ++ # set VC keymap ++ assert_rc 0 localectl set-keymap "$i" ++ output=$(localectl) ++ ++ # check VC keymap ++ assert_in "KEYMAP=$i" "$(cat /etc/vconsole.conf)" ++ assert_in "VC Keymap: $i" "$output" ++ ++ # check VC -> X11 keymap conversion ++ if [[ "$i" == "us" ]]; then ++ assert_in "X11 Layout: us" "$output" ++ assert_in "X11 Model: pc105\+inet" "$output" ++ assert_not_in "X11 Variant:" "$output" ++ assert_in "X11 Options: terminate:ctrl_alt_bksp" "$output" ++ elif [[ "$i" == "us-acentos" ]]; then ++ assert_in "X11 Layout: us" "$output" ++ assert_in 'X11 Model: pc105$' "$output" ++ assert_in "X11 Variant: intl" "$output" ++ assert_in "X11 Options: terminate:ctrl_alt_bksp" "$output" ++ elif [[ "$i" =~ ^us-.* ]]; then ++ assert_in "X11 Layout: n/a" "$output" ++ assert_not_in "X11 Model:" "$output" ++ assert_not_in "X11 Variant:" "$output" ++ assert_not_in "X11 Options:" "$output" ++ fi ++ done ++ ++ # gets along without config file ++ systemctl stop systemd-localed.service ++ wait_vconsole_setup ++ rm -f /etc/vconsole.conf ++ assert_in "VC Keymap: n/a" "$(localectl)" ++} ++ ++test_x11_keymap() { ++ local output ++ ++ if [[ -z "$(localectl list-x11-keymap-layouts)" ]]; then ++ echo "No x11 keymap installed, skipping test." ++ return ++ fi ++ ++ backup_keymap ++ trap restore_keymap RETURN ++ ++ # should activate daemon and work ++ assert_in "X11 Layout:" "$(localectl)" ++ ++ # set x11 keymap (layout, model, variant, options) ++ assert_rc 0 localectl set-x11-keymap us pc105+inet intl terminate:ctrl_alt_bksp ++ ++ if [[ -f /etc/default/keyboard ]]; then ++ assert_eq "$(cat /etc/default/keyboard)" "XKBLAYOUT=us ++XKBMODEL=pc105+inet ++XKBVARIANT=intl ++XKBOPTIONS=terminate:ctrl_alt_bksp" ++ else ++ output=$(cat /etc/X11/xorg.conf.d/00-keyboard.conf) ++ assert_in 'Option "XkbLayout" "us"' "$output" ++ assert_in 'Option "XkbModel" "pc105\+inet"' "$output" ++ assert_in 'Option "XkbVariant" "intl"' "$output" ++ assert_in 'Option "XkbOptions" "terminate:ctrl_alt_bksp"' "$output" ++ fi ++ ++ output=$(localectl) ++ assert_in "X11 Layout: us" "$output" ++ assert_in "X11 Model: pc105\+inet" "$output" ++ assert_in "X11 Variant: intl" "$output" ++ assert_in "X11 Options: terminate:ctrl_alt_bksp" "$output" ++ ++ # Debian/Ubuntu patch is buggy, unspecified settings are not cleared ++ rm -f /etc/default/keyboard ++ ++ # set x11 keymap (layout, model, variant) ++ assert_rc 0 localectl set-x11-keymap us pc105+inet intl ++ ++ if [[ -f /etc/default/keyboard ]]; then ++ assert_eq "$(cat /etc/default/keyboard)" "XKBLAYOUT=us ++XKBMODEL=pc105+inet ++XKBVARIANT=intl" ++ else ++ output=$(cat /etc/X11/xorg.conf.d/00-keyboard.conf) ++ assert_in 'Option "XkbLayout" "us"' "$output" ++ assert_in 'Option "XkbModel" "pc105\+inet"' "$output" ++ assert_in 'Option "XkbVariant" "intl"' "$output" ++ assert_not_in 'Option "XkbOptions"' "$output" ++ fi ++ ++ output=$(localectl) ++ assert_in "X11 Layout: us" "$output" ++ assert_in "X11 Model: pc105\+inet" "$output" ++ assert_in "X11 Variant: intl" "$output" ++ assert_not_in "X11 Options:" "$output" ++ ++ # Debian/Ubuntu patch is buggy, unspecified settings are not cleared ++ rm -f /etc/default/keyboard ++ ++ # set x11 keymap (layout, model) ++ assert_rc 0 localectl set-x11-keymap us pc105+inet ++ ++ if [[ -f /etc/default/keyboard ]]; then ++ assert_eq "$(cat /etc/default/keyboard)" "XKBLAYOUT=us ++XKBMODEL=pc105+inet" ++ else ++ output=$(cat /etc/X11/xorg.conf.d/00-keyboard.conf) ++ assert_in 'Option "XkbLayout" "us"' "$output" ++ assert_in 'Option "XkbModel" "pc105\+inet"' "$output" ++ assert_not_in 'Option "XkbVariant"' "$output" ++ assert_not_in 'Option "XkbOptions"' "$output" ++ fi ++ ++ output=$(localectl) ++ assert_in "X11 Layout: us" "$output" ++ assert_in "X11 Model: pc105\+inet" "$output" ++ assert_not_in "X11 Variant:" "$output" ++ assert_not_in "X11 Options:" "$output" ++ ++ # Debian/Ubuntu patch is buggy, unspecified settings are not cleared ++ rm -f /etc/default/keyboard ++ ++ # set x11 keymap (layout) ++ assert_rc 0 localectl set-x11-keymap us ++ ++ if [[ -f /etc/default/keyboard ]]; then ++ assert_eq "$(cat /etc/default/keyboard)" "XKBLAYOUT=us" ++ else ++ output=$(cat /etc/X11/xorg.conf.d/00-keyboard.conf) ++ assert_in 'Option "XkbLayout" "us"' "$output" ++ assert_not_in 'Option "XkbModel"' "$output" ++ assert_not_in 'Option "XkbVariant"' "$output" ++ assert_not_in 'Option "XkbOptions"' "$output" ++ fi ++ ++ output=$(localectl) ++ assert_in "X11 Layout: us" "$output" ++ assert_not_in "X11 Model:" "$output" ++ assert_not_in "X11 Variant:" "$output" ++ assert_not_in "X11 Options:" "$output" ++ ++ # gets along without config file ++ systemctl stop systemd-localed.service ++ rm -f /etc/X11/xorg.conf.d/00-keyboard.conf /etc/default/keyboard ++ output=$(localectl) ++ assert_in "X11 Layout: n/a" "$output" ++ assert_not_in "X11 Model:" "$output" ++ assert_not_in "X11 Variant:" "$output" ++ assert_not_in "X11 Options:" "$output" ++} ++ ++: >/failed ++ ++enable_debug ++test_locale ++test_vc_keymap ++test_x11_keymap ++ ++touch /testok ++rm /failed diff --git a/0235-unit-check-for-mount-rate-limiting-before-checking-a.patch b/0235-unit-check-for-mount-rate-limiting-before-checking-a.patch new file mode 100644 index 0000000..bf74518 --- /dev/null +++ b/0235-unit-check-for-mount-rate-limiting-before-checking-a.patch @@ -0,0 +1,52 @@ +From 7131b76b1ef9382396cdc9dc1a23999d94bb79f8 Mon Sep 17 00:00:00 2001 +From: Michal Sekletar +Date: Mon, 30 May 2022 11:55:41 +0200 +Subject: [PATCH] unit: check for mount rate limiting before checking active + state + +Having this check as part of mount_can_start() is too late because +UNIT(u)->can_start() virtual method is called after checking the active +state of unit in unit_start(). + +We need to hold off running mount start jobs when /p/s/mountinfo monitor +is rate limited even when given mount unit is already active. + +Fixes #20329 + +(cherry picked from commit b161bc394b2cc8b271dda9208e310cc2af0cc29d) + +Related: #2087652 +--- + src/core/mount.c | 3 --- + src/core/unit.c | 4 ++++ + 2 files changed, 4 insertions(+), 3 deletions(-) + +diff --git a/src/core/mount.c b/src/core/mount.c +index d63884e47e..8011389bcc 100644 +--- a/src/core/mount.c ++++ b/src/core/mount.c +@@ -2169,9 +2169,6 @@ static int mount_can_start(Unit *u) { + + assert(m); + +- if (sd_event_source_is_ratelimited(u->manager->mount_event_source)) +- return -EAGAIN; +- + r = unit_test_start_limit(u); + if (r < 0) { + mount_enter_dead(m, MOUNT_FAILURE_START_LIMIT_HIT); +diff --git a/src/core/unit.c b/src/core/unit.c +index 6eaa553255..569f712e85 100644 +--- a/src/core/unit.c ++++ b/src/core/unit.c +@@ -1848,6 +1848,10 @@ int unit_start(Unit *u) { + + assert(u); + ++ /* Let's hold off running start jobs for mount units when /proc/self/mountinfo monitor is rate limited. */ ++ if (u->type == UNIT_MOUNT && sd_event_source_is_ratelimited(u->manager->mount_event_source)) ++ return -EAGAIN; ++ + /* If this is already started, then this will succeed. Note that this will even succeed if this unit + * is not startable by the user. This is relied on to detect when we need to wait for units and when + * waiting is finished. */ diff --git a/0236-tests-make-sure-we-delay-running-mount-start-jobs-wh.patch b/0236-tests-make-sure-we-delay-running-mount-start-jobs-wh.patch new file mode 100644 index 0000000..034bd39 --- /dev/null +++ b/0236-tests-make-sure-we-delay-running-mount-start-jobs-wh.patch @@ -0,0 +1,84 @@ +From 94f643c328cd2d3c7376219573e0bc5dedea10d8 Mon Sep 17 00:00:00 2001 +From: Michal Sekletar +Date: Mon, 30 May 2022 14:50:05 +0200 +Subject: [PATCH] tests: make sure we delay running mount start jobs when + /p/s/mountinfo is rate limited + +(cherry picked from commit 9e15be6c8d55abd800bf33f9776dd0e307ed37bc) + +Related: #2087652 +--- + test/units/testsuite-60.sh | 53 ++++++++++++++++++++++++++++++++++++++ + 1 file changed, 53 insertions(+) + +diff --git a/test/units/testsuite-60.sh b/test/units/testsuite-60.sh +index 239d7b0d4c..8cb3f466b6 100755 +--- a/test/units/testsuite-60.sh ++++ b/test/units/testsuite-60.sh +@@ -3,6 +3,56 @@ + set -eux + set -o pipefail + ++test_issue_20329() { ++ local tmpdir unit ++ tmpdir="$(mktemp -d)" ++ unit=$(systemd-escape --suffix mount --path "$tmpdir") ++ ++ # Set up test mount unit ++ cat > /run/systemd/system/"$unit" <&2 "Test mount \"$unit\" unit isn't mounted" ++ return 1 ++ } ++ mountpoint -q "$tmpdir" ++ ++ trap 'systemctl stop $unit' RETURN ++ ++ # Trigger the mount ratelimiting ++ cd "$(mktemp -d)" ++ mkdir foo ++ for ((i=0;i<50;++i)); do ++ mount --bind foo foo ++ umount foo ++ done ++ ++ # Unmount the test mount and start it immediately again via systemd ++ umount "$tmpdir" ++ systemctl start "$unit" ++ ++ # Make sure it is seen as mounted by systemd and it actually is mounted ++ [[ "$(systemctl show --property SubState --value "$unit")" = "mounted" ]] || { ++ echo >&2 "Test mount \"$unit\" unit isn't in \"mounted\" state" ++ return 1 ++ } ++ ++ mountpoint -q "$tmpdir" || { ++ echo >&2 "Test mount \"$unit\" is in \"mounted\" state, actually is not mounted" ++ return 1 ++ } ++} ++ + systemd-analyze log-level debug + systemd-analyze log-target journal + +@@ -87,6 +137,9 @@ if systemctl list-units -t mount tmp-meow* | grep -q tmp-meow; then + exit 42 + fi + ++# test that handling of mount start jobs is delayed when /proc/self/mouninfo monitor is rate limited ++test_issue_20329 ++ + systemd-analyze log-level info + + echo OK >/testok diff --git a/0237-test-insert-space-in-for-loop.patch b/0237-test-insert-space-in-for-loop.patch new file mode 100644 index 0000000..6f5aaac --- /dev/null +++ b/0237-test-insert-space-in-for-loop.patch @@ -0,0 +1,139 @@ +From a480327b20deb75d5595878f2924490ef3aa4064 Mon Sep 17 00:00:00 2001 +From: Yu Watanabe +Date: Tue, 14 Jun 2022 21:05:10 +0900 +Subject: [PATCH] test: insert space in for loop + +(cherry picked from commit 2f34ee33291c92fd46308213689540cb76fb8e2b) + +Related: #2087652 +--- + test/units/testsuite-17.06.sh | 6 +++--- + test/units/testsuite-35.sh | 8 ++++---- + test/units/testsuite-45.sh | 6 +++--- + test/units/testsuite-46.sh | 2 +- + test/units/testsuite-60.sh | 2 +- + 5 files changed, 12 insertions(+), 12 deletions(-) + +diff --git a/test/units/testsuite-17.06.sh b/test/units/testsuite-17.06.sh +index f2a0442dc3..224063f6a6 100755 +--- a/test/units/testsuite-17.06.sh ++++ b/test/units/testsuite-17.06.sh +@@ -18,18 +18,18 @@ function check_validity() { + function check() { + local i j + +- for ((i=0;i<2;i++)); do ++ for ((i = 0; i < 2; i++)); do + systemctl restart systemd-udevd.service + udevadm control --ping + udevadm settle + check_validity + +- for ((j=0;j<2;j++)); do ++ for ((j = 0; j < 2; j++)); do + udevadm trigger -w --action add --subsystem-match=block + check_validity + done + +- for ((j=0;j<2;j++)); do ++ for ((j = 0; j < 2; j++)); do + udevadm trigger -w --action change --subsystem-match=block + check_validity + done +diff --git a/test/units/testsuite-35.sh b/test/units/testsuite-35.sh +index 0a7198c3fe..e369cf8701 100755 +--- a/test/units/testsuite-35.sh ++++ b/test/units/testsuite-35.sh +@@ -149,7 +149,7 @@ EOF + evemu-device /run/lidswitch.evemu & + KILL_PID="$!" + +- for ((i=0;i<20;i++)); do ++ for ((i = 0; i < 20; i++)); do + if (( i != 0 )); then sleep .5; fi + + INPUT_NAME=$(grep -l '^Fake Lid Switch' /sys/class/input/*/device/name || :) +@@ -287,7 +287,7 @@ EOF + + # check session + ret=1 +- for ((i=0;i<30;i++)); do ++ for ((i = 0; i < 30; i++)); do + if (( i != 0)); then sleep 1; fi + if check_session; then + ret=0 +@@ -315,7 +315,7 @@ EOF + # coldplug: logind started with existing device + systemctl stop systemd-logind.service + modprobe scsi_debug +- for ((i=0;i<30;i++)); do ++ for ((i = 0; i < 30; i++)); do + if (( i != 0)); then sleep 1; fi + if dev=/dev/$(ls /sys/bus/pseudo/drivers/scsi_debug/adapter*/host*/target*/*:*/block 2>/dev/null); then + break +@@ -342,7 +342,7 @@ EOF + # hotplug: new device appears while logind is running + rmmod scsi_debug + modprobe scsi_debug +- for ((i=0;i<30;i++)); do ++ for ((i = 0; i < 30; i++)); do + if (( i != 0)); then sleep 1; fi + if dev=/dev/$(ls /sys/bus/pseudo/drivers/scsi_debug/adapter*/host*/target*/*:*/block 2>/dev/null); then + break +diff --git a/test/units/testsuite-45.sh b/test/units/testsuite-45.sh +index d0f9dd9461..fd8a99076b 100755 +--- a/test/units/testsuite-45.sh ++++ b/test/units/testsuite-45.sh +@@ -197,7 +197,7 @@ start_mon() { + } + + wait_mon() { +- for ((i=0;i<10;i++)); do ++ for ((i = 0; i < 10; i++)); do + if (( i != 0 )); then sleep 1; fi + if grep -q "$1" "$mon"; then break; fi + done +@@ -228,7 +228,7 @@ EOF + + echo 'disable NTP' + timedatectl set-ntp false +- for ((i=0;i<10;i++)); do ++ for ((i = 0; i < 10; i++)); do + if (( i != 0 )); then sleep 1; fi + if [[ "$(systemctl show systemd-timesyncd --property ActiveState)" == "ActiveState=inactive" ]]; then + break; +@@ -243,7 +243,7 @@ EOF + timedatectl set-ntp true + wait_mon "NTP" "BOOLEAN true" + assert_ntp "true" +- for ((i=0;i<10;i++)); do ++ for ((i = 0; i < 10; i++)); do + if (( i != 0 )); then sleep 1; fi + if [[ "$(systemctl show systemd-timesyncd --property ActiveState)" == "ActiveState=active" ]]; then + break; +diff --git a/test/units/testsuite-46.sh b/test/units/testsuite-46.sh +index 61ee921151..3724a3b5f6 100755 +--- a/test/units/testsuite-46.sh ++++ b/test/units/testsuite-46.sh +@@ -27,7 +27,7 @@ inspect() { + } + + wait_for_state() { +- for ((i=0;i<10;i++)) ; do ++ for ((i = 0; i < 10; i++)) ; do + homectl inspect "$1" | grep -qF "State: $2" && break + sleep .5 + done +diff --git a/test/units/testsuite-60.sh b/test/units/testsuite-60.sh +index 8cb3f466b6..3a097816ca 100755 +--- a/test/units/testsuite-60.sh ++++ b/test/units/testsuite-60.sh +@@ -32,7 +32,7 @@ EOF + # Trigger the mount ratelimiting + cd "$(mktemp -d)" + mkdir foo +- for ((i=0;i<50;++i)); do ++ for ((i = 0; i < 50; i++)); do + mount --bind foo foo + umount foo + done diff --git a/0238-test-move-do-at-the-end-of-line.patch b/0238-test-move-do-at-the-end-of-line.patch new file mode 100644 index 0000000..5b42606 --- /dev/null +++ b/0238-test-move-do-at-the-end-of-line.patch @@ -0,0 +1,46 @@ +From 9adf5125e39e15b2868a22fc481c4ce027de4f55 Mon Sep 17 00:00:00 2001 +From: Yu Watanabe +Date: Tue, 14 Jun 2022 21:06:06 +0900 +Subject: [PATCH] test: move "do" at the end of line + +(cherry picked from commit 4627fb80bf54f5824570d3b94df9286971f028ac) + +Related: #2087652 +--- + test/test-functions | 9 +++------ + 1 file changed, 3 insertions(+), 6 deletions(-) + +diff --git a/test/test-functions b/test/test-functions +index cab3e3c015..1b10112329 100644 +--- a/test/test-functions ++++ b/test/test-functions +@@ -2250,8 +2250,7 @@ convert_abs_rel() { + __abssize=${#__absolute[@]} + __cursize=${#__current[@]} + +- while [[ "${__absolute[__level]}" == "${__current[__level]}" ]] +- do ++ while [[ "${__absolute[__level]}" == "${__current[__level]}" ]]; do + (( __level++ )) + if (( __level > __abssize || __level > __cursize )) + then +@@ -2259,8 +2258,7 @@ convert_abs_rel() { + fi + done + +- for ((__i = __level; __i < __cursize-1; __i++)) +- do ++ for ((__i = __level; __i < __cursize-1; __i++)); do + if ((__i > __level)) + then + __newpath=$__newpath"/" +@@ -2268,8 +2266,7 @@ convert_abs_rel() { + __newpath=$__newpath".." + done + +- for ((__i = __level; __i < __abssize; __i++)) +- do ++ for ((__i = __level; __i < __abssize; __i++)); do + if [[ -n $__newpath ]] + then + __newpath=$__newpath"/" diff --git a/0239-test-use-trap-RETURN.patch b/0239-test-use-trap-RETURN.patch new file mode 100644 index 0000000..e5ce153 --- /dev/null +++ b/0239-test-use-trap-RETURN.patch @@ -0,0 +1,97 @@ +From 60bc6c654dfbcbfeac0120143dd9869ceeb1a56e Mon Sep 17 00:00:00 2001 +From: Yu Watanabe +Date: Tue, 14 Jun 2022 21:08:04 +0900 +Subject: [PATCH] test: use trap RETURN + +(cherry picked from commit 6243063824838e027754cc2737bb975472d62de2) + +Related: #2087652 +--- + test/units/testsuite-35.sh | 10 ++-------- + test/units/testsuite-45.sh | 10 ++-------- + 2 files changed, 4 insertions(+), 16 deletions(-) + +diff --git a/test/units/testsuite-35.sh b/test/units/testsuite-35.sh +index e369cf8701..05d2a6c4c3 100755 +--- a/test/units/testsuite-35.sh ++++ b/test/units/testsuite-35.sh +@@ -91,7 +91,7 @@ test_suspend_on_lid() { + fi + + KILL_PID= +- trap test_suspend_tear_down EXIT ++ trap test_suspend_tear_down RETURN + + # create fake suspend + mkdir -p /run/systemd/system/systemd-suspend.service.d +@@ -184,9 +184,6 @@ EOF + echo "logind crashed" >&2 + exit 1 + fi +- +- test_suspend_tear_down +- trap - EXIT + } + + test_shutdown() { +@@ -269,7 +266,7 @@ test_session() { + return + fi + +- trap test_session_tear_down EXIT ++ trap test_session_tear_down RETURN + + # add user + useradd -s /bin/bash logind-test-user +@@ -361,9 +358,6 @@ EOF + getfacl -p "$dev" >&2 + exit 1 + fi +- +- test_session_tear_down +- trap - EXIT + } + + : >/failed +diff --git a/test/units/testsuite-45.sh b/test/units/testsuite-45.sh +index fd8a99076b..322d8086e7 100755 +--- a/test/units/testsuite-45.sh ++++ b/test/units/testsuite-45.sh +@@ -23,7 +23,7 @@ test_timezone() { + mv /etc/timezone /tmp/timezone.bak + fi + +- trap restore_timezone EXIT ++ trap restore_timezone RETURN + + if [[ -L /etc/localtime ]]; then + ORIG_TZ=$(readlink /etc/localtime | sed 's#^.*zoneinfo/##') +@@ -49,9 +49,6 @@ test_timezone() { + assert_eq "$(cat /etc/timezone)" "$ORIG_TZ" + fi + fi +- +- restore_timezone +- trap - EXIT + } + + restore_adjtime() { +@@ -75,7 +72,7 @@ test_adjtime() { + mv /etc/adjtime /etc/adjtime.bak + fi + +- trap restore_adjtime EXIT ++ trap restore_adjtime RETURN + + echo 'no adjtime file' + rm -f /etc/adjtime +@@ -182,9 +179,6 @@ LOCAL" + assert_eq "$(cat /etc/adjtime)" "0.0 0 0 + 0 + LOCAL" +- +- restore_adjtime +- trap - EXIT + } + + assert_ntp() { diff --git a/0240-test-ignore-the-error-about-our-own-libraries-missin.patch b/0240-test-ignore-the-error-about-our-own-libraries-missin.patch new file mode 100644 index 0000000..9653e95 --- /dev/null +++ b/0240-test-ignore-the-error-about-our-own-libraries-missin.patch @@ -0,0 +1,56 @@ +From 07d0debc02fb8a9f51ff06a03ceb2302e4982166 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Wed, 15 Dec 2021 09:14:44 +0100 +Subject: [PATCH] test: ignore the error about our own libraries missing during + image creation + +19:50:59 F: Missing a shared library required by /var/tmp/systemd-test.NIPT2q/root/lib/systemd/libsystemd-core-250.so. +19:50:59 F: Run "ldd /var/tmp/systemd-test.NIPT2q/root/lib/systemd/libsystemd-core-250.so" to find out what it is. +19:50:59 F: libsystemd-shared-250.so => not found +19:50:59 F: Cannot create a test image. +(cherry picked from commit ff254eea8feb55bbea9ec5d731e3dc9299b80b9e) + +Related: #2087652 +--- + test/test-functions | 14 ++++++++------ + 1 file changed, 8 insertions(+), 6 deletions(-) + +diff --git a/test/test-functions b/test/test-functions +index 1b10112329..a0ad8b2fb1 100644 +--- a/test/test-functions ++++ b/test/test-functions +@@ -2021,11 +2021,9 @@ inst_libs() { + + while read -r line; do + [[ "$line" = 'not a dynamic executable' ]] && break +- # Skip a harmless error when running the tests on a system with a significantly +- # older systemd version (ldd tries to resolve the unprefixed RPATH for libsystemd.so.0, +- # which is in this case older than the already installed libsystemd.so.0 in $initdir). +- # The issue is triggered by installing test dependencies in install_missing_libraries(). +- [[ "$line" =~ libsystemd.so.*:\ version\ .*\ not\ found ]] && continue ++ # Ignore errors about our own stuff missing. This is most likely caused ++ # by ldd attempting to use the unprefixed RPATH. ++ [[ "$line" =~ libsystemd.*\ not\ found ]] && continue + + if [[ "$line" =~ $so_regex ]]; then + file="${BASH_REMATCH[1]}" +@@ -2413,7 +2411,7 @@ inst_binary() { + # In certain cases we might attempt to install a binary which is already + # present in the test image, yet it's missing from the host system. + # In such cases, let's check if the binary indeed exists in the image +- # before doing any other chcecks. If it does, immediately return with ++ # before doing any other checks. If it does, immediately return with + # success. + if [[ $# -eq 1 ]]; then + for path in "" bin sbin usr/bin usr/sbin; do +@@ -2432,6 +2430,10 @@ inst_binary() { + while read -r line; do + [[ "$line" = 'not a dynamic executable' ]] && break + ++ # Ignore errors about our own stuff missing. This is most likely caused ++ # by ldd attempting to use the unprefixed RPATH. ++ [[ "$line" =~ libsystemd.*\ not\ found ]] && continue ++ + if [[ "$line" =~ $so_regex ]]; then + file="${BASH_REMATCH[1]}" + [[ -e "${initdir}/$file" ]] && continue diff --git a/0241-test-wrap-binaries-using-systemd-DSOs-when-running-w.patch b/0241-test-wrap-binaries-using-systemd-DSOs-when-running-w.patch new file mode 100644 index 0000000..f5b7fb4 --- /dev/null +++ b/0241-test-wrap-binaries-using-systemd-DSOs-when-running-w.patch @@ -0,0 +1,85 @@ +From 75037db319f9eb240d73186eee457f62d4b16c7d Mon Sep 17 00:00:00 2001 +From: Frantisek Sumsal +Date: Tue, 14 Jun 2022 22:54:39 +0200 +Subject: [PATCH] test: wrap binaries using systemd DSOs when running w/ ASan + +Let's detect & wrap binaries which are linked against systemd DSOs and +we're running under ASan, since otherwise running such binaries ends +with: + +``` +==633==ASan runtime does not come first in initial library list; you should either link runtime to your application or manually preload it with LD_PRELOAD. +``` + +(cherry picked from commit 3917534d620c2b358a196431b9e2593218ba1ac9) + +Related: #2087652 +--- + test/test-functions | 40 +++++++++++++++++++++++++++++++++++++++- + 1 file changed, 39 insertions(+), 1 deletion(-) + +diff --git a/test/test-functions b/test/test-functions +index a0ad8b2fb1..34aeac339f 100644 +--- a/test/test-functions ++++ b/test/test-functions +@@ -2426,6 +2426,9 @@ inst_binary() { + + local file line + local so_regex='([^ ]*/lib[^/]*/[^ ]*\.so[^ ]*)' ++ # DSOs provided by systemd ++ local systemd_so_regex='/(libudev|libsystemd.*|.+[\-_]systemd([\-_].+)?|libnss_(mymachines|myhostname|resolve)).so' ++ local wrap_binary=0 + # I love bash! + while read -r line; do + [[ "$line" = 'not a dynamic executable' ]] && break +@@ -2434,6 +2437,12 @@ inst_binary() { + # by ldd attempting to use the unprefixed RPATH. + [[ "$line" =~ libsystemd.*\ not\ found ]] && continue + ++ # We're built with ASan and the target binary loads one of the systemd's ++ # DSOs, so we need to tweak the environment before executing the binary ++ if get_bool "$IS_BUILT_WITH_ASAN" && [[ "$line" =~ $systemd_so_regex ]]; then ++ wrap_binary=1 ++ fi ++ + if [[ "$line" =~ $so_regex ]]; then + file="${BASH_REMATCH[1]}" + [[ -e "${initdir}/$file" ]] && continue +@@ -2449,7 +2458,36 @@ inst_binary() { + exit 1 + fi + done < <(LC_ALL=C ldd "$bin" 2>/dev/null) +- inst_simple "$bin" "$target" ++ ++ # Same as above, but we need to wrap certain libraries unconditionally ++ # ++ # login - dlopen()s (not only) systemd's PAM modules ++ # tar - called by machinectl in TEST-25 ++ if get_bool "$IS_BUILT_WITH_ASAN" && [[ "$bin" =~ /(login|tar)$ ]]; then ++ wrap_binary=1 ++ fi ++ ++ if get_bool "$wrap_binary"; then ++ dinfo "Creating ASan-compatible wrapper for binary '$target'" ++ # Install the target binary with a ".orig" suffix ++ inst_simple "$bin" "${target}.orig" ++ # Create a simple shell wrapper in place of the target binary, which ++ # sets necessary ASan-related env variables and then exec()s the ++ # suffixed target binary ++ cat >"$initdir/$target" < +Date: Mon, 6 Jun 2022 14:45:11 +0200 +Subject: [PATCH] test: set $ASAN_RT_PATH along with $LD_PRELOAD to the ASan + runtime DSO + +Since we unset $LD_PRELOAD in the testsuite-* units (due to another +issue), let's store the path to the ASan DSO in another env variable, so +we can easily access it in the testsuite scripts when needed. + +(cherry picked from commit 3ea18a2e36a5b8ac60c76e407f9dd38800455725) + +Related: #2087652 +--- + test/test-functions | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/test/test-functions b/test/test-functions +index 34aeac339f..a9ff561083 100644 +--- a/test/test-functions ++++ b/test/test-functions +@@ -820,7 +820,7 @@ mount -o remount,rw / + + # A lot of services (most notably dbus) won't start without preloading libasan + # See https://github.com/systemd/systemd/issues/5004 +-DEFAULT_ENVIRONMENT="\$DEFAULT_ENVIRONMENT LD_PRELOAD=$ASAN_RT_PATH" ++DEFAULT_ENVIRONMENT="\$DEFAULT_ENVIRONMENT LD_PRELOAD=$ASAN_RT_PATH ASAN_RT_PATH=$ASAN_RT_PATH" + + if [[ "$ASAN_COMPILER" == "clang" ]]; then + # Let's add the ASan DSO's path to the dynamic linker's cache. This is pretty diff --git a/0243-test-drop-all-LD_PRELOAD-related-ASan-workarounds.patch b/0243-test-drop-all-LD_PRELOAD-related-ASan-workarounds.patch new file mode 100644 index 0000000..138ae6b --- /dev/null +++ b/0243-test-drop-all-LD_PRELOAD-related-ASan-workarounds.patch @@ -0,0 +1,101 @@ +From 137a22e0192941fa275b70665af7a0d54f6ad614 Mon Sep 17 00:00:00 2001 +From: Frantisek Sumsal +Date: Wed, 15 Jun 2022 12:32:51 +0200 +Subject: [PATCH] test: drop all LD_PRELOAD-related ASan workarounds + +since they shouldn't be necessary anymore, as we tweak the "problematic" +binaries on per-binary basis. + +(cherry picked from commit fa65ba6baac8c9241cf30802bb5fd3698d1f3189) + +Related: #2087652 +--- + test/test-functions | 54 +-------------------------------------------- + 1 file changed, 1 insertion(+), 53 deletions(-) + +diff --git a/test/test-functions b/test/test-functions +index a9ff561083..f55e64493d 100644 +--- a/test/test-functions ++++ b/test/test-functions +@@ -593,10 +593,6 @@ install_verity_minimal() { + # missing $LD_PRELOAD libraries. + inst_libs "$ASAN_RT_PATH" + inst_library "$ASAN_RT_PATH" +- # Create a dummy LSan suppression file otherwise gcc's ASan +- # complains as it doesn't exist in the minimal image +- # (i.e. when running TEST-29 or TEST-50 under sanitizers) +- touch "$initdir/systemd-lsan.supp" + fi + cp "$os_release" "$initdir/usr/lib/os-release" + ln -s ../usr/lib/os-release "$initdir/etc/os-release" +@@ -792,20 +788,6 @@ if [[ ! -e "$ASAN_RT_PATH" ]]; then + exit 1 + fi + +-# Suppress certain leaks reported by LSan (either in external tools or bogus +-# ones) +-# Docs: # https://github.com/google/sanitizers/wiki/AddressSanitizerLeakSanitizer#suppressions +-# +-# - fsck is called by systemd-homed and is reporting a leak we're not interested +-# in +-# - libLLVM is a "side effect" caused by the previous fsck leak +-cat >/systemd-lsan.supp </etc/systemd/system/systemd-journal-flush.service.d/timeout.conf + +-# D-Bus has troubles during system shutdown causing it to fail. Although it's +-# harmless, it causes unnecessary noise in the logs, so let's disable LSan's +-# at_exit check just for the dbus.service +-mkdir -p /etc/systemd/system/dbus.service.d +-printf "[Service]\nEnvironment=ASAN_OPTIONS=leak_check_at_exit=false\n" >/etc/systemd/system/dbus.service.d/disable-lsan.conf +- +-# Some utilities run via IMPORT/RUN/PROGRAM udev directives fail because +-# they're uninstrumented (like dmsetup). Let's add a simple rule which sets +-# LD_PRELOAD to the ASan RT library to fix this. +-mkdir -p /etc/udev/rules.d +-cat >/etc/udev/rules.d/00-set-LD_PRELOAD.rules <"\$_dropin_dir/unset_ld_preload.conf" +-} +- +-unset_ld_preload systemd-remount-fs +-unset_ld_preload testsuite- +- + export ASAN_OPTIONS=\$DEFAULT_ASAN_OPTIONS:log_path=/systemd.asan.log UBSAN_OPTIONS=\$DEFAULT_UBSAN_OPTIONS + exec "$ROOTLIBDIR/systemd" "\$@" + EOF diff --git a/0244-test-don-t-wrap-binaries-built-with-ASan.patch b/0244-test-don-t-wrap-binaries-built-with-ASan.patch new file mode 100644 index 0000000..b7ef69f --- /dev/null +++ b/0244-test-don-t-wrap-binaries-built-with-ASan.patch @@ -0,0 +1,57 @@ +From e5ecc772a0bb0813cdcf0a24f48ba3278da6e276 Mon Sep 17 00:00:00 2001 +From: Frantisek Sumsal +Date: Wed, 15 Jun 2022 19:43:11 +0200 +Subject: [PATCH] test: don't wrap binaries built with ASan + +since they should handle loading other instrumented libraries without +issues. + +(cherry picked from commit b727d7e02d6c88476ae9e46211e1f9c24720d5c3) + +Related: #2087652 +--- + test/test-functions | 10 +++++++--- + 1 file changed, 7 insertions(+), 3 deletions(-) + +diff --git a/test/test-functions b/test/test-functions +index f55e64493d..57d4df3e7e 100644 +--- a/test/test-functions ++++ b/test/test-functions +@@ -228,6 +228,8 @@ DEBUGTOOLS=( + ) + + is_built_with_asan() { ++ local _bin="${1:?}" ++ + if ! type -P objdump >/dev/null; then + ddebug "Failed to find objdump. Assuming systemd hasn't been built with ASAN." + return 1 +@@ -235,7 +237,7 @@ is_built_with_asan() { + + # Borrowed from https://github.com/google/oss-fuzz/blob/cd9acd02f9d3f6e80011cc1e9549be526ce5f270/infra/base-images/base-runner/bad_build_check#L182 + local _asan_calls +- _asan_calls="$(objdump -dC "$SYSTEMD_JOURNALD" | grep -E "(callq?|brasl?|bl)\s.+__asan" -c)" ++ _asan_calls="$(objdump -dC "$_bin" | grep -E "(callq?|brasl?|bl)\s.+__asan" -c)" + if ((_asan_calls < 1000)); then + return 1 + else +@@ -251,7 +253,7 @@ is_built_with_coverage() { + meson configure "${BUILD_DIR:?}" | grep 'b_coverage' | awk '{ print $2 }' | grep -q 'true' + } + +-IS_BUILT_WITH_ASAN=$(is_built_with_asan && echo yes || echo no) ++IS_BUILT_WITH_ASAN=$(is_built_with_asan "$SYSTEMD_JOURNALD" && echo yes || echo no) + IS_BUILT_WITH_COVERAGE=$(is_built_with_coverage && echo yes || echo no) + + if get_bool "$IS_BUILT_WITH_ASAN"; then +@@ -2415,7 +2417,9 @@ inst_binary() { + wrap_binary=1 + fi + +- if get_bool "$wrap_binary"; then ++ # If the target binary is built with ASan support, we don't need to wrap ++ # it, as it should handle everything by itself ++ if get_bool "$wrap_binary" && ! is_built_with_asan "$bin"; then + dinfo "Creating ASan-compatible wrapper for binary '$target'" + # Install the target binary with a ".orig" suffix + inst_simple "$bin" "${target}.orig" diff --git a/0245-test-send-stdout-stderr-of-testsuite-units-to-journa.patch b/0245-test-send-stdout-stderr-of-testsuite-units-to-journa.patch new file mode 100644 index 0000000..250eb9b --- /dev/null +++ b/0245-test-send-stdout-stderr-of-testsuite-units-to-journa.patch @@ -0,0 +1,108 @@ +From 4dd51db0381048f15973dc0046fe5fdec1f40aa8 Mon Sep 17 00:00:00 2001 +From: Frantisek Sumsal +Date: Thu, 16 Jun 2022 22:16:53 +0200 +Subject: [PATCH] test: send stdout/stderr of testsuite units to journal & + console + +to make debugging in CIs slightly easier. + +(cherry picked from commit ba7abf79a5a2df2a93332fc32e8e3c268c74abc7) + +Related: #2087652 +--- + test/test-functions | 12 ++++++++++++ + test/units/testsuite-22.service | 2 -- + test/units/testsuite-35.service | 2 -- + test/units/testsuite-45.service | 2 -- + test/units/testsuite-64.service | 2 -- + test/units/testsuite-71.service | 2 -- + test/units/testsuite-73.service | 2 -- + 7 files changed, 12 insertions(+), 12 deletions(-) + +diff --git a/test/test-functions b/test/test-functions +index 57d4df3e7e..77d4a0afff 100644 +--- a/test/test-functions ++++ b/test/test-functions +@@ -2867,6 +2867,18 @@ test_setup() { + mask_supporting_services + fi + ++ # Send stdout/stderr of testsuite-*.service units to both journal and ++ # console to make debugging in CIs easier ++ # Note: we can't use a dropin for `testsuite-.service`, since that also ++ # overrides 'sub-units' of some tests that already use a specific ++ # value for Standard(Output|Error)= ++ # (e.g. test/units/testsuite-66-deviceisolation.service) ++ if ! get_bool "$INTERACTIVE_DEBUG"; then ++ local dropin_dir="${initdir:?}/etc/systemd/system/testsuite-${TESTID:?}.service.d" ++ mkdir -p "$dropin_dir" ++ printf '[Service]\nStandardOutput=journal+console\nStandardError=journal+console' >"$dropin_dir/99-stdout.conf" ++ fi ++ + if get_bool "$hook_defined"; then + test_append_files "${initdir:?}" + fi +diff --git a/test/units/testsuite-22.service b/test/units/testsuite-22.service +index b9ecc4c5d6..a5ed660c62 100644 +--- a/test/units/testsuite-22.service ++++ b/test/units/testsuite-22.service +@@ -9,5 +9,3 @@ Wants=getty-pre.target + ExecStartPre=rm -f /failed /testok + ExecStart=/usr/lib/systemd/tests/testdata/units/%N.sh + Type=oneshot +-StandardOutput=tty +-StandardError=tty +diff --git a/test/units/testsuite-35.service b/test/units/testsuite-35.service +index 556a57a384..0599f6104e 100644 +--- a/test/units/testsuite-35.service ++++ b/test/units/testsuite-35.service +@@ -5,6 +5,4 @@ Description=TEST-35-LOGIN + [Service] + ExecStartPre=rm -f /failed /testok + ExecStart=/usr/lib/systemd/tests/testdata/units/%N.sh +-StandardOutput=journal+console +-StandardError=journal+console + Type=oneshot +diff --git a/test/units/testsuite-45.service b/test/units/testsuite-45.service +index 79c0a6f117..b16ce9933f 100644 +--- a/test/units/testsuite-45.service ++++ b/test/units/testsuite-45.service +@@ -5,6 +5,4 @@ Description=TEST-45-TIMEDATE + [Service] + ExecStartPre=rm -f /failed /testok + ExecStart=/usr/lib/systemd/tests/testdata/units/%N.sh +-StandardOutput=journal+console +-StandardError=journal+console + Type=oneshot +diff --git a/test/units/testsuite-64.service b/test/units/testsuite-64.service +index 10b61e7e53..f75a3d7aad 100644 +--- a/test/units/testsuite-64.service ++++ b/test/units/testsuite-64.service +@@ -6,5 +6,3 @@ Description=TEST-64-UDEV + ExecStartPre=rm -f /failed /testok + ExecStart=/usr/lib/systemd/tests/testdata/units/%N.sh + Type=oneshot +-StandardOutput=journal+console +-StandardError=journal+console +diff --git a/test/units/testsuite-71.service b/test/units/testsuite-71.service +index 019e8bff24..1718629c05 100644 +--- a/test/units/testsuite-71.service ++++ b/test/units/testsuite-71.service +@@ -5,6 +5,4 @@ Description=TEST-71-HOSTNAME + [Service] + ExecStartPre=rm -f /failed /testok + ExecStart=/usr/lib/systemd/tests/testdata/units/%N.sh +-StandardOutput=journal+console +-StandardError=journal+console + Type=oneshot +diff --git a/test/units/testsuite-73.service b/test/units/testsuite-73.service +index bee8c4215d..3ebd24da18 100644 +--- a/test/units/testsuite-73.service ++++ b/test/units/testsuite-73.service +@@ -5,6 +5,4 @@ Description=TEST-73-LOCALE + [Service] + ExecStartPre=rm -f /failed /testok + ExecStart=/usr/lib/systemd/tests/testdata/units/%N.sh +-StandardOutput=journal+console +-StandardError=journal+console + Type=oneshot diff --git a/0246-test-make-the-busy-loop-in-TEST-02-less-verbose.patch b/0246-test-make-the-busy-loop-in-TEST-02-less-verbose.patch new file mode 100644 index 0000000..c9fb57b --- /dev/null +++ b/0246-test-make-the-busy-loop-in-TEST-02-less-verbose.patch @@ -0,0 +1,49 @@ +From 1e684870a7f893fcd9138c0ca6bde0fcf3bf752a Mon Sep 17 00:00:00 2001 +From: Frantisek Sumsal +Date: Fri, 17 Jun 2022 14:44:49 +0200 +Subject: [PATCH] test: make the busy loop in TEST-02 less verbose + +as it unnecessarily clogs the logs. + +(cherry picked from commit 582547cbd38a02289451c1cea36a32f446b66677) + +Related: #2087652 +--- + test/units/testsuite-02.sh | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/test/units/testsuite-02.sh b/test/units/testsuite-02.sh +index af6e007825..54927a6377 100755 +--- a/test/units/testsuite-02.sh ++++ b/test/units/testsuite-02.sh +@@ -49,6 +49,7 @@ function report_result() { + systemd-cat cat "/$name.log" + } + ++set +x + # Associative array for running tasks, where running[test-path]=PID + declare -A running=() + for task in "${TEST_LIST[@]}"; do +@@ -72,6 +73,7 @@ for task in "${TEST_LIST[@]}"; do + done + + if [[ -x $task ]]; then ++ echo "Executing test '$task'" + log_file="/${task##*/}.log" + $task &>"$log_file" & + running[$task]=$! +@@ -80,11 +82,14 @@ done + + # Wait for remaining running tasks + for key in "${!running[@]}"; do ++ echo "Waiting for test '$key' to finish" + wait ${running[$key]} && ec=0 || ec=$? + report_result "$key" $ec + unset running["$key"] + done + ++set -x ++ + # Test logs are sometimes lost, as the system shuts down immediately after + journalctl --sync + diff --git a/0247-test-always-wrap-useradd-userdel-when-running-w-ASan.patch b/0247-test-always-wrap-useradd-userdel-when-running-w-ASan.patch new file mode 100644 index 0000000..e30e1b5 --- /dev/null +++ b/0247-test-always-wrap-useradd-userdel-when-running-w-ASan.patch @@ -0,0 +1,30 @@ +From d9055b5394aff8a8ec9c75c7cf4fc43f0617e6dd Mon Sep 17 00:00:00 2001 +From: Frantisek Sumsal +Date: Fri, 17 Jun 2022 14:47:10 +0200 +Subject: [PATCH] test: always wrap useradd/userdel when running w/ ASan + +since they dlopen() PAM modules, including systemd ones. + +(cherry picked from commit 94850fb956458703e0c6e0bee7f482aa41a47e9e) + +Related: #2087652 +--- + test/test-functions | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/test/test-functions b/test/test-functions +index 77d4a0afff..b5fcf07818 100644 +--- a/test/test-functions ++++ b/test/test-functions +@@ -2411,9 +2411,9 @@ inst_binary() { + + # Same as above, but we need to wrap certain libraries unconditionally + # +- # login - dlopen()s (not only) systemd's PAM modules ++ # login, useradd, userdel - dlopen()s (not only) systemd's PAM modules + # tar - called by machinectl in TEST-25 +- if get_bool "$IS_BUILT_WITH_ASAN" && [[ "$bin" =~ /(login|tar)$ ]]; then ++ if get_bool "$IS_BUILT_WITH_ASAN" && [[ "$bin" =~ /(login|tar|useradd|userdel)$ ]]; then + wrap_binary=1 + fi + diff --git a/0248-test-don-t-flush-debug-logs-to-the-console.patch b/0248-test-don-t-flush-debug-logs-to-the-console.patch new file mode 100644 index 0000000..ce6295c --- /dev/null +++ b/0248-test-don-t-flush-debug-logs-to-the-console.patch @@ -0,0 +1,239 @@ +From da2408f522a4ea65b30fb86619dd3f11e1308ac4 Mon Sep 17 00:00:00 2001 +From: Frantisek Sumsal +Date: Fri, 17 Jun 2022 15:06:59 +0200 +Subject: [PATCH] test: don't flush debug logs to the console + +Let's keep the debug logs in the journal, while logging only +testsute-*.sh stdout/stderr to the console (ba7abf7). This should make +the test output log a bit more readable and potentially the tests itself +a bit faster by avoiding console oversaturation. + +Also, it should significantly reduce the size of artifacts kept by CIs. + +(cherry picked from commit c84d1c9822bd181c37a5bd26b607edd67096839f) + +Related: #2087652 +--- + test/units/testsuite-20.sh | 1 - + test/units/testsuite-23.sh | 1 - + test/units/testsuite-27.sh | 1 - + test/units/testsuite-30.sh | 1 - + test/units/testsuite-32.sh | 1 - + test/units/testsuite-34.sh | 1 - + test/units/testsuite-38.sh | 1 - + test/units/testsuite-39.sh | 1 - + test/units/testsuite-40.sh | 1 - + test/units/testsuite-41.sh | 1 - + test/units/testsuite-46.sh | 1 - + test/units/testsuite-47.sh | 1 - + test/units/testsuite-52.sh | 1 - + test/units/testsuite-55.sh | 1 - + test/units/testsuite-59.sh | 1 - + test/units/testsuite-62.sh | 1 - + test/units/testsuite-66.sh | 1 - + 17 files changed, 17 deletions(-) + +diff --git a/test/units/testsuite-20.sh b/test/units/testsuite-20.sh +index fc87c18c4c..338769aacc 100755 +--- a/test/units/testsuite-20.sh ++++ b/test/units/testsuite-20.sh +@@ -4,7 +4,6 @@ set -eux + set -o pipefail + + systemd-analyze log-level debug +-systemd-analyze log-target console + + test "$(systemctl show -P MainPID testsuite-20.service)" -eq $$ + +diff --git a/test/units/testsuite-23.sh b/test/units/testsuite-23.sh +index 46e45c8780..e8f99ff60d 100755 +--- a/test/units/testsuite-23.sh ++++ b/test/units/testsuite-23.sh +@@ -4,7 +4,6 @@ set -eux + set -o pipefail + + systemd-analyze log-level debug +-systemd-analyze log-target console + + # Create a binary for which execve() will fail + touch /tmp/brokenbinary +diff --git a/test/units/testsuite-27.sh b/test/units/testsuite-27.sh +index 3b2f925153..c0701f35c3 100755 +--- a/test/units/testsuite-27.sh ++++ b/test/units/testsuite-27.sh +@@ -4,7 +4,6 @@ set -eux + set -o pipefail + + systemd-analyze log-level debug +-systemd-analyze log-target console + + systemd-run --wait --unit=test27-one \ + -p StandardOutput=file:/tmp/stdout \ +diff --git a/test/units/testsuite-30.sh b/test/units/testsuite-30.sh +index 51b9bdd093..57f46669f9 100755 +--- a/test/units/testsuite-30.sh ++++ b/test/units/testsuite-30.sh +@@ -4,7 +4,6 @@ set -eux + set -o pipefail + + systemd-analyze log-level debug +-systemd-analyze log-target console + + systemctl disable --now systemd-timesyncd.service + +diff --git a/test/units/testsuite-32.sh b/test/units/testsuite-32.sh +index 20ab67f6f1..5c289d0abf 100755 +--- a/test/units/testsuite-32.sh ++++ b/test/units/testsuite-32.sh +@@ -11,7 +11,6 @@ set -o pipefail + + if test -f /sys/fs/cgroup/system.slice/testsuite-32.service/memory.oom.group; then + systemd-analyze log-level debug +- systemd-analyze log-target console + + # Run a service that is guaranteed to be the first candidate for OOM killing + systemd-run --unit=oomtest.service \ +diff --git a/test/units/testsuite-34.sh b/test/units/testsuite-34.sh +index 57a7b950a0..e6171beaa6 100755 +--- a/test/units/testsuite-34.sh ++++ b/test/units/testsuite-34.sh +@@ -4,7 +4,6 @@ set -eux + set -o pipefail + + systemd-analyze log-level debug +-systemd-analyze log-target console + + function test_directory() { + local directory="$1" +diff --git a/test/units/testsuite-38.sh b/test/units/testsuite-38.sh +index f2f61b961f..438990d1c5 100755 +--- a/test/units/testsuite-38.sh ++++ b/test/units/testsuite-38.sh +@@ -5,7 +5,6 @@ set -eux + set -o pipefail + + systemd-analyze log-level debug +-systemd-analyze log-target console + + unit=testsuite-38-sleep.service + +diff --git a/test/units/testsuite-39.sh b/test/units/testsuite-39.sh +index 03abf391f1..5b77bbbaf1 100755 +--- a/test/units/testsuite-39.sh ++++ b/test/units/testsuite-39.sh +@@ -4,7 +4,6 @@ set -eux + set -o pipefail + + systemd-analyze log-level debug +-systemd-analyze log-target console + + export SYSTEMD_PAGER= + SERVICE_PATH="$(mktemp /etc/systemd/system/execreloadXXX.service)" +diff --git a/test/units/testsuite-40.sh b/test/units/testsuite-40.sh +index dd54fa174c..cec1fd3a7a 100755 +--- a/test/units/testsuite-40.sh ++++ b/test/units/testsuite-40.sh +@@ -4,7 +4,6 @@ set -eux + set -o pipefail + + systemd-analyze log-level debug +-systemd-analyze log-target console + + declare -A property + +diff --git a/test/units/testsuite-41.sh b/test/units/testsuite-41.sh +index 3b41db03f5..13bc684c2d 100755 +--- a/test/units/testsuite-41.sh ++++ b/test/units/testsuite-41.sh +@@ -7,7 +7,6 @@ set -o pipefail + MAX_SECS=60 + + systemd-analyze log-level debug +-systemd-analyze log-target console + + # test one: Restart=on-failure should restart the service + systemd-run --unit=one -p Type=oneshot -p Restart=on-failure /bin/bash -c "exit 1" \ +diff --git a/test/units/testsuite-46.sh b/test/units/testsuite-46.sh +index 3724a3b5f6..658613abb6 100755 +--- a/test/units/testsuite-46.sh ++++ b/test/units/testsuite-46.sh +@@ -34,7 +34,6 @@ wait_for_state() { + } + + systemd-analyze log-level debug +-systemd-analyze log-target console + systemctl service-log-level systemd-homed debug + + # Create a tmpfs to use as backing store for the home dir. That way we can enforce a size limit nicely. +diff --git a/test/units/testsuite-47.sh b/test/units/testsuite-47.sh +index ff10602df7..529e9617a5 100755 +--- a/test/units/testsuite-47.sh ++++ b/test/units/testsuite-47.sh +@@ -4,7 +4,6 @@ set -eux + set -o pipefail + + systemd-analyze log-level debug +-systemd-analyze log-target console + + systemctl start testsuite-47-repro + sleep 4 +diff --git a/test/units/testsuite-52.sh b/test/units/testsuite-52.sh +index 8a76ff6ed6..d78fdd53ba 100755 +--- a/test/units/testsuite-52.sh ++++ b/test/units/testsuite-52.sh +@@ -4,7 +4,6 @@ set -ex + set -o pipefail + + systemd-analyze log-level debug +-systemd-analyze log-target console + + systemctl enable test-honor-first-shutdown.service + systemctl start test-honor-first-shutdown.service +diff --git a/test/units/testsuite-55.sh b/test/units/testsuite-55.sh +index 379ea9e569..74dd285460 100755 +--- a/test/units/testsuite-55.sh ++++ b/test/units/testsuite-55.sh +@@ -4,7 +4,6 @@ set -eux + set -o pipefail + + systemd-analyze log-level debug +-systemd-analyze log-target console + + # Loose checks to ensure the environment has the necessary features for systemd-oomd + [[ -e /proc/pressure ]] || echo "no PSI" >>/skipped +diff --git a/test/units/testsuite-59.sh b/test/units/testsuite-59.sh +index 143e44ec63..83db053107 100755 +--- a/test/units/testsuite-59.sh ++++ b/test/units/testsuite-59.sh +@@ -28,7 +28,6 @@ wait_on_state_or_fail () { + } + + systemd-analyze log-level debug +-systemd-analyze log-target console + + + cat >/run/systemd/system/testservice-fail-59.service < +Date: Fri, 17 Jun 2022 15:28:17 +0200 +Subject: [PATCH] test: fix a couple of issues found by shellcheck + +(cherry picked from commit 72f0e89c0da3584d5d0a0124d791b02f0f04e769) + +Related: #2087652 +--- + test/units/testsuite-02.sh | 4 ++-- + test/units/testsuite-38.sh | 8 ++++---- + 2 files changed, 6 insertions(+), 6 deletions(-) + +diff --git a/test/units/testsuite-02.sh b/test/units/testsuite-02.sh +index 54927a6377..8ebcc575ee 100755 +--- a/test/units/testsuite-02.sh ++++ b/test/units/testsuite-02.sh +@@ -61,7 +61,7 @@ for task in "${TEST_LIST[@]}"; do + # Task has finished, report its result and drop it from the queue + wait "${running[$key]}" && ec=0 || ec=$? + report_result "$key" $ec +- unset running["$key"] ++ unset "running[$key]" + # Break from inner for loop and outer while loop to skip + # the sleep below when we find a free slot in the queue + break 2 +@@ -85,7 +85,7 @@ for key in "${!running[@]}"; do + echo "Waiting for test '$key' to finish" + wait ${running[$key]} && ec=0 || ec=$? + report_result "$key" $ec +- unset running["$key"] ++ unset "running[$key]" + done + + set -x +diff --git a/test/units/testsuite-38.sh b/test/units/testsuite-38.sh +index 438990d1c5..c5f9bcc22c 100755 +--- a/test/units/testsuite-38.sh ++++ b/test/units/testsuite-38.sh +@@ -17,7 +17,7 @@ dbus_freeze() { + local name object_path suffix + + suffix="${1##*.}" +- name="${1%.$suffix}" ++ name="${1%".$suffix"}" + object_path="/org/freedesktop/systemd1/unit/${name//-/_2d}_2e${suffix}" + + busctl call \ +@@ -31,7 +31,7 @@ dbus_thaw() { + local name object_path suffix + + suffix="${1##*.}" +- name="${1%.$suffix}" ++ name="${1%".$suffix"}" + object_path="/org/freedesktop/systemd1/unit/${name//-/_2d}_2e${suffix}" + + busctl call \ +@@ -65,7 +65,7 @@ dbus_can_freeze() { + local name object_path suffix + + suffix="${1##*.}" +- name="${1%.$suffix}" ++ name="${1%".$suffix"}" + object_path="/org/freedesktop/systemd1/unit/${name//-/_2d}_2e${suffix}" + + busctl get-property \ +@@ -79,7 +79,7 @@ check_freezer_state() { + local name object_path suffix + + suffix="${1##*.}" +- name="${1%.$suffix}" ++ name="${1%".$suffix"}" + object_path="/org/freedesktop/systemd1/unit/${name//-/_2d}_2e${suffix}" + + for _ in {0..10}; do diff --git a/0250-test-pass-the-initdir-to-check_result_-qemu-nspawn-h.patch b/0250-test-pass-the-initdir-to-check_result_-qemu-nspawn-h.patch new file mode 100644 index 0000000..ae0c9b8 --- /dev/null +++ b/0250-test-pass-the-initdir-to-check_result_-qemu-nspawn-h.patch @@ -0,0 +1,45 @@ +From e235b10483fb5b33f20ff0611ac5ed707d35d850 Mon Sep 17 00:00:00 2001 +From: Frantisek Sumsal +Date: Fri, 18 Feb 2022 14:10:15 +0100 +Subject: [PATCH] test: pass the initdir to check_result_{qemu,nspawn} hooks + +(cherry picked from commit 4b9a0c3aebdcf000f8d7ee569cb8a1806d07c397) + +Related: #2087652 +--- + test/test-functions | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/test/test-functions b/test/test-functions +index b5fcf07818..93ab32b68d 100644 +--- a/test/test-functions ++++ b/test/test-functions +@@ -1438,7 +1438,7 @@ check_result_nspawn() { + + # Run additional test-specific checks if defined by check_result_nspawn_hook() + if declare -F check_result_nspawn_hook >/dev/null; then +- if ! check_result_nspawn_hook; then ++ if ! check_result_nspawn_hook "${workspace}"; then + derror "check_result_nspawn_hook() returned with EC > 0" + ret=4 + fi +@@ -1457,16 +1457,16 @@ check_result_qemu() { + check_result_common "${initdir:?}" + ret=$? + +- _umount_dir "${initdir:?}" +- + # Run additional test-specific checks if defined by check_result_qemu_hook() + if declare -F check_result_qemu_hook >/dev/null; then +- if ! check_result_qemu_hook; then ++ if ! check_result_qemu_hook "${initdir:?}"; then + derror "check_result_qemu_hook() returned with EC > 0" + ret=4 + fi + fi + ++ _umount_dir "${initdir:?}" ++ + return $ret + } + diff --git a/0251-test-run-the-custom-check-hooks-before-common-checks.patch b/0251-test-run-the-custom-check-hooks-before-common-checks.patch new file mode 100644 index 0000000..840a55e --- /dev/null +++ b/0251-test-run-the-custom-check-hooks-before-common-checks.patch @@ -0,0 +1,64 @@ +From 895cc5ef78f91ed542d8be6a057033b7992ad91e Mon Sep 17 00:00:00 2001 +From: Frantisek Sumsal +Date: Fri, 17 Jun 2022 17:28:13 +0200 +Subject: [PATCH] test: run the custom check hooks before common checks + +since we delete the guest journals as part of the save_journal() step in +check_result_common(), making journal inaccessible from the custom check +hooks. + +(cherry picked from commit 35d2d2e61c7695b87a4ee3dc54d065f4de95f260) + +Related: #2087652 +--- + test/test-functions | 16 ++++++++-------- + 1 file changed, 8 insertions(+), 8 deletions(-) + +diff --git a/test/test-functions b/test/test-functions +index 93ab32b68d..1306dcf260 100644 +--- a/test/test-functions ++++ b/test/test-functions +@@ -1433,10 +1433,7 @@ check_result_nspawn() { + local workspace="${1:?}" + local ret + +- check_result_common "${workspace}" +- ret=$? +- +- # Run additional test-specific checks if defined by check_result_nspawn_hook() ++ # Run a test-specific checks if defined by check_result_nspawn_hook() + if declare -F check_result_nspawn_hook >/dev/null; then + if ! check_result_nspawn_hook "${workspace}"; then + derror "check_result_nspawn_hook() returned with EC > 0" +@@ -1444,6 +1441,9 @@ check_result_nspawn() { + fi + fi + ++ check_result_common "${workspace}" ++ ret=$? ++ + _umount_dir "${initdir:?}" + + return $ret +@@ -1454,10 +1454,7 @@ check_result_qemu() { + local ret + mount_initdir + +- check_result_common "${initdir:?}" +- ret=$? +- +- # Run additional test-specific checks if defined by check_result_qemu_hook() ++ # Run a test-specific checks if defined by check_result_qemu_hook() + if declare -F check_result_qemu_hook >/dev/null; then + if ! check_result_qemu_hook "${initdir:?}"; then + derror "check_result_qemu_hook() returned with EC > 0" +@@ -1465,6 +1462,9 @@ check_result_qemu() { + fi + fi + ++ check_result_common "${initdir:?}" ++ ret=$? ++ + _umount_dir "${initdir:?}" + + return $ret diff --git a/0252-test-check-journal-directly-instead-of-capturing-con.patch b/0252-test-check-journal-directly-instead-of-capturing-con.patch new file mode 100644 index 0000000..6c294d9 --- /dev/null +++ b/0252-test-check-journal-directly-instead-of-capturing-con.patch @@ -0,0 +1,37 @@ +From 37b398e2a3d6cd225a3121843540a033f4415b80 Mon Sep 17 00:00:00 2001 +From: Frantisek Sumsal +Date: Fri, 17 Jun 2022 17:29:22 +0200 +Subject: [PATCH] test: check journal directly instead of capturing console + output + +(cherry picked from commit 8cda7b91ff267fc21325d4886980e243389a7566) + +Related: #2087652 +--- + test/TEST-52-HONORFIRSTSHUTDOWN/test.sh | 13 ++++--------- + 1 file changed, 4 insertions(+), 9 deletions(-) + +diff --git a/test/TEST-52-HONORFIRSTSHUTDOWN/test.sh b/test/TEST-52-HONORFIRSTSHUTDOWN/test.sh +index 936e801c51..6a1ec9ca29 100755 +--- a/test/TEST-52-HONORFIRSTSHUTDOWN/test.sh ++++ b/test/TEST-52-HONORFIRSTSHUTDOWN/test.sh +@@ -14,15 +14,10 @@ TEST_NO_QEMU=1 + # could turn into a reboot if the test fails. + NSPAWN_TIMEOUT=60 + +-# Remove this file if it exists. This is used along with +-# the make target "finish". Since concrete confirmation is +-# only found from the console during the poweroff. +-rm -f /tmp/honorfirstshutdown.log >/dev/null +- + check_result_nspawn_hook() { +- grep -q "Shutdown is already active. Skipping emergency action request" /tmp/honorfirstshutdown.log ++ local workspace="${1:?}" ++ ++ "${JOURNALCTL:?}" -D "${workspace:?}/var/log/journal" --grep "Shutdown is already active. Skipping emergency action request" --no-pager + } + +-# Note: don't use a pipe in the following expression, as it breaks the trap +-# handlers we have defined in test/test-functions. +-do_test "$@" > >(tee /tmp/honorfirstshutdown.log) ++do_test "$@" diff --git a/0253-test-use-saved-process-PID-instead-of.patch b/0253-test-use-saved-process-PID-instead-of.patch new file mode 100644 index 0000000..533ce85 --- /dev/null +++ b/0253-test-use-saved-process-PID-instead-of.patch @@ -0,0 +1,37 @@ +From c81dea716e04419f8f7b83346015ae8f834ec30c Mon Sep 17 00:00:00 2001 +From: Frantisek Sumsal +Date: Mon, 20 Jun 2022 12:27:39 +0200 +Subject: [PATCH] test: use saved process PID instead of %% + +As the `%%` specifier might fail if the current job (i.e. the last +background job) already finished: + +``` +[ 61.692196] testsuite-04.sh[656]: ++ systemd-id128 new +[ 61.705407] testsuite-04.sh[263]: + ID=912cb8f8ef304153a123f772bb0fe9e0 +[ 61.706318] testsuite-04.sh[657]: + systemd-cat -t 912cb8f8ef304153a123f772bb0fe9e0 bash -c 'echo parent; (echo child) & wait' +[ 61.720940] testsuite-04.sh[263]: + PID=657 +[ 61.721126] testsuite-04.sh[263]: + wait %% +[ 61.723014] testsuite-04.sh[263]: /usr/lib/systemd/tests/testdata/units/testsuite-04.sh: line 96: wait: %%: no such job +``` + +(cherry picked from commit 08970485003c25ce2c4adfaeea2d58558d311d42) + +Related: #2087652 +--- + test/units/testsuite-04.sh | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/test/units/testsuite-04.sh b/test/units/testsuite-04.sh +index 7521a6d2e5..b5468cbea4 100755 +--- a/test/units/testsuite-04.sh ++++ b/test/units/testsuite-04.sh +@@ -93,7 +93,7 @@ cmp /expected /output + ID=$(systemd-id128 new) + systemd-cat -t "$ID" bash -c 'echo parent; (echo child) & wait' & + PID=$! +-wait %% ++wait $PID + journalctl --sync + # We can drop this grep when https://github.com/systemd/systemd/issues/13937 + # has a fix. diff --git a/0254-test-account-for-ADDR_NO_RANDOMIZE-if-it-s-set.patch b/0254-test-account-for-ADDR_NO_RANDOMIZE-if-it-s-set.patch new file mode 100644 index 0000000..3a735a4 --- /dev/null +++ b/0254-test-account-for-ADDR_NO_RANDOMIZE-if-it-s-set.patch @@ -0,0 +1,58 @@ +From f55e25db1b2f69cd5d19508bda34c52f5f92e800 Mon Sep 17 00:00:00 2001 +From: Frantisek Sumsal +Date: Thu, 9 Jun 2022 11:34:09 +0200 +Subject: [PATCH] test: account for ADDR_NO_RANDOMIZE if it's set + +On ppc64le sanitizers disable ASLR (i.e. by setting ADDR_NO_RANDOMIZE), +which opinionated_personality() doesn't return. Let's tweak the current +personality ourselves in such cases. + +See: https://github.com/llvm/llvm-project/commit/78f7a6eaa601bfdd6ae70ffd3da2254c21ff77f9 + +Resolves: #23666 +(cherry picked from commit 894dad2975c61f59e71561cab21d6f85e8523b57) + +Related: #2087652 +--- + src/test/test-seccomp.c | 16 ++++++++++++---- + 1 file changed, 12 insertions(+), 4 deletions(-) + +diff --git a/src/test/test-seccomp.c b/src/test/test-seccomp.c +index 7ccfeadbb8..1f96ba4f80 100644 +--- a/src/test/test-seccomp.c ++++ b/src/test/test-seccomp.c +@@ -934,8 +934,15 @@ TEST(lock_personality) { + } + + assert_se(opinionated_personality(¤t) >= 0); ++ /* On ppc64le sanitizers disable ASLR (i.e. by setting ADDR_NO_RANDOMIZE), ++ * which opinionated_personality() doesn't return. Let's tweak the current ++ * personality ourselves in such cases. ++ * See: https://github.com/llvm/llvm-project/commit/78f7a6eaa601bfdd6ae70ffd3da2254c21ff77f9 ++ */ ++ if (FLAGS_SET(safe_personality(PERSONALITY_INVALID), ADDR_NO_RANDOMIZE)) ++ current |= ADDR_NO_RANDOMIZE; + +- log_info("current personality=%lu", current); ++ log_info("current personality=0x%lX", current); + + pid = fork(); + assert_se(pid >= 0); +@@ -945,13 +952,14 @@ TEST(lock_personality) { + + assert_se((unsigned long) safe_personality(current) == current); + +- /* Note, we also test that safe_personality() works correctly, by checkig whether errno is properly ++ /* Note, we also test that safe_personality() works correctly, by checking whether errno is properly + * set, in addition to the return value */ + errno = 0; +- assert_se(safe_personality(PER_LINUX | ADDR_NO_RANDOMIZE) == -EPERM); ++ assert_se(safe_personality(PER_LINUX | MMAP_PAGE_ZERO) == -EPERM); + assert_se(errno == EPERM); + +- assert_se(safe_personality(PER_LINUX | MMAP_PAGE_ZERO) == -EPERM); ++ if (!FLAGS_SET(current, ADDR_NO_RANDOMIZE)) ++ assert_se(safe_personality(PER_LINUX | ADDR_NO_RANDOMIZE) == -EPERM); + assert_se(safe_personality(PER_LINUX | ADDR_COMPAT_LAYOUT) == -EPERM); + assert_se(safe_personality(PER_LINUX | READ_IMPLIES_EXEC) == -EPERM); + assert_se(safe_personality(PER_LINUX_32BIT) == -EPERM); diff --git a/0255-fuzz-bcd-silence-warning-about-always-true-compariso.patch b/0255-fuzz-bcd-silence-warning-about-always-true-compariso.patch new file mode 100644 index 0000000..13aeca4 --- /dev/null +++ b/0255-fuzz-bcd-silence-warning-about-always-true-compariso.patch @@ -0,0 +1,27 @@ +From e161d3a1297408415842731be73af765fbdc5c3b Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Tue, 4 Jan 2022 09:31:25 +0100 +Subject: [PATCH] fuzz-bcd: silence warning about always-true comparison + +Occurs with gcc-11.2.1-7.fc35.x86_64. + +(cherry picked from commit 5377ad4ea44e771b5eb436d381ea9f3506488295) + +Related: #2087652 +--- + src/boot/efi/fuzz-bcd.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/src/boot/efi/fuzz-bcd.c b/src/boot/efi/fuzz-bcd.c +index e5ed6638a4..3df55a5c36 100644 +--- a/src/boot/efi/fuzz-bcd.c ++++ b/src/boot/efi/fuzz-bcd.c +@@ -21,6 +21,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { + assert_se(p); + + char16_t *title = get_bcd_title(p, size); +- assert_se(!title || char16_strlen(title) >= 0); ++ if (title) ++ (void) char16_strlen(title); + return 0; + } diff --git a/0256-test-disable-test_ntp-on-RHEL.patch b/0256-test-disable-test_ntp-on-RHEL.patch new file mode 100644 index 0000000..1290369 --- /dev/null +++ b/0256-test-disable-test_ntp-on-RHEL.patch @@ -0,0 +1,26 @@ +From 9c9187a252300f5f453d995ac50edf88c5e0c855 Mon Sep 17 00:00:00 2001 +From: Frantisek Sumsal +Date: Wed, 22 Jun 2022 15:29:02 +0200 +Subject: [PATCH] test: disable test_ntp on RHEL + +since we don't ship systemd-timesyncd. + +rhel-only + +Related: #2087652 +--- + test/units/testsuite-45.sh | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/test/units/testsuite-45.sh b/test/units/testsuite-45.sh +index 322d8086e7..75e07bc09a 100755 +--- a/test/units/testsuite-45.sh ++++ b/test/units/testsuite-45.sh +@@ -258,7 +258,6 @@ EOF + + test_timezone + test_adjtime +-test_ntp + + touch /testok + rm /failed diff --git a/0257-core-do-not-filter-out-systemd.unit-and-run-level-sp.patch b/0257-core-do-not-filter-out-systemd.unit-and-run-level-sp.patch new file mode 100644 index 0000000..e5c6950 --- /dev/null +++ b/0257-core-do-not-filter-out-systemd.unit-and-run-level-sp.patch @@ -0,0 +1,40 @@ +From b6d5a57b8181cc2565e2231fc9baf95fc9cc481e Mon Sep 17 00:00:00 2001 +From: Yu Watanabe +Date: Sat, 2 Jul 2022 04:18:41 +0900 +Subject: [PATCH] core: do not filter out systemd.unit= and run-level specifier + from kernel command line + +Fixes a bug introduced by 846f1da465beda990c1c01346311393f485df467. + +The commit 846f1da465beda990c1c01346311393f485df467 made systemd.unit= +filtered out from the command line. That causes debug-generator does not +work as expected on daemon-reexecute, and we cannot call `systemctl +daemon-reexecute` in our test suite running on nspawn. + +Fixes issue reported in https://github.com/systemd/systemd/pull/23851#issuecomment-1170992052. + +(cherry picked from commit bffde9b5869fffc09e7824d2ac0aeb82a31a134b) + +Related: #2087652 +--- + src/core/main.c | 7 ------- + 1 file changed, 7 deletions(-) + +diff --git a/src/core/main.c b/src/core/main.c +index 667e972364..03efaa03be 100644 +--- a/src/core/main.c ++++ b/src/core/main.c +@@ -1812,13 +1812,6 @@ static void filter_args( + continue; + } + +- if (startswith(src[i], +- in_initrd() ? "rd.systemd.unit=" : "systemd.unit=")) +- continue; +- +- if (runlevel_to_target(src[i])) +- continue; +- + /* Seems we have a good old option. Let's pass it over to the new instance. */ + dst[(*dst_index)++] = src[i]; + } diff --git a/0258-test-add-a-simple-test-for-daemon-reexec.patch b/0258-test-add-a-simple-test-for-daemon-reexec.patch new file mode 100644 index 0000000..2d3c08d --- /dev/null +++ b/0258-test-add-a-simple-test-for-daemon-reexec.patch @@ -0,0 +1,27 @@ +From a1b8ff570b5ed95697f4748cfe3bbe154802c37e Mon Sep 17 00:00:00 2001 +From: Frantisek Sumsal +Date: Sat, 2 Jul 2022 05:21:52 +0900 +Subject: [PATCH] test: add a simple test for daemon-reexec + +(cherry picked from commit d1b1bbfbfa1cb7d225250fc08089d1de17eaef7c) + +Related: #2087652 +--- + test/units/testsuite-03.sh | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/test/units/testsuite-03.sh b/test/units/testsuite-03.sh +index 070e978cda..7c5a3b8f19 100755 +--- a/test/units/testsuite-03.sh ++++ b/test/units/testsuite-03.sh +@@ -3,6 +3,10 @@ + set -eux + set -o pipefail + ++# Simple test for that daemon-reexec works in container. ++# See: https://github.com/systemd/systemd/pull/23883 ++systemctl daemon-reexec ++ + # Test merging of a --job-mode=ignore-dependencies job into a previously + # installed job. + diff --git a/0259-test-install-usr-libexec-vi-as-well.patch b/0259-test-install-usr-libexec-vi-as-well.patch new file mode 100644 index 0000000..f9560a2 --- /dev/null +++ b/0259-test-install-usr-libexec-vi-as-well.patch @@ -0,0 +1,27 @@ +From e6dfbe67f94d60b889f3031ebb644ed262d7fe35 Mon Sep 17 00:00:00 2001 +From: Frantisek Sumsal +Date: Sat, 16 Apr 2022 14:43:17 +0200 +Subject: [PATCH] test: install /usr/libexec/vi as well + +since `/bin/vi` (at least on Fedora) is a shell wrapper which runs +either `/bin/vim` or `/usr/libexec/vi` based on availability. + +(cherry picked from commit 8afe2f53b25ca99bc5bd1ec0c5dff7e183712577) + +Related: #2087652 +--- + test/test-functions | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/test/test-functions b/test/test-functions +index 1306dcf260..9e171cba30 100644 +--- a/test/test-functions ++++ b/test/test-functions +@@ -225,6 +225,7 @@ DEBUGTOOLS=( + stty + tty + vi ++ /usr/libexec/vi + ) + + is_built_with_asan() { diff --git a/0260-test-resize-the-terminal-automagically-with-INTERACT.patch b/0260-test-resize-the-terminal-automagically-with-INTERACT.patch new file mode 100644 index 0000000..72dbd31 --- /dev/null +++ b/0260-test-resize-the-terminal-automagically-with-INTERACT.patch @@ -0,0 +1,37 @@ +From 70ff2f68c1cf9bdfe79ab4719ee0a051bbcb22eb Mon Sep 17 00:00:00 2001 +From: Frantisek Sumsal +Date: Sun, 17 Apr 2022 19:49:17 +0200 +Subject: [PATCH] test: resize the terminal automagically with + INTERACTIVE_DEBUG=yes + +(cherry picked from commit 17082e8ac1b5335465876d100774893ba735fca4) + +Related: #2087652 +--- + test/test-functions | 12 +++++------- + 1 file changed, 5 insertions(+), 7 deletions(-) + +diff --git a/test/test-functions b/test/test-functions +index 9e171cba30..42ad16050c 100644 +--- a/test/test-functions ++++ b/test/test-functions +@@ -1678,14 +1678,12 @@ install_debug_tools() { + local getty_override="${initdir:?}/etc/systemd/system/serial-getty@.service.d" + mkdir -p "$getty_override" + echo -e "[Service]\nEnvironment=TERM=linux" >"$getty_override/default-TERM.conf" ++ echo 'export TERM=linux' >>"$initdir/etc/profile" + +- cat >"$initdir/etc/motd" </dev/null; then ++ image_install resize ++ echo "resize" >>"$initdir/etc/profile" ++ fi + fi + } + diff --git a/0261-test-create-an-ASan-wrapper-for-getent-and-su.patch b/0261-test-create-an-ASan-wrapper-for-getent-and-su.patch new file mode 100644 index 0000000..12f3b92 --- /dev/null +++ b/0261-test-create-an-ASan-wrapper-for-getent-and-su.patch @@ -0,0 +1,31 @@ +From ab5ddf261e2a8c840c0224b5c8ef5932465e4eb8 Mon Sep 17 00:00:00 2001 +From: Frantisek Sumsal +Date: Thu, 7 Jul 2022 14:12:38 +0200 +Subject: [PATCH] test: create an ASan wrapper for `getent` and `su` + +since they "suffer" from the same issue as `login` and other binaries +that load PAM stuff + +(cherry picked from commit fdb70dd9222219307ca53662e789fc9304ca3616) + +Related: #2087652 +--- + test/test-functions | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/test/test-functions b/test/test-functions +index 42ad16050c..8523cf2d21 100644 +--- a/test/test-functions ++++ b/test/test-functions +@@ -2410,9 +2410,9 @@ inst_binary() { + + # Same as above, but we need to wrap certain libraries unconditionally + # +- # login, useradd, userdel - dlopen()s (not only) systemd's PAM modules ++ # getent, login, su, useradd, userdel - dlopen()s (not only) systemd's PAM modules + # tar - called by machinectl in TEST-25 +- if get_bool "$IS_BUILT_WITH_ASAN" && [[ "$bin" =~ /(login|tar|useradd|userdel)$ ]]; then ++ if get_bool "$IS_BUILT_WITH_ASAN" && [[ "$bin" =~ /(getent|login|su|tar|useradd|userdel)$ ]]; then + wrap_binary=1 + fi + diff --git a/0262-test-mark-partition-bootable.patch b/0262-test-mark-partition-bootable.patch new file mode 100644 index 0000000..fd719a2 --- /dev/null +++ b/0262-test-mark-partition-bootable.patch @@ -0,0 +1,29 @@ +From f039730a8e2d0a6c8ea7539ffb1a54c8951f3622 Mon Sep 17 00:00:00 2001 +From: Ludwig Nussel +Date: Mon, 27 Dec 2021 10:34:52 +0100 +Subject: [PATCH] test: mark partition bootable + +Make test suite partition bootable so nspawn can use the image directly. +Useful for local testing. + +https://systemd.io/DISCOVERABLE_PARTITIONS/ +(cherry picked from commit b13a8b5b377f60cacad98fa8a989e992e8724c0e) + +Related: #2087652 +--- + test/test-functions | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/test/test-functions b/test/test-functions +index 8523cf2d21..b596ce1382 100644 +--- a/test/test-functions ++++ b/test/test-functions +@@ -1219,7 +1219,7 @@ create_empty_image() { + LOOPDEV=$(losetup --show -P -f "$IMAGE_PUBLIC") + [ -b "$LOOPDEV" ] || return 1 + sfdisk "$LOOPDEV" < +Date: Thu, 7 Jul 2022 14:13:32 +0200 +Subject: [PATCH] test: bump the data partition size if we don't strip binaries + +so we can run TEST-24 under sanitizers as well. + +Also, when at it, use the 'named-fields' sfdisk format to make the code +a bit more descriptive without needing a manual. + +(cherry picked from commit 98b27937cb02dac98d8a9f0c48ba677b45df0831) + +Related: #2087652 +--- + test/test-functions | 23 ++++++++++++++--------- + 1 file changed, 14 insertions(+), 9 deletions(-) + +diff --git a/test/test-functions b/test/test-functions +index b596ce1382..b0f3b28def 100644 +--- a/test/test-functions ++++ b/test/test-functions +@@ -1194,33 +1194,38 @@ create_empty_image() { + exit 1 + fi + +- local size=500 ++ # Partition sizes are in MiBs ++ local root_size=500 ++ local data_size=50 + if ! get_bool "$NO_BUILD"; then + if meson configure "${BUILD_DIR:?}" | grep 'static-lib\|standalone-binaries' | awk '{ print $2 }' | grep -q 'true'; then +- size=$((size+=200)) ++ root_size=$((root_size+=200)) + fi + if meson configure "${BUILD_DIR:?}" | grep 'link-.*-shared' | awk '{ print $2 }' | grep -q 'false'; then +- size=$((size+=200)) ++ root_size=$((root_size+=200)) + fi + if get_bool "$IS_BUILT_WITH_COVERAGE"; then +- size=$((size+=250)) ++ root_size=$((root_size+=250)) + fi + fi + if ! get_bool "$STRIP_BINARIES"; then +- size=$((4 * size)) ++ root_size=$((4 * root_size)) ++ data_size=$((2 * data_size)) + fi + +- echo "Setting up ${IMAGE_PUBLIC:?} (${size} MB)" ++ echo "Setting up ${IMAGE_PUBLIC:?} (${root_size} MB)" + rm -f "${IMAGE_PRIVATE:?}" "$IMAGE_PUBLIC" + + # Create the blank file to use as a root filesystem +- truncate -s "${size}M" "$IMAGE_PUBLIC" ++ truncate -s "${root_size}M" "$IMAGE_PUBLIC" + + LOOPDEV=$(losetup --show -P -f "$IMAGE_PUBLIC") + [ -b "$LOOPDEV" ] || return 1 ++ # Create two partitions - a root one and a data one (utilized by some tests) + sfdisk "$LOOPDEV" < +Date: Thu, 7 Jul 2022 17:16:31 +0200 +Subject: [PATCH] test: use PBKDF2 with capped iterations instead of Argon2 + +to reduce the amount of resources the test needs (similarly to TEST-24 +where we do the same thing). + +(cherry picked from commit 8fec14a7d397f52b93024bf3417de8f77b0d85e6) + +Related: #2087652 +--- + test/units/testsuite-70.sh | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/test/units/testsuite-70.sh b/test/units/testsuite-70.sh +index f395ef4e5e..09f78a0226 100755 +--- a/test/units/testsuite-70.sh ++++ b/test/units/testsuite-70.sh +@@ -9,7 +9,7 @@ export SYSTEMD_LOG_LEVEL=debug + img="/var/tmp/test.img" + dd if=/dev/zero of=$img bs=1024k count=20 status=none + echo -n passphrase >/tmp/passphrase +-cryptsetup luksFormat -q --use-urandom $img /tmp/passphrase ++cryptsetup luksFormat -q --pbkdf pbkdf2 --pbkdf-force-iterations 1000 --use-urandom $img /tmp/passphrase + + # Enroll unlock with default PCR policy + env PASSWORD=passphrase systemd-cryptenroll --tpm2-device=auto $img diff --git a/0265-locale-drop-unnecessary-allocation.patch b/0265-locale-drop-unnecessary-allocation.patch new file mode 100644 index 0000000..f123b35 --- /dev/null +++ b/0265-locale-drop-unnecessary-allocation.patch @@ -0,0 +1,31 @@ +From b93eca3f277547c7e45c6840f2a582b20319a93a Mon Sep 17 00:00:00 2001 +From: Yu Watanabe +Date: Sat, 18 Jun 2022 11:06:46 +0900 +Subject: [PATCH] locale: drop unnecessary allocation + +Fixes a bug introduced by 3d36b5d7e7b191fca7c5c65dbab94d99cf5f0230. + +Fixes #23777. + +(cherry picked from commit e83cfbf97247e391e9fc19a7abb2712c77f3b4c0) + +Related: #2087652 +--- + src/locale/localed.c | 4 ---- + 1 file changed, 4 deletions(-) + +diff --git a/src/locale/localed.c b/src/locale/localed.c +index 2c324efb14..791b5e60dd 100644 +--- a/src/locale/localed.c ++++ b/src/locale/localed.c +@@ -152,10 +152,6 @@ static int property_get_locale( + if (r < 0) + return r; + +- l = new0(char*, _VARIABLE_LC_MAX+1); +- if (!l) +- return -ENOMEM; +- + r = locale_context_build_env(&c->locale_context, &l, NULL); + if (r < 0) + return r; diff --git a/systemd.spec b/systemd.spec index d4356c1..f371606 100644 --- a/systemd.spec +++ b/systemd.spec @@ -21,7 +21,7 @@ Name: systemd Url: https://www.freedesktop.org/wiki/Software/systemd Version: 250 -Release: 7%{?dist} +Release: 8%{?dist} # For a breakdown of the licensing, see README License: LGPLv2+ and MIT and GPLv2+ Summary: System and Service Manager @@ -152,6 +152,197 @@ Patch0071: 0071-man-clarify-Environmentfile-format.patch Patch0072: 0072-test-load-fragment-add-a-basic-test-for-config_parse.patch Patch0073: 0073-core-execute-use-_cleanup_-in-exec_context_load_envi.patch Patch0074: 0074-test-env-file-add-tests-for-quoting-in-env-files.patch +Patch0075: 0075-core-shorten-long-unit-names-that-are-based-on-paths.patch +Patch0076: 0076-tests-add-test-case-for-long-unit-names.patch +Patch0077: 0077-tests-reflect-that-we-can-now-handle-devices-with-ve.patch +Patch0078: 0078-test-extend-the-hashed-unit-names-coverage-a-bit.patch +Patch0079: 0079-Revert-kernel-install-also-remove-modules.builtin.al.patch +Patch0080: 0080-Revert-kernel-install-prefer-boot-over-boot-efi-for-.patch +Patch0081: 0081-kernel-install-50-depmod-port-to-bin-sh.patch +Patch0082: 0082-kernel-install-90-loaderentry-port-to-bin-sh.patch +Patch0083: 0083-kernel-install-fix-shellcheck.patch +Patch0084: 0084-kernel-install-port-to-bin-sh.patch +Patch0085: 0085-kernel-install-90-loaderentry-error-out-on-nonexiste.patch +Patch0086: 0086-kernel-install-don-t-pull-out-KERNEL_IMAGE.patch +Patch0087: 0087-kernel-install-prefer-boot-over-boot-efi-for-BOOT_RO.patch +Patch0088: 0088-kernel-install-also-remove-modules.builtin.alias.bin.patch +Patch0089: 0089-kernel-install-add-new-variable-KERNEL_INSTALL_INITR.patch +Patch0090: 0090-kernel-install-k-i-already-creates-ENTRY_DIR_ABS-no-.patch +Patch0091: 0091-kernel-install-prefix-errors-with-Error-exit-immedia.patch +Patch0092: 0092-kernel-install-add-KERNEL_INSTALL_STAGING_AREA-direc.patch +Patch0093: 0093-kernel-install-add-missing-log-line.patch +Patch0094: 0094-kernel-install-don-t-try-to-persist-used-machine-ID-.patch +Patch0095: 0095-kernel-install-add-a-new-ENTRY_TOKEN-variable-for-na.patch +Patch0096: 0096-kernel-install-only-generate-systemd.boot_id-in-kern.patch +Patch0097: 0097-kernel-install-search-harder-for-kernel-image-initrd.patch +Patch0098: 0098-kernel-install-add-new-inspect-verb-showing-paths-an.patch +Patch0099: 0099-ci-Mergify-configuration-update.patch +Patch0100: 0100-ci-Mergify-fix-copy-paste-bug.patch +Patch0101: 0101-shared-Fix-memory-leak-in-bus_append_execute_propert.patch +Patch0102: 0102-fuzz-no-longer-skip-empty-files.patch +Patch0103: 0103-networkctl-open-the-bus-just-once.patch +Patch0104: 0104-json-align-table.patch +Patch0105: 0105-fuzz-json-optionally-allow-logging-and-output.patch +Patch0106: 0106-shared-json-reduce-scope-of-variables.patch +Patch0107: 0107-fuzz-json-also-do-sorting-and-normalizing-and-other-.patch +Patch0108: 0108-shared-json-wrap-long-comments.patch +Patch0109: 0109-shared-json-fix-memory-leak-on-failed-normalization.patch +Patch0110: 0110-shared-json-add-helper-to-ref-first-unref-second.patch +Patch0111: 0111-basic-alloc-util-remove-unnecessary-parens.patch +Patch0112: 0112-fuzz-json-also-try-self-merge-operations.patch +Patch0113: 0113-shared-json-fix-another-memleak-in-normalization.patch +Patch0114: 0114-shared-json-fix-memleak-in-sort.patch +Patch0115: 0115-execute-fix-resource-leak.patch +Patch0116: 0116-tests-ignore-dbus-broker-launcher.patch +Patch0117: 0117-core-timer-fix-memleak.patch +Patch0118: 0118-timedatectl-fix-a-memory-leak.patch +Patch0119: 0119-test-fix-file-descriptor-leak-in-test-psi-util.patch +Patch0120: 0120-test-fix-file-descriptor-leak-in-test-tmpfiles.c.patch +Patch0121: 0121-test-fix-file-descriptor-leak-in-test-fs-util.patch +Patch0122: 0122-test-fix-file-descriptor-leak-in-test-oomd-util.patch +Patch0123: 0123-test-fix-file-descriptor-leak-in-test-catalog.patch +Patch0124: 0124-test-make-masking-of-supplementary-services-configur.patch +Patch0125: 0125-test-fuzz-our-dbus-interfaces-with-dfuzzer.patch +Patch0126: 0126-test-skip-TEST-21-DFUZZER-without-ASan.patch +Patch0127: 0127-core-annotate-Reexecute-as-NoReply.patch +Patch0128: 0128-test-always-force-a-new-image-for-dfuzzer.patch +Patch0129: 0129-test-make-dfuzzer-less-verbose.patch +Patch0130: 0130-test-drop-the-at_exit-coredump-check.patch +Patch0131: 0131-test-make-the-shutdown-routine-a-bit-more-robust.patch +Patch0132: 0132-tree-wide-drop-manually-crafted-message-for-missing-.patch +Patch0133: 0133-test-allow-overriding-QEMU_MEM-when-running-w-ASan.patch +Patch0134: 0134-test-don-t-test-buses-we-don-t-ship.patch +Patch0135: 0135-shutdown-get-only-active-md-arrays.patch +Patch0136: 0136-bus-Use-OrderedSet-for-introspection.patch +Patch0137: 0137-logind-session-dbus-allow-to-set-display-name-via-db.patch +Patch0138: 0138-ci-limit-which-env-variables-we-pass-through-sudo.patch +Patch0139: 0139-ci-Mergify-Add-ci-waived-logic.patch +Patch0140: 0140-json-use-unsigned-for-refernce-counter.patch +Patch0141: 0141-macro-check-over-flow-in-reference-counter.patch +Patch0142: 0142-sd-bus-fix-reference-counter-to-be-incremented.patch +Patch0143: 0143-sd-bus-introduce-ref-unref-function-for-track_item.patch +Patch0144: 0144-sd-bus-do-not-read-unused-value.patch +Patch0145: 0145-sd-bus-do-not-return-negative-errno-when-unknown-nam.patch +Patch0146: 0146-sd-bus-use-hashmap_contains-and-drop-unnecessary-cas.patch +Patch0147: 0147-test-shorten-code-a-bit.patch +Patch0148: 0148-test-add-several-tests-for-track-item.patch +Patch0149: 0149-core-slice-make-slice_freezer_action-return-0-if-fre.patch +Patch0150: 0150-core-unit-fix-use-after-free.patch +Patch0151: 0151-core-timer-fix-potential-use-after-free.patch +Patch0152: 0152-core-command-argument-can-be-longer-than-PATH_MAX.patch +Patch0153: 0153-shared-install-consistently-use-lp-as-the-name-for-t.patch +Patch0154: 0154-shared-specifier-treat-NULL-the-same-as.patch +Patch0155: 0155-shared-install-do-not-print-aliases-longer-than-UNIT.patch +Patch0156: 0156-shared-install-printf-drop-now-unused-install_path_p.patch +Patch0157: 0157-strv-declare-iterator-of-FOREACH_STRING-in-the-loop.patch +Patch0158: 0158-basic-unit-file-split-out-the-subroutine-for-symlink.patch +Patch0159: 0159-basic-stat-util-add-null_or_empty_path_with_root.patch +Patch0160: 0160-shared-install-reuse-the-standard-symlink-verificati.patch +Patch0161: 0161-shared-install-add-a-bit-more-quoting.patch +Patch0162: 0162-test-add-test-for-systemctl-link-enable.patch +Patch0163: 0163-tests-add-helper-for-creating-tempfiles-with-content.patch +Patch0164: 0164-man-clarify-the-descriptions-of-aliases-and-linked-u.patch +Patch0165: 0165-basic-add-new-variable-SYSTEMD_OS_RELEASE-to-overrid.patch +Patch0166: 0166-test-os-util-add-basic-tests-for-os-release-parsing.patch +Patch0167: 0167-basic-env-file-make-load-env-file-deduplicate-entrie.patch +Patch0168: 0168-man-os-release-add-a-note-about-repeating-entries.patch +Patch0169: 0169-shared-specifier-clarify-and-add-test-for-missing-da.patch +Patch0170: 0170-shared-specifier-provide-proper-error-messages-when-.patch +Patch0171: 0171-shared-install-provide-proper-error-messages-when-in.patch +Patch0172: 0172-shared-install-move-scope-into-InstallContext.patch +Patch0173: 0173-shared-specifier-fix-u-U-g-G-when-called-as-unprivil.patch +Patch0174: 0174-shared-install-simplify-unit_file_dump_changes.patch +Patch0175: 0175-shared-install-propagate-errors-about-invalid-aliase.patch +Patch0176: 0176-shared-install-return-failure-when-enablement-fails-.patch +Patch0177: 0177-systemctl-fix-silent-failure-when-root-is-not-found.patch +Patch0178: 0178-shared-install-also-check-for-self-aliases-during-in.patch +Patch0179: 0179-docs-Correct-WantedBy-regarding-template-units.patch +Patch0180: 0180-man-fix-invalid-description-of-template-handling-in-.patch +Patch0181: 0181-shared-install-drop-unnecessary-casts.patch +Patch0182: 0182-strv-make-iterator-in-STRV_FOREACH-declaread-in-the-.patch +Patch0183: 0183-core-ExecContext-restrict_filesystems-is-set-of-stri.patch +Patch0184: 0184-install-when-linking-a-file-create-the-link-first-or.patch +Patch0185: 0185-shared-install-split-unit_file_-disable-enable-so-_r.patch +Patch0186: 0186-shared-install-fix-reenable-on-linked-unit-files.patch +Patch0187: 0187-test-systemctl-enable-extend-the-test-for-repeated-W.patch +Patch0188: 0188-shared-install-when-we-fail-to-chase-a-symlink-show-.patch +Patch0189: 0189-shared-install-do-not-try-to-resolve-symlinks-outsid.patch +Patch0190: 0190-test-systemctl-enable-enhance-the-test-for-unit-file.patch +Patch0191: 0191-shared-install-skip-unnecessary-chasing-of-symlinks-.patch +Patch0192: 0192-shared-install-also-remove-symlinks-like-.wants-foo-.patch +Patch0193: 0193-shared-install-create-relative-symlinks-for-enableme.patch +Patch0194: 0194-shared-install-when-looking-for-symlinks-in-.wants-..patch +Patch0195: 0195-shared-install-stop-passing-duplicate-root-argument-.patch +Patch0196: 0196-basic-unit-file-reverse-negative-conditional.patch +Patch0197: 0197-shared-install-split-UNIT_FILE_SYMLINK-into-two-stat.patch +Patch0198: 0198-shared-install-fix-handling-of-a-linked-unit-file.patch +Patch0199: 0199-test-systemctl-enable-make-shellcheck-happy.patch +Patch0200: 0200-shared-install-when-creating-symlinks-accept-differe.patch +Patch0201: 0201-test-systemctl-enable-use-magic-syntax-to-allow-inve.patch +Patch0202: 0202-test-systemctl-enable-also-use-freshly-built-systemd.patch +Patch0203: 0203-test-systemctl-enable-disable-the-test-for-a-for-now.patch +Patch0204: 0204-Rename-UnitFileScope-to-LookupScope.patch +Patch0205: 0205-core-handle-lookup-paths-being-symlinks.patch +Patch0206: 0206-shared-install-use-correct-cleanup-function.patch +Patch0207: 0207-udev-net_id-avoid-slot-based-names-only-for-single-f.patch +Patch0208: 0208-test-import-logind-test-from-debian-ubuntu-test-suit.patch +Patch0209: 0209-test-drop-redundant-IMAGE_NAME.patch +Patch0210: 0210-test-import-timedated-test-from-debian-ubuntu-test-s.patch +Patch0211: 0211-test-introduce-assert_not_in-helper-function.patch +Patch0212: 0212-test-drop-unnecessary-no-pager-option.patch +Patch0213: 0213-test-support-debian-ubuntu-specific-timezone-config-.patch +Patch0214: 0214-test-import-hostnamed-tests-from-debian-ubuntu-test-.patch +Patch0215: 0215-locale-util-fix-memleak-on-failure.patch +Patch0216: 0216-locale-util-check-if-enumerated-locales-are-valid.patch +Patch0217: 0217-locale-util-align-locale-entries.patch +Patch0218: 0218-core-inline-an-iterator-variable.patch +Patch0219: 0219-locale-setup-merge-locale-handling-in-PID1-and-local.patch +Patch0220: 0220-locale-rename-keymap-util.-ch-localed-util.-ch.patch +Patch0221: 0221-test-add-one-more-path-to-search-keymaps.patch +Patch0222: 0222-test-introduce-inst_recursive-helper-function.patch +Patch0223: 0223-hmac-sha256-move-size-define-to-sha256.h.patch +Patch0224: 0224-tpm2-support-policies-with-PIN.patch +Patch0225: 0225-cryptenroll-add-support-for-TPM2-pin.patch +Patch0226: 0226-cryptsetup-add-support-for-TPM2-pin.patch +Patch0227: 0227-cryptsetup-add-libcryptsetup-TPM2-PIN-support.patch +Patch0228: 0228-cryptenroll-add-TPM2-PIN-documentation.patch +Patch0229: 0229-cryptsetup-add-manual-TPM2-PIN-configuration.patch +Patch0230: 0230-cryptenroll-add-tests-for-TPM2-unlocking.patch +Patch0231: 0231-env-util-replace-unsetenv_erase-by-new-getenv_steal_.patch +Patch0232: 0232-test-install-libxkbcommon-and-x11-keymaps.patch +Patch0233: 0233-test-install-C.UTF-8-and-English-locales.patch +Patch0234: 0234-test-import-localed-tests-from-debian-ubuntu-test-su.patch +Patch0235: 0235-unit-check-for-mount-rate-limiting-before-checking-a.patch +Patch0236: 0236-tests-make-sure-we-delay-running-mount-start-jobs-wh.patch +Patch0237: 0237-test-insert-space-in-for-loop.patch +Patch0238: 0238-test-move-do-at-the-end-of-line.patch +Patch0239: 0239-test-use-trap-RETURN.patch +Patch0240: 0240-test-ignore-the-error-about-our-own-libraries-missin.patch +Patch0241: 0241-test-wrap-binaries-using-systemd-DSOs-when-running-w.patch +Patch0242: 0242-test-set-ASAN_RT_PATH-along-with-LD_PRELOAD-to-the-A.patch +Patch0243: 0243-test-drop-all-LD_PRELOAD-related-ASan-workarounds.patch +Patch0244: 0244-test-don-t-wrap-binaries-built-with-ASan.patch +Patch0245: 0245-test-send-stdout-stderr-of-testsuite-units-to-journa.patch +Patch0246: 0246-test-make-the-busy-loop-in-TEST-02-less-verbose.patch +Patch0247: 0247-test-always-wrap-useradd-userdel-when-running-w-ASan.patch +Patch0248: 0248-test-don-t-flush-debug-logs-to-the-console.patch +Patch0249: 0249-test-fix-a-couple-of-issues-found-by-shellcheck.patch +Patch0250: 0250-test-pass-the-initdir-to-check_result_-qemu-nspawn-h.patch +Patch0251: 0251-test-run-the-custom-check-hooks-before-common-checks.patch +Patch0252: 0252-test-check-journal-directly-instead-of-capturing-con.patch +Patch0253: 0253-test-use-saved-process-PID-instead-of.patch +Patch0254: 0254-test-account-for-ADDR_NO_RANDOMIZE-if-it-s-set.patch +Patch0255: 0255-fuzz-bcd-silence-warning-about-always-true-compariso.patch +Patch0256: 0256-test-disable-test_ntp-on-RHEL.patch +Patch0257: 0257-core-do-not-filter-out-systemd.unit-and-run-level-sp.patch +Patch0258: 0258-test-add-a-simple-test-for-daemon-reexec.patch +Patch0259: 0259-test-install-usr-libexec-vi-as-well.patch +Patch0260: 0260-test-resize-the-terminal-automagically-with-INTERACT.patch +Patch0261: 0261-test-create-an-ASan-wrapper-for-getent-and-su.patch +Patch0262: 0262-test-mark-partition-bootable.patch +Patch0263: 0263-test-bump-the-data-partition-size-if-we-don-t-strip-.patch +Patch0264: 0264-test-use-PBKDF2-with-capped-iterations-instead-of-Ar.patch +Patch0265: 0265-locale-drop-unnecessary-allocation.patch # Downstream-only patches (9000–9999) @@ -933,6 +1124,199 @@ getent passwd systemd-oom &>/dev/null || useradd -r -l -g systemd-oom -d / -s /s %files standalone-sysusers -f .file-list-standalone-sysusers %changelog +* Wed Jul 20 2022 systemd maintenance team - 250-8 +- core: shorten long unit names that are based on paths and append path hash at the end (#2083493) +- tests: add test case for long unit names (#2083493) +- tests: reflect that we can now handle devices with very long sysfs paths (#2083493) +- test: extend the "hashed" unit names coverage a bit (#2083493) +- Revert "kernel-install: also remove modules.builtin.alias.bin" (#2065061) +- Revert "kernel-install: prefer /boot over /boot/efi for $BOOT_ROOT" (#2065061) +- kernel-install: 50-depmod: port to /bin/sh (#2065061) +- kernel-install: 90-loaderentry: port to /bin/sh (#2065061) +- kernel-install: fix shellcheck (#2065061) +- kernel-install: port to /bin/sh (#2065061) +- kernel-install: 90-loaderentry: error out on nonexistent initrds instead of swallowing them quietly (#2065061) +- kernel-install: don't pull out KERNEL_IMAGE (#2065061) +- kernel-install: prefer /boot over /boot/efi for $BOOT_ROOT (#2065061) +- kernel-install: also remove modules.builtin.alias.bin (#2065061) +- kernel-install: add new variable $KERNEL_INSTALL_INITRD_GENERATOR (#2065061) +- kernel-install: k-i already creates $ENTRY_DIR_ABS, no need to do it again (#2065061) +- kernel-install: prefix errors with "Error:", exit immediately (#2065061) +- kernel-install: add "$KERNEL_INSTALL_STAGING_AREA" directory (#2065061) +- kernel-install: add missing log line (#2065061) +- kernel-install: don't try to persist used machine ID locally (#2065061) +- kernel-install: add a new $ENTRY_TOKEN variable for naming boot entries (#2065061) +- kernel-install: only generate systemd.boot_id= in kernel command line if used for naming the boot loader spec files/dirs (#2065061) +- kernel-install: search harder for kernel image/initrd drop-in dir (#2065061) +- kernel-install: add new "inspect" verb, showing paths and parameters we discovered (#2065061) +- ci(Mergify): configuration update (#2087652) +- ci(Mergify): fix copy&paste bug (#2087652) +- shared: Fix memory leak in bus_append_execute_property() (#2087652) +- fuzz: no longer skip empty files (#2087652) +- networkctl: open the bus just once (#2087652) +- json: align table (#2087652) +- fuzz-json: optionally allow logging and output (#2087652) +- shared/json: reduce scope of variables (#2087652) +- fuzz-json: also do sorting and normalizing and other easy calls (#2087652) +- shared/json: wrap long comments (#2087652) +- shared/json: fix memory leak on failed normalization (#2087652) +- shared/json: add helper to ref first, unref second (#2087652) +- basic/alloc-util: remove unnecessary parens (#2087652) +- fuzz-json: also try self-merge operations (#2087652) +- shared/json: fix another memleak in normalization (#2087652) +- shared/json: fix memleak in sort (#2087652) +- execute: fix resource leak (#2087652) +- tests: ignore dbus-broker-launcher (#2087652) +- core/timer: fix memleak (#2087652) +- timedatectl: fix a memory leak (#2087652) +- test: fix file descriptor leak in test-psi-util (#2087652) +- test: fix file descriptor leak in test-tmpfiles.c (#2087652) +- test: fix file descriptor leak in test-fs-util (#2087652) +- test: fix file descriptor leak in test-oomd-util (#2087652) +- test: fix file descriptor leak in test-catalog (#2087652) +- test: make masking of supplementary services configurable (#2087652) +- test: fuzz our dbus interfaces with dfuzzer (#2087652) +- test: skip TEST-21-DFUZZER without ASan (#2087652) +- core: annotate Reexecute() as NoReply (#2087652) +- test: always force a new image for dfuzzer (#2087652) +- test: make dfuzzer less verbose (#2087652) +- test: drop the at_exit() coredump check (#2087652) +- test: make the shutdown routine a bit more "robust" (#2087652) +- tree-wide: drop manually-crafted message for missing variables (#2087652) +- test: allow overriding $QEMU_MEM when running w/ ASan (#2087652) +- test: don't test buses we don't ship (#2087652) +- shutdown: get only active md arrays. (#2047682) +- bus: Use OrderedSet for introspection (#2068131) +- logind-session-dbus: allow to set display name via dbus (#2100340) +- ci: limit which env variables we pass through `sudo` (#2087652) +- ci(Mergify): Add `ci-waived` logic (#2087652) +- json: use unsigned for refernce counter (#2087652) +- macro: check over flow in reference counter (#2087652) +- sd-bus: fix reference counter to be incremented (#2087652) +- sd-bus: introduce ref/unref function for track_item (#2087652) +- sd-bus: do not read unused value (#2087652) +- sd-bus: do not return negative errno when unknown name is specified (#2087652) +- sd-bus: use hashmap_contains() and drop unnecessary cast (#2087652) +- test: shorten code a bit (#2087652) +- test: add several tests for track item (#2087652) +- core/slice: make slice_freezer_action() return 0 if freezing state is unchanged (#2087652) +- core/unit: fix use-after-free (#2087652) +- core/timer: fix potential use-after-free (#2087652) +- core: command argument can be longer than PATH_MAX (#2073994) +- shared/install: consistently use 'lp' as the name for the LookupPaths instance (#2082131) +- shared/specifier: treat NULL the same as "" (#2082131) +- shared/install: do not print aliases longer than UNIT_NAME_MAX (#2082131) +- shared/install-printf: drop now-unused install_path_printf() (#2082131) +- strv: declare iterator of FOREACH_STRING() in the loop (#2082131) +- basic/unit-file: split out the subroutine for symlink verification (#2082131) +- basic/stat-util: add null_or_empty_path_with_root() (#2082131) +- shared/install: reuse the standard symlink verification subroutine (#2082131) +- shared/install: add a bit more quoting (#2082131) +- test: add test for systemctl link & enable (#2082131) +- tests: add helper for creating tempfiles with content (#2082131) +- man: clarify the descriptions of aliases and linked unit files (#2082131) +- basic: add new variable $SYSTEMD_OS_RELEASE to override location of os-release (#2082131) +- test-os-util: add basic tests for os-release parsing (#2082131) +- basic/env-file: make load-env-file deduplicate entries with the same key (#2082131) +- man/os-release: add a note about repeating entries (#2082131) +- shared/specifier: clarify and add test for missing data (#2082131) +- shared/specifier: provide proper error messages when specifiers fail to read files (#2082131) +- shared/install: provide proper error messages when invalid specifiers are used (#2082131) +- shared/install: move scope into InstallContext (#2082131) +- shared/specifier: fix %u/%U/%g/%G when called as unprivileged user (#2082131) +- shared/install: simplify unit_file_dump_changes() (#2082131) +- shared/install: propagate errors about invalid aliases and such too (#2082131) +- shared/install: return failure when enablement fails, but process as much as possible (#2082131) +- systemctl: fix silent failure when --root is not found (#2082131) +- shared/install: also check for self-aliases during installation and ignore them (#2082131) +- docs: Correct WantedBy= regarding template units (#2082131) +- man: fix invalid description of template handling in WantedBy= (#2082131) +- shared/install: drop unnecessary casts (#2082131) +- strv: make iterator in STRV_FOREACH() declaread in the loop (#2082131) +- core: ExecContext::restrict_filesystems is set of string (#2082131) +- install: when linking a file, create the link first or abort (#2082131) +- shared/install: split unit_file_{disable,enable}() so _reenable doesn't do setup twice (#2082131) +- shared/install: fix reenable on linked unit files (#2082131) +- test-systemctl-enable: extend the test for repeated WantedBy/RequiredBy (#2082131) +- shared/install: when we fail to chase a symlink, show some logs (#2082131) +- shared/install: do not try to resolve symlinks outside of root directory (#2082131) +- test-systemctl-enable: enhance the test for unit file linking (#2082131) +- shared/install: skip unnecessary chasing of symlinks in disable (#2082131) +- shared/install: also remove symlinks like .wants/foo@one.service → ../foo@one.service (#2082131) +- shared/install: create relative symlinks for enablement and aliasing (#2082131) +- shared/install: when looking for symlinks in .wants/.requires, ignore symlink target (#2082131) +- shared/install: stop passing duplicate root argument to install_name_printf() (#2082131) +- basic/unit-file: reverse negative conditional (#2082131) +- shared/install: split UNIT_FILE_SYMLINK into two states (#2082131) +- shared/install: fix handling of a linked unit file (#2082131) +- test-systemctl-enable: make shellcheck happy (#2082131) +- shared/install: when creating symlinks, accept different but equivalent symlinks (#2082131) +- test-systemctl-enable: use magic syntax to allow inverted tests (#2082131) +- test-systemctl-enable: also use freshly-built systemd-id128 (#2082131) +- test-systemctl-enable: disable the test for %a for now (#2082131) +- Rename UnitFileScope to LookupScope (#2082131) +- core: handle lookup paths being symlinks (#2082131) +- shared/install: use correct cleanup function (#2082131) +- udev/net_id: avoid slot based names only for single function devices (#2073003) +- test: import logind test from debian/ubuntu test suite (#2087652) +- test: drop redundant IMAGE_NAME= (#2087652) +- test: import timedated test from debian/ubuntu test suite (#2087652) +- test: introduce assert_not_in() helper function (#2087652) +- test: drop unnecessary --no-pager option (#2087652) +- test: support debian/ubuntu specific timezone config file (#2087652) +- test: import hostnamed tests from debian/ubuntu test suite (#2087652) +- locale-util: fix memleak on failure (#2087652) +- locale-util: check if enumerated locales are valid (#2087652) +- locale-util: align locale entries (#2087652) +- core: inline an iterator variable (#2087652) +- locale-setup: merge locale handling in PID1 and localed (#2087652) +- locale: rename keymap-util.[ch] -> localed-util.[ch] (#2087652) +- test: add one more path to search keymaps (#2087652) +- test: introduce inst_recursive() helper function (#2087652) +- hmac/sha256: move size define to sha256.h (#2087652) +- tpm2: support policies with PIN (#2087652) +- cryptenroll: add support for TPM2 pin (#2087652) +- cryptsetup: add support for TPM2 pin (#2087652) +- cryptsetup: add libcryptsetup TPM2 PIN support (#2087652) +- cryptenroll: add TPM2 PIN documentation (#2087652) +- cryptsetup: add manual TPM2 PIN configuration (#2087652) +- cryptenroll: add tests for TPM2 unlocking (#2087652) +- env-util: replace unsetenv_erase() by new getenv_steal_erase() helper (#2087652) +- test: install libxkbcommon and x11 keymaps (#2087652) +- test: install C.UTF-8 and English locales (#2087652) +- test: import localed tests from debian/ubuntu test suite (#2087652) +- unit: check for mount rate limiting before checking active state (#2087652) +- tests: make sure we delay running mount start jobs when /p/s/mountinfo is rate limited (#2087652) +- test: insert space in for loop (#2087652) +- test: move "do" at the end of line (#2087652) +- test: use trap RETURN (#2087652) +- test: ignore the error about our own libraries missing during image creation (#2087652) +- test: wrap binaries using systemd DSOs when running w/ ASan (#2087652) +- test: set $ASAN_RT_PATH along with $LD_PRELOAD to the ASan runtime DSO (#2087652) +- test: drop all LD_PRELOAD-related ASan workarounds (#2087652) +- test: don't wrap binaries built with ASan (#2087652) +- test: send stdout/stderr of testsuite units to journal & console (#2087652) +- test: make the busy loop in TEST-02 less verbose (#2087652) +- test: always wrap useradd/userdel when running w/ ASan (#2087652) +- test: don't flush debug logs to the console (#2087652) +- test: fix a couple of issues found by shellcheck (#2087652) +- test: pass the initdir to check_result_{qemu,nspawn} hooks (#2087652) +- test: run the custom check hooks before common checks (#2087652) +- test: check journal directly instead of capturing console output (#2087652) +- test: use saved process PID instead of %% (#2087652) +- test: account for ADDR_NO_RANDOMIZE if it's set (#2087652) +- fuzz-bcd: silence warning about always-true comparison (#2087652) +- test: disable test_ntp on RHEL (#2087652) +- core: do not filter out systemd.unit= and run-level specifier from kernel command line (#2087652) +- test: add a simple test for daemon-reexec (#2087652) +- test: install /usr/libexec/vi as well (#2087652) +- test: resize the terminal automagically with INTERACTIVE_DEBUG=yes (#2087652) +- test: create an ASan wrapper for `getent` and `su` (#2087652) +- test: mark partition bootable (#2087652) +- test: bump the data partition size if we don't strip binaries (#2087652) +- test: use PBKDF2 with capped iterations instead of Argon2 (#2087652) +- locale: drop unnecessary allocation (#2087652) + * Wed Apr 20 2022 systemd maintenance team - 250-7 - test: check systemd RPM macros (#2017035) - test: do not assume x86-64 arch in TEST-58-REPART (#2017035)