systemd-250-8

Resolves: #2047682,#2068043,#2068131,#2073003,#2073994,#2082131,#2083493,#2087652,#2100340
This commit is contained in:
Jan Macku 2022-07-20 08:20:57 +02:00
parent c895351950
commit 0daf48d9aa
192 changed files with 33675 additions and 1 deletions

View File

@ -0,0 +1,275 @@
From 4bc17b038971160f94321c7be9cd924b256d9ef8 Mon Sep 17 00:00:00 2001
From: Michal Sekletar <msekleta@redhat.com>
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 <stdint.h>
#include <stdlib.h>
+#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) {

View File

@ -0,0 +1,42 @@
From 1121def1f02c847df894611e171a1025f859fb3d Mon Sep 17 00:00:00 2001
From: Michal Sekletar <msekleta@redhat.com>
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

View File

@ -0,0 +1,37 @@
From 87e45d9c58c74ae7ba46f99a3f0e2db39cf345ff Mon Sep 17 00:00:00 2001
From: Michal Sekletar <msekleta@redhat.com>
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

View File

@ -0,0 +1,63 @@
From c9fe9526f07ad24d29842fa853ee458b68660896 Mon Sep 17 00:00:00 2001
From: Frantisek Sumsal <frantisek@sumsal.cz>
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

View File

@ -0,0 +1,29 @@
From 17f516c0714e05d3dea7f168304286658aead870 Mon Sep 17 00:00:00 2001
From: Michal Sekletar <msekleta@redhat.com>
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

View File

@ -0,0 +1,29 @@
From 3fae5c22831288c075e371e67ecc91968ab60d63 Mon Sep 17 00:00:00 2001
From: Michal Sekletar <msekleta@redhat.com>
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

View File

@ -0,0 +1,60 @@
From d90268728f268f4e5291d29bc2b899137cd7ddf5 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=D0=BD=D0=B0=D0=B1?= <nabijaczleweli@nabijaczleweli.xyz>
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

View File

@ -0,0 +1,181 @@
From 7b05dc8184e1a459d0a073dfe569560681525980 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=D0=BD=D0=B0=D0=B1?= <nabijaczleweli@nabijaczleweli.xyz>
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" ' ' </etc/kernel/cmdline)"
+elif [ -r /usr/lib/kernel/cmdline ]; then
+ BOOT_OPTIONS="$(tr -s "$IFS" ' ' </usr/lib/kernel/cmdline)"
else
- declare -a BOOT_OPTIONS
-
- read -r -d '' -a line < /proc/cmdline
- for i in "${line[@]}"; do
- [[ "${i#initrd=*}" != "$i" ]] && continue
- [[ "${i#BOOT_IMAGE=*}" != "$i" ]] && continue
- BOOT_OPTIONS+=("$i")
- done
+ BOOT_OPTIONS="$(tr -s "$IFS" '\n' </proc/cmdline | grep -ve '^BOOT_IMAGE=' -e '^initrd=' | tr '\n' ' ')"
fi
+BOOT_OPTIONS="${BOOT_OPTIONS% }"
-if [[ -f /etc/kernel/tries ]]; then
+if [ -r /etc/kernel/tries ]; then
read -r TRIES </etc/kernel/tries
- if ! [[ "$TRIES" =~ ^[0-9]+$ ]] ; then
+ if ! echo "$TRIES" | grep -q '^[0-9][0-9]*$'; then
echo "/etc/kernel/tries does not contain an integer." >&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
}

View File

@ -0,0 +1,82 @@
From 52f6eedb3bb4dc7a57fea6a8991b9058dedc8edc Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=D0=BD=D0=B0=D0=B1?= <nabijaczleweli@nabijaczleweli.xyz>
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"

View File

@ -0,0 +1,205 @@
From 1f9eec4ab2a8a2213fec66194c537086e8242a0d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=D0=BD=D0=B0=D0=B1?= <nabijaczleweli@nabijaczleweli.xyz>
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 <http://www.gnu.org/licenses/>.
-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-id
-[ -n "$MACHINE_ID" ] && [ -z "$KERNEL_INSTALL_MACHINE_ID" ] && echo "KERNEL_INSTALL_MACHINE_ID=$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-id
+[ -n "$MACHINE_ID" ] && [ -z "$KERNEL_INSTALL_MACHINE_ID" ] && echo "KERNEL_INSTALL_MACHINE_ID=$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

View File

@ -0,0 +1,51 @@
From bc1c914ebdec526151964c1aa3c2aeea0d4e2680 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=D0=BD=D0=B0=D0=B1?= <nabijaczleweli@nabijaczleweli.xyz>
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

View File

@ -0,0 +1,68 @@
From 8a52c3a1797084956ddcd2acfb65a4023a4f0655 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=D0=BD=D0=B0=D0=B1?= <nabijaczleweli@nabijaczleweli.xyz>
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 ))

View File

@ -0,0 +1,32 @@
From 8bcb1df836fccb5ddb6fb071b022bfd490f94e11 Mon Sep 17 00:00:00 2001
From: Adam Williamson <awilliam@redhat.com>
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 <awilliam@redhat.com>
(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

View File

@ -0,0 +1,26 @@
From 491f0e55e1f1095b1d52d45e5753d5f1ea621231 Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
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" \

View File

@ -0,0 +1,77 @@
From 931ae9749924a396a78044f8b1536085ff574ae6 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
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 @@
<para><varname>KERNEL_INSTALL_BOOT_ROOT=</varname> 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 <varname>BOOT_ROOT=</varname>.</para>
- <para><varname>KERNEL_INSTALL_LAYOUT=bls|other|...</varname> specifies the installation layout.
+ <para><varname>KERNEL_INSTALL_LAYOUT=bls|other|...</varname> is set for the plugins to specify the installation layout.
Defaults to <option>bls</option> if <filename>$BOOT/<replaceable>MACHINE-ID</replaceable></filename> exists, or <option>other</option> 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 <varname>layout=</varname> in <filename>install.conf</filename> upon initial installation.</para>
+ <para><varname>KERNEL_INSTALL_INITRD_GENERATOR=...</varname> is set for plugins to select the initrd generator.
+ This should be configured as <varname>initrd_generator=</varname> in <filename>install.conf</filename>.
+ </para>
+
<variablelist>
<varlistentry>
<term>bls</term>
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=$?

View File

@ -0,0 +1,32 @@
From 27b017353a06a22d42dc8bbabbaf602200730719 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
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" || {

View File

@ -0,0 +1,118 @@
From 7e5ff353f8b35352f6c36233841754154b4f453b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
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

View File

@ -0,0 +1,108 @@
From 0f4ea4aee6e404dfbd6e3c4bbfb4f805e4e257f6 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
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 <varname>initrd_generator=</varname> in <filename>install.conf</filename>.
</para>
+ <para><varname>KERNEL_INSTALL_STAGING_AREA=...</varname> 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.</para>
+
<variablelist>
<varlistentry>
<term>bls</term>
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 <http://www.gnu.org/licenses/>.
+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=$?

View File

@ -0,0 +1,25 @@
From 9f36dbd7cb7ca1f2e77ea6c1a3129988f346b287 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
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"

View File

@ -0,0 +1,83 @@
From 7738d7793bc83421536f9962c794633006613725 Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
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' </proc/cmdline | grep -ve '^BOOT_IMAGE=' -e '^initrd=' | tr '\n' ' ')"
fi
-BOOT_OPTIONS="${BOOT_OPTIONS% }"
+
+# Suffix with the machine ID we use, so that the machine ID remains stable,
+# even during factory reset, in the initrd (where the system's machine ID is
+# not directly accessible yet), and if the root file system is volatile.
+BOOT_OPTIONS="${BOOT_OPTIONS% } systemd.machine_id=$MACHINE_ID"
if [ -r /etc/kernel/tries ]; then
read -r TRIES </etc/kernel/tries
diff --git a/src/kernel-install/kernel-install b/src/kernel-install/kernel-install
index 8cfef3208d..e94aa79bc6 100755
--- a/src/kernel-install/kernel-install
+++ b/src/kernel-install/kernel-install
@@ -89,15 +89,13 @@ elif [ -r "/usr/lib/kernel/install.conf" ]; then
. /usr/lib/kernel/install.conf
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" ] && [ -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-id
-[ -n "$MACHINE_ID" ] && [ -z "$KERNEL_INSTALL_MACHINE_ID" ] && echo "KERNEL_INSTALL_MACHINE_ID=$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" ] && [ -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 </etc/machine-id
+[ -z "$MACHINE_ID" ] && MACHINE_ID="$(systemd-id128 new)"
[ -z "$BOOT_ROOT" ] && for suff in "$MACHINE_ID" "loader/entries"; do
for pref in "/efi" "/boot" "/boot/efi" ; do

View File

@ -0,0 +1,136 @@
From 455b9b9dd4d462db7482f67d8e730b25e75b1505 Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
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 </etc/machine-id
[ -z "$MACHINE_ID" ] && MACHINE_ID="$(systemd-id128 new)"
-[ -z "$BOOT_ROOT" ] && for suff in "$MACHINE_ID" "loader/entries"; do
+# Now that we determined the machine ID to use, let's determine the "token" for
+# the boot loader entry to generate. We use that for naming the directory below
+# $BOOT where we want to place the kernel/initrd and related resources, as well
+# 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 </etc/kernel/entry-token
+[ -z "$ENTRY_TOKEN" ] && ENTRY_TOKEN="$MACHINE_ID"
+
+# NB: The $MACHINE_ID is guaranteed to be a valid machine ID, but
+# $ENTRY_TOKEN can be any string that fits into a VFAT filename, though
+# typically is just the machine ID.
+
+[ -z "$BOOT_ROOT" ] && for suff in "$ENTRY_TOKEN" "loader/entries"; do
for pref in "/efi" "/boot" "/boot/efi" ; do
if [ -d "$pref/$suff" ]; then
BOOT_ROOT="$pref"
@@ -117,14 +129,14 @@ done
if [ -z "$layout" ]; then
# Administrative decision: if not present, some scripts generate into /boot.
- if [ -d "$BOOT_ROOT/$MACHINE_ID" ]; then
+ if [ -d "$BOOT_ROOT/$ENTRY_TOKEN" ]; then
layout="bls"
else
layout="other"
fi
fi
-ENTRY_DIR_ABS="$BOOT_ROOT/$MACHINE_ID/$KERNEL_VERSION"
+ENTRY_DIR_ABS="$BOOT_ROOT/$ENTRY_TOKEN/$KERNEL_VERSION"
# Provide a directory where to store generated initrds
cleanup() {
@@ -136,6 +148,7 @@ 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_ENTRY_TOKEN="$ENTRY_TOKEN"
export KERNEL_INSTALL_BOOT_ROOT="$BOOT_ROOT"
export KERNEL_INSTALL_LAYOUT="$layout"
export KERNEL_INSTALL_INITRD_GENERATOR="$initrd_generator"
@@ -168,7 +181,7 @@ case "$COMMAND" in
fi
if [ "$MAKE_ENTRY_DIR_ABS" -eq 0 ]; then
- # Compatibility with earlier versions that used the presence of $BOOT_ROOT/$MACHINE_ID
+ # Compatibility with earlier versions that used the presence of $BOOT_ROOT/$ENTRY_TOKEN
# to signal to 00-entry-directory to create $ENTRY_DIR_ABS
# to serve as the indication to use or to not use the BLS
if [ "$KERNEL_INSTALL_VERBOSE" -gt 0 ]; then

View File

@ -0,0 +1,59 @@
From 5eb855bddaf8270e7274132ded0e36325d8ffbbe Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
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' </proc/cmdline | grep -ve '^BOOT_IMAGE=' -e '^initrd=' | tr '\n' ' ')"
fi
-# Suffix with the machine ID we use, so that the machine ID remains stable,
-# even during factory reset, in the initrd (where the system's machine ID is
-# not directly accessible yet), and if the root file system is volatile.
-BOOT_OPTIONS="${BOOT_OPTIONS% } systemd.machine_id=$MACHINE_ID"
+BOOT_OPTIONS="${BOOT_OPTIONS% }"
+
+# If the boot entries are named after the machine ID, then suffix the kernel
+# command line with the machine ID we use, so that the machine ID remains
+# stable, even during factory reset, in the initrd (where the system's machine
+# ID is not directly accessible yet), and if the root file system is volatile.
+if [ "$ENTRY_TOKEN" = "$MACHINE_ID" ]; then
+ BOOT_OPTIONS="$BOOT_OPTIONS systemd.machine_id=$MACHINE_ID"
+fi
if [ -r /etc/kernel/tries ]; then
read -r TRIES </etc/kernel/tries
@@ -121,7 +126,10 @@ mkdir -p "${LOADER_ENTRY%/*}" || {
{
echo "title $PRETTY_NAME"
echo "version $KERNEL_VERSION"
- echo "machine-id $MACHINE_ID"
+ if [ "$ENTRY_TOKEN" = "$MACHINE_ID" ]; then
+ # See similar logic above for the systemd.machine_id= kernel command line option
+ echo "machine-id $MACHINE_ID"
+ fi
echo "options $BOOT_OPTIONS"
echo "linux $ENTRY_DIR/linux"

View File

@ -0,0 +1,75 @@
From a774b3d6c43863b632f211aa21e61cb48e2ee736 Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
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 </etc/kernel/entry-token
-[ -z "$ENTRY_TOKEN" ] && ENTRY_TOKEN="$MACHINE_ID"
+if [ -z "$ENTRY_TOKEN" ]; then
+ # If not configured explicitly, then use a few candidates: the machine ID,
+ # the IMAGE_ID= and ID= fields from /etc/os-release and finally the fixed
+ # string "Default"
+ ENTRY_TOKEN_SEARCH="$MACHINE_ID"
+ [ -r /etc/os-release ] && . /etc/os-release
+ [ -n "$IMAGE_ID" ] && ENTRY_TOKEN_SEARCH="$ENTRY_TOKEN_SEARCH $IMAGE_ID"
+ [ -n "$ID" ] && ENTRY_TOKEN_SEARCH="$ENTRY_TOKEN_SEARCH $ID"
+ ENTRY_TOKEN_SEARCH="$ENTRY_TOKEN_SEARCH Default"
+else
+ ENTRY_TOKEN_SEARCH="$ENTRY_TOKEN"
+fi
# NB: The $MACHINE_ID is guaranteed to be a valid machine ID, but
# $ENTRY_TOKEN can be any string that fits into a VFAT filename, though
# typically is just the machine ID.
-[ -z "$BOOT_ROOT" ] && for suff in "$ENTRY_TOKEN" "loader/entries"; do
- for pref in "/efi" "/boot" "/boot/efi" ; do
+[ -z "$BOOT_ROOT" ] && for suff in $ENTRY_TOKEN_SEARCH; do
+ for pref in "/efi" "/boot" "/boot/efi"; do
if [ -d "$pref/$suff" ]; then
BOOT_ROOT="$pref"
+ ENTRY_TOKEN="$suff"
break 2
fi
done
done
+[ -z "$BOOT_ROOT" ] && for pref in "/efi" "/boot" "/boot/efi"; do
+ if [ -d "$pref/loader/entries" ]; then
+ BOOT_ROOT="$pref"
+ break
+ fi
+done
+
[ -z "$BOOT_ROOT" ] && for pref in "/efi" "/boot/efi"; do
if mountpoint -q "$pref"; then
BOOT_ROOT="$pref"
break
fi
done
+
[ -z "$BOOT_ROOT" ] && BOOT_ROOT="/boot"
+[ -z "$ENTRY_TOKEN" ] && ENTRY_TOKEN="$MACHINE_ID"
if [ -z "$layout" ]; then
# Administrative decision: if not present, some scripts generate into /boot.

View File

@ -0,0 +1,68 @@
From 8742d040aa5ef5e784c903d0c3efacba7d69ade2 Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
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

View File

@ -0,0 +1,97 @@
From caf80cd558222a08687e8db95e3e1fcad0d69946 Mon Sep 17 00:00:00 2001
From: Jan Macku <jamacku@redhat.com>
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

View File

@ -0,0 +1,34 @@
From 14b8f663049a902aac962f9a522595df9db6b6bc Mon Sep 17 00:00:00 2001
From: David Tardon <dtardon@redhat.com>
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

View File

@ -0,0 +1,26 @@
From 18b0bc42dc097af6147324deef100c41dedfa755 Mon Sep 17 00:00:00 2001
From: Daan De Meyer <daan.j.demeyer@gmail.com>
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 {

View File

@ -0,0 +1,187 @@
From 0235f9ea3d221aba513f4b6215418bf554e02791 Mon Sep 17 00:00:00 2001
From: Evgeny Vereshchagin <evvers@ya.ru>
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 <stddef.h>
#include <stdint.h>
+#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.

View File

@ -0,0 +1,276 @@
From 3852f94de9582dc1acb44844579873cd0e2f3162 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
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);

View File

@ -0,0 +1,55 @@
From ee588179205de7c1584bd45bd22ec59028f11405 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
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);

View File

@ -0,0 +1,60 @@
From 3087505025b78b80951ab3a5f496eb255f1a9a21 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
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;
}

View File

@ -0,0 +1,435 @@
From 272d6e85877bb436709ed54c02d3b68101e0438d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
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;

View File

@ -0,0 +1,97 @@
From 495eb07a2d8aa7f19b775b4508466fecb1b3ce50 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
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;
}

View File

@ -0,0 +1,106 @@
From eb01fd30cb625e90d5620b3ca31ca6474e1b0ac0 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
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;

View File

@ -0,0 +1,42 @@
From 0c5992cdb85ac6d9d14b95e77f03797600e87667 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
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

View File

@ -0,0 +1,141 @@
From fb195ccc27d1643d4152ee874144c36c0104c56d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
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);

View File

@ -0,0 +1,28 @@
From 965a99f34a185bb3b3aa5ac0e9e5d5eb05d0fac0 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
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; \
})

View File

@ -0,0 +1,32 @@
From 03795a6ae06088bc434906f3ef7222acfbdbe8cb Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
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;
}

View File

@ -0,0 +1,43 @@
From 6e0d847273e6ef6ee1011fb1c8b6689e64a94276 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
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

View File

@ -0,0 +1,43 @@
From 51bbb027e93637f5821215ebb067454ad6620190 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
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

View File

@ -0,0 +1,26 @@
From 08b6aa9dfbe9476ad71b48edd0f4454511d9ac19 Mon Sep 17 00:00:00 2001
From: Shreenidhi Shedi <sshedi@vmware.com>
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) {

View File

@ -0,0 +1,31 @@
From ae27d5b4be42cd98b3db299d161a2e3ea77eb604 Mon Sep 17 00:00:00 2001
From: Evgeny Vereshchagin <evvers@ya.ru>
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}'

View File

@ -0,0 +1,59 @@
From d35c27e44abcde252abddf369762dee8da309903 Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
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) {

View File

@ -0,0 +1,44 @@
From 9c166afe17888b08d1e269cfd83a31838d601534 Mon Sep 17 00:00:00 2001
From: Evgeny Vereshchagin <evvers@ya.ru>
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)

View File

@ -0,0 +1,42 @@
From 12274971840068b3effb7a933d62f1b5fe8009e1 Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
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);

View File

@ -0,0 +1,36 @@
From 936e8cd5aff044832c98e5a6a97c9f057f44b476 Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
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);

View File

@ -0,0 +1,46 @@
From 3ca37c58cb3ff022e029b28539fd2e3b208802fd Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
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 */

View File

@ -0,0 +1,48 @@
From 9e37cb1855c8fc1667f7e404376070952c015788 Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
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);

View File

@ -0,0 +1,34 @@
From d947339b49eb7935ce282e808a7e75a6098d088a Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
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);

View File

@ -0,0 +1,49 @@
From 4197469aa26e8e3e61c859341002e37bde751ada Mon Sep 17 00:00:00 2001
From: Frantisek Sumsal <frantisek@sumsal.cz>
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

View File

@ -0,0 +1,186 @@
From 25338c37915521876c84bca196de50d73c3c17ea Mon Sep 17 00:00:00 2001
From: Frantisek Sumsal <frantisek@sumsal.cz>
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

View File

@ -0,0 +1,31 @@
From 8f848593293b69f293734e07ec975ee76a3e6df5 Mon Sep 17 00:00:00 2001
From: Frantisek Sumsal <frantisek@sumsal.cz>
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:?}"

View File

@ -0,0 +1,41 @@
From fc6e005962167c26b9ef6cdd9e3476abeeb47313 Mon Sep 17 00:00:00 2001
From: Frantisek Sumsal <frantisek@sumsal.cz>
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,

View File

@ -0,0 +1,28 @@
From e162696827d97449e6395fc017fe6865aa6f1ad1 Mon Sep 17 00:00:00 2001
From: Frantisek Sumsal <frantisek@sumsal.cz>
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"

View File

@ -0,0 +1,38 @@
From 0e72d8a8bbed61ffa3cbf2637f1b29ade7af45be Mon Sep 17 00:00:00 2001
From: Frantisek Sumsal <frantisek@sumsal.cz>
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

View File

@ -0,0 +1,37 @@
From e5291b4fb0d9adfc9da510f4acc7330d57e3e415 Mon Sep 17 00:00:00 2001
From: Frantisek Sumsal <frantisek@sumsal.cz>
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

View File

@ -0,0 +1,54 @@
From a0464b064c46f9a63fd3f8d6f2d8560c7e5d32d3 Mon Sep 17 00:00:00 2001
From: Frantisek Sumsal <frantisek@sumsal.cz>
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

View File

@ -0,0 +1,167 @@
From 910711b21c5fe4f26ad20a4d86e1acfb2a0afbdb Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
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 <<EOF
diff --git a/test/units/testsuite-36.sh b/test/units/testsuite-36.sh
index b6c00c4845..cc4deffdbd 100755
--- a/test/units/testsuite-36.sh
+++ b/test/units/testsuite-36.sh
@@ -72,7 +72,7 @@ checkNUMA() {
writePID1NUMAPolicy() {
cat >"$confDir/numa.conf" <<EOF
[Manager]
-NUMAPolicy=${1:?missing argument: NUMAPolicy}
+NUMAPolicy=${1:?}
NUMAMask=${2:-""}
EOF
}
@@ -85,7 +85,7 @@ writeTestUnit() {
writeTestUnitNUMAPolicy() {
cat >"$testUnitNUMAConf" <<EOF
[Service]
-NUMAPolicy=${1:?missing argument: NUMAPolicy}
+NUMAPolicy=${1:?}
NUMAMask=${2:-""}
EOF
systemctl daemon-reload
@@ -106,25 +106,25 @@ pid1ReloadWithJournal() {
pid1StartUnitWithStrace() {
startStrace '-f'
- systemctl start "${1:?missing unit name}"
+ systemctl start "${1:?}"
sleep $sleepAfterStart
stopStrace
}
pid1StartUnitWithJournal() {
startJournalctl
- systemctl start "${1:?missing unit name}"
+ systemctl start "${1:?}"
sleep $sleepAfterStart
stopJournalctl
}
pid1StopUnit() {
- systemctl stop "${1:?missing unit name}"
+ systemctl stop "${1:?}"
}
systemctlCheckNUMAProperties() {
- local UNIT_NAME="${1:?missing unit name}"
- local NUMA_POLICY="${2:?missing NUMAPolicy}"
+ local UNIT_NAME="${1:?}"
+ local NUMA_POLICY="${2:?}"
local NUMA_MASK="${3:-""}"
local LOGFILE
diff --git a/test/units/testsuite-46.sh b/test/units/testsuite-46.sh
index c3e57cec95..61ee921151 100755
--- a/test/units/testsuite-46.sh
+++ b/test/units/testsuite-46.sh
@@ -15,7 +15,7 @@ inspect() {
# avoid unexpected fails. To see the full outputs of both homectl &
# userdbctl (for debugging purposes) drop the fields just before the
# comparison.
- local USERNAME="${1:?missing argument}"
+ local USERNAME="${1:?}"
homectl inspect "$USERNAME" | tee /tmp/a
userdbctl user "$USERNAME" | tee /tmp/b
diff --git a/tools/check-directives.sh b/tools/check-directives.sh
index 0661da4d3b..af846c4d73 100755
--- a/tools/check-directives.sh
+++ b/tools/check-directives.sh
@@ -3,8 +3,8 @@
set -eu
set -o pipefail
-SOURCE_ROOT="${1:?Missing argument: project source root}"
-BUILD_ROOT="${2:?Missing argument: project build root}"
+SOURCE_ROOT="${1:?}"
+BUILD_ROOT="${2:?}"
command -v gawk &>/dev/null || exit 77

View File

@ -0,0 +1,56 @@
From 3e31fc66a206c272e7f73581c5ca752b4439fec3 Mon Sep 17 00:00:00 2001
From: Frantisek Sumsal <frantisek@sumsal.cz>
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"

View File

@ -0,0 +1,39 @@
From a2c46d33809334614f93964b1707b01cbe2e05a5 Mon Sep 17 00:00:00 2001
From: Frantisek Sumsal <frantisek@sumsal.cz>
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

View File

@ -0,0 +1,68 @@
From 00ee9938c9c2333dc445b44e475974a3d3e37c10 Mon Sep 17 00:00:00 2001
From: Mariusz Tkaczyk <mariusz.tkaczyk@linux.intel.com>
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 <mariusz.tkaczyk@linux.intel.com>
(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;

View File

@ -0,0 +1,276 @@
From 52af91cfd0eece566cb2b6877e622b16289525a4 Mon Sep 17 00:00:00 2001
From: Jan Janssen <medhefgo@web.de>
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();
}

View File

@ -0,0 +1,160 @@
From 5cfd162864213c5247d97ea31cfacce98b1caefc Mon Sep 17 00:00:00 2001
From: David Tardon <dtardon@redhat.com>
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 {
<variablelist class="dbus-method" generated="True" extra-ref="SetType()"/>
+ <variablelist class="dbus-method" generated="True" extra-ref="SetDisplay()"/>
+
<variablelist class="dbus-method" generated="True" extra-ref="TakeDevice()"/>
<variablelist class="dbus-method" generated="True" extra-ref="ReleaseDevice()"/>
@@ -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 <varname>type</varname> is the new session type.</para>
+ <para><function>SetDisplay()</function> 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 <function>TakeControl()</function> has not been called, this method will fail. The only argument
+ <varname>display</varname> is the new display name.</para>
+
<para><function>TakeDevice()</function> 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
<filename>systemd-logind</filename> 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"/>
+ <allow send_destination="org.freedesktop.login1"
+ send_interface="org.freedesktop.login1.Session"
+ send_member="SetDisplay"/>
+
<allow receive_sender="org.freedesktop.login1"/>
</policy>

View File

@ -0,0 +1,35 @@
From 433d2036ecf211e9a7c85d57e4c91d8723f80cbb Mon Sep 17 00:00:00 2001
From: Frantisek Sumsal <frantisek@sumsal.cz>
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 }}

View File

@ -0,0 +1,104 @@
From 09eeda8d25f0f45d2c545c05fd8ae84404c83d83 Mon Sep 17 00:00:00 2001
From: Jan Macku <jamacku@redhat.com>
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:

View File

@ -0,0 +1,36 @@
From 46118fd04a49b25bc0c686b07d1b26309ab4e395 Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
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.) */

View File

@ -0,0 +1,31 @@
From eb7eca006b5f290481720dc4d7fcdba88d8613cb Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
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; \
}

View File

@ -0,0 +1,34 @@
From 4dcd6089addae3ef6b6c82e36b30b178a4261249 Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
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);

View File

@ -0,0 +1,105 @@
From 6fcc3befd0ca9897071af071287e8758a30046f0 Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
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;
}

View File

@ -0,0 +1,32 @@
From 5f241b4af41402be5357d6ab10b4c54378363c89 Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
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;

View File

@ -0,0 +1,35 @@
From f2ca27c7fa3e98cbb412871d7ea18b51e7f5f048 Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
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)

View File

@ -0,0 +1,25 @@
From 73c3e230dd66bedc82fa6dbf020c8d24592a32be Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
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) {

View File

@ -0,0 +1,99 @@
From 6ddb7fc35d7051627fa2772226e07296c28b316f Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
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);

View File

@ -0,0 +1,97 @@
From 4895d281d18e244d8238c1f77e597ce43310531c Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
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);

View File

@ -0,0 +1,46 @@
From 776aab7656db605a856d2d3e9225f23779da5483 Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
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;
}

View File

@ -0,0 +1,29 @@
From b8ccf30c4654ed5697562842a8a608e627425370 Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
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);

View File

@ -0,0 +1,25 @@
From e9acfceb104c8f9ccec8b468b5d111844285f43a Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
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) {

View File

@ -0,0 +1,64 @@
From fdc436432f1ca2dd9df2f24728916ab1201015c1 Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
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, "",

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,191 @@
From c36354b26c757e526e9f3d8c5bc78aa36f095f61 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
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);
}

View File

@ -0,0 +1,30 @@
From 5f66b67ac6594a3dee6e463a5f31c2d1051503cc Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
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;

View File

@ -0,0 +1,50 @@
From b635f03ba218df6c184da4d53648b13241b6b07d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
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);

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,213 @@
From d49d646d00078b201cdde2978b7941d20acb1d4b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
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;
}
}

View File

@ -0,0 +1,100 @@
From fae45af368a90cdce95680d82b66d8e460ab939f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
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";

View File

@ -0,0 +1,298 @@
From 5ec751ab9a06dadc62b30dc07e9dd7a41f8da403 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
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;
}

View File

@ -0,0 +1,118 @@
From 348699605248eb30743c0aac4f2ecbff5dd986ad Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
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);

View File

@ -0,0 +1,587 @@
From e7bd636e75a5435b80a1df478e9e637dd2f7b851 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
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" <<EOF
+[Install]
+WantedBy=default.target
+RequiredBy=special.target
+EOF
+
+"$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 ! -e "$root/etc/systemd/system/default.target.wants/test1.service"
+test ! -e "$root/etc/systemd/system/special.target.requires/test1.service"
+
+: ------suffix guessing---------------------------------------
+"$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"
+
+"$systemctl" --root="$root" reenable test1
+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
+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" <<EOF
+Alias=test1-goodalias.service
+Alias=test1@badalias.service
+Alias=test1-badalias.target
+Alias=test1-badalias.socket
+EOF
+
+: -------aliases in reeanble----------------------------------
+"$systemctl" --root="$root" reenable test1
+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"
+
+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"
+
+"$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"
+
+: -------also units-------------------------------------------
+cat >"$root/etc/systemd/system/test2.socket" <<EOF
+[Install]
+WantedBy=sockets.target
+Also=test2.service
+EOF
+
+cat >"$root/etc/systemd/system/test2.service" <<EOF
+[Install]
+WantedBy=default.target
+Also=test2.socket
+EOF
+
+"$systemctl" --root="$root" reenable test2.service
+test -h "$root/etc/systemd/system/default.target.wants/test2.service"
+test -h "$root/etc/systemd/system/sockets.target.wants/test2.socket"
+
+"$systemctl" --root="$root" reenable test2.socket
+test -h "$root/etc/systemd/system/default.target.wants/test2.service"
+test -h "$root/etc/systemd/system/sockets.target.wants/test2.socket"
+
+"$systemctl" --root="$root" disable test2.socket
+test ! -e "$root/etc/systemd/system/default.target.wants/test2.service"
+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; }
+test ! -e "$root/etc/systemd/system/link1.path"
+
+cat >"$root/link1.path" <<EOF
+[Install]
+WantedBy=paths.target
+EOF
+
+"$systemctl" --root="$root" link '/link1.path'
+islink "$root/etc/systemd/system/link1.path" "/link1.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-------------------
+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--------------------------------------
+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" <<EOF
+[Install]
+WantedBy=services.target
+EOF
+
+ln -s "/link3.suffix" "$root/etc/systemd/system/link3.service"
+
+# SYSTEMD_LOG_LEVEL=debug SYSTEMD_LOG_LOCATION=1 "$systemctl" --root="$root" enable 'link3.service'
+# islink "$root/etc/systemd/system/link3.service" "/link3.suffix"
+# islink "$root/etc/systemd/system/services.target.wants/link3.service" "../link3.service"
+# unit_file_load_or_readlink() needs to be fixed to not follow links
+
+: -------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; }
+
+: -------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" <<EOF
+[Install]
+WantedBy=services.target
+Also=link5.service
+EOF
+cat >"$root/etc/systemd/system/myown.d/link5.service" <<EOF
+[Install]
+WantedBy=services.target
+Also=link5-also.service
+EOF
+
+"$systemctl" --root="$root" enable 'link5.service' && { echo "Expected failure" >&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" <<EOF
+[Install]
+WantedBy=services.target
+EOF
+
+# No instance here — this can't succeed.
+"$systemctl" --root="$root" enable 'templ1@.service' && { echo "Expected failure" >&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" <<EOF
+DefaultInstance=333
+EOF
+# FIXME: should we deduplicate the target? Right now we warn twice if WantedBy= is repeated.
+# WantedBy=services.target services.target
+
+"$systemctl" --root="$root" enable 'templ1@.service'
+test ! -h "$root/etc/systemd/system/services.target.wants/templ1@.service"
+islink "$root/etc/systemd/system/services.target.wants/templ1@333.service" "/etc/systemd/system/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@333.service" "/etc/systemd/system/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@333.service" "/etc/systemd/system/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"
+islink "$root/etc/systemd/system/services.target.wants/templ1@333.service" "/etc/systemd/system/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"
+
+# disable both remaining links here
+"$systemctl" --root="$root" disable 'templ1@.service'
+test ! -h "$root/etc/systemd/system/services.target.wants/templ1@.service"
+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"
+
+: -------aliases w/ and w/o instance--------------------------
+test ! -e "$root/etc/systemd/system/link4.service"
+cat >"$root/etc/systemd/system/link4.service" <<EOF
+[Install]
+# FIXME: self-alias should be ignored
+# Alias=link4.service
+Alias=link4@.service
+Alias=link4@inst.service
+Alias=link4alias.service
+Alias=link4alias2.service
+EOF
+
+"$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"
+islink "$root/etc/systemd/system/link4alias.service" "/etc/systemd/system/link4.service"
+islink "$root/etc/systemd/system/link4alias2.service" "/etc/systemd/system/link4.service"
+
+"$systemctl" --root="$root" disable 'link4.service'
+test ! -h "$root/etc/systemd/system/link4.service"
+test ! -h "$root/etc/systemd/system/link4@.service"
+test ! -h "$root/etc/systemd/system/link4@inst.service"
+test ! -h "$root/etc/systemd/system/link4alias.service"
+test ! -h "$root/etc/systemd/system/link4alias2.service"
+
+: -------systemctl enable on path to unit file----------------
+# Apparently this works. I'm not sure what to think.
+"$systemctl" --root="$root" enable '/etc/systemd/system/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"
+islink "$root/etc/systemd/system/link4alias.service" "/etc/systemd/system/link4.service"
+islink "$root/etc/systemd/system/link4alias2.service" "/etc/systemd/system/link4.service"
+
+"$systemctl" --root="$root" disable '/etc/systemd/system/link4.service'
+test ! -h "$root/etc/systemd/system/link4.service"
+test ! -h "$root/etc/systemd/system/link4@.service"
+test ! -h "$root/etc/systemd/system/link4@inst.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--------------
+test ! -e "$root/etc/systemd/system/link5.service"
+cat >"$root/etc/systemd/system/link5.service" <<EOF
+[Install]
+# FIXME: self-alias should be ignored
+# Alias=link5.service
+Alias=link5@.service
+Alias=link5@inst.service
+Alias=link5alias.service
+Alias=link5alias2.service
+EOF
+
+"$systemctl" --root="$root" enable 'link5.service'
+test ! -h "$root/etc/systemd/system/link5.service" # this is our file
+test ! -h "$root/etc/systemd/system/link5@.service"
+test ! -h "$root/etc/systemd/system/link5@inst.service"
+# FIXME/CLARIFYME: will systemd think that link5alias2, link5alias, link5 are all aliases?
+# https://github.com/systemd/systemd/issues/661#issuecomment-1057931149
+islink "$root/etc/systemd/system/link5alias.service" "/etc/systemd/system/link5.service"
+islink "$root/etc/systemd/system/link5alias2.service" "/etc/systemd/system/link5.service"
+
+"$systemctl" --root="$root" disable 'link5.service'
+test ! -h "$root/etc/systemd/system/link5.service"
+test ! -h "$root/etc/systemd/system/link5@.service"
+test ! -h "$root/etc/systemd/system/link5@inst.service"
+test ! -h "$root/etc/systemd/system/link5alias.service"
+test ! -h "$root/etc/systemd/system/link5alias2.service"
+
+: ----issue 19437: plain templates in .wants/ or .requires/---
+test ! -e "$root/etc/systemd/system/link5@.path"
+cat >"$root/etc/systemd/system/link5@.path" <<EOF
+[Install]
+WantedBy=target5@.target
+RequiredBy=target5@.target
+WantedBy=target5@inst.target
+RequiredBy=target5@inst.target
+EOF
+
+"$systemctl" --root="$root" enable 'link5@.path'
+test ! -h "$root/etc/systemd/system/link5@.path" # this is our file
+islink "$root/etc/systemd/system/target5@.target.wants/link5@.path" "/etc/systemd/system/link5@.path"
+islink "$root/etc/systemd/system/target5@.target.requires/link5@.path" "/etc/systemd/system/link5@.path"
+islink "$root/etc/systemd/system/target5@inst.target.wants/link5@.path" "/etc/systemd/system/link5@.path"
+islink "$root/etc/systemd/system/target5@inst.target.requires/link5@.path" "/etc/systemd/system/link5@.path"
+
+"$systemctl" --root="$root" disable 'link5@.path'
+test ! -h "$root/etc/systemd/system/link5@.path" # this is our file
+test ! -h "$root/etc/systemd/system/target5@.target.wants/link5@.path"
+test ! -h "$root/etc/systemd/system/target5@.target.requires/link5@.path"
+test ! -h "$root/etc/systemd/system/target5@inst.target.wants/link5@.path"
+test ! -h "$root/etc/systemd/system/target5@inst.target.requires/link5@.path"
+
+: -------removal of symlinks not listed in [Install]----------
+# c.f. 66a19d85a533b15ed32f4066ec880b5a8c06babd
+test ! -e "$root/etc/systemd/system/multilink.mount"
+cat >"$root/etc/systemd/system/multilink.mount" <<EOF
+[Install]
+WantedBy=multilink.target
+EOF
+
+mkdir -p "$root/etc/systemd/system/default.target.wants"
+ln -s ../multilink.mount "$root/etc/systemd/system/default.target.wants/"
+ln -s ../multilink.mount "$root/etc/systemd/system/multilink-alias.mount"
+ln -s ../multilink.mount "$root/etc/systemd/system/multilink-badalias.service"
+
+"$systemctl" --root="$root" disable 'multilink.mount'
+test -e "$root/etc/systemd/system/multilink.mount" # this is our file
+test ! -h "$root/etc/systemd/system/default.target.wants/"
+test ! -h "$root/etc/systemd/system/multilink-alias.mount"
+test ! -h "$root/etc/systemd/system/multilink-badalias.service"
+
+: -------merge 20017: specifiers in the unit file-------------
+test ! -e "$root/etc/systemd/system/some-some-link6@.socket"
+# c.f. de61a04b188f81a85cdb5c64ddb4987dcd9d30d3
+
+check_alias() {
+ : ------------------ %$1 -------------------------------------
+ cat >"$root/etc/systemd/system/some-some-link6@.socket" <<EOF
+[Install]
+Alias=target@$1:%$1.socket
+EOF
+ SYSTEMD_LOG_LEVEL=debug "$systemctl" --root="$root" enable 'some-some-link6@.socket' || return 1
+ islink "$root/etc/systemd/system/target@$1:$2.socket" "/etc/systemd/system/some-some-link6@.socket" || return 2
+}
+
+check_alias a "$(uname -m | tr '_' '-')"
+
+# FIXME: when os-release is not found, we fail we a cryptic error
+# Alias=target@%A.socket
+
+check_alias b "$(systemd-id128 boot-id)"
+
+# Alias=target@%B.socket
+
+# FIXME: Failed to enable: Invalid slot.
+# Alias=target@%C.socket
+# Alias=target@%E.socket
+# Alias=target@%f.socket
+
+# 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
+
+# FIXME: Failed to enable: No such file or directory.
+# Alias=target@%m.socket
+
+# FIXME: Failed to enable: No such file or directory.
+# Alias=target@%M.socket
+
+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.
+# 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
+
+# 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; }
+
+# 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

View File

@ -0,0 +1,248 @@
From ad50f15e51f4f2ffc4ebbfab10a3e1c5739c9ce6 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
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);

View File

@ -0,0 +1,106 @@
From 2c9079ca0eaa2a1df2a1775c28fa7a49785999df Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
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 <command>systemd</command> is asked through D-Bus to load
<filename>dbus-org.freedesktop.network1.service</filename>, it'll load
<filename>systemd-networkd.service</filename>. As another example, <filename>default.target</filename> —
- 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
<filename>multi-user.target</filename> or <filename>graphical.target</filename> to select what is started
by default. Alias names may be used in commands like <command>disable</command>,
<command>start</command>, <command>stop</command>, <command>status</command>, and similar, and in all
@@ -156,8 +156,12 @@
template instance (e.g. <literal>alias@inst.service</literal>) may be a symlink to different template
(e.g. <literal>template@inst.service</literal>). In that case, just this specific instance is aliased,
while other instances of the template (e.g. <literal>alias@foo.service</literal>,
- <literal>alias@bar.service</literal>) 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.</para>
+ <literal>alias@bar.service</literal>) 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.</para>
<para>Unit files may specify aliases through the <varname>Alias=</varname> 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 <varname>Requires=</varname> type dependencies as well, the directory suffix is
<filename>.requires/</filename> 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
- <varname>Wants=</varname>, see below. The preferred way to create symlinks in the
- <filename>.wants/</filename> or <filename>.requires/</filename> 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 <command>enable</command> or <command>preset</command> commands of
- <citerefentry><refentrytitle>systemctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>.</para>
+ <varname>Wants=</varname> and <varname>Requires=</varname>, see below. The preferred way to create
+ symlinks in the <filename>.wants/</filename> or <filename>.requires/</filename> directories is by
+ specifying the dependency in [Install] section of the target unit, and creating the symlink in the file
+ system with the <command>enable</command> or <command>preset</command> commands of
+ <citerefentry><refentrytitle>systemctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>. 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
+ <filename>.wants/</filename> or <filename>.requires/</filename> 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.</para>
<para>Along with a unit file <filename>foo.service</filename>, a "drop-in" directory
<filename>foo.service.d/</filename> may exist. All files with the suffix
@@ -503,13 +514,30 @@
<programlisting>systemd-analyze --user unit-paths</programlisting>
</para>
- <para>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 <command>systemctl link</command>
- for this operation. See
- <citerefentry><refentrytitle>systemctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>
- for its usage and precaution.
- </para>
+ <para>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 <command>systemctl
+ link</command> for this; see
+ <citerefentry><refentrytitle>systemctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>. The file
+ system where the linked unit files are located must be accessible when systemd is started (e.g. anything
+ underneath <filename>/home/</filename> or <filename>/var/</filename> is not allowed, unless those
+ directories are located on the root file system).</para>
+
+ <para>It is important to distinguish "linked unit files" from "unit file aliases": any symlink where the
+ symlink <emphasis>target</emphasis> 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
+ <filename index='false'>/etc/systemd/system/alias1.service</filename> → <filename index='false'>service1.service</filename>,
+ <filename index='false'>/etc/systemd/system/alias2.service</filename> → <filename index='false'>/usr/lib/systemd/service1.service</filename>,
+ <filename index='false'>/etc/systemd/system/alias3.service</filename> → <filename index='false'>/etc/systemd/system/service1.service</filename>
+ are all valid aliases and <filename index='false'>service1.service</filename> will have
+ four names, even if the unit file is located at
+ <filename index='false'>/run/systemd/system/service1.service</filename>. In contrast,
+ a symlink <filename index='false'>/etc/systemd/system/link1.service</filename> → <filename index='false'>../link1_service_file</filename>
+ means that <filename index='false'>link1.service</filename> is a "linked unit" and the contents of
+ <filename index='false'>/etc/systemd/link1_service_file</filename> provide its configuration.</para>
</refsect1>
<refsect1>

View File

@ -0,0 +1,85 @@
From d424adce45d593d41e52294bd8f32fd33c625498 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
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" <<EOF
+ID='the-id2'
+EOF
+
+SYSTEMD_OS_RELEASE="$root/etc/os-release2" check_alias o 'the-id2'

View File

@ -0,0 +1,92 @@
From b8ebf512d4afa0f64503a96c2b58b12d9de531fb Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
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 <errno.h>
+#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);

View File

@ -0,0 +1,104 @@
From f990ee961a75791adfdea2f5efb35017a51a310e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
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);

View File

@ -0,0 +1,33 @@
From b4087419bac3cd656a3f8ba82653750fd60c19b9 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
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.</para>
+ <para><filename>os-release</filename> 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.</para>
+
<para>For a longer rationale for <filename>os-release</filename>
please refer to the <ulink
url="http://0pointer.de/blog/projects/os-release">Announcement of <filename>/etc/os-release</filename></ulink>.</para>

View File

@ -0,0 +1,55 @@
From fb51d78042fec1a2df2a7da1f9a759875bd7e07e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
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);

View File

@ -0,0 +1,278 @@
From b3b45ed9385341e72edfc1bae08819026d841d46 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
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" <<EOF
+# empty
+EOF
-check_alias b "$(systemd-id128 boot-id)"
+check_alias A ''
+check_alias B ''
+check_alias M ''
+check_alias o ''
+check_alias w ''
+check_alias W ''
+
+cat >"$root/etc/os-release" <<EOF
+ID='the-id'
+VERSION_ID=39a
+BUILD_ID=build-id
+VARIANT_ID=wrong
+VARIANT_ID=right
+IMAGE_ID="foobar"
+IMAGE_VERSION='1-2-3'
+EOF
-# Alias=target@%B.socket
+check_alias A '1-2-3'
+check_alias B 'build-id'
+check_alias M 'foobar'
+check_alias o 'the-id'
+check_alias w '39a'
+check_alias W 'right'
+
+check_alias b "$(systemd-id128 boot-id)"
# FIXME: Failed to enable: Invalid slot.
# Alias=target@%C.socket
@@ -479,18 +512,15 @@ check_alias l "$(uname -n | sed 's/\..*//')"
# FIXME: Failed to enable: Invalid slot.
# Alias=target@%L.socket
-# FIXME: Failed to enable: No such file or directory.
-# Alias=target@%m.socket
+test ! -e "$root/etc/machine-id"
+check_alias m '' && { echo "Expected failure" >&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; }

View File

@ -0,0 +1,142 @@
From 256e0d19abd531ab34ed28181ffdae5d5c0dcfed Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
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; }

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,549 @@
From 87df0601074b024ab591534e0e78b2d1e7013a8d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
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,

View File

@ -0,0 +1,118 @@
From cb49e80f8adf8fe81b6aa96b17a39a96850dcfa6 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
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);
}

Some files were not shown because too many files have changed in this diff Show More