From d2a9a2aabfe827e0d34e86a6ba5b37b8e826a4ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Thu, 29 May 2025 11:39:48 +0200 Subject: [PATCH 01/64] shared/bus-unit-util: drop spurious parentheses --- 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 cc0449dd96..a0ebf6ba32 100644 --- a/src/shared/bus-unit-util.c +++ b/src/shared/bus-unit-util.c @@ -708,7 +708,7 @@ static int bus_append_cgroup_property(sd_bus_message *m, const char *field, cons if (r < 0) return log_error_errno(r, "CPU quota '%s' invalid.", eq); - r = sd_bus_message_append(m, "(sv)", "CPUQuotaPerSecUSec", "t", (((uint64_t) r * USEC_PER_SEC) / 10000U)); + r = sd_bus_message_append(m, "(sv)", "CPUQuotaPerSecUSec", "t", ((uint64_t) r * USEC_PER_SEC) / 10000U); } if (r < 0) From e47fb4abd2fd2ab54557140d0072843c52ed8dd3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Wed, 4 Jun 2025 09:10:12 +0200 Subject: [PATCH 02/64] Rename STRV_MAKE_EMPTY to just STRV_EMPTY Even though this creates a stack allocation, it is not a function macro, so drop the "make" from the name. --- src/basic/macro.h | 2 +- src/test/test-conf-parser.c | 4 ++-- src/test/test-nulstr-util.c | 8 ++++---- src/test/test-proc-cmdline.c | 2 +- src/test/test-serialize.c | 2 +- src/test/test-socket-bind.c | 2 +- src/test/test-string-util.c | 2 +- src/test/test-strv.c | 10 +++++----- src/test/test-verbs.c | 2 +- 9 files changed, 17 insertions(+), 17 deletions(-) diff --git a/src/basic/macro.h b/src/basic/macro.h index caefa7c57c..3ddc5272b8 100644 --- a/src/basic/macro.h +++ b/src/basic/macro.h @@ -152,7 +152,7 @@ static inline unsigned long ALIGN_POWER2(unsigned long u) { } while (false) #define STRV_MAKE(...) ((char**) ((const char*[]) { __VA_ARGS__, NULL })) -#define STRV_MAKE_EMPTY ((char*[1]) { NULL }) +#define STRV_EMPTY ((char*[1]) { NULL }) #define STRV_MAKE_CONST(...) ((const char* const*) ((const char*[]) { __VA_ARGS__, NULL })) /* Pointers range from NULL to POINTER_MAX */ diff --git a/src/test/test-conf-parser.c b/src/test/test-conf-parser.c index 77e321d94c..e2f9f28792 100644 --- a/src/test/test-conf-parser.c +++ b/src/test/test-conf-parser.c @@ -171,14 +171,14 @@ TEST(config_parse_unsigned) { } TEST(config_parse_strv) { - test_config_parse_strv_one("", false, STRV_MAKE_EMPTY); + test_config_parse_strv_one("", false, STRV_EMPTY); test_config_parse_strv_one("foo", false, STRV_MAKE("foo")); test_config_parse_strv_one("foo bar foo", false, STRV_MAKE("foo", "bar", "foo")); test_config_parse_strv_one("\"foo bar\" foo", false, STRV_MAKE("foo bar", "foo")); test_config_parse_strv_one("\xc3\x80", false, STRV_MAKE("\xc3\x80")); test_config_parse_strv_one("\xc3\x7f", false, STRV_MAKE("\xc3\x7f")); - test_config_parse_strv_one("", true, STRV_MAKE_EMPTY); + test_config_parse_strv_one("", true, STRV_EMPTY); test_config_parse_strv_one("foo", true, STRV_MAKE("foo")); test_config_parse_strv_one("foo bar foo", true, STRV_MAKE("foo", "bar")); test_config_parse_strv_one("\"foo bar\" foo", true, STRV_MAKE("foo bar", "foo")); diff --git a/src/test/test-nulstr-util.c b/src/test/test-nulstr-util.c index 5110435778..bb0f1b32d1 100644 --- a/src/test/test-nulstr-util.c +++ b/src/test/test-nulstr-util.c @@ -42,22 +42,22 @@ TEST(strv_parse_nulstr_full) { STRV_MAKE("hoge", "hoge2", "hoge3", "", "hoge5", "", "xxx")); strv_parse_nulstr_full_one(((const char[0]) {}), 0, - STRV_MAKE_EMPTY, STRV_MAKE_EMPTY); + STRV_EMPTY, STRV_EMPTY); strv_parse_nulstr_full_one(((const char[1]) { 0 }), 1, - STRV_MAKE(""), STRV_MAKE_EMPTY); + STRV_MAKE(""), STRV_EMPTY); strv_parse_nulstr_full_one(((const char[1]) { 'x' }), 1, STRV_MAKE("x"), STRV_MAKE("x")); strv_parse_nulstr_full_one(((const char[2]) { 0, 0 }), 2, - STRV_MAKE("", ""), STRV_MAKE_EMPTY); + STRV_MAKE("", ""), STRV_EMPTY); strv_parse_nulstr_full_one(((const char[2]) { 'x', 0 }), 2, STRV_MAKE("x"), STRV_MAKE("x")); strv_parse_nulstr_full_one(((const char[3]) { 0, 0, 0 }), 3, - STRV_MAKE("", "", ""), STRV_MAKE_EMPTY); + STRV_MAKE("", "", ""), STRV_EMPTY); strv_parse_nulstr_full_one(((const char[3]) { 'x', 0, 0 }), 3, STRV_MAKE("x", ""), STRV_MAKE("x")); diff --git a/src/test/test-proc-cmdline.c b/src/test/test-proc-cmdline.c index 478974b0a9..68c4e77f75 100644 --- a/src/test/test-proc-cmdline.c +++ b/src/test/test-proc-cmdline.c @@ -244,7 +244,7 @@ TEST(proc_cmdline_key_startswith) { TEST(proc_cmdline_filter_pid1_args) { test_proc_cmdline_filter_pid1_args_one("systemd\0", - STRV_MAKE_EMPTY); + STRV_EMPTY); /* short option */ test_proc_cmdline_filter_pid1_args_one("systemd\0" diff --git a/src/test/test-serialize.c b/src/test/test-serialize.c index 86b1f5f2e0..bd66722456 100644 --- a/src/test/test-serialize.c +++ b/src/test/test-serialize.c @@ -110,7 +110,7 @@ TEST(serialize_strv) { log_info("/* %s (%s) */", __func__, fn); assert_se(serialize_strv(f, "strv1", NULL) == 0); - assert_se(serialize_strv(f, "strv2", STRV_MAKE_EMPTY) == 0); + assert_se(serialize_strv(f, "strv2", STRV_EMPTY) == 0); assert_se(serialize_strv(f, "strv3", strv) == 1); assert_se(serialize_strv(f, "strv4", STRV_MAKE(long_string)) == -EINVAL); diff --git a/src/test/test-socket-bind.c b/src/test/test-socket-bind.c index f6f48f6723..fec8269f2b 100644 --- a/src/test/test-socket-bind.c +++ b/src/test/test-socket-bind.c @@ -139,7 +139,7 @@ int main(int argc, char *argv[]) { assert_se(test_socket_bind(m, "socket_bind_test.service", netcat_path, "2000", STRV_MAKE("ipv6:2001-2002"), STRV_MAKE("any")) >= 0); assert_se(test_socket_bind(m, "socket_bind_test.service", netcat_path, "6666", STRV_MAKE("ipv4:6666", "6667"), STRV_MAKE("any")) >= 0); assert_se(test_socket_bind(m, "socket_bind_test.service", netcat_path, "6666", STRV_MAKE("6667", "6668", ""), STRV_MAKE("any")) >= 0); - assert_se(test_socket_bind(m, "socket_bind_test.service", netcat_path, "7777", STRV_MAKE_EMPTY, STRV_MAKE_EMPTY) >= 0); + assert_se(test_socket_bind(m, "socket_bind_test.service", netcat_path, "7777", STRV_EMPTY, STRV_EMPTY) >= 0); assert_se(test_socket_bind(m, "socket_bind_test.service", netcat_path, "8888", STRV_MAKE("any"), STRV_MAKE("any")) >= 0); assert_se(test_socket_bind(m, "socket_bind_test.service", netcat_path, "8888", STRV_MAKE("ipv6:tcp:8888-8889"), STRV_MAKE("any")) >= 0); assert_se(test_socket_bind(m, "socket_bind_test.service", netcat_path, "10000", STRV_MAKE("ipv6:udp:9999-10000"), STRV_MAKE("any")) >= 0); diff --git a/src/test/test-string-util.c b/src/test/test-string-util.c index 2439dd12ec..90ac579707 100644 --- a/src/test/test-string-util.c +++ b/src/test/test-string-util.c @@ -496,7 +496,7 @@ TEST(foreach_word_quoted) { true); check("test\\", - STRV_MAKE_EMPTY, + STRV_EMPTY, true); } diff --git a/src/test/test-strv.c b/src/test/test-strv.c index d2524fb52b..88505993cd 100644 --- a/src/test/test-strv.c +++ b/src/test/test-strv.c @@ -224,9 +224,9 @@ static void test_strv_unquote_one(const char *quoted, char **list) { TEST(strv_unquote) { test_strv_unquote_one(" foo=bar \"waldo\" zzz ", STRV_MAKE("foo=bar", "waldo", "zzz")); - test_strv_unquote_one("", STRV_MAKE_EMPTY); - test_strv_unquote_one(" ", STRV_MAKE_EMPTY); - test_strv_unquote_one(" ", STRV_MAKE_EMPTY); + test_strv_unquote_one("", STRV_EMPTY); + test_strv_unquote_one(" ", STRV_EMPTY); + test_strv_unquote_one(" ", STRV_EMPTY); test_strv_unquote_one(" x", STRV_MAKE("x")); test_strv_unquote_one("x ", STRV_MAKE("x")); test_strv_unquote_one(" x ", STRV_MAKE("x")); @@ -774,7 +774,7 @@ TEST(strv_foreach_backwards) { STRV_FOREACH_BACKWARDS(check, (char**) NULL) assert_not_reached(); - STRV_FOREACH_BACKWARDS(check, STRV_MAKE_EMPTY) + STRV_FOREACH_BACKWARDS(check, STRV_EMPTY) assert_not_reached(); unsigned count = 0; @@ -1049,7 +1049,7 @@ TEST(strv_fnmatch) { _cleanup_strv_free_ char **v = NULL; size_t pos; - assert_se(!strv_fnmatch(STRV_MAKE_EMPTY, "a")); + assert_se(!strv_fnmatch(STRV_EMPTY, "a")); v = strv_new("xxx", "*\\*", "yyy"); assert_se(!strv_fnmatch_full(v, "\\", 0, NULL)); diff --git a/src/test/test-verbs.c b/src/test/test-verbs.c index 03b4836e90..a28fc9b55b 100644 --- a/src/test/test-verbs.c +++ b/src/test/test-verbs.c @@ -43,7 +43,7 @@ TEST(verbs) { test_dispatch_one(STRV_MAKE("copy-to", "foo", "bar", "baz", "quux", "qaax"), verbs, -EINVAL); /* no verb, but a default is set */ - test_dispatch_one(STRV_MAKE_EMPTY, verbs, 0); + test_dispatch_one(STRV_EMPTY, verbs, 0); } TEST(verbs_no_default) { From 010d2e42c25dba389cf3e46c6a0ccc3ba3d84280 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Wed, 18 Jun 2025 14:31:18 +0200 Subject: [PATCH 03/64] shared/bus-unit-util: use common helper in one more place --- src/shared/bus-unit-util.c | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c index a0ebf6ba32..4f82d91536 100644 --- a/src/shared/bus-unit-util.c +++ b/src/shared/bus-unit-util.c @@ -717,19 +717,8 @@ static int bus_append_cgroup_property(sd_bus_message *m, const char *field, cons return 1; } - if (streq(field, "CPUQuotaPeriodSec")) { - usec_t u = USEC_INFINITY; - - r = parse_sec_def_infinity(eq, &u); - if (r < 0) - return log_error_errno(r, "CPU quota period '%s' invalid.", eq); - - r = sd_bus_message_append(m, "(sv)", "CPUQuotaPeriodUSec", "t", u); - if (r < 0) - return bus_log_create_error(r); - - return 1; - } + if (streq(field, "CPUQuotaPeriodSec")) + return bus_append_parse_sec_rename(m, field, isempty(eq) ? "infinity" : eq); if (streq(field, "DeviceAllow")) { if (isempty(eq)) From 411b998da8e042c525a2ffd23e791b7eb0f90a63 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Wed, 18 Jun 2025 14:42:02 +0200 Subject: [PATCH 04/64] shared/bus-unit-util: fix appending of IODeviceLatencyTargetSec= --- 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 4f82d91536..f99ced824f 100644 --- a/src/shared/bus-unit-util.c +++ b/src/shared/bus-unit-util.c @@ -808,7 +808,7 @@ static int bus_append_cgroup_property(sd_bus_message *m, const char *field, cons const char *field_usec = "IODeviceLatencyTargetUSec"; if (isempty(eq)) - r = sd_bus_message_append(m, "(sv)", field_usec, "a(st)", USEC_INFINITY); + r = sd_bus_message_append(m, "(sv)", field_usec, "a(st)", 0); else { const char *path, *target, *e; usec_t usec; From 965489c9350e14d844b52f54012faec451949696 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Wed, 18 Jun 2025 15:24:34 +0200 Subject: [PATCH 05/64] shared/bus-unit-util: define helper for ManagedOOMMemoryPressureLimit= --- src/shared/bus-unit-util.c | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c index f99ced824f..d08d1585a2 100644 --- a/src/shared/bus-unit-util.c +++ b/src/shared/bus-unit-util.c @@ -268,6 +268,21 @@ static int bus_append_parse_size(sd_bus_message *m, const char *field, const cha return 1; } +static int bus_append_parse_permyriad(sd_bus_message *m, const char *field, const char *eq) { + int r; + + r = parse_permyriad(eq); + if (r < 0) + return log_error_errno(r, "Failed to parse %s=%s: %m", field, eq); + + /* Pass around scaled to 2^32-1 == 100% */ + r = sd_bus_message_append(m, "(sv)", field, "u", UINT32_SCALE_FROM_PERMYRIAD(r)); + if (r < 0) + return bus_log_create_error(r); + + return 1; +} + static int bus_append_exec_command(sd_bus_message *m, const char *field, const char *eq) { bool explicit_path = false, done = false, ambient_hack = false; _cleanup_strv_free_ char **l = NULL, **ex_opts = NULL; @@ -582,18 +597,8 @@ static int bus_append_cgroup_property(sd_bus_message *m, const char *field, cons "DelegateSubgroup")) return bus_append_string(m, field, eq); - if (STR_IN_SET(field, "ManagedOOMMemoryPressureLimit")) { - r = parse_permyriad(eq); - if (r < 0) - return log_error_errno(r, "Failed to parse %s value: %s", field, eq); - - /* Pass around scaled to 2^32-1 == 100% */ - r = sd_bus_message_append(m, "(sv)", field, "u", UINT32_SCALE_FROM_PERMYRIAD(r)); - if (r < 0) - return bus_log_create_error(r); - - return 1; - } + if (STR_IN_SET(field, "ManagedOOMMemoryPressureLimit")) + return bus_append_parse_permyriad(m, field, eq); if (STR_IN_SET(field, "MemoryAccounting", "MemoryZSwapWriteback", From ca197282fb0c7340102a8718344b31603201db6d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Fri, 27 Jun 2025 13:43:09 +0200 Subject: [PATCH 06/64] shared/bus-unit-util: define helper for StartupAllowedMemoryNodes= and friends --- src/shared/bus-unit-util.c | 35 +++++++++++++++++++---------------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c index d08d1585a2..a9c9a0138c 100644 --- a/src/shared/bus-unit-util.c +++ b/src/shared/bus-unit-util.c @@ -283,6 +283,23 @@ static int bus_append_parse_permyriad(sd_bus_message *m, const char *field, cons return 1; } +static int bus_append_parse_cpu_set(sd_bus_message *m, const char *field, const char *eq) { + _cleanup_(cpu_set_done) CPUSet cpuset = {}; + _cleanup_free_ uint8_t *array = NULL; + size_t allocated; + int r; + + r = parse_cpu_set(eq, &cpuset); + if (r < 0) + return log_error_errno(r, "Failed to parse %s value: %s", field, eq); + + r = cpu_set_to_dbus(&cpuset, &array, &allocated); + if (r < 0) + return log_error_errno(r, "Failed to serialize %s: %m", field); + + return bus_append_byte_array(m, field, array, allocated); +} + static int bus_append_exec_command(sd_bus_message *m, const char *field, const char *eq) { bool explicit_path = false, done = false, ambient_hack = false; _cleanup_strv_free_ char **l = NULL, **ex_opts = NULL; @@ -619,22 +636,8 @@ static int bus_append_cgroup_property(sd_bus_message *m, const char *field, cons if (STR_IN_SET(field, "AllowedCPUs", "StartupAllowedCPUs", "AllowedMemoryNodes", - "StartupAllowedMemoryNodes")) { - - _cleanup_(cpu_set_done) CPUSet cpuset = {}; - _cleanup_free_ uint8_t *array = NULL; - size_t allocated; - - r = parse_cpu_set(eq, &cpuset); - if (r < 0) - return log_error_errno(r, "Failed to parse %s value: %s", field, eq); - - r = cpu_set_to_dbus(&cpuset, &array, &allocated); - if (r < 0) - return log_error_errno(r, "Failed to serialize CPUSet: %m"); - - return bus_append_byte_array(m, field, array, allocated); - } + "StartupAllowedMemoryNodes")) + return bus_append_parse_cpu_set(m, field, eq); if (streq(field, "DisableControllers")) return bus_append_strv(m, "DisableControllers", eq, /* separator= */ NULL, EXTRACT_UNQUOTE); From 3704d0ad1b575058a797d2d1bd6a4735567871f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Fri, 27 Jun 2025 13:44:09 +0200 Subject: [PATCH 07/64] shared/bus-unit-util: define helper for Delegate= --- src/shared/bus-unit-util.c | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c index a9c9a0138c..de6413135c 100644 --- a/src/shared/bus-unit-util.c +++ b/src/shared/bus-unit-util.c @@ -300,6 +300,20 @@ static int bus_append_parse_cpu_set(sd_bus_message *m, const char *field, const return bus_append_byte_array(m, field, array, allocated); } +static int bus_append_parse_delegate(sd_bus_message *m, const char *field, const char *eq) { + int r; + + r = parse_boolean(eq); + if (r < 0) + return bus_append_strv(m, "DelegateControllers", eq, /* separator= */ NULL, EXTRACT_UNQUOTE); + + r = sd_bus_message_append(m, "(sv)", "Delegate", "b", r); + if (r < 0) + return bus_log_create_error(r); + + return 1; +} + static int bus_append_exec_command(sd_bus_message *m, const char *field, const char *eq) { bool explicit_path = false, done = false, ambient_hack = false; _cleanup_strv_free_ char **l = NULL, **ex_opts = NULL; @@ -640,19 +654,10 @@ static int bus_append_cgroup_property(sd_bus_message *m, const char *field, cons return bus_append_parse_cpu_set(m, field, eq); if (streq(field, "DisableControllers")) - return bus_append_strv(m, "DisableControllers", eq, /* separator= */ NULL, EXTRACT_UNQUOTE); + return bus_append_strv(m, field, eq, /* separator= */ NULL, EXTRACT_UNQUOTE); - if (streq(field, "Delegate")) { - r = parse_boolean(eq); - if (r < 0) - return bus_append_strv(m, "DelegateControllers", eq, /* separator= */ NULL, EXTRACT_UNQUOTE); - - r = sd_bus_message_append(m, "(sv)", "Delegate", "b", r); - if (r < 0) - return bus_log_create_error(r); - - return 1; - } + if (streq(field, "Delegate")) + return bus_append_parse_delegate(m, field, eq); if (STR_IN_SET(field, "MemoryMin", "DefaultMemoryLow", From 40fcb3185df23a9440f41d256e2613c42df41c5b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Wed, 18 Jun 2025 15:28:59 +0200 Subject: [PATCH 08/64] shared/bus-unit-util: define helper function for resource limits --- src/shared/bus-unit-util.c | 85 +++++++++++++++++++------------------- 1 file changed, 42 insertions(+), 43 deletions(-) diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c index de6413135c..35c6b8eceb 100644 --- a/src/shared/bus-unit-util.c +++ b/src/shared/bus-unit-util.c @@ -314,6 +314,46 @@ static int bus_append_parse_delegate(sd_bus_message *m, const char *field, const return 1; } +static int bus_append_parse_resource_limit(sd_bus_message *m, const char *field, const char *eq) { + int r; + + if (isempty(eq) || streq(eq, "infinity")) { + uint64_t x = streq(eq, "infinity") ? CGROUP_LIMIT_MAX : + STR_IN_SET(field, + "DefaultMemoryLow", + "DefaultMemoryMin", + "MemoryLow", + "MemoryMin") ? CGROUP_LIMIT_MIN : CGROUP_LIMIT_MAX; + + r = sd_bus_message_append(m, "(sv)", field, "t", x); + if (r < 0) + return bus_log_create_error(r); + + return 1; + } + + r = parse_permyriad(eq); + if (r >= 0) { + char *n; + + /* When this is a percentage we'll convert this into a relative value in the range + * 0…UINT32_MAX and pass it in the MemoryLowScale property (and related ones). This + * way the physical memory size can be determined server-side. */ + + n = strjoina(field, "Scale"); + r = sd_bus_message_append(m, "(sv)", n, "u", UINT32_SCALE_FROM_PERMYRIAD(r)); + if (r < 0) + return bus_log_create_error(r); + + return 1; + } + + if (streq(field, "TasksMax")) + return bus_append_safe_atou64(m, field, eq); + + return bus_append_parse_size(m, field, eq, 1024); +} + static int bus_append_exec_command(sd_bus_message *m, const char *field, const char *eq) { bool explicit_path = false, done = false, ambient_hack = false; _cleanup_strv_free_ char **l = NULL, **ex_opts = NULL; @@ -667,49 +707,8 @@ static int bus_append_cgroup_property(sd_bus_message *m, const char *field, cons "MemoryMax", "MemorySwapMax", "MemoryZSwapMax", - "TasksMax")) { - - if (streq(eq, "infinity")) { - r = sd_bus_message_append(m, "(sv)", field, "t", CGROUP_LIMIT_MAX); - if (r < 0) - return bus_log_create_error(r); - return 1; - } else if (isempty(eq)) { - uint64_t empty_value = STR_IN_SET(field, - "DefaultMemoryLow", - "DefaultMemoryMin", - "MemoryLow", - "MemoryMin") ? - CGROUP_LIMIT_MIN : - CGROUP_LIMIT_MAX; - - r = sd_bus_message_append(m, "(sv)", field, "t", empty_value); - if (r < 0) - return bus_log_create_error(r); - return 1; - } - - r = parse_permyriad(eq); - if (r >= 0) { - char *n; - - /* When this is a percentage we'll convert this into a relative value in the range - * 0…UINT32_MAX and pass it in the MemoryLowScale property (and related ones). This - * way the physical memory size can be determined server-side. */ - - n = strjoina(field, "Scale"); - r = sd_bus_message_append(m, "(sv)", n, "u", UINT32_SCALE_FROM_PERMYRIAD(r)); - if (r < 0) - return bus_log_create_error(r); - - return 1; - } - - if (streq(field, "TasksMax")) - return bus_append_safe_atou64(m, field, eq); - - return bus_append_parse_size(m, field, eq, 1024); - } + "TasksMax")) + return bus_append_parse_resource_limit(m, field, eq); if (streq(field, "CPUQuota")) { if (isempty(eq)) From b4cf928f24ed9ba3ce8be0dd4b9b2c853c6619fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Wed, 18 Jun 2025 15:43:55 +0200 Subject: [PATCH 09/64] shared/bus-unit-util: define helper function for CPUQuota= Unfortunately we can't nicely fold it in with the other helpers, because of the unusual naming mismatch: CPUQuota vs. CPUQuotaPerSecUSec. --- src/shared/bus-unit-util.c | 42 ++++++++++++++++++++++---------------- 1 file changed, 24 insertions(+), 18 deletions(-) diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c index 35c6b8eceb..611d8a1858 100644 --- a/src/shared/bus-unit-util.c +++ b/src/shared/bus-unit-util.c @@ -354,6 +354,28 @@ static int bus_append_parse_resource_limit(sd_bus_message *m, const char *field, return bus_append_parse_size(m, field, eq, 1024); } +static int bus_append_parse_cpu_quota(sd_bus_message *m, const char *field, const char *eq) { + uint64_t x; + int r; + + if (isempty(eq)) + x = USEC_INFINITY; + else { + r = parse_permyriad_unbounded(eq); + if (r == 0) + return log_error_errno(SYNTHETIC_ERRNO(ERANGE), "%s value too small.", field); + if (r < 0) + return log_error_errno(r, "Failed to parse %s=%s: %m", field, eq); + x = r * USEC_PER_SEC / 10000U; + } + + r = sd_bus_message_append(m, "(sv)", "CPUQuotaPerSecUSec", "t", x); + if (r < 0) + return bus_log_create_error(r); + + return 1; +} + static int bus_append_exec_command(sd_bus_message *m, const char *field, const char *eq) { bool explicit_path = false, done = false, ambient_hack = false; _cleanup_strv_free_ char **l = NULL, **ex_opts = NULL; @@ -710,24 +732,8 @@ static int bus_append_cgroup_property(sd_bus_message *m, const char *field, cons "TasksMax")) return bus_append_parse_resource_limit(m, field, eq); - if (streq(field, "CPUQuota")) { - if (isempty(eq)) - r = sd_bus_message_append(m, "(sv)", "CPUQuotaPerSecUSec", "t", USEC_INFINITY); - else { - r = parse_permyriad_unbounded(eq); - if (r == 0) - return log_error_errno(SYNTHETIC_ERRNO(ERANGE), "CPU quota too small."); - if (r < 0) - return log_error_errno(r, "CPU quota '%s' invalid.", eq); - - r = sd_bus_message_append(m, "(sv)", "CPUQuotaPerSecUSec", "t", ((uint64_t) r * USEC_PER_SEC) / 10000U); - } - - if (r < 0) - return bus_log_create_error(r); - - return 1; - } + if (streq(field, "CPUQuota")) + return bus_append_parse_cpu_quota(m, field, eq); if (streq(field, "CPUQuotaPeriodSec")) return bus_append_parse_sec_rename(m, field, isempty(eq) ? "infinity" : eq); From ff0bbeff3a706de1da44431837e6cc6428fec3fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Wed, 18 Jun 2025 15:58:22 +0200 Subject: [PATCH 10/64] basic/cgroup-util: align tables --- src/basic/cgroup-util.c | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/src/basic/cgroup-util.c b/src/basic/cgroup-util.c index 8073925b4a..c0ba6b9401 100644 --- a/src/basic/cgroup-util.c +++ b/src/basic/cgroup-util.c @@ -2048,34 +2048,34 @@ int cg_has_coredump_receive(const char *path) { } const uint64_t cgroup_io_limit_defaults[_CGROUP_IO_LIMIT_TYPE_MAX] = { - [CGROUP_IO_RBPS_MAX] = CGROUP_LIMIT_MAX, - [CGROUP_IO_WBPS_MAX] = CGROUP_LIMIT_MAX, - [CGROUP_IO_RIOPS_MAX] = CGROUP_LIMIT_MAX, - [CGROUP_IO_WIOPS_MAX] = CGROUP_LIMIT_MAX, + [CGROUP_IO_RBPS_MAX] = CGROUP_LIMIT_MAX, + [CGROUP_IO_WBPS_MAX] = CGROUP_LIMIT_MAX, + [CGROUP_IO_RIOPS_MAX] = CGROUP_LIMIT_MAX, + [CGROUP_IO_WIOPS_MAX] = CGROUP_LIMIT_MAX, }; static const char* const cgroup_io_limit_type_table[_CGROUP_IO_LIMIT_TYPE_MAX] = { - [CGROUP_IO_RBPS_MAX] = "IOReadBandwidthMax", - [CGROUP_IO_WBPS_MAX] = "IOWriteBandwidthMax", - [CGROUP_IO_RIOPS_MAX] = "IOReadIOPSMax", - [CGROUP_IO_WIOPS_MAX] = "IOWriteIOPSMax", + [CGROUP_IO_RBPS_MAX] = "IOReadBandwidthMax", + [CGROUP_IO_WBPS_MAX] = "IOWriteBandwidthMax", + [CGROUP_IO_RIOPS_MAX] = "IOReadIOPSMax", + [CGROUP_IO_WIOPS_MAX] = "IOWriteIOPSMax", }; DEFINE_STRING_TABLE_LOOKUP(cgroup_io_limit_type, CGroupIOLimitType); static const char *const cgroup_controller_table[_CGROUP_CONTROLLER_MAX] = { - [CGROUP_CONTROLLER_CPU] = "cpu", - [CGROUP_CONTROLLER_CPUACCT] = "cpuacct", - [CGROUP_CONTROLLER_CPUSET] = "cpuset", - [CGROUP_CONTROLLER_IO] = "io", - [CGROUP_CONTROLLER_BLKIO] = "blkio", - [CGROUP_CONTROLLER_MEMORY] = "memory", - [CGROUP_CONTROLLER_DEVICES] = "devices", - [CGROUP_CONTROLLER_PIDS] = "pids", - [CGROUP_CONTROLLER_BPF_FIREWALL] = "bpf-firewall", - [CGROUP_CONTROLLER_BPF_DEVICES] = "bpf-devices", - [CGROUP_CONTROLLER_BPF_FOREIGN] = "bpf-foreign", - [CGROUP_CONTROLLER_BPF_SOCKET_BIND] = "bpf-socket-bind", + [CGROUP_CONTROLLER_CPU] = "cpu", + [CGROUP_CONTROLLER_CPUACCT] = "cpuacct", + [CGROUP_CONTROLLER_CPUSET] = "cpuset", + [CGROUP_CONTROLLER_IO] = "io", + [CGROUP_CONTROLLER_BLKIO] = "blkio", + [CGROUP_CONTROLLER_MEMORY] = "memory", + [CGROUP_CONTROLLER_DEVICES] = "devices", + [CGROUP_CONTROLLER_PIDS] = "pids", + [CGROUP_CONTROLLER_BPF_FIREWALL] = "bpf-firewall", + [CGROUP_CONTROLLER_BPF_DEVICES] = "bpf-devices", + [CGROUP_CONTROLLER_BPF_FOREIGN] = "bpf-foreign", + [CGROUP_CONTROLLER_BPF_SOCKET_BIND] = "bpf-socket-bind", [CGROUP_CONTROLLER_BPF_RESTRICT_NETWORK_INTERFACES] = "bpf-restrict-network-interfaces", }; From 619d378f55bfd89a5194043cc62e8e1e223261b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Wed, 18 Jun 2025 16:17:50 +0200 Subject: [PATCH 11/64] shared/bus-unit-util: define helper for DeviceAllow= --- src/shared/bus-unit-util.c | 43 +++++++++++++++++++++----------------- 1 file changed, 24 insertions(+), 19 deletions(-) diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c index 611d8a1858..1eb3fa30d4 100644 --- a/src/shared/bus-unit-util.c +++ b/src/shared/bus-unit-util.c @@ -376,6 +376,28 @@ static int bus_append_parse_cpu_quota(sd_bus_message *m, const char *field, cons return 1; } +static int bus_append_parse_device_allow(sd_bus_message *m, const char *field, const char *eq) { + int r; + + if (isempty(eq)) + r = sd_bus_message_append(m, "(sv)", field, "a(ss)", 0); + else { + const char *path = eq, *rwm = NULL, *e; + + e = strchr(eq, ' '); + if (e) { + path = strndupa_safe(eq, e - eq); + rwm = e + 1; + } + + r = sd_bus_message_append(m, "(sv)", field, "a(ss)", 1, path, strempty(rwm)); + } + if (r < 0) + return bus_log_create_error(r); + + return 1; +} + static int bus_append_exec_command(sd_bus_message *m, const char *field, const char *eq) { bool explicit_path = false, done = false, ambient_hack = false; _cleanup_strv_free_ char **l = NULL, **ex_opts = NULL; @@ -738,26 +760,9 @@ static int bus_append_cgroup_property(sd_bus_message *m, const char *field, cons if (streq(field, "CPUQuotaPeriodSec")) return bus_append_parse_sec_rename(m, field, isempty(eq) ? "infinity" : eq); - if (streq(field, "DeviceAllow")) { - if (isempty(eq)) - r = sd_bus_message_append(m, "(sv)", field, "a(ss)", 0); - else { - const char *path = eq, *rwm = NULL, *e; + if (streq(field, "DeviceAllow")) + return bus_append_parse_device_allow(m, field, eq); - e = strchr(eq, ' '); - if (e) { - path = strndupa_safe(eq, e - eq); - rwm = e+1; - } - - r = sd_bus_message_append(m, "(sv)", field, "a(ss)", 1, path, strempty(rwm)); - } - - if (r < 0) - return bus_log_create_error(r); - - return 1; - } if (cgroup_io_limit_type_from_string(field) >= 0) { From 5852a3e673d3e3d65e1ac02d07d621c45756c3c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Fri, 27 Jun 2025 13:51:47 +0200 Subject: [PATCH 12/64] shared/bus-unit-util: add helper for group io limits --- src/shared/bus-unit-util.c | 68 +++++++++++++++++++------------------- 1 file changed, 34 insertions(+), 34 deletions(-) diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c index 1eb3fa30d4..5254062f04 100644 --- a/src/shared/bus-unit-util.c +++ b/src/shared/bus-unit-util.c @@ -398,6 +398,38 @@ static int bus_append_parse_device_allow(sd_bus_message *m, const char *field, c return 1; } +static int bus_append_parse_cgroup_io_limit(sd_bus_message *m, const char *field, const char *eq) { + int r; + + if (isempty(eq)) + r = sd_bus_message_append(m, "(sv)", field, "a(st)", 0); + else { + const char *e = strchr(eq, ' '); + if (!e) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), + "Failed to parse %s value %s.", + field, eq); + + const char *path = strndupa_safe(eq, e - eq); + const char *bandwidth = e + 1; + + uint64_t bytes; + if (streq(bandwidth, "infinity")) + bytes = CGROUP_LIMIT_MAX; + else { + r = parse_size(bandwidth, 1000, &bytes); + if (r < 0) + return log_error_errno(r, "Failed to parse byte value %s: %m", bandwidth); + } + + r = sd_bus_message_append(m, "(sv)", field, "a(st)", 1, path, bytes); + } + if (r < 0) + return bus_log_create_error(r); + + return 1; +} + static int bus_append_exec_command(sd_bus_message *m, const char *field, const char *eq) { bool explicit_path = false, done = false, ambient_hack = false; _cleanup_strv_free_ char **l = NULL, **ex_opts = NULL; @@ -763,40 +795,8 @@ static int bus_append_cgroup_property(sd_bus_message *m, const char *field, cons if (streq(field, "DeviceAllow")) return bus_append_parse_device_allow(m, field, eq); - - if (cgroup_io_limit_type_from_string(field) >= 0) { - - if (isempty(eq)) - r = sd_bus_message_append(m, "(sv)", field, "a(st)", 0); - else { - const char *path, *bandwidth, *e; - uint64_t bytes; - - e = strchr(eq, ' '); - if (!e) - return log_error_errno(SYNTHETIC_ERRNO(EINVAL), - "Failed to parse %s value %s.", - field, eq); - - path = strndupa_safe(eq, e - eq); - bandwidth = e+1; - - if (streq(bandwidth, "infinity")) - bytes = CGROUP_LIMIT_MAX; - else { - r = parse_size(bandwidth, 1000, &bytes); - if (r < 0) - return log_error_errno(r, "Failed to parse byte value %s: %m", bandwidth); - } - - r = sd_bus_message_append(m, "(sv)", field, "a(st)", 1, path, bytes); - } - - if (r < 0) - return bus_log_create_error(r); - - return 1; - } + if (cgroup_io_limit_type_from_string(field) >= 0) + return bus_append_parse_cgroup_io_limit(m, field, eq); if (streq(field, "IODeviceWeight")) { if (isempty(eq)) From 335f7c7f0158f87261c7b19879a8f24bf363739c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Fri, 27 Jun 2025 13:53:25 +0200 Subject: [PATCH 13/64] shared/bus-unit-util: define helper for IODeviceWeight= --- src/shared/bus-unit-util.c | 58 ++++++++++++++++++++------------------ 1 file changed, 30 insertions(+), 28 deletions(-) diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c index 5254062f04..ec8657d819 100644 --- a/src/shared/bus-unit-util.c +++ b/src/shared/bus-unit-util.c @@ -430,6 +430,34 @@ static int bus_append_parse_cgroup_io_limit(sd_bus_message *m, const char *field return 1; } +static int bus_append_parse_io_device_weight(sd_bus_message *m, const char *field, const char *eq) { + int r; + + if (isempty(eq)) + r = sd_bus_message_append(m, "(sv)", field, "a(st)", 0); + else { + const char *e = strchr(eq, ' '); + if (!e) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), + "Failed to parse %s value %s.", + field, eq); + + const char *path = strndupa_safe(eq, e - eq); + const char *weight = e + 1; + + uint64_t u; + r = safe_atou64(weight, &u); + if (r < 0) + return log_error_errno(r, "Failed to parse %s value %s: %m", field, weight); + + r = sd_bus_message_append(m, "(sv)", field, "a(st)", 1, path, u); + } + if (r < 0) + return bus_log_create_error(r); + + return 1; +} + static int bus_append_exec_command(sd_bus_message *m, const char *field, const char *eq) { bool explicit_path = false, done = false, ambient_hack = false; _cleanup_strv_free_ char **l = NULL, **ex_opts = NULL; @@ -798,34 +826,8 @@ static int bus_append_cgroup_property(sd_bus_message *m, const char *field, cons if (cgroup_io_limit_type_from_string(field) >= 0) return bus_append_parse_cgroup_io_limit(m, field, eq); - if (streq(field, "IODeviceWeight")) { - if (isempty(eq)) - r = sd_bus_message_append(m, "(sv)", field, "a(st)", 0); - else { - const char *path, *weight, *e; - uint64_t u; - - e = strchr(eq, ' '); - if (!e) - return log_error_errno(SYNTHETIC_ERRNO(EINVAL), - "Failed to parse %s value %s.", - field, eq); - - path = strndupa_safe(eq, e - eq); - weight = e+1; - - r = safe_atou64(weight, &u); - if (r < 0) - return log_error_errno(r, "Failed to parse %s value %s: %m", field, weight); - - r = sd_bus_message_append(m, "(sv)", field, "a(st)", 1, path, u); - } - - if (r < 0) - return bus_log_create_error(r); - - return 1; - } + if (streq(field, "IODeviceWeight")) + return bus_append_parse_io_device_weight(m, field, eq); if (streq(field, "IODeviceLatencyTargetSec")) { const char *field_usec = "IODeviceLatencyTargetUSec"; From 235c580d80f269625bbe1efb96ad3091b53bbf0d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Fri, 27 Jun 2025 13:54:12 +0200 Subject: [PATCH 14/64] shared/bus-unit-util: define helper for IODeviceLatencyTargetSec= --- src/shared/bus-unit-util.c | 61 +++++++++++++++++++------------------- 1 file changed, 31 insertions(+), 30 deletions(-) diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c index ec8657d819..a343263a60 100644 --- a/src/shared/bus-unit-util.c +++ b/src/shared/bus-unit-util.c @@ -458,6 +458,35 @@ static int bus_append_parse_io_device_weight(sd_bus_message *m, const char *fiel return 1; } +static int bus_append_parse_io_device_latency(sd_bus_message *m, const char *field, const char *eq) { + const char *field_usec = "IODeviceLatencyTargetUSec"; + int r; + + if (isempty(eq)) + r = sd_bus_message_append(m, "(sv)", field_usec, "a(st)", 0); + else { + const char *e = strchr(eq, ' '); + if (!e) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), + "Failed to parse %s value %s.", + field, eq); + + const char *path = strndupa_safe(eq, e - eq); + const char *target = e + 1; + + usec_t usec; + r = parse_sec(target, &usec); + if (r < 0) + return log_error_errno(r, "Failed to parse %s value %s: %m", field, target); + + r = sd_bus_message_append(m, "(sv)", field_usec, "a(st)", 1, path, usec); + } + if (r < 0) + return bus_log_create_error(r); + + return 1; +} + static int bus_append_exec_command(sd_bus_message *m, const char *field, const char *eq) { bool explicit_path = false, done = false, ambient_hack = false; _cleanup_strv_free_ char **l = NULL, **ex_opts = NULL; @@ -829,36 +858,8 @@ static int bus_append_cgroup_property(sd_bus_message *m, const char *field, cons if (streq(field, "IODeviceWeight")) return bus_append_parse_io_device_weight(m, field, eq); - if (streq(field, "IODeviceLatencyTargetSec")) { - const char *field_usec = "IODeviceLatencyTargetUSec"; - - if (isempty(eq)) - r = sd_bus_message_append(m, "(sv)", field_usec, "a(st)", 0); - else { - const char *path, *target, *e; - usec_t usec; - - e = strchr(eq, ' '); - if (!e) - return log_error_errno(SYNTHETIC_ERRNO(EINVAL), - "Failed to parse %s value %s.", - field, eq); - - path = strndupa_safe(eq, e - eq); - target = e+1; - - r = parse_sec(target, &usec); - if (r < 0) - return log_error_errno(r, "Failed to parse %s value %s: %m", field, target); - - r = sd_bus_message_append(m, "(sv)", field_usec, "a(st)", 1, path, usec); - } - - if (r < 0) - return bus_log_create_error(r); - - return 1; - } + if (streq(field, "IODeviceLatencyTargetSec")) + return bus_append_parse_io_device_latency(m, field, eq); if (STR_IN_SET(field, "IPAddressAllow", "IPAddressDeny")) { From af33eb4bb73ca3a5821b613fcd502a7f1c7bcbfa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Wed, 18 Jun 2025 16:18:50 +0200 Subject: [PATCH 15/64] shared/bus-unit-util: define helper function for IPAddressAllow=/IPAddressDeny= --- src/shared/bus-unit-util.c | 240 +++++++++++++++++++------------------ 1 file changed, 121 insertions(+), 119 deletions(-) diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c index a343263a60..e04beb1fd4 100644 --- a/src/shared/bus-unit-util.c +++ b/src/shared/bus-unit-util.c @@ -704,6 +704,125 @@ static int bus_append_ip_address_access(sd_bus_message *m, int family, const uni return sd_bus_message_close_container(m); } +static int bus_append_parse_ip_address_filter(sd_bus_message *m, const char *field, const char *eq) { + union in_addr_union prefix = {}; + unsigned char prefixlen; + int family, r; + + if (isempty(eq)) { + r = sd_bus_message_append(m, "(sv)", field, "a(iayu)", 0); + if (r < 0) + return bus_log_create_error(r); + + return 1; + } + + r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv"); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_open_container(m, 'v', "a(iayu)"); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_open_container(m, 'a', "(iayu)"); + if (r < 0) + return bus_log_create_error(r); + + if (streq(eq, "any")) { + /* "any" is a shortcut for 0.0.0.0/0 and ::/0 */ + + r = bus_append_ip_address_access(m, AF_INET, &prefix, 0); + if (r < 0) + return bus_log_create_error(r); + + r = bus_append_ip_address_access(m, AF_INET6, &prefix, 0); + if (r < 0) + return bus_log_create_error(r); + + } else if (is_localhost(eq)) { + /* "localhost" is a shortcut for 127.0.0.0/8 and ::1/128 */ + + prefix.in.s_addr = htobe32(0x7f000000); + r = bus_append_ip_address_access(m, AF_INET, &prefix, 8); + if (r < 0) + return bus_log_create_error(r); + + prefix.in6 = (struct in6_addr) IN6ADDR_LOOPBACK_INIT; + r = bus_append_ip_address_access(m, AF_INET6, &prefix, 128); + if (r < 0) + return r; + + } else if (streq(eq, "link-local")) { + /* "link-local" is a shortcut for 169.254.0.0/16 and fe80::/64 */ + + prefix.in.s_addr = htobe32((UINT32_C(169) << 24 | UINT32_C(254) << 16)); + r = bus_append_ip_address_access(m, AF_INET, &prefix, 16); + if (r < 0) + return bus_log_create_error(r); + + prefix.in6 = (struct in6_addr) { + .s6_addr32[0] = htobe32(0xfe800000) + }; + r = bus_append_ip_address_access(m, AF_INET6, &prefix, 64); + if (r < 0) + return bus_log_create_error(r); + + } else if (streq(eq, "multicast")) { + /* "multicast" is a shortcut for 224.0.0.0/4 and ff00::/8 */ + + prefix.in.s_addr = htobe32((UINT32_C(224) << 24)); + r = bus_append_ip_address_access(m, AF_INET, &prefix, 4); + if (r < 0) + return bus_log_create_error(r); + + prefix.in6 = (struct in6_addr) { + .s6_addr32[0] = htobe32(0xff000000) + }; + r = bus_append_ip_address_access(m, AF_INET6, &prefix, 8); + if (r < 0) + return bus_log_create_error(r); + + } else + for (;;) { + _cleanup_free_ char *word = NULL; + + r = extract_first_word(&eq, &word, NULL, 0); + if (r == 0) + break; + if (r == -ENOMEM) + return log_oom(); + if (r < 0) + return log_error_errno(r, "Failed to parse %s: %s", field, eq); + + r = in_addr_prefix_from_string_auto(word, &family, &prefix, &prefixlen); + if (r < 0) + return log_error_errno(r, "Failed to parse IP address prefix: %s", word); + + r = bus_append_ip_address_access(m, family, &prefix, prefixlen); + if (r < 0) + return bus_log_create_error(r); + } + + r = sd_bus_message_close_container(m); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_close_container(m); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_close_container(m); + if (r < 0) + return bus_log_create_error(r); + + return 1; +} + static int bus_append_nft_set(sd_bus_message *m, const char *field, const char *eq) { int r; @@ -862,125 +981,8 @@ static int bus_append_cgroup_property(sd_bus_message *m, const char *field, cons return bus_append_parse_io_device_latency(m, field, eq); if (STR_IN_SET(field, "IPAddressAllow", - "IPAddressDeny")) { - unsigned char prefixlen; - union in_addr_union prefix = {}; - int family; - - if (isempty(eq)) { - r = sd_bus_message_append(m, "(sv)", field, "a(iayu)", 0); - if (r < 0) - return bus_log_create_error(r); - - return 1; - } - - r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv"); - if (r < 0) - return bus_log_create_error(r); - - r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field); - if (r < 0) - return bus_log_create_error(r); - - r = sd_bus_message_open_container(m, 'v', "a(iayu)"); - if (r < 0) - return bus_log_create_error(r); - - r = sd_bus_message_open_container(m, 'a', "(iayu)"); - if (r < 0) - return bus_log_create_error(r); - - if (streq(eq, "any")) { - /* "any" is a shortcut for 0.0.0.0/0 and ::/0 */ - - r = bus_append_ip_address_access(m, AF_INET, &prefix, 0); - if (r < 0) - return bus_log_create_error(r); - - r = bus_append_ip_address_access(m, AF_INET6, &prefix, 0); - if (r < 0) - return bus_log_create_error(r); - - } else if (is_localhost(eq)) { - /* "localhost" is a shortcut for 127.0.0.0/8 and ::1/128 */ - - prefix.in.s_addr = htobe32(0x7f000000); - r = bus_append_ip_address_access(m, AF_INET, &prefix, 8); - if (r < 0) - return bus_log_create_error(r); - - prefix.in6 = (struct in6_addr) IN6ADDR_LOOPBACK_INIT; - r = bus_append_ip_address_access(m, AF_INET6, &prefix, 128); - if (r < 0) - return r; - - } else if (streq(eq, "link-local")) { - /* "link-local" is a shortcut for 169.254.0.0/16 and fe80::/64 */ - - prefix.in.s_addr = htobe32((UINT32_C(169) << 24 | UINT32_C(254) << 16)); - r = bus_append_ip_address_access(m, AF_INET, &prefix, 16); - if (r < 0) - return bus_log_create_error(r); - - prefix.in6 = (struct in6_addr) { - .s6_addr32[0] = htobe32(0xfe800000) - }; - r = bus_append_ip_address_access(m, AF_INET6, &prefix, 64); - if (r < 0) - return bus_log_create_error(r); - - } else if (streq(eq, "multicast")) { - /* "multicast" is a shortcut for 224.0.0.0/4 and ff00::/8 */ - - prefix.in.s_addr = htobe32((UINT32_C(224) << 24)); - r = bus_append_ip_address_access(m, AF_INET, &prefix, 4); - if (r < 0) - return bus_log_create_error(r); - - prefix.in6 = (struct in6_addr) { - .s6_addr32[0] = htobe32(0xff000000) - }; - r = bus_append_ip_address_access(m, AF_INET6, &prefix, 8); - if (r < 0) - return bus_log_create_error(r); - - } else { - for (;;) { - _cleanup_free_ char *word = NULL; - - r = extract_first_word(&eq, &word, NULL, 0); - if (r == 0) - break; - if (r == -ENOMEM) - return log_oom(); - if (r < 0) - return log_error_errno(r, "Failed to parse %s: %s", field, eq); - - r = in_addr_prefix_from_string_auto(word, &family, &prefix, &prefixlen); - if (r < 0) - return log_error_errno(r, "Failed to parse IP address prefix: %s", word); - - r = bus_append_ip_address_access(m, family, &prefix, prefixlen); - if (r < 0) - return bus_log_create_error(r); - } - } - - r = sd_bus_message_close_container(m); - if (r < 0) - return bus_log_create_error(r); - - r = sd_bus_message_close_container(m); - if (r < 0) - return bus_log_create_error(r); - - r = sd_bus_message_close_container(m); - if (r < 0) - return bus_log_create_error(r); - - return 1; - } + "IPAddressDeny")) + return bus_append_parse_ip_address_filter(m, field, eq); if (STR_IN_SET(field, "IPIngressFilterPath", "IPEgressFilterPath")) { From 9f17f68bc52554afad19579ede03c475c08cc7c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Wed, 18 Jun 2025 16:36:03 +0200 Subject: [PATCH 16/64] shared/bus-unit-util: add helper for IPIngressFilterPath=/IPEgressFilterPath= --- src/shared/bus-unit-util.c | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c index e04beb1fd4..1235cf1eed 100644 --- a/src/shared/bus-unit-util.c +++ b/src/shared/bus-unit-util.c @@ -823,6 +823,19 @@ static int bus_append_parse_ip_address_filter(sd_bus_message *m, const char *fie return 1; } +static int bus_append_ip_filter_path(sd_bus_message *m, const char *field, const char *eq) { + int r; + + if (isempty(eq)) + r = sd_bus_message_append(m, "(sv)", field, "as", 0); + else + r = sd_bus_message_append(m, "(sv)", field, "as", 1, eq); + if (r < 0) + return bus_log_create_error(r); + + return 1; +} + static int bus_append_nft_set(sd_bus_message *m, const char *field, const char *eq) { int r; @@ -985,17 +998,8 @@ static int bus_append_cgroup_property(sd_bus_message *m, const char *field, cons return bus_append_parse_ip_address_filter(m, field, eq); if (STR_IN_SET(field, "IPIngressFilterPath", - "IPEgressFilterPath")) { - if (isempty(eq)) - r = sd_bus_message_append(m, "(sv)", field, "as", 0); - else - r = sd_bus_message_append(m, "(sv)", field, "as", 1, eq); - - if (r < 0) - return bus_log_create_error(r); - - return 1; - } + "IPEgressFilterPath")) + return bus_append_ip_filter_path(m, field, eq); if (streq(field, "BPFProgram")) { if (isempty(eq)) From 513026c4bfc237a181ca03320396450384974ed2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Fri, 27 Jun 2025 13:57:29 +0200 Subject: [PATCH 17/64] shared/bus-unit-util: define helper for BPFProgram= --- src/shared/bus-unit-util.c | 43 +++++++++++++++++++++----------------- 1 file changed, 24 insertions(+), 19 deletions(-) diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c index 1235cf1eed..dfa4b75a1b 100644 --- a/src/shared/bus-unit-util.c +++ b/src/shared/bus-unit-util.c @@ -487,6 +487,28 @@ static int bus_append_parse_io_device_latency(sd_bus_message *m, const char *fie return 1; } +static int bus_append_bpf_program(sd_bus_message *m, const char *field, const char *eq) { + int r; + + if (isempty(eq)) + r = sd_bus_message_append(m, "(sv)", field, "a(ss)", 0); + else { + _cleanup_free_ char *word = NULL; + + r = extract_first_word(&eq, &word, ":", 0); + if (r == -ENOMEM) + return log_oom(); + if (r < 0) + return log_error_errno(r, "Failed to parse %s: %m", field); + + r = sd_bus_message_append(m, "(sv)", field, "a(ss)", 1, word, eq); + } + if (r < 0) + return bus_log_create_error(r); + + return 1; +} + static int bus_append_exec_command(sd_bus_message *m, const char *field, const char *eq) { bool explicit_path = false, done = false, ambient_hack = false; _cleanup_strv_free_ char **l = NULL, **ex_opts = NULL; @@ -1001,25 +1023,8 @@ static int bus_append_cgroup_property(sd_bus_message *m, const char *field, cons "IPEgressFilterPath")) return bus_append_ip_filter_path(m, field, eq); - if (streq(field, "BPFProgram")) { - if (isempty(eq)) - r = sd_bus_message_append(m, "(sv)", field, "a(ss)", 0); - else { - _cleanup_free_ char *word = NULL; - - r = extract_first_word(&eq, &word, ":", 0); - if (r == -ENOMEM) - return log_oom(); - if (r < 0) - return log_error_errno(r, "Failed to parse %s: %m", field); - - r = sd_bus_message_append(m, "(sv)", field, "a(ss)", 1, word, eq); - } - if (r < 0) - return bus_log_create_error(r); - - return 1; - } + if (streq(field, "BPFProgram")) + return bus_append_bpf_program(m, field, eq); if (STR_IN_SET(field, "SocketBindAllow", "SocketBindDeny")) { From 4eb516e319bd35e2e5622d14f92bd8ecc7647666 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Fri, 27 Jun 2025 13:58:11 +0200 Subject: [PATCH 18/64] shared/bus-unit-util: add helper for SocketBindAllow=/SocketBindDeny= --- src/shared/bus-unit-util.c | 49 ++++++++++++++++++++------------------ 1 file changed, 26 insertions(+), 23 deletions(-) diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c index dfa4b75a1b..a54070d614 100644 --- a/src/shared/bus-unit-util.c +++ b/src/shared/bus-unit-util.c @@ -509,6 +509,30 @@ static int bus_append_bpf_program(sd_bus_message *m, const char *field, const ch return 1; } +static int bus_append_socket_filter(sd_bus_message *m, const char *field, const char *eq) { + int r; + + if (isempty(eq)) + r = sd_bus_message_append(m, "(sv)", field, "a(iiqq)", 0); + else { + int32_t family, ip_protocol; + uint16_t nr_ports, port_min; + + r = parse_socket_bind_item(eq, &family, &ip_protocol, &nr_ports, &port_min); + if (r == -ENOMEM) + return log_oom(); + if (r < 0) + return log_error_errno(r, "Failed to parse %s", field); + + r = sd_bus_message_append( + m, "(sv)", field, "a(iiqq)", 1, family, ip_protocol, nr_ports, port_min); + } + if (r < 0) + return bus_log_create_error(r); + + return 1; +} + static int bus_append_exec_command(sd_bus_message *m, const char *field, const char *eq) { bool explicit_path = false, done = false, ambient_hack = false; _cleanup_strv_free_ char **l = NULL, **ex_opts = NULL; @@ -944,8 +968,6 @@ static int bus_append_nft_set(sd_bus_message *m, const char *field, const char * } static int bus_append_cgroup_property(sd_bus_message *m, const char *field, const char *eq) { - int r; - if (STR_IN_SET(field, "DevicePolicy", "Slice", "ManagedOOMSwap", @@ -1027,27 +1049,8 @@ static int bus_append_cgroup_property(sd_bus_message *m, const char *field, cons return bus_append_bpf_program(m, field, eq); if (STR_IN_SET(field, "SocketBindAllow", - "SocketBindDeny")) { - if (isempty(eq)) - r = sd_bus_message_append(m, "(sv)", field, "a(iiqq)", 0); - else { - int32_t family, ip_protocol; - uint16_t nr_ports, port_min; - - r = parse_socket_bind_item(eq, &family, &ip_protocol, &nr_ports, &port_min); - if (r == -ENOMEM) - return log_oom(); - if (r < 0) - return log_error_errno(r, "Failed to parse %s", field); - - r = sd_bus_message_append( - m, "(sv)", field, "a(iiqq)", 1, family, ip_protocol, nr_ports, port_min); - } - if (r < 0) - return bus_log_create_error(r); - - return 1; - } + "SocketBindDeny")) + return bus_append_socket_filter(m, field, eq); if (streq(field, "MemoryPressureThresholdSec")) return bus_append_parse_sec_rename(m, field, eq); From 7c4b4a93d60ab147722c3fa63674213a0734ff37 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Wed, 18 Jun 2025 16:45:49 +0200 Subject: [PATCH 19/64] shared/bus-unit-util: define helper function for EnvironmentFile= --- src/shared/bus-unit-util.c | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c index a54070d614..774dbc78d4 100644 --- a/src/shared/bus-unit-util.c +++ b/src/shared/bus-unit-util.c @@ -967,6 +967,21 @@ static int bus_append_nft_set(sd_bus_message *m, const char *field, const char * return 1; } +static int bus_append_environment_files(sd_bus_message *m, const char *field, const char *eq) { + int r; + + if (isempty(eq)) + r = sd_bus_message_append(m, "(sv)", "EnvironmentFiles", "a(sb)", 0); + else + r = sd_bus_message_append(m, "(sv)", "EnvironmentFiles", "a(sb)", 1, + eq[0] == '-' ? eq + 1 : eq, + eq[0] == '-'); + if (r < 0) + return bus_log_create_error(r); + + return 1; +} + static int bus_append_cgroup_property(sd_bus_message *m, const char *field, const char *eq) { if (STR_IN_SET(field, "DevicePolicy", "Slice", @@ -1234,18 +1249,9 @@ static int bus_append_execute_property(sd_bus_message *m, const char *field, con "PassEnvironment")) return bus_append_strv(m, field, eq, /* separator= */ NULL, EXTRACT_UNQUOTE|EXTRACT_CUNESCAPE); - if (streq(field, "EnvironmentFile")) { - if (isempty(eq)) - r = sd_bus_message_append(m, "(sv)", "EnvironmentFiles", "a(sb)", 0); - else - r = sd_bus_message_append(m, "(sv)", "EnvironmentFiles", "a(sb)", 1, - eq[0] == '-' ? eq + 1 : eq, - eq[0] == '-'); - if (r < 0) - return bus_log_create_error(r); + if (streq(field, "EnvironmentFile")) + return bus_append_environment_files(m, field, eq); - return 1; - } if (STR_IN_SET(field, "SetCredential", "SetCredentialEncrypted")) { r = sd_bus_message_open_container(m, 'r', "sv"); From 82e009a212770aea0dc57d55cd07a3b07694edc8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Fri, 27 Jun 2025 14:02:27 +0200 Subject: [PATCH 20/64] shared/bus-unit-util: define helper for SetCredential=/SetCredentialEncrypted= --- src/shared/bus-unit-util.c | 165 +++++++++++++++++++------------------ 1 file changed, 85 insertions(+), 80 deletions(-) diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c index 774dbc78d4..04db19aa47 100644 --- a/src/shared/bus-unit-util.c +++ b/src/shared/bus-unit-util.c @@ -982,6 +982,89 @@ static int bus_append_environment_files(sd_bus_message *m, const char *field, co return 1; } +static int bus_append_set_credential(sd_bus_message *m, const char *field, const char *eq) { + int r; + + r = sd_bus_message_open_container(m, 'r', "sv"); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_append_basic(m, 's', field); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_open_container(m, 'v', "a(say)"); + if (r < 0) + return bus_log_create_error(r); + + if (isempty(eq)) + r = sd_bus_message_append(m, "a(say)", 0); + else { + _cleanup_free_ char *word = NULL; + const char *p = eq; + + r = extract_first_word(&p, &word, ":", EXTRACT_DONT_COALESCE_SEPARATORS); + if (r == -ENOMEM) + return log_oom(); + if (r < 0) + return log_error_errno(r, "Failed to parse %s= parameter: %s", field, eq); + if (r == 0 || !p) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Missing argument to %s=.", field); + + r = sd_bus_message_open_container(m, 'a', "(say)"); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_open_container(m, 'r', "say"); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_append(m, "s", word); + if (r < 0) + return bus_log_create_error(r); + + if (streq(field, "SetCredentialEncrypted")) { + _cleanup_free_ void *decoded = NULL; + size_t decoded_size; + + r = unbase64mem(p, &decoded, &decoded_size); + if (r < 0) + return log_error_errno(r, "Failed to base64 decode encrypted credential: %m"); + + r = sd_bus_message_append_array(m, 'y', decoded, decoded_size); + } else { + _cleanup_free_ char *unescaped = NULL; + ssize_t l; + + l = cunescape(p, UNESCAPE_ACCEPT_NUL, &unescaped); + if (l < 0) + return log_error_errno(l, "Failed to unescape %s= value: %s", field, p); + + r = sd_bus_message_append_array(m, 'y', unescaped, l); + } + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_close_container(m); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_close_container(m); + } + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_close_container(m); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_close_container(m); + if (r < 0) + return bus_log_create_error(r); + + return 1; +} + static int bus_append_cgroup_property(sd_bus_message *m, const char *field, const char *eq) { if (STR_IN_SET(field, "DevicePolicy", "Slice", @@ -1252,87 +1335,9 @@ static int bus_append_execute_property(sd_bus_message *m, const char *field, con if (streq(field, "EnvironmentFile")) return bus_append_environment_files(m, field, eq); + if (STR_IN_SET(field, "SetCredential", "SetCredentialEncrypted")) + return bus_append_set_credential(m, field, eq); - if (STR_IN_SET(field, "SetCredential", "SetCredentialEncrypted")) { - r = sd_bus_message_open_container(m, 'r', "sv"); - if (r < 0) - return bus_log_create_error(r); - - r = sd_bus_message_append_basic(m, 's', field); - if (r < 0) - return bus_log_create_error(r); - - r = sd_bus_message_open_container(m, 'v', "a(say)"); - if (r < 0) - return bus_log_create_error(r); - - if (isempty(eq)) - r = sd_bus_message_append(m, "a(say)", 0); - else { - _cleanup_free_ char *word = NULL; - const char *p = eq; - - r = extract_first_word(&p, &word, ":", EXTRACT_DONT_COALESCE_SEPARATORS); - if (r == -ENOMEM) - return log_oom(); - if (r < 0) - return log_error_errno(r, "Failed to parse %s= parameter: %s", field, eq); - if (r == 0 || !p) - return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Missing argument to %s=.", field); - - r = sd_bus_message_open_container(m, 'a', "(say)"); - if (r < 0) - return bus_log_create_error(r); - - r = sd_bus_message_open_container(m, 'r', "say"); - if (r < 0) - return bus_log_create_error(r); - - r = sd_bus_message_append(m, "s", word); - if (r < 0) - return bus_log_create_error(r); - - if (streq(field, "SetCredentialEncrypted")) { - _cleanup_free_ void *decoded = NULL; - size_t decoded_size; - - r = unbase64mem(p, &decoded, &decoded_size); - if (r < 0) - return log_error_errno(r, "Failed to base64 decode encrypted credential: %m"); - - r = sd_bus_message_append_array(m, 'y', decoded, decoded_size); - } else { - _cleanup_free_ char *unescaped = NULL; - ssize_t l; - - l = cunescape(p, UNESCAPE_ACCEPT_NUL, &unescaped); - if (l < 0) - return log_error_errno(l, "Failed to unescape %s= value: %s", field, p); - - r = sd_bus_message_append_array(m, 'y', unescaped, l); - } - if (r < 0) - return bus_log_create_error(r); - - r = sd_bus_message_close_container(m); - if (r < 0) - return bus_log_create_error(r); - - r = sd_bus_message_close_container(m); - } - if (r < 0) - return bus_log_create_error(r); - - r = sd_bus_message_close_container(m); - if (r < 0) - return bus_log_create_error(r); - - r = sd_bus_message_close_container(m); - if (r < 0) - return bus_log_create_error(r); - - return 1; - } if (STR_IN_SET(field, "LoadCredential", "LoadCredentialEncrypted")) { r = sd_bus_message_open_container(m, 'r', "sv"); From 068c4c8677f8c8a95d1cebbc13182d0ce319fffa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Fri, 27 Jun 2025 14:02:56 +0200 Subject: [PATCH 21/64] shared/bus-unit-util: define helper for LoadCredential=/LoadCredentialEncrypted= --- src/shared/bus-unit-util.c | 96 ++++++++++++++++++++------------------ 1 file changed, 50 insertions(+), 46 deletions(-) diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c index 04db19aa47..cda870cc0f 100644 --- a/src/shared/bus-unit-util.c +++ b/src/shared/bus-unit-util.c @@ -1065,6 +1065,54 @@ static int bus_append_set_credential(sd_bus_message *m, const char *field, const return 1; } +static int bus_append_load_credential(sd_bus_message *m, const char *field, const char *eq) { + int r; + + r = sd_bus_message_open_container(m, 'r', "sv"); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_append_basic(m, 's', field); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_open_container(m, 'v', "a(ss)"); + if (r < 0) + return bus_log_create_error(r); + + if (isempty(eq)) + r = sd_bus_message_append(m, "a(ss)", 0); + else { + _cleanup_free_ char *word = NULL; + const char *p = eq; + + r = extract_first_word(&p, &word, ":", EXTRACT_DONT_COALESCE_SEPARATORS); + if (r == -ENOMEM) + return log_oom(); + if (r < 0) + return log_error_errno(r, "Failed to parse %s= parameter: %s", field, eq); + if (r == 0) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Missing argument to %s=.", field); + + if (isempty(p)) /* If only one field is specified, then this means "inherit from above" */ + p = eq; + + r = sd_bus_message_append(m, "a(ss)", 1, word, p); + } + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_close_container(m); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_close_container(m); + if (r < 0) + return bus_log_create_error(r); + + return 1; +} + static int bus_append_cgroup_property(sd_bus_message *m, const char *field, const char *eq) { if (STR_IN_SET(field, "DevicePolicy", "Slice", @@ -1338,52 +1386,8 @@ static int bus_append_execute_property(sd_bus_message *m, const char *field, con if (STR_IN_SET(field, "SetCredential", "SetCredentialEncrypted")) return bus_append_set_credential(m, field, eq); - - if (STR_IN_SET(field, "LoadCredential", "LoadCredentialEncrypted")) { - r = sd_bus_message_open_container(m, 'r', "sv"); - if (r < 0) - return bus_log_create_error(r); - - r = sd_bus_message_append_basic(m, 's', field); - if (r < 0) - return bus_log_create_error(r); - - r = sd_bus_message_open_container(m, 'v', "a(ss)"); - if (r < 0) - return bus_log_create_error(r); - - if (isempty(eq)) - r = sd_bus_message_append(m, "a(ss)", 0); - else { - _cleanup_free_ char *word = NULL; - const char *p = eq; - - r = extract_first_word(&p, &word, ":", EXTRACT_DONT_COALESCE_SEPARATORS); - if (r == -ENOMEM) - return log_oom(); - if (r < 0) - return log_error_errno(r, "Failed to parse %s= parameter: %s", field, eq); - if (r == 0) - return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Missing argument to %s=.", field); - - if (isempty(p)) /* If only one field is specified, then this means "inherit from above" */ - p = eq; - - r = sd_bus_message_append(m, "a(ss)", 1, word, p); - } - if (r < 0) - return bus_log_create_error(r); - - r = sd_bus_message_close_container(m); - if (r < 0) - return bus_log_create_error(r); - - r = sd_bus_message_close_container(m); - if (r < 0) - return bus_log_create_error(r); - - return 1; - } + if (STR_IN_SET(field, "LoadCredential", "LoadCredentialEncrypted")) + return bus_append_load_credential(m, field, eq); if (streq(field, "ImportCredential")) { if (isempty(eq)) From 4b98aeb6ef61b270ad01b44a56d4efc51c1845af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Fri, 27 Jun 2025 14:03:32 +0200 Subject: [PATCH 22/64] shared/bus-unit-util: add helper for ImportCredentialEx= and fix naming confusion We add D-Bus properties like "*Ex" because we cannot change the D-Bus property type without breaking backward comapatibility. But those names are only for D-Bus, not for config file stanzas or the command-line parser. There, we can change the type, or in other words, there is no type, just a free-form string whose interpretation we can extend or change. Commit 831f208783aeac443e6f2fc2efc3119535a032ef that added ProtectHostnameEx was confused, because it added ImportCredentialEx in places where parsing of ImportCredential should be have been extended. On D-Bus, we send ImportCrednential in preference, and ImportCredentialEx only when required. This way we send less bytes on the wire and support older systems that don't understand the new property. Partially resolves https://github.com/systemd/systemd/issues/37174. --- src/shared/bus-unit-util.c | 105 ++++++++++++++++++------------------- 1 file changed, 52 insertions(+), 53 deletions(-) diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c index cda870cc0f..aa61ab8dbc 100644 --- a/src/shared/bus-unit-util.c +++ b/src/shared/bus-unit-util.c @@ -1113,6 +1113,56 @@ static int bus_append_load_credential(sd_bus_message *m, const char *field, cons return 1; } +static int bus_append_import_credential(sd_bus_message *m, const char *field, const char *eq) { + int r; + + if (isempty(eq)) + r = sd_bus_message_append(m, "(sv)", "ImportCredential", "as", 0); + else { + _cleanup_free_ char *word = NULL; + const char *p = eq; + + r = extract_first_word(&p, &word, ":", EXTRACT_DONT_COALESCE_SEPARATORS); + if (r == -ENOMEM) + return log_oom(); + if (r < 0) + return log_error_errno(r, "Failed to parse %s= parameter: %s", field, eq); + if (r == 0) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Missing argument to %s=.", field); + + if (!p) + r = sd_bus_message_append(m, "(sv)", "ImportCredential", "as", 1, eq); + else { + /* We need to send ImportCredentialEx */ + r = sd_bus_message_open_container(m, 'r', "sv"); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_append_basic(m, 's', "ImportCredentialEx"); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_open_container(m, 'v', "a(ss)"); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_append(m, "a(ss)", 1, word, p); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_close_container(m); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_close_container(m); + } + } + if (r < 0) + return bus_log_create_error(r); + + return 1; +} + static int bus_append_cgroup_property(sd_bus_message *m, const char *field, const char *eq) { if (STR_IN_SET(field, "DevicePolicy", "Slice", @@ -1389,59 +1439,8 @@ static int bus_append_execute_property(sd_bus_message *m, const char *field, con if (STR_IN_SET(field, "LoadCredential", "LoadCredentialEncrypted")) return bus_append_load_credential(m, field, eq); - if (streq(field, "ImportCredential")) { - if (isempty(eq)) - r = sd_bus_message_append(m, "(sv)", field, "as", 0); - else - r = sd_bus_message_append(m, "(sv)", field, "as", 1, eq); - if (r < 0) - return bus_log_create_error(r); - - return 1; - } - - if (streq(field, "ImportCredentialEx")) { - r = sd_bus_message_open_container(m, 'r', "sv"); - if (r < 0) - return bus_log_create_error(r); - - r = sd_bus_message_append_basic(m, 's', field); - if (r < 0) - return bus_log_create_error(r); - - r = sd_bus_message_open_container(m, 'v', "a(ss)"); - if (r < 0) - return bus_log_create_error(r); - - if (isempty(eq)) - r = sd_bus_message_append(m, "a(ss)", 0); - else { - _cleanup_free_ char *word = NULL; - const char *p = eq; - - r = extract_first_word(&p, &word, ":", EXTRACT_DONT_COALESCE_SEPARATORS); - if (r == -ENOMEM) - return log_oom(); - if (r < 0) - return log_error_errno(r, "Failed to parse %s= parameter: %s", field, eq); - if (r == 0) - return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Missing argument to %s=.", field); - - r = sd_bus_message_append(m, "a(ss)", 1, word, p); - } - if (r < 0) - return bus_log_create_error(r); - - r = sd_bus_message_close_container(m); - if (r < 0) - return bus_log_create_error(r); - - r = sd_bus_message_close_container(m); - if (r < 0) - return bus_log_create_error(r); - - return 1; - } + if (STR_IN_SET(field, "ImportCredential", "ImportCredentialEx")) + return bus_append_import_credential(m, field, eq); if (streq(field, "LogExtraFields")) { r = sd_bus_message_open_container(m, 'r', "sv"); From 0b5b043733bbb3f9362a0106cabcd02c0c3ef837 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Fri, 27 Jun 2025 15:48:55 +0200 Subject: [PATCH 23/64] TEST-54-CREDS: s/ImportCredentialEx/ImportCredential/ except for one place This is a separate commit because the tests are supposed to pass with both the old spelling and the new. --- test/units/TEST-54-CREDS.sh | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/test/units/TEST-54-CREDS.sh b/test/units/TEST-54-CREDS.sh index dae8d6a242..7016aee85a 100755 --- a/test/units/TEST-54-CREDS.sh +++ b/test/units/TEST-54-CREDS.sh @@ -334,7 +334,7 @@ systemd-run -p "ImportCredential=test.creds.*" \ test ! -e '${CREDENTIALS_DIRECTORY}/test.creds.hoge:invalid' # Check if credentials with invalid names are not imported (with renaming). -systemd-run -p "ImportCredentialEx=test.creds.*:renamed.creds." \ +systemd-run -p "ImportCredential=test.creds.*:renamed.creds." \ --unit=test-54-ImportCredential.service \ -p DynamicUser=1 \ --wait \ @@ -352,8 +352,8 @@ systemd-run -p "ImportCredential=test.creds.*" \ '${CREDENTIALS_DIRECTORY}/test.creds.third' >/tmp/ts54-concat cmp /tmp/ts54-concat <(echo -n abc) -# Check that ImportCredentialEx= works without renaming. -systemd-run -p "ImportCredentialEx=test.creds.*" \ +# Check that ImportCredential= works without renaming. +systemd-run -p "ImportCredential=test.creds.*" \ --unit=test-54-ImportCredential.service \ -p DynamicUser=1 \ --wait \ @@ -364,7 +364,7 @@ systemd-run -p "ImportCredentialEx=test.creds.*" \ cmp /tmp/ts54-concat <(echo -n abc) # Check that renaming with globs works as expected. -systemd-run -p "ImportCredentialEx=test.creds.*:renamed.creds." \ +systemd-run -p "ImportCredential=test.creds.*:renamed.creds." \ --unit=test-54-ImportCredential.service \ -p DynamicUser=1 \ --wait \ @@ -375,7 +375,7 @@ systemd-run -p "ImportCredentialEx=test.creds.*:renamed.creds." \ cmp /tmp/ts54-concat <(echo -n abc) # Check that renaming without globs works as expected. -systemd-run -p "ImportCredentialEx=test.creds.first:renamed.creds.first" \ +systemd-run -p "ImportCredential=test.creds.first:renamed.creds.first" \ --unit=test-54-ImportCredential.service \ -p DynamicUser=1 \ --wait \ @@ -384,8 +384,8 @@ systemd-run -p "ImportCredentialEx=test.creds.first:renamed.creds.first" \ cmp /tmp/ts54-concat <(echo -n a) # Test that multiple renames are processed in the correct order. -systemd-run -p "ImportCredentialEx=test.creds.first:renamed.creds.first" \ - -p "ImportCredentialEx=test.creds.second:renamed.creds.first" \ +systemd-run -p "ImportCredential=test.creds.first:renamed.creds.first" \ + -p "ImportCredential=test.creds.second:renamed.creds.first" \ --unit=test-54-ImportCredential.service \ -p DynamicUser=1 \ --wait \ @@ -394,6 +394,7 @@ systemd-run -p "ImportCredentialEx=test.creds.first:renamed.creds.first" \ cmp /tmp/ts54-concat <(echo -n a) # Test that a credential can be imported multiple times with different names. +# We use the deprecated name ImportCredentialEx= on purpose to check that it works. systemd-run -p "ImportCredentialEx=test.creds.first" \ -p "ImportCredentialEx=test.creds.first:renamed.creds.first" \ -p "ImportCredentialEx=test.creds.first:renamed.creds.second" \ From 50dd808d693e827d1d64e60071f79d3575ef4616 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Wed, 18 Jun 2025 16:49:41 +0200 Subject: [PATCH 24/64] shared/bus-unit-util: define helper for LogExtraFields= --- src/shared/bus-unit-util.c | 75 ++++++++++++++++++++------------------ 1 file changed, 40 insertions(+), 35 deletions(-) diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c index aa61ab8dbc..ad9d183341 100644 --- a/src/shared/bus-unit-util.c +++ b/src/shared/bus-unit-util.c @@ -1163,6 +1163,44 @@ static int bus_append_import_credential(sd_bus_message *m, const char *field, co return 1; } +static int bus_append_log_extra_fields(sd_bus_message *m, const char *field, const char *eq) { + int r; + + r = sd_bus_message_open_container(m, 'r', "sv"); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_append_basic(m, 's', field); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_open_container(m, 'v', "aay"); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_open_container(m, 'a', "ay"); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_append_array(m, 'y', eq, strlen(eq)); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_close_container(m); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_close_container(m); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_close_container(m); + if (r < 0) + return bus_log_create_error(r); + + return 1; +} + static int bus_append_cgroup_property(sd_bus_message *m, const char *field, const char *eq) { if (STR_IN_SET(field, "DevicePolicy", "Slice", @@ -1442,41 +1480,8 @@ static int bus_append_execute_property(sd_bus_message *m, const char *field, con if (STR_IN_SET(field, "ImportCredential", "ImportCredentialEx")) return bus_append_import_credential(m, field, eq); - if (streq(field, "LogExtraFields")) { - r = sd_bus_message_open_container(m, 'r', "sv"); - if (r < 0) - return bus_log_create_error(r); - - r = sd_bus_message_append_basic(m, 's', "LogExtraFields"); - if (r < 0) - return bus_log_create_error(r); - - r = sd_bus_message_open_container(m, 'v', "aay"); - if (r < 0) - return bus_log_create_error(r); - - r = sd_bus_message_open_container(m, 'a', "ay"); - if (r < 0) - return bus_log_create_error(r); - - r = sd_bus_message_append_array(m, 'y', eq, strlen(eq)); - if (r < 0) - return bus_log_create_error(r); - - r = sd_bus_message_close_container(m); - if (r < 0) - return bus_log_create_error(r); - - r = sd_bus_message_close_container(m); - if (r < 0) - return bus_log_create_error(r); - - r = sd_bus_message_close_container(m); - if (r < 0) - return bus_log_create_error(r); - - return 1; - } + if (streq(field, "LogExtraFields")) + return bus_append_log_extra_fields(m, field, eq); if (streq(field, "LogFilterPatterns")) { r = sd_bus_message_append(m, "(sv)", "LogFilterPatterns", "a(bs)", 1, From 32adb97cf12db2cff38e30e2419b6b36400645e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Fri, 27 Jun 2025 14:05:04 +0200 Subject: [PATCH 25/64] shared/bus-unit-util: define helper for LogFilterPatterns= --- src/shared/bus-unit-util.c | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c index ad9d183341..74448a96fd 100644 --- a/src/shared/bus-unit-util.c +++ b/src/shared/bus-unit-util.c @@ -1201,6 +1201,18 @@ static int bus_append_log_extra_fields(sd_bus_message *m, const char *field, con return 1; } +static int bus_append_log_filter_patterns(sd_bus_message *m, const char *field, const char *eq) { + int r; + + r = sd_bus_message_append(m, "(sv)", "LogFilterPatterns", "a(bs)", 1, + eq[0] != '~', + eq[0] != '~' ? eq : eq + 1); + if (r < 0) + return bus_log_create_error(r); + + return 1; +} + static int bus_append_cgroup_property(sd_bus_message *m, const char *field, const char *eq) { if (STR_IN_SET(field, "DevicePolicy", "Slice", @@ -1483,15 +1495,8 @@ static int bus_append_execute_property(sd_bus_message *m, const char *field, con if (streq(field, "LogExtraFields")) return bus_append_log_extra_fields(m, field, eq); - if (streq(field, "LogFilterPatterns")) { - r = sd_bus_message_append(m, "(sv)", "LogFilterPatterns", "a(bs)", 1, - eq[0] != '~', - eq[0] != '~' ? eq : eq + 1); - if (r < 0) - return bus_log_create_error(r); - - return 1; - } + if (streq(field, "LogFilterPatterns")) + return bus_append_log_filter_patterns(m, field, eq); if (STR_IN_SET(field, "StandardInput", "StandardOutput", From 375351d0039a91417458ec14046ab4d8ee62248b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Wed, 18 Jun 2025 16:55:34 +0200 Subject: [PATCH 26/64] shared/bus-unit-util: define helper functions for StandardInput/Output/Error= --- src/shared/bus-unit-util.c | 48 +++++++++++++++++++++----------------- 1 file changed, 26 insertions(+), 22 deletions(-) diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c index 74448a96fd..fbf6e31a4e 100644 --- a/src/shared/bus-unit-util.c +++ b/src/shared/bus-unit-util.c @@ -1213,6 +1213,30 @@ static int bus_append_log_filter_patterns(sd_bus_message *m, const char *field, return 1; } +static int bus_append_standard_inputs(sd_bus_message *m, const char *field, const char *eq) { + const char *n, *appended; + int r; + + if ((n = startswith(eq, "fd:"))) { + appended = strjoina(field, "FileDescriptorName"); + r = sd_bus_message_append(m, "(sv)", appended, "s", n); + } else if ((n = startswith(eq, "file:"))) { + appended = strjoina(field, "File"); + r = sd_bus_message_append(m, "(sv)", appended, "s", n); + } else if ((n = startswith(eq, "append:"))) { + appended = strjoina(field, "FileToAppend"); + r = sd_bus_message_append(m, "(sv)", appended, "s", n); + } else if ((n = startswith(eq, "truncate:"))) { + appended = strjoina(field, "FileToTruncate"); + r = sd_bus_message_append(m, "(sv)", appended, "s", n); + } else + r = sd_bus_message_append(m, "(sv)", field, "s", eq); + if (r < 0) + return bus_log_create_error(r); + + return 1; +} + static int bus_append_cgroup_property(sd_bus_message *m, const char *field, const char *eq) { if (STR_IN_SET(field, "DevicePolicy", "Slice", @@ -1500,28 +1524,8 @@ static int bus_append_execute_property(sd_bus_message *m, const char *field, con if (STR_IN_SET(field, "StandardInput", "StandardOutput", - "StandardError")) { - const char *n, *appended; - - if ((n = startswith(eq, "fd:"))) { - appended = strjoina(field, "FileDescriptorName"); - r = sd_bus_message_append(m, "(sv)", appended, "s", n); - } else if ((n = startswith(eq, "file:"))) { - appended = strjoina(field, "File"); - r = sd_bus_message_append(m, "(sv)", appended, "s", n); - } else if ((n = startswith(eq, "append:"))) { - appended = strjoina(field, "FileToAppend"); - r = sd_bus_message_append(m, "(sv)", appended, "s", n); - } else if ((n = startswith(eq, "truncate:"))) { - appended = strjoina(field, "FileToTruncate"); - r = sd_bus_message_append(m, "(sv)", appended, "s", n); - } else - r = sd_bus_message_append(m, "(sv)", field, "s", eq); - if (r < 0) - return bus_log_create_error(r); - - return 1; - } + "StandardError")) + return bus_append_standard_inputs(m, field, eq); if (streq(field, "StandardInputText")) { _cleanup_free_ char *unescaped = NULL; From 6bb442010046db0e4f18ee934d58496fdb0c51b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Fri, 27 Jun 2025 14:06:23 +0200 Subject: [PATCH 27/64] shared/bus-unit-util: define helper for StandardInputText= --- src/shared/bus-unit-util.c | 35 +++++++++++++++++++---------------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c index fbf6e31a4e..2a49d5717d 100644 --- a/src/shared/bus-unit-util.c +++ b/src/shared/bus-unit-util.c @@ -1237,6 +1237,23 @@ static int bus_append_standard_inputs(sd_bus_message *m, const char *field, cons return 1; } +static int bus_append_standard_input_text(sd_bus_message *m, const char *field, const char *eq) { + _cleanup_free_ char *unescaped = NULL; + ssize_t l; + + l = cunescape(eq, 0, &unescaped); + if (l < 0) + return log_error_errno(l, "Failed to unescape text '%s': %m", eq); + + if (!strextend(&unescaped, "\n")) + return log_oom(); + + /* Note that we don't expand specifiers here, but that should be OK, as this is a + * programmatic interface anyway */ + + return bus_append_byte_array(m, field, unescaped, l + 1); +} + static int bus_append_cgroup_property(sd_bus_message *m, const char *field, const char *eq) { if (STR_IN_SET(field, "DevicePolicy", "Slice", @@ -1527,22 +1544,8 @@ static int bus_append_execute_property(sd_bus_message *m, const char *field, con "StandardError")) return bus_append_standard_inputs(m, field, eq); - if (streq(field, "StandardInputText")) { - _cleanup_free_ char *unescaped = NULL; - ssize_t l; - - l = cunescape(eq, 0, &unescaped); - if (l < 0) - return log_error_errno(l, "Failed to unescape text '%s': %m", eq); - - if (!strextend(&unescaped, "\n")) - return log_oom(); - - /* Note that we don't expand specifiers here, but that should be OK, as this is a - * programmatic interface anyway */ - - return bus_append_byte_array(m, field, unescaped, l + 1); - } + if (streq(field, "StandardInputText")) + return bus_append_standard_input_text(m, field, eq); if (streq(field, "StandardInputData")) { _cleanup_free_ void *decoded = NULL; From 5c41755fe6ddc0a1bc9f6f2816910dd2748a5501 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Fri, 27 Jun 2025 14:06:32 +0200 Subject: [PATCH 28/64] shared/bus-unit-util: define helper for StandardInputData= --- src/shared/bus-unit-util.c | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c index 2a49d5717d..59b5fe9353 100644 --- a/src/shared/bus-unit-util.c +++ b/src/shared/bus-unit-util.c @@ -1254,6 +1254,18 @@ static int bus_append_standard_input_text(sd_bus_message *m, const char *field, return bus_append_byte_array(m, field, unescaped, l + 1); } +static int bus_append_standard_input_data(sd_bus_message *m, const char *field, const char *eq) { + _cleanup_free_ void *decoded = NULL; + size_t sz; + int r; + + r = unbase64mem(eq, &decoded, &sz); + if (r < 0) + return log_error_errno(r, "Failed to decode base64 data '%s': %m", eq); + + return bus_append_byte_array(m, field, decoded, sz); +} + static int bus_append_cgroup_property(sd_bus_message *m, const char *field, const char *eq) { if (STR_IN_SET(field, "DevicePolicy", "Slice", @@ -1547,16 +1559,8 @@ static int bus_append_execute_property(sd_bus_message *m, const char *field, con if (streq(field, "StandardInputText")) return bus_append_standard_input_text(m, field, eq); - if (streq(field, "StandardInputData")) { - _cleanup_free_ void *decoded = NULL; - size_t sz; - - r = unbase64mem(eq, &decoded, &sz); - if (r < 0) - return log_error_errno(r, "Failed to decode base64 data '%s': %m", eq); - - return bus_append_byte_array(m, field, decoded, sz); - } + if (streq(field, "StandardInputData")) + return bus_append_standard_input_data(m, field, eq); if ((suffix = startswith(field, "Limit"))) { int rl; From 94abee6063bcc01474a358b106d9916075f0fd0b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Wed, 18 Jun 2025 17:06:12 +0200 Subject: [PATCH 29/64] shared/bus-unit-util: define helper function for rlimits Strictly speaking, we call startswith twice now. This duplication shall be eliminated later. --- src/shared/bus-unit-util.c | 52 ++++++++++++++++++++------------------ 1 file changed, 27 insertions(+), 25 deletions(-) diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c index 59b5fe9353..0255f4fb02 100644 --- a/src/shared/bus-unit-util.c +++ b/src/shared/bus-unit-util.c @@ -1266,6 +1266,31 @@ static int bus_append_standard_input_data(sd_bus_message *m, const char *field, return bus_append_byte_array(m, field, decoded, sz); } +static int bus_append_resource_limit(sd_bus_message *m, const char *field, const char *eq) { + const char *suffix = ASSERT_PTR(startswith(field, "Limit")); + int rl, r; + + rl = rlimit_from_string(suffix); + if (rl < 0) + return log_error_errno(rl, "Unknown setting '%s'.", field); + + struct rlimit l; + r = rlimit_parse(rl, eq, &l); + if (r < 0) + return log_error_errno(r, "Failed to parse resource limit: %s", eq); + + r = sd_bus_message_append(m, "(sv)", field, "t", (uint64_t) l.rlim_max); + if (r < 0) + return bus_log_create_error(r); + + const char *sn = strjoina(field, "Soft"); + r = sd_bus_message_append(m, "(sv)", sn, "t", (uint64_t) l.rlim_cur); + if (r < 0) + return bus_log_create_error(r); + + return 1; +} + static int bus_append_cgroup_property(sd_bus_message *m, const char *field, const char *eq) { if (STR_IN_SET(field, "DevicePolicy", "Slice", @@ -1393,7 +1418,6 @@ static int bus_append_automount_property(sd_bus_message *m, const char *field, c } static int bus_append_execute_property(sd_bus_message *m, const char *field, const char *eq) { - const char *suffix; int r; if (STR_IN_SET(field, "User", @@ -1562,30 +1586,8 @@ static int bus_append_execute_property(sd_bus_message *m, const char *field, con if (streq(field, "StandardInputData")) return bus_append_standard_input_data(m, field, eq); - if ((suffix = startswith(field, "Limit"))) { - int rl; - - rl = rlimit_from_string(suffix); - if (rl >= 0) { - const char *sn; - struct rlimit l; - - r = rlimit_parse(rl, eq, &l); - if (r < 0) - return log_error_errno(r, "Failed to parse resource limit: %s", eq); - - r = sd_bus_message_append(m, "(sv)", field, "t", (uint64_t) l.rlim_max); - if (r < 0) - return bus_log_create_error(r); - - sn = strjoina(field, "Soft"); - r = sd_bus_message_append(m, "(sv)", sn, "t", (uint64_t) l.rlim_cur); - if (r < 0) - return bus_log_create_error(r); - - return 1; - } - } + if (startswith(field, "Limit")) + return bus_append_resource_limit(m, field, eq); if (STR_IN_SET(field, "AppArmorProfile", "SmackProcessLabel")) { From 8f0824f9dbf9b7d55a0e377a710d3ae9cf2067c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Wed, 18 Jun 2025 17:24:53 +0200 Subject: [PATCH 30/64] shared/bus-unit-util: define helper for CapabilityBoundingSet=/AmbientCapabilities= --- src/shared/bus-unit-util.c | 48 +++++++++++++++++++++----------------- 1 file changed, 26 insertions(+), 22 deletions(-) diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c index 0255f4fb02..4ad3e49e44 100644 --- a/src/shared/bus-unit-util.c +++ b/src/shared/bus-unit-util.c @@ -1291,6 +1291,30 @@ static int bus_append_resource_limit(sd_bus_message *m, const char *field, const return 1; } +static int bus_append_capabilities(sd_bus_message *m, const char *field, const char *eq) { + uint64_t sum = 0; + bool invert = false; + const char *p = eq; + int r; + + if (*p == '~') { + invert = true; + p++; + } + + r = capability_set_from_string(p, &sum); + if (r < 0) + return log_error_errno(r, "Failed to parse %s value %s: %m", field, eq); + + sum = invert ? ~sum : sum; + + r = sd_bus_message_append(m, "(sv)", field, "t", sum); + if (r < 0) + return bus_log_create_error(r); + + return 1; +} + static int bus_append_cgroup_property(sd_bus_message *m, const char *field, const char *eq) { if (STR_IN_SET(field, "DevicePolicy", "Slice", @@ -1607,28 +1631,8 @@ static int bus_append_execute_property(sd_bus_message *m, const char *field, con } if (STR_IN_SET(field, "CapabilityBoundingSet", - "AmbientCapabilities")) { - uint64_t sum = 0; - bool invert = false; - const char *p = eq; - - if (*p == '~') { - invert = true; - p++; - } - - r = capability_set_from_string(p, &sum); - if (r < 0) - return log_error_errno(r, "Failed to parse %s value %s: %m", field, eq); - - sum = invert ? ~sum : sum; - - r = sd_bus_message_append(m, "(sv)", field, "t", sum); - if (r < 0) - return bus_log_create_error(r); - - return 1; - } + "AmbientCapabilities")) + return bus_append_capabilities(m, field, eq); if (streq(field, "CPUAffinity")) { _cleanup_(cpu_set_done) CPUSet cpuset = {}; From 6dd31c8339db8c46cd5224b69eae646a3a6caf5a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Fri, 27 Jun 2025 14:07:50 +0200 Subject: [PATCH 31/64] shared/bus-unit-util: define helper for CPUAffinity= --- src/shared/bus-unit-util.c | 37 +++++++++++++++---------------------- 1 file changed, 15 insertions(+), 22 deletions(-) diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c index 4ad3e49e44..e88fa24f43 100644 --- a/src/shared/bus-unit-util.c +++ b/src/shared/bus-unit-util.c @@ -1315,6 +1315,19 @@ static int bus_append_capabilities(sd_bus_message *m, const char *field, const c return 1; } +static int bus_append_cpu_affinity(sd_bus_message *m, const char *field, const char *eq) { + int r; + + if (streq_ptr(eq, "numa")) { + r = sd_bus_message_append(m, "(sv)", "CPUAffinityFromNUMA", "b", true); + if (r < 0) + return bus_log_create_error(r); + return r; + } + + return bus_append_parse_cpu_set(m, field, eq); +} + static int bus_append_cgroup_property(sd_bus_message *m, const char *field, const char *eq) { if (STR_IN_SET(field, "DevicePolicy", "Slice", @@ -1634,28 +1647,8 @@ static int bus_append_execute_property(sd_bus_message *m, const char *field, con "AmbientCapabilities")) return bus_append_capabilities(m, field, eq); - if (streq(field, "CPUAffinity")) { - _cleanup_(cpu_set_done) CPUSet cpuset = {}; - _cleanup_free_ uint8_t *array = NULL; - size_t allocated; - - if (eq && streq(eq, "numa")) { - r = sd_bus_message_append(m, "(sv)", "CPUAffinityFromNUMA", "b", true); - if (r < 0) - return bus_log_create_error(r); - return r; - } - - r = parse_cpu_set(eq, &cpuset); - if (r < 0) - return log_error_errno(r, "Failed to parse %s value: %s", field, eq); - - r = cpu_set_to_dbus(&cpuset, &array, &allocated); - if (r < 0) - return log_error_errno(r, "Failed to serialize CPUAffinity: %m"); - - return bus_append_byte_array(m, field, array, allocated); - } + if (streq(field, "CPUAffinity")) + return bus_append_cpu_affinity(m, field, eq); if (streq(field, "NUMAPolicy")) { r = mpol_from_string(eq); From 85eb4381d384d5ef5576b97362ce03991c95b71a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Wed, 18 Jun 2025 17:26:54 +0200 Subject: [PATCH 32/64] shared/bus-unit-util: use common helper for NUMAPolicy= --- src/shared/bus-unit-util.c | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c index e88fa24f43..ccb5c8ed81 100644 --- a/src/shared/bus-unit-util.c +++ b/src/shared/bus-unit-util.c @@ -125,6 +125,7 @@ DEFINE_BUS_APPEND_PARSE("i", sched_policy_from_string); DEFINE_BUS_APPEND_PARSE("i", secure_bits_from_string); DEFINE_BUS_APPEND_PARSE("i", signal_from_string); DEFINE_BUS_APPEND_PARSE("i", parse_ip_protocol); +DEFINE_BUS_APPEND_PARSE("i", mpol_from_string); DEFINE_BUS_APPEND_PARSE_PTR("i", int32_t, int, ioprio_parse_priority); DEFINE_BUS_APPEND_PARSE_PTR("i", int32_t, int, parse_nice); DEFINE_BUS_APPEND_PARSE_PTR("i", int32_t, int, safe_atoi); @@ -1650,17 +1651,8 @@ static int bus_append_execute_property(sd_bus_message *m, const char *field, con if (streq(field, "CPUAffinity")) return bus_append_cpu_affinity(m, field, eq); - if (streq(field, "NUMAPolicy")) { - r = mpol_from_string(eq); - if (r < 0) - return log_error_errno(r, "Failed to parse %s value: %s", field, eq); - - r = sd_bus_message_append(m, "(sv)", field, "i", (int32_t) r); - if (r < 0) - return bus_log_create_error(r); - - return 1; - } + if (streq(field, "NUMAPolicy")) + return bus_append_mpol_from_string(m, field, eq); if (streq(field, "NUMAMask")) { _cleanup_(cpu_set_done) CPUSet nodes = {}; From 187b248e5b43953158162267b4f4952327f6e400 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Wed, 18 Jun 2025 17:32:20 +0200 Subject: [PATCH 33/64] shared/bus-unit-util: add helper for NUMAMask= --- src/shared/bus-unit-util.c | 46 +++++++++++++++++++++----------------- 1 file changed, 25 insertions(+), 21 deletions(-) diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c index ccb5c8ed81..d3d2eb6dcf 100644 --- a/src/shared/bus-unit-util.c +++ b/src/shared/bus-unit-util.c @@ -1329,6 +1329,29 @@ static int bus_append_cpu_affinity(sd_bus_message *m, const char *field, const c return bus_append_parse_cpu_set(m, field, eq); } +static int bus_append_numa_mask(sd_bus_message *m, const char *field, const char *eq) { + _cleanup_(cpu_set_done) CPUSet nodes = {}; + _cleanup_free_ uint8_t *array = NULL; + size_t allocated; + int r; + + if (eq && streq(eq, "all")) { + r = numa_mask_add_all(&nodes); + if (r < 0) + return log_error_errno(r, "Failed to create NUMA mask representing \"all\" NUMA nodes: %m"); + } else { + r = parse_cpu_set(eq, &nodes); + if (r < 0) + return log_error_errno(r, "Failed to parse %s value: %s", field, eq); + } + + r = cpu_set_to_dbus(&nodes, &array, &allocated); + if (r < 0) + return log_error_errno(r, "Failed to serialize %s: %m", field); + + return bus_append_byte_array(m, field, array, allocated); +} + static int bus_append_cgroup_property(sd_bus_message *m, const char *field, const char *eq) { if (STR_IN_SET(field, "DevicePolicy", "Slice", @@ -1654,27 +1677,8 @@ static int bus_append_execute_property(sd_bus_message *m, const char *field, con if (streq(field, "NUMAPolicy")) return bus_append_mpol_from_string(m, field, eq); - if (streq(field, "NUMAMask")) { - _cleanup_(cpu_set_done) CPUSet nodes = {}; - _cleanup_free_ uint8_t *array = NULL; - size_t allocated; - - if (eq && streq(eq, "all")) { - r = numa_mask_add_all(&nodes); - if (r < 0) - return log_error_errno(r, "Failed to create NUMA mask representing \"all\" NUMA nodes: %m"); - } else { - r = parse_cpu_set(eq, &nodes); - if (r < 0) - return log_error_errno(r, "Failed to parse %s value: %s", field, eq); - } - - r = cpu_set_to_dbus(&nodes, &array, &allocated); - if (r < 0) - return log_error_errno(r, "Failed to serialize NUMAMask: %m"); - - return bus_append_byte_array(m, field, array, allocated); - } + if (streq(field, "NUMAMask")) + return bus_append_numa_mask(m, field, eq); if (STR_IN_SET(field, "RestrictAddressFamilies", "RestrictFileSystems", From c622449cb7393b4ba9f7085742c6b1121c5273e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Wed, 18 Jun 2025 17:54:06 +0200 Subject: [PATCH 34/64] shared/bus-unit-util: add helper for filter lists --- src/shared/bus-unit-util.c | 138 +++++++++++++++++++------------------ 1 file changed, 71 insertions(+), 67 deletions(-) diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c index d3d2eb6dcf..b79df51292 100644 --- a/src/shared/bus-unit-util.c +++ b/src/shared/bus-unit-util.c @@ -1352,6 +1352,75 @@ static int bus_append_numa_mask(sd_bus_message *m, const char *field, const char return bus_append_byte_array(m, field, array, allocated); } +static int bus_append_filter_list(sd_bus_message *m, const char *field, const char *eq) { + int allow_list = 1; + const char *p = eq; + int r; + + if (*p == '~') { + allow_list = 0; + p++; + } + + r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv"); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_open_container(m, 'v', "(bas)"); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_open_container(m, 'r', "bas"); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_append_basic(m, 'b', &allow_list); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_open_container(m, 'a', "s"); + if (r < 0) + return bus_log_create_error(r); + + for (;;) { + _cleanup_free_ char *word = NULL; + + r = extract_first_word(&p, &word, NULL, EXTRACT_UNQUOTE); + if (r == 0) + break; + if (r == -ENOMEM) + return log_oom(); + if (r < 0) + return log_error_errno(r, "Invalid syntax: %s", eq); + + r = sd_bus_message_append_basic(m, 's', word); + if (r < 0) + return bus_log_create_error(r); + } + + r = sd_bus_message_close_container(m); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_close_container(m); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_close_container(m); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_close_container(m); + if (r < 0) + return bus_log_create_error(r); + + return 1; +} + static int bus_append_cgroup_property(sd_bus_message *m, const char *field, const char *eq) { if (STR_IN_SET(field, "DevicePolicy", "Slice", @@ -1684,73 +1753,8 @@ static int bus_append_execute_property(sd_bus_message *m, const char *field, con "RestrictFileSystems", "SystemCallFilter", "SystemCallLog", - "RestrictNetworkInterfaces")) { - int allow_list = 1; - const char *p = eq; - - if (*p == '~') { - allow_list = 0; - p++; - } - - r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv"); - if (r < 0) - return bus_log_create_error(r); - - r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field); - if (r < 0) - return bus_log_create_error(r); - - r = sd_bus_message_open_container(m, 'v', "(bas)"); - if (r < 0) - return bus_log_create_error(r); - - r = sd_bus_message_open_container(m, 'r', "bas"); - if (r < 0) - return bus_log_create_error(r); - - r = sd_bus_message_append_basic(m, 'b', &allow_list); - if (r < 0) - return bus_log_create_error(r); - - r = sd_bus_message_open_container(m, 'a', "s"); - if (r < 0) - return bus_log_create_error(r); - - for (;;) { - _cleanup_free_ char *word = NULL; - - r = extract_first_word(&p, &word, NULL, EXTRACT_UNQUOTE); - if (r == 0) - break; - if (r == -ENOMEM) - return log_oom(); - if (r < 0) - return log_error_errno(r, "Invalid syntax: %s", eq); - - r = sd_bus_message_append_basic(m, 's', word); - if (r < 0) - return bus_log_create_error(r); - } - - r = sd_bus_message_close_container(m); - if (r < 0) - return bus_log_create_error(r); - - r = sd_bus_message_close_container(m); - if (r < 0) - return bus_log_create_error(r); - - r = sd_bus_message_close_container(m); - if (r < 0) - return bus_log_create_error(r); - - r = sd_bus_message_close_container(m); - if (r < 0) - return bus_log_create_error(r); - - return 1; - } + "RestrictNetworkInterfaces")) + return bus_append_filter_list(m, field, eq); if (STR_IN_SET(field, "RestrictNamespaces", "DelegateNamespaces")) { From af677b7a25d23cef0d137abfa1acc6b97e94f01f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Fri, 27 Jun 2025 14:15:46 +0200 Subject: [PATCH 35/64] shared/bus-unit-util: define helper for RestrictNamespaces=/DelegateNamespaces= --- src/shared/bus-unit-util.c | 70 ++++++++++++++++++++------------------ 1 file changed, 37 insertions(+), 33 deletions(-) diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c index b79df51292..f806ffb8b6 100644 --- a/src/shared/bus-unit-util.c +++ b/src/shared/bus-unit-util.c @@ -1421,6 +1421,41 @@ static int bus_append_filter_list(sd_bus_message *m, const char *field, const ch return 1; } +static int bus_append_namespace_list(sd_bus_message *m, const char *field, const char *eq) { + bool invert = false; + unsigned long all = UPDATE_FLAG(NAMESPACE_FLAGS_ALL, CLONE_NEWUSER, !streq(field, "DelegateNamespaces")); + unsigned long flags; + int r; + + r = parse_boolean(eq); + if (r > 0) + /* RestrictNamespaces= value gets stored into a field with reverse semantics (the + * namespaces which are retained), so RestrictNamespaces=true means we retain no + * access to any namespaces and vice-versa. */ + flags = streq(field, "RestrictNamespaces") ? 0 : all; + else if (r == 0) + flags = streq(field, "RestrictNamespaces") ? all : 0; + else { + if (eq[0] == '~') { + invert = true; + eq++; + } + + r = namespace_flags_from_string(eq, &flags); + if (r < 0) + return log_error_errno(r, "Failed to parse %s value %s.", field, eq); + } + + if (invert) + flags = (~flags) & all; + + r = sd_bus_message_append(m, "(sv)", field, "t", (uint64_t) flags); + if (r < 0) + return bus_log_create_error(r); + + return 1; +} + static int bus_append_cgroup_property(sd_bus_message *m, const char *field, const char *eq) { if (STR_IN_SET(field, "DevicePolicy", "Slice", @@ -1757,39 +1792,8 @@ static int bus_append_execute_property(sd_bus_message *m, const char *field, con return bus_append_filter_list(m, field, eq); if (STR_IN_SET(field, "RestrictNamespaces", - "DelegateNamespaces")) { - bool invert = false; - unsigned long all = UPDATE_FLAG(NAMESPACE_FLAGS_ALL, CLONE_NEWUSER, !streq(field, "DelegateNamespaces")); - unsigned long flags; - - r = parse_boolean(eq); - if (r > 0) - /* RestrictNamespaces= value gets stored into a field with reverse semantics (the - * namespaces which are retained), so RestrictNamespaces=true means we retain no - * access to any namespaces and vice-versa. */ - flags = streq(field, "RestrictNamespaces") ? 0 : all; - else if (r == 0) - flags = streq(field, "RestrictNamespaces") ? all : 0; - else { - if (eq[0] == '~') { - invert = true; - eq++; - } - - r = namespace_flags_from_string(eq, &flags); - if (r < 0) - return log_error_errno(r, "Failed to parse %s value %s.", field, eq); - } - - if (invert) - flags = (~flags) & all; - - r = sd_bus_message_append(m, "(sv)", field, "t", (uint64_t) flags); - if (r < 0) - return bus_log_create_error(r); - - return 1; - } + "DelegateNamespaces")) + return bus_append_namespace_list(m, field, eq); if (STR_IN_SET(field, "BindPaths", "BindReadOnlyPaths")) { From 0fdcbaf63369d8b139974a720e599a47904a1df4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Fri, 27 Jun 2025 14:17:34 +0200 Subject: [PATCH 36/64] shared/bus-unit-util: define helper for BindPaths=/BindReadOnlyPaths= --- src/shared/bus-unit-util.c | 174 +++++++++++++++++++------------------ 1 file changed, 88 insertions(+), 86 deletions(-) diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c index f806ffb8b6..4e85d7edba 100644 --- a/src/shared/bus-unit-util.c +++ b/src/shared/bus-unit-util.c @@ -1456,6 +1456,92 @@ static int bus_append_namespace_list(sd_bus_message *m, const char *field, const return 1; } +static int bus_append_bind_paths(sd_bus_message *m, const char *field, const char *eq) { + const char *p = eq; + int r; + + r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv"); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_open_container(m, 'v', "a(ssbt)"); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_open_container(m, 'a', "(ssbt)"); + if (r < 0) + return bus_log_create_error(r); + + for (;;) { + _cleanup_free_ char *source = NULL, *destination = NULL; + char *s = NULL, *d = NULL; + bool ignore_enoent = false; + uint64_t flags = MS_REC; + + r = extract_first_word(&p, &source, ":" WHITESPACE, EXTRACT_UNQUOTE|EXTRACT_DONT_COALESCE_SEPARATORS); + if (r < 0) + return log_error_errno(r, "Failed to parse argument: %m"); + if (r == 0) + break; + + s = source; + if (s[0] == '-') { + ignore_enoent = true; + s++; + } + + if (p && p[-1] == ':') { + r = extract_first_word(&p, &destination, ":" WHITESPACE, EXTRACT_UNQUOTE|EXTRACT_DONT_COALESCE_SEPARATORS); + if (r < 0) + return log_error_errno(r, "Failed to parse argument: %m"); + if (r == 0) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), + "Missing argument after ':': %s", eq); + + d = destination; + + if (p && p[-1] == ':') { + _cleanup_free_ char *options = NULL; + + r = extract_first_word(&p, &options, NULL, EXTRACT_UNQUOTE); + if (r < 0) + return log_error_errno(r, "Failed to parse argument: %m"); + + if (isempty(options) || streq(options, "rbind")) + flags = MS_REC; + else if (streq(options, "norbind")) + flags = 0; + else + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), + "Unknown options: %s", eq); + } + } else + d = s; + + r = sd_bus_message_append(m, "(ssbt)", s, d, ignore_enoent, flags); + if (r < 0) + return bus_log_create_error(r); + } + + r = sd_bus_message_close_container(m); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_close_container(m); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_close_container(m); + if (r < 0) + return bus_log_create_error(r); + + return 1; +} + static int bus_append_cgroup_property(sd_bus_message *m, const char *field, const char *eq) { if (STR_IN_SET(field, "DevicePolicy", "Slice", @@ -1796,92 +1882,8 @@ static int bus_append_execute_property(sd_bus_message *m, const char *field, con return bus_append_namespace_list(m, field, eq); if (STR_IN_SET(field, "BindPaths", - "BindReadOnlyPaths")) { - const char *p = eq; - - r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv"); - if (r < 0) - return bus_log_create_error(r); - - r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field); - if (r < 0) - return bus_log_create_error(r); - - r = sd_bus_message_open_container(m, 'v', "a(ssbt)"); - if (r < 0) - return bus_log_create_error(r); - - r = sd_bus_message_open_container(m, 'a', "(ssbt)"); - if (r < 0) - return bus_log_create_error(r); - - for (;;) { - _cleanup_free_ char *source = NULL, *destination = NULL; - char *s = NULL, *d = NULL; - bool ignore_enoent = false; - uint64_t flags = MS_REC; - - r = extract_first_word(&p, &source, ":" WHITESPACE, EXTRACT_UNQUOTE|EXTRACT_DONT_COALESCE_SEPARATORS); - if (r < 0) - return log_error_errno(r, "Failed to parse argument: %m"); - if (r == 0) - break; - - s = source; - if (s[0] == '-') { - ignore_enoent = true; - s++; - } - - if (p && p[-1] == ':') { - r = extract_first_word(&p, &destination, ":" WHITESPACE, EXTRACT_UNQUOTE|EXTRACT_DONT_COALESCE_SEPARATORS); - if (r < 0) - return log_error_errno(r, "Failed to parse argument: %m"); - if (r == 0) - return log_error_errno(SYNTHETIC_ERRNO(EINVAL), - "Missing argument after ':': %s", - eq); - - d = destination; - - if (p && p[-1] == ':') { - _cleanup_free_ char *options = NULL; - - r = extract_first_word(&p, &options, NULL, EXTRACT_UNQUOTE); - if (r < 0) - return log_error_errno(r, "Failed to parse argument: %m"); - - if (isempty(options) || streq(options, "rbind")) - flags = MS_REC; - else if (streq(options, "norbind")) - flags = 0; - else - return log_error_errno(SYNTHETIC_ERRNO(EINVAL), - "Unknown options: %s", - eq); - } - } else - d = s; - - r = sd_bus_message_append(m, "(ssbt)", s, d, ignore_enoent, flags); - if (r < 0) - return bus_log_create_error(r); - } - - r = sd_bus_message_close_container(m); - if (r < 0) - return bus_log_create_error(r); - - r = sd_bus_message_close_container(m); - if (r < 0) - return bus_log_create_error(r); - - r = sd_bus_message_close_container(m); - if (r < 0) - return bus_log_create_error(r); - - return 1; - } + "BindReadOnlyPaths")) + return bus_append_bind_paths(m, field, eq); if (streq(field, "TemporaryFileSystem")) { const char *p = eq; From 8f90f4b86fcf976d442516681e2dc81b681113fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Fri, 27 Jun 2025 14:18:31 +0200 Subject: [PATCH 37/64] shared/bus-unit-util: define helper for TemporaryFileSystem= --- src/shared/bus-unit-util.c | 117 +++++++++++++++++++------------------ 1 file changed, 60 insertions(+), 57 deletions(-) diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c index 4e85d7edba..71b141fe99 100644 --- a/src/shared/bus-unit-util.c +++ b/src/shared/bus-unit-util.c @@ -1542,6 +1542,64 @@ static int bus_append_bind_paths(sd_bus_message *m, const char *field, const cha return 1; } +static int bus_append_temporary_file_system(sd_bus_message *m, const char *field, const char *eq) { + const char *p = eq; + int r; + + r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv"); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_open_container(m, 'v', "a(ss)"); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_open_container(m, 'a', "(ss)"); + if (r < 0) + return bus_log_create_error(r); + + for (;;) { + _cleanup_free_ char *word = NULL, *path = NULL; + const char *w; + + r = extract_first_word(&p, &word, NULL, EXTRACT_UNQUOTE); + if (r < 0) + return log_error_errno(r, "Failed to parse argument: %m"); + if (r == 0) + break; + + w = word; + r = extract_first_word(&w, &path, ":", EXTRACT_DONT_COALESCE_SEPARATORS); + if (r < 0) + return log_error_errno(r, "Failed to parse argument: %m"); + if (r == 0) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), + "Failed to parse argument: %s", p); + + r = sd_bus_message_append(m, "(ss)", path, w); + if (r < 0) + return bus_log_create_error(r); + } + + r = sd_bus_message_close_container(m); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_close_container(m); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_close_container(m); + if (r < 0) + return bus_log_create_error(r); + + return 1; +} + static int bus_append_cgroup_property(sd_bus_message *m, const char *field, const char *eq) { if (STR_IN_SET(field, "DevicePolicy", "Slice", @@ -1885,63 +1943,8 @@ static int bus_append_execute_property(sd_bus_message *m, const char *field, con "BindReadOnlyPaths")) return bus_append_bind_paths(m, field, eq); - if (streq(field, "TemporaryFileSystem")) { - const char *p = eq; - - r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv"); - if (r < 0) - return bus_log_create_error(r); - - r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field); - if (r < 0) - return bus_log_create_error(r); - - r = sd_bus_message_open_container(m, 'v', "a(ss)"); - if (r < 0) - return bus_log_create_error(r); - - r = sd_bus_message_open_container(m, 'a', "(ss)"); - if (r < 0) - return bus_log_create_error(r); - - for (;;) { - _cleanup_free_ char *word = NULL, *path = NULL; - const char *w; - - r = extract_first_word(&p, &word, NULL, EXTRACT_UNQUOTE); - if (r < 0) - return log_error_errno(r, "Failed to parse argument: %m"); - if (r == 0) - break; - - w = word; - r = extract_first_word(&w, &path, ":", EXTRACT_DONT_COALESCE_SEPARATORS); - if (r < 0) - return log_error_errno(r, "Failed to parse argument: %m"); - if (r == 0) - return log_error_errno(SYNTHETIC_ERRNO(EINVAL), - "Failed to parse argument: %s", - p); - - r = sd_bus_message_append(m, "(ss)", path, w); - if (r < 0) - return bus_log_create_error(r); - } - - r = sd_bus_message_close_container(m); - if (r < 0) - return bus_log_create_error(r); - - r = sd_bus_message_close_container(m); - if (r < 0) - return bus_log_create_error(r); - - r = sd_bus_message_close_container(m); - if (r < 0) - return bus_log_create_error(r); - - return 1; - } + if (streq(field, "TemporaryFileSystem")) + return bus_append_temporary_file_system(m, field, eq); if (streq(field, "RootHash")) { _cleanup_free_ void *roothash_decoded = NULL; From 4d92c1da4595986fd7d5479072d06cf4398862c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Fri, 27 Jun 2025 14:19:29 +0200 Subject: [PATCH 38/64] shared/bus-unit-util: define helper for RootHash= --- src/shared/bus-unit-util.c | 38 +++++++++++++++++++++----------------- 1 file changed, 21 insertions(+), 17 deletions(-) diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c index 71b141fe99..ba4ba65dfa 100644 --- a/src/shared/bus-unit-util.c +++ b/src/shared/bus-unit-util.c @@ -1600,6 +1600,25 @@ static int bus_append_temporary_file_system(sd_bus_message *m, const char *field return 1; } +static int bus_append_root_hash(sd_bus_message *m, const char *field, const char *eq) { + _cleanup_free_ void *roothash_decoded = NULL; + size_t roothash_decoded_size = 0; + int r; + + /* We have the path to a roothash to load and decode, eg: RootHash=/foo/bar.roothash */ + if (path_is_absolute(eq)) + return bus_append_string(m, "RootHashPath", eq); + + /* We have a roothash to decode, eg: RootHash=012345789abcdef */ + r = unhexmem(eq, &roothash_decoded, &roothash_decoded_size); + if (r < 0) + return log_error_errno(r, "Failed to decode RootHash= '%s': %m", eq); + if (roothash_decoded_size < sizeof(sd_id128_t)) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "RootHash= '%s' is too short.", eq); + + return bus_append_byte_array(m, field, roothash_decoded, roothash_decoded_size); +} + static int bus_append_cgroup_property(sd_bus_message *m, const char *field, const char *eq) { if (STR_IN_SET(field, "DevicePolicy", "Slice", @@ -1946,23 +1965,8 @@ static int bus_append_execute_property(sd_bus_message *m, const char *field, con if (streq(field, "TemporaryFileSystem")) return bus_append_temporary_file_system(m, field, eq); - if (streq(field, "RootHash")) { - _cleanup_free_ void *roothash_decoded = NULL; - size_t roothash_decoded_size = 0; - - /* We have the path to a roothash to load and decode, eg: RootHash=/foo/bar.roothash */ - if (path_is_absolute(eq)) - return bus_append_string(m, "RootHashPath", eq); - - /* We have a roothash to decode, eg: RootHash=012345789abcdef */ - r = unhexmem(eq, &roothash_decoded, &roothash_decoded_size); - if (r < 0) - return log_error_errno(r, "Failed to decode RootHash= '%s': %m", eq); - if (roothash_decoded_size < sizeof(sd_id128_t)) - return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "RootHash= '%s' is too short.", eq); - - return bus_append_byte_array(m, field, roothash_decoded, roothash_decoded_size); - } + if (streq(field, "RootHash")) + return bus_append_root_hash(m, field, eq); if (streq(field, "RootHashSignature")) { _cleanup_free_ void *roothash_sig_decoded = NULL; From 5517273715556c4b4fa32eb16fe831d586ef3b79 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Fri, 27 Jun 2025 14:20:51 +0200 Subject: [PATCH 39/64] shared/bus-unit-util: define helper for RootHashSignature= --- src/shared/bus-unit-util.c | 44 ++++++++++++++++++++++---------------- 1 file changed, 25 insertions(+), 19 deletions(-) diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c index ba4ba65dfa..a8925c1a00 100644 --- a/src/shared/bus-unit-util.c +++ b/src/shared/bus-unit-util.c @@ -1619,6 +1619,29 @@ static int bus_append_root_hash(sd_bus_message *m, const char *field, const char return bus_append_byte_array(m, field, roothash_decoded, roothash_decoded_size); } +static int bus_append_root_hash_signature(sd_bus_message *m, const char *field, const char *eq) { + char *value; + _cleanup_free_ void *roothash_sig_decoded = NULL; + size_t roothash_sig_decoded_size = 0; + int r; + + /* We have the path to a roothash signature to load and decode, eg: RootHash=/foo/bar.roothash.p7s */ + if (path_is_absolute(eq)) + return bus_append_string(m, "RootHashSignaturePath", eq); + + if (!(value = startswith(eq, "base64:"))) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), + "Failed to decode %s=%s: neither a path nor starts with 'base64:'.", + field, eq); + + /* We have a roothash signature to decode, eg: RootHashSignature=base64:012345789abcdef */ + r = unbase64mem(value, &roothash_sig_decoded, &roothash_sig_decoded_size); + if (r < 0) + return log_error_errno(r, "Failed to decode %s=%s: %m", field, eq); + + return bus_append_byte_array(m, field, roothash_sig_decoded, roothash_sig_decoded_size); +} + static int bus_append_cgroup_property(sd_bus_message *m, const char *field, const char *eq) { if (STR_IN_SET(field, "DevicePolicy", "Slice", @@ -1968,25 +1991,8 @@ static int bus_append_execute_property(sd_bus_message *m, const char *field, con if (streq(field, "RootHash")) return bus_append_root_hash(m, field, eq); - if (streq(field, "RootHashSignature")) { - _cleanup_free_ void *roothash_sig_decoded = NULL; - char *value; - size_t roothash_sig_decoded_size = 0; - - /* We have the path to a roothash signature to load and decode, eg: RootHash=/foo/bar.roothash.p7s */ - if (path_is_absolute(eq)) - return bus_append_string(m, "RootHashSignaturePath", eq); - - if (!(value = startswith(eq, "base64:"))) - return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to decode RootHashSignature= '%s', not a path but doesn't start with 'base64:'.", eq); - - /* We have a roothash signature to decode, eg: RootHashSignature=base64:012345789abcdef */ - r = unbase64mem(value, &roothash_sig_decoded, &roothash_sig_decoded_size); - if (r < 0) - return log_error_errno(r, "Failed to decode RootHashSignature= '%s': %m", eq); - - return bus_append_byte_array(m, field, roothash_sig_decoded, roothash_sig_decoded_size); - } + if (streq(field, "RootHashSignature")) + return bus_append_root_hash_signature(m, field, eq); if (streq(field, "RootImageOptions")) { _cleanup_strv_free_ char **l = NULL; From 79decd4e4912eb03f5d8dd403f69c87601788906 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Fri, 27 Jun 2025 14:21:43 +0200 Subject: [PATCH 40/64] shared/bus-unit-util: define helper for RootImageOptions= --- src/shared/bus-unit-util.c | 96 ++++++++++++++++++++------------------ 1 file changed, 50 insertions(+), 46 deletions(-) diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c index a8925c1a00..9d22a60d34 100644 --- a/src/shared/bus-unit-util.c +++ b/src/shared/bus-unit-util.c @@ -1642,6 +1642,54 @@ static int bus_append_root_hash_signature(sd_bus_message *m, const char *field, return bus_append_byte_array(m, field, roothash_sig_decoded, roothash_sig_decoded_size); } +static int bus_append_root_image_options(sd_bus_message *m, const char *field, const char *eq) { + _cleanup_strv_free_ char **l = NULL; + const char *p = eq; + int r; + + r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv"); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_open_container(m, 'v', "a(ss)"); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_open_container(m, 'a', "(ss)"); + if (r < 0) + return bus_log_create_error(r); + + r = strv_split_colon_pairs(&l, p); + if (r < 0) + return log_error_errno(r, "Failed to parse argument: %m"); + + STRV_FOREACH_PAIR(first, second, l) { + r = sd_bus_message_append(m, "(ss)", + !isempty(*second) ? *first : "root", + !isempty(*second) ? *second : *first); + if (r < 0) + return bus_log_create_error(r); + } + + r = sd_bus_message_close_container(m); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_close_container(m); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_close_container(m); + if (r < 0) + return bus_log_create_error(r); + + return 1; +} + static int bus_append_cgroup_property(sd_bus_message *m, const char *field, const char *eq) { if (STR_IN_SET(field, "DevicePolicy", "Slice", @@ -1994,52 +2042,8 @@ static int bus_append_execute_property(sd_bus_message *m, const char *field, con if (streq(field, "RootHashSignature")) return bus_append_root_hash_signature(m, field, eq); - if (streq(field, "RootImageOptions")) { - _cleanup_strv_free_ char **l = NULL; - const char *p = eq; - - r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv"); - if (r < 0) - return bus_log_create_error(r); - - r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field); - if (r < 0) - return bus_log_create_error(r); - - r = sd_bus_message_open_container(m, 'v', "a(ss)"); - if (r < 0) - return bus_log_create_error(r); - - r = sd_bus_message_open_container(m, 'a', "(ss)"); - if (r < 0) - return bus_log_create_error(r); - - r = strv_split_colon_pairs(&l, p); - if (r < 0) - return log_error_errno(r, "Failed to parse argument: %m"); - - STRV_FOREACH_PAIR(first, second, l) { - r = sd_bus_message_append(m, "(ss)", - !isempty(*second) ? *first : "root", - !isempty(*second) ? *second : *first); - if (r < 0) - return bus_log_create_error(r); - } - - r = sd_bus_message_close_container(m); - if (r < 0) - return bus_log_create_error(r); - - r = sd_bus_message_close_container(m); - if (r < 0) - return bus_log_create_error(r); - - r = sd_bus_message_close_container(m); - if (r < 0) - return bus_log_create_error(r); - - return 1; - } + if (streq(field, "RootImageOptions")) + return bus_append_root_image_options(m, field, eq); if (streq(field, "MountImages")) { const char *p = eq; From 1c202720bebb2221113f1317c21b797c84627763 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Fri, 27 Jun 2025 14:23:10 +0200 Subject: [PATCH 41/64] shared/bus-unit-util: define helper for MountImages= --- src/shared/bus-unit-util.c | 213 +++++++++++++++++++------------------ 1 file changed, 108 insertions(+), 105 deletions(-) diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c index 9d22a60d34..81e59aaa76 100644 --- a/src/shared/bus-unit-util.c +++ b/src/shared/bus-unit-util.c @@ -1690,6 +1690,112 @@ static int bus_append_root_image_options(sd_bus_message *m, const char *field, c return 1; } +static int bus_append_mount_images(sd_bus_message *m, const char *field, const char *eq) { + const char *p = eq; + int r; + + r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv"); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_open_container(m, 'v', "a(ssba(ss))"); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_open_container(m, 'a', "(ssba(ss))"); + if (r < 0) + return bus_log_create_error(r); + + for (;;) { + _cleanup_free_ char *first = NULL, *second = NULL, *tuple = NULL; + const char *q = NULL, *source = NULL; + bool permissive = false; + + r = extract_first_word(&p, &tuple, NULL, EXTRACT_UNQUOTE|EXTRACT_RETAIN_ESCAPE); + if (r < 0) + return log_error_errno(r, "Failed to parse %s property: %s", field, eq); + if (r == 0) + break; + + q = tuple; + r = extract_many_words(&q, ":", EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS, &first, &second); + if (r < 0) + return log_error_errno(r, "Failed to parse %s property: %s", field, eq); + if (r == 0) + continue; + + source = first; + if (source[0] == '-') { + permissive = true; + source++; + } + + if (isempty(second)) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), + "Missing argument after ':' for %s: %s", field, eq); + + r = sd_bus_message_open_container(m, 'r', "ssba(ss)"); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_append(m, "ssb", source, second, permissive); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_open_container(m, 'a', "(ss)"); + if (r < 0) + return bus_log_create_error(r); + + for (;;) { + _cleanup_free_ char *partition = NULL, *mount_options = NULL; + + r = extract_many_words(&q, ":", EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS, &partition, &mount_options); + if (r < 0) + return log_error_errno(r, "Failed to parse %s property: %s", field, eq); + if (r == 0) + break; + /* Single set of options, applying to the root partition/single filesystem */ + if (r == 1) { + r = sd_bus_message_append(m, "(ss)", "root", partition); + if (r < 0) + return bus_log_create_error(r); + + break; + } + + r = sd_bus_message_append(m, "(ss)", partition, mount_options); + if (r < 0) + return bus_log_create_error(r); + } + + r = sd_bus_message_close_container(m); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_close_container(m); + if (r < 0) + return bus_log_create_error(r); + } + + r = sd_bus_message_close_container(m); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_close_container(m); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_close_container(m); + if (r < 0) + return bus_log_create_error(r); + + return 1; +} + static int bus_append_cgroup_property(sd_bus_message *m, const char *field, const char *eq) { if (STR_IN_SET(field, "DevicePolicy", "Slice", @@ -2045,111 +2151,8 @@ static int bus_append_execute_property(sd_bus_message *m, const char *field, con if (streq(field, "RootImageOptions")) return bus_append_root_image_options(m, field, eq); - if (streq(field, "MountImages")) { - const char *p = eq; - - r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv"); - if (r < 0) - return bus_log_create_error(r); - - r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field); - if (r < 0) - return bus_log_create_error(r); - - r = sd_bus_message_open_container(m, 'v', "a(ssba(ss))"); - if (r < 0) - return bus_log_create_error(r); - - r = sd_bus_message_open_container(m, 'a', "(ssba(ss))"); - if (r < 0) - return bus_log_create_error(r); - - for (;;) { - _cleanup_free_ char *first = NULL, *second = NULL, *tuple = NULL; - const char *q = NULL, *source = NULL; - bool permissive = false; - - r = extract_first_word(&p, &tuple, NULL, EXTRACT_UNQUOTE|EXTRACT_RETAIN_ESCAPE); - if (r < 0) - return log_error_errno(r, "Failed to parse MountImages= property: %s", eq); - if (r == 0) - break; - - q = tuple; - r = extract_many_words(&q, ":", EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS, &first, &second); - if (r < 0) - return log_error_errno(r, "Failed to parse MountImages= property: %s", eq); - if (r == 0) - continue; - - source = first; - if (source[0] == '-') { - permissive = true; - source++; - } - - if (isempty(second)) - return log_error_errno(SYNTHETIC_ERRNO(EINVAL), - "Missing argument after ':': %s", - eq); - - r = sd_bus_message_open_container(m, 'r', "ssba(ss)"); - if (r < 0) - return bus_log_create_error(r); - - r = sd_bus_message_append(m, "ssb", source, second, permissive); - if (r < 0) - return bus_log_create_error(r); - - r = sd_bus_message_open_container(m, 'a', "(ss)"); - if (r < 0) - return bus_log_create_error(r); - - for (;;) { - _cleanup_free_ char *partition = NULL, *mount_options = NULL; - - r = extract_many_words(&q, ":", EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS, &partition, &mount_options); - if (r < 0) - return log_error_errno(r, "Failed to parse MountImages= property: %s", eq); - if (r == 0) - break; - /* Single set of options, applying to the root partition/single filesystem */ - if (r == 1) { - r = sd_bus_message_append(m, "(ss)", "root", partition); - if (r < 0) - return bus_log_create_error(r); - - break; - } - - r = sd_bus_message_append(m, "(ss)", partition, mount_options); - if (r < 0) - return bus_log_create_error(r); - } - - r = sd_bus_message_close_container(m); - if (r < 0) - return bus_log_create_error(r); - - r = sd_bus_message_close_container(m); - if (r < 0) - return bus_log_create_error(r); - } - - r = sd_bus_message_close_container(m); - if (r < 0) - return bus_log_create_error(r); - - r = sd_bus_message_close_container(m); - if (r < 0) - return bus_log_create_error(r); - - r = sd_bus_message_close_container(m); - if (r < 0) - return bus_log_create_error(r); - - return 1; - } + if (streq(field, "MountImages")) + return bus_append_mount_images(m, field, eq); if (streq(field, "ExtensionImages")) { const char *p = eq; From e04484ad7c69f0b3ad27c515c722a9188c0a3c65 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Fri, 27 Jun 2025 14:23:26 +0200 Subject: [PATCH 42/64] shared/bus-unit-util: define helper for ExtensionImages= --- src/shared/bus-unit-util.c | 204 +++++++++++++++++++------------------ 1 file changed, 104 insertions(+), 100 deletions(-) diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c index 81e59aaa76..91eacac249 100644 --- a/src/shared/bus-unit-util.c +++ b/src/shared/bus-unit-util.c @@ -1796,6 +1796,108 @@ static int bus_append_mount_images(sd_bus_message *m, const char *field, const c return 1; } +static int bus_append_extension_images(sd_bus_message *m, const char *field, const char *eq) { + const char *p = eq; + int r; + + r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv"); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_open_container(m, 'v', "a(sba(ss))"); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_open_container(m, 'a', "(sba(ss))"); + if (r < 0) + return bus_log_create_error(r); + + for (;;) { + _cleanup_free_ char *source = NULL, *tuple = NULL; + const char *q = NULL, *s = NULL; + bool permissive = false; + + r = extract_first_word(&p, &tuple, NULL, EXTRACT_UNQUOTE|EXTRACT_RETAIN_ESCAPE); + if (r < 0) + return log_error_errno(r, "Failed to parse %s property: %s", field, eq); + if (r == 0) + break; + + q = tuple; + r = extract_first_word(&q, &source, ":", EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS); + if (r < 0) + return log_error_errno(r, "Failed to parse %s property: %s", field, eq); + if (r == 0) + continue; + + s = source; + if (s[0] == '-') { + permissive = true; + s++; + } + + r = sd_bus_message_open_container(m, 'r', "sba(ss)"); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_append(m, "sb", s, permissive); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_open_container(m, 'a', "(ss)"); + if (r < 0) + return bus_log_create_error(r); + + for (;;) { + _cleanup_free_ char *partition = NULL, *mount_options = NULL; + + r = extract_many_words(&q, ":", EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS, &partition, &mount_options); + if (r < 0) + return log_error_errno(r, "Failed to parse %s property: %s", field, eq); + if (r == 0) + break; + /* Single set of options, applying to the root partition/single filesystem */ + if (r == 1) { + r = sd_bus_message_append(m, "(ss)", "root", partition); + if (r < 0) + return bus_log_create_error(r); + + break; + } + + r = sd_bus_message_append(m, "(ss)", partition, mount_options); + if (r < 0) + return bus_log_create_error(r); + } + + r = sd_bus_message_close_container(m); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_close_container(m); + if (r < 0) + return bus_log_create_error(r); + } + + r = sd_bus_message_close_container(m); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_close_container(m); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_close_container(m); + if (r < 0) + return bus_log_create_error(r); + + return 1; +} + static int bus_append_cgroup_property(sd_bus_message *m, const char *field, const char *eq) { if (STR_IN_SET(field, "DevicePolicy", "Slice", @@ -2154,106 +2256,8 @@ static int bus_append_execute_property(sd_bus_message *m, const char *field, con if (streq(field, "MountImages")) return bus_append_mount_images(m, field, eq); - if (streq(field, "ExtensionImages")) { - const char *p = eq; - - r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv"); - if (r < 0) - return bus_log_create_error(r); - - r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field); - if (r < 0) - return bus_log_create_error(r); - - r = sd_bus_message_open_container(m, 'v', "a(sba(ss))"); - if (r < 0) - return bus_log_create_error(r); - - r = sd_bus_message_open_container(m, 'a', "(sba(ss))"); - if (r < 0) - return bus_log_create_error(r); - - for (;;) { - _cleanup_free_ char *source = NULL, *tuple = NULL; - const char *q = NULL, *s = NULL; - bool permissive = false; - - r = extract_first_word(&p, &tuple, NULL, EXTRACT_UNQUOTE|EXTRACT_RETAIN_ESCAPE); - if (r < 0) - return log_error_errno(r, "Failed to parse ExtensionImages= property: %s", eq); - if (r == 0) - break; - - q = tuple; - r = extract_first_word(&q, &source, ":", EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS); - if (r < 0) - return log_error_errno(r, "Failed to parse ExtensionImages= property: %s", eq); - if (r == 0) - continue; - - s = source; - if (s[0] == '-') { - permissive = true; - s++; - } - - r = sd_bus_message_open_container(m, 'r', "sba(ss)"); - if (r < 0) - return bus_log_create_error(r); - - r = sd_bus_message_append(m, "sb", s, permissive); - if (r < 0) - return bus_log_create_error(r); - - r = sd_bus_message_open_container(m, 'a', "(ss)"); - if (r < 0) - return bus_log_create_error(r); - - for (;;) { - _cleanup_free_ char *partition = NULL, *mount_options = NULL; - - r = extract_many_words(&q, ":", EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS, &partition, &mount_options); - if (r < 0) - return log_error_errno(r, "Failed to parse ExtensionImages= property: %s", eq); - if (r == 0) - break; - /* Single set of options, applying to the root partition/single filesystem */ - if (r == 1) { - r = sd_bus_message_append(m, "(ss)", "root", partition); - if (r < 0) - return bus_log_create_error(r); - - break; - } - - r = sd_bus_message_append(m, "(ss)", partition, mount_options); - if (r < 0) - return bus_log_create_error(r); - } - - r = sd_bus_message_close_container(m); - if (r < 0) - return bus_log_create_error(r); - - r = sd_bus_message_close_container(m); - if (r < 0) - return bus_log_create_error(r); - } - - r = sd_bus_message_close_container(m); - if (r < 0) - return bus_log_create_error(r); - - r = sd_bus_message_close_container(m); - if (r < 0) - return bus_log_create_error(r); - - r = sd_bus_message_close_container(m); - if (r < 0) - return bus_log_create_error(r); - - return 1; - } + if (streq(field, "ExtensionImages")) + return bus_append_extension_images(m, field, eq); if (STR_IN_SET(field, "StateDirectory", "RuntimeDirectory", "CacheDirectory", "LogsDirectory")) { _cleanup_strv_free_ char **symlinks = NULL, **symlinks_ro = NULL, **sources = NULL, **sources_ro = NULL; From 779aed7443283c1db96ad1354b5ab24eb524538a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Wed, 18 Jun 2025 17:56:02 +0200 Subject: [PATCH 43/64] shared/bus-unit-util: add a helper function for directory args --- src/shared/bus-unit-util.c | 284 +++++++++++++++++++------------------ 1 file changed, 144 insertions(+), 140 deletions(-) diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c index 91eacac249..4763679b15 100644 --- a/src/shared/bus-unit-util.c +++ b/src/shared/bus-unit-util.c @@ -1898,6 +1898,148 @@ static int bus_append_extension_images(sd_bus_message *m, const char *field, con return 1; } +static int bus_append_directory(sd_bus_message *m, const char *field, const char *eq) { + _cleanup_strv_free_ char **symlinks = NULL, **symlinks_ro = NULL, **sources = NULL, **sources_ro = NULL; + const char *p = eq; + int r; + + /* Adding new directories is supported from both *DirectorySymlink methods and the + * older ones, so first parse the input, and if we are given a new-style src:dst + * tuple use the new method, else use the old one. */ + + for (;;) { + _cleanup_free_ char *tuple = NULL, *source = NULL, *dest = NULL, *flags = NULL; + + r = extract_first_word(&p, &tuple, NULL, EXTRACT_UNQUOTE); + if (r < 0) + return log_error_errno(r, "Failed to parse argument: %m"); + if (r == 0) + break; + + const char *t = tuple; + r = extract_many_words(&t, ":", EXTRACT_UNQUOTE|EXTRACT_DONT_COALESCE_SEPARATORS, &source, &dest, &flags); + if (r <= 0) + return log_error_errno(r ?: SYNTHETIC_ERRNO(EINVAL), "Failed to parse argument: %m"); + + path_simplify(source); + + if (isempty(dest) && isempty(flags)) { + r = strv_consume(&sources, TAKE_PTR(source)); + if (r < 0) + return bus_log_create_error(r); + } else if (isempty(flags)) { + path_simplify(dest); + r = strv_consume_pair(&symlinks, TAKE_PTR(source), TAKE_PTR(dest)); + if (r < 0) + return log_oom(); + } else { + ExecDirectoryFlags exec_directory_flags = exec_directory_flags_from_string(flags); + if (exec_directory_flags < 0 || (exec_directory_flags & ~_EXEC_DIRECTORY_FLAGS_PUBLIC) != 0) + return log_error_errno(r, "Failed to parse flags: %s", flags); + + if (!isempty(dest)) { + path_simplify(dest); + r = strv_consume_pair(&symlinks_ro, TAKE_PTR(source), TAKE_PTR(dest)); + } else + r = strv_consume(&sources_ro, TAKE_PTR(source)); + if (r < 0) + return log_oom(); + } + } + + if (!strv_isempty(sources)) { + r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv"); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_open_container(m, 'v', "as"); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_append_strv(m, sources); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_close_container(m); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_close_container(m); + if (r < 0) + return bus_log_create_error(r); + } + + /* For State and Runtime directories we support an optional destination parameter, which + * will be used to create a symlink to the source. But it is new so we cannot change the + * old DBUS signatures, so append a new message type. */ + if (!strv_isempty(symlinks) || !strv_isempty(symlinks_ro) || !strv_isempty(sources_ro)) { + const char *symlink_field; + + r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv"); + if (r < 0) + return bus_log_create_error(r); + + if (streq(field, "StateDirectory")) + symlink_field = "StateDirectorySymlink"; + else if (streq(field, "RuntimeDirectory")) + symlink_field = "RuntimeDirectorySymlink"; + else if (streq(field, "CacheDirectory")) + symlink_field = "CacheDirectorySymlink"; + else if (streq(field, "LogsDirectory")) + symlink_field = "LogsDirectorySymlink"; + else + assert_not_reached(); + + r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, symlink_field); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_open_container(m, 'v', "a(sst)"); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_open_container(m, 'a', "(sst)"); + if (r < 0) + return bus_log_create_error(r); + + STRV_FOREACH_PAIR(source, destination, symlinks) { + r = sd_bus_message_append(m, "(sst)", *source, *destination, UINT64_C(0)); + if (r < 0) + return bus_log_create_error(r); + } + + STRV_FOREACH_PAIR(source, destination, symlinks_ro) { + r = sd_bus_message_append(m, "(sst)", *source, *destination, (uint64_t) EXEC_DIRECTORY_READ_ONLY); + if (r < 0) + return bus_log_create_error(r); + } + + STRV_FOREACH(source, sources_ro) { + r = sd_bus_message_append(m, "(sst)", *source, "", (uint64_t) EXEC_DIRECTORY_READ_ONLY); + if (r < 0) + return bus_log_create_error(r); + } + + r = sd_bus_message_close_container(m); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_close_container(m); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_close_container(m); + if (r < 0) + return bus_log_create_error(r); + } + + return 1; +} + static int bus_append_cgroup_property(sd_bus_message *m, const char *field, const char *eq) { if (STR_IN_SET(field, "DevicePolicy", "Slice", @@ -2259,146 +2401,8 @@ static int bus_append_execute_property(sd_bus_message *m, const char *field, con if (streq(field, "ExtensionImages")) return bus_append_extension_images(m, field, eq); - if (STR_IN_SET(field, "StateDirectory", "RuntimeDirectory", "CacheDirectory", "LogsDirectory")) { - _cleanup_strv_free_ char **symlinks = NULL, **symlinks_ro = NULL, **sources = NULL, **sources_ro = NULL; - const char *p = eq; - - /* Adding new directories is supported from both *DirectorySymlink methods and the - * older ones, so first parse the input, and if we are given a new-style src:dst - * tuple use the new method, else use the old one. */ - - for (;;) { - _cleanup_free_ char *tuple = NULL, *source = NULL, *dest = NULL, *flags = NULL; - - r = extract_first_word(&p, &tuple, NULL, EXTRACT_UNQUOTE); - if (r < 0) - return log_error_errno(r, "Failed to parse argument: %m"); - if (r == 0) - break; - - const char *t = tuple; - r = extract_many_words(&t, ":", EXTRACT_UNQUOTE|EXTRACT_DONT_COALESCE_SEPARATORS, &source, &dest, &flags); - if (r <= 0) - return log_error_errno(r ?: SYNTHETIC_ERRNO(EINVAL), "Failed to parse argument: %m"); - - path_simplify(source); - - if (isempty(dest) && isempty(flags)) { - r = strv_consume(&sources, TAKE_PTR(source)); - if (r < 0) - return bus_log_create_error(r); - } else if (isempty(flags)) { - path_simplify(dest); - r = strv_consume_pair(&symlinks, TAKE_PTR(source), TAKE_PTR(dest)); - if (r < 0) - return log_oom(); - } else { - ExecDirectoryFlags exec_directory_flags = exec_directory_flags_from_string(flags); - if (exec_directory_flags < 0 || (exec_directory_flags & ~_EXEC_DIRECTORY_FLAGS_PUBLIC) != 0) - return log_error_errno(r, "Failed to parse flags: %s", flags); - - if (!isempty(dest)) { - path_simplify(dest); - r = strv_consume_pair(&symlinks_ro, TAKE_PTR(source), TAKE_PTR(dest)); - } else - r = strv_consume(&sources_ro, TAKE_PTR(source)); - if (r < 0) - return log_oom(); - } - } - - if (!strv_isempty(sources)) { - r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv"); - if (r < 0) - return bus_log_create_error(r); - - r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field); - if (r < 0) - return bus_log_create_error(r); - - r = sd_bus_message_open_container(m, 'v', "as"); - if (r < 0) - return bus_log_create_error(r); - - r = sd_bus_message_append_strv(m, sources); - if (r < 0) - return bus_log_create_error(r); - - r = sd_bus_message_close_container(m); - if (r < 0) - return bus_log_create_error(r); - - r = sd_bus_message_close_container(m); - if (r < 0) - return bus_log_create_error(r); - } - - /* For State and Runtime directories we support an optional destination parameter, which - * will be used to create a symlink to the source. But it is new so we cannot change the - * old DBUS signatures, so append a new message type. */ - if (!strv_isempty(symlinks) || !strv_isempty(symlinks_ro) || !strv_isempty(sources_ro)) { - const char *symlink_field; - - r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv"); - if (r < 0) - return bus_log_create_error(r); - - if (streq(field, "StateDirectory")) - symlink_field = "StateDirectorySymlink"; - else if (streq(field, "RuntimeDirectory")) - symlink_field = "RuntimeDirectorySymlink"; - else if (streq(field, "CacheDirectory")) - symlink_field = "CacheDirectorySymlink"; - else if (streq(field, "LogsDirectory")) - symlink_field = "LogsDirectorySymlink"; - else - assert_not_reached(); - - r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, symlink_field); - if (r < 0) - return bus_log_create_error(r); - - r = sd_bus_message_open_container(m, 'v', "a(sst)"); - if (r < 0) - return bus_log_create_error(r); - - r = sd_bus_message_open_container(m, 'a', "(sst)"); - if (r < 0) - return bus_log_create_error(r); - - STRV_FOREACH_PAIR(source, destination, symlinks) { - r = sd_bus_message_append(m, "(sst)", *source, *destination, UINT64_C(0)); - if (r < 0) - return bus_log_create_error(r); - } - - STRV_FOREACH_PAIR(source, destination, symlinks_ro) { - r = sd_bus_message_append(m, "(sst)", *source, *destination, (uint64_t) EXEC_DIRECTORY_READ_ONLY); - if (r < 0) - return bus_log_create_error(r); - } - - STRV_FOREACH(source, sources_ro) { - r = sd_bus_message_append(m, "(sst)", *source, "", (uint64_t) EXEC_DIRECTORY_READ_ONLY); - if (r < 0) - return bus_log_create_error(r); - } - - r = sd_bus_message_close_container(m); - if (r < 0) - return bus_log_create_error(r); - - r = sd_bus_message_close_container(m); - if (r < 0) - return bus_log_create_error(r); - - r = sd_bus_message_close_container(m); - if (r < 0) - return bus_log_create_error(r); - } - - return 1; - } + if (STR_IN_SET(field, "StateDirectory", "RuntimeDirectory", "CacheDirectory", "LogsDirectory")) + return bus_append_directory(m, field, eq); if (streq(field, "ProtectHostnameEx")) { const char *colon = strchr(eq, ':'); From 9e3bc6406b7e7d212e9aa32e6ba6c0becd1c6d13 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Wed, 18 Jun 2025 17:58:02 +0200 Subject: [PATCH 44/64] shared/bus-unit-util: add helper for ProtectHostnameEx and fix naming confusion MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As with grandparent commit for ImportCredentialEx=, the whole series of commits that extended ProtectHostname was confused (6746f288548a240148c7c9643e14996bfe960017, cf48bde7aea52b18ac3fa218d3f60fd3d533ef66, e76fcd0e40a6910f4818a374c6a8d854d644ff93), because it added ProtectHostnameEx in places where parsing of ProtectHostname should be have been extended. Accept ProtectHostname=… with the new extended syntax, keep accepting ProtectHostnameEx=… for compat with release v257. Prefer sending ProtectHostname. Partially resolves https://github.com/systemd/systemd/issues/37174. --- src/shared/bus-unit-util.c | 49 ++++++++++++++++++++++++-------------- 1 file changed, 31 insertions(+), 18 deletions(-) diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c index 4763679b15..c7fce7e77f 100644 --- a/src/shared/bus-unit-util.c +++ b/src/shared/bus-unit-util.c @@ -2040,6 +2040,35 @@ static int bus_append_directory(sd_bus_message *m, const char *field, const char return 1; } +static int bus_append_protect_hostname(sd_bus_message *m, const char *field, const char *eq) { + int r; + + /* The command-line field is called "ProtectHostname". We also accept "ProtectHostnameEx" as the + * field name for backward compatibility. We set ProtectHostame or ProtectHostnameEx. */ + + r = parse_boolean(eq); + if (r >= 0) + r = sd_bus_message_append(m, "(sv)", "ProtectHostname", "b", r); + else { + const char *colon = strchr(eq, ':'); + if (colon) { + if (isempty(colon + 1)) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to parse argument: %s=%s", field, eq); + + _cleanup_free_ char *p = strndup(eq, colon - eq); + if (!p) + return -ENOMEM; + + r = sd_bus_message_append(m, "(sv)", "ProtectHostnameEx", "(ss)", p, colon + 1); + } else + r = sd_bus_message_append(m, "(sv)", "ProtectHostnameEx", "(ss)", eq, NULL); + } + if (r < 0) + return bus_log_create_error(r); + + return 1; +} + static int bus_append_cgroup_property(sd_bus_message *m, const char *field, const char *eq) { if (STR_IN_SET(field, "DevicePolicy", "Slice", @@ -2225,7 +2254,6 @@ static int bus_append_execute_property(sd_bus_message *m, const char *field, con "BindLogSockets", "CPUSchedulingResetOnFork", "LockPersonality", - "ProtectHostname", "MemoryKSM", "RestrictSUIDSGID", "RootEphemeral", @@ -2404,24 +2432,9 @@ static int bus_append_execute_property(sd_bus_message *m, const char *field, con if (STR_IN_SET(field, "StateDirectory", "RuntimeDirectory", "CacheDirectory", "LogsDirectory")) return bus_append_directory(m, field, eq); - if (streq(field, "ProtectHostnameEx")) { - const char *colon = strchr(eq, ':'); - if (colon) { - if (isempty(colon + 1)) - return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to parse argument: %s=%s", field, eq); + if (STR_IN_SET(field, "ProtectHostname", "ProtectHostnameEx")) + return bus_append_protect_hostname(m, field, eq); - _cleanup_free_ char *p = strndup(eq, colon - eq); - if (!p) - return -ENOMEM; - - r = sd_bus_message_append(m, "(sv)", field, "(ss)", p, colon + 1); - } else - r = sd_bus_message_append(m, "(sv)", field, "(ss)", eq, NULL); - if (r < 0) - return bus_log_create_error(r); - - return 1; - } return 0; } From 9228d67dc8baf2cade5b9afc3f3b2a14dea72994 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Fri, 27 Jun 2025 13:38:29 +0200 Subject: [PATCH 45/64] test: drop ProtectHostnameEx, add one test for ProtectHostnameEx This is a separate commit because the parent commit is supposed to be backward compatible, i.e. the tests must pass with both the bogus ProtectHostnameEx name and ProtectHostname. A test is added for ProtectHostnameEx to verify that it is still accepted for backward compat. --- test/units/TEST-07-PID1.delegate-namespaces.sh | 4 ++-- test/units/TEST-07-PID1.protect-hostname.sh | 16 ++++++++++++---- .../TEST-07-PID1.transient-unit-container.sh | 2 +- 3 files changed, 15 insertions(+), 7 deletions(-) diff --git a/test/units/TEST-07-PID1.delegate-namespaces.sh b/test/units/TEST-07-PID1.delegate-namespaces.sh index 6d8d51caff..3fd1287fb2 100755 --- a/test/units/TEST-07-PID1.delegate-namespaces.sh +++ b/test/units/TEST-07-PID1.delegate-namespaces.sh @@ -45,8 +45,8 @@ testcase_pid() { } testcase_uts() { - (! systemd-run -p PrivateUsersEx=self -p ProtectHostnameEx=private --wait --pipe -- hostname abc) - systemd-run -p PrivateUsersEx=self -p ProtectHostnameEx=private -p DelegateNamespaces=uts --wait --pipe -- hostname abc + (! systemd-run -p PrivateUsersEx=self -p ProtectHostname=private --wait --pipe -- hostname abc) + systemd-run -p PrivateUsersEx=self -p ProtectHostname=private -p DelegateNamespaces=uts --wait --pipe -- hostname abc } testcase_implied_private_users_self() { diff --git a/test/units/TEST-07-PID1.protect-hostname.sh b/test/units/TEST-07-PID1.protect-hostname.sh index 4633dab57b..4a18fe5e21 100755 --- a/test/units/TEST-07-PID1.protect-hostname.sh +++ b/test/units/TEST-07-PID1.protect-hostname.sh @@ -22,7 +22,7 @@ testcase_yes() { (! systemd-run --wait -p ProtectHostname=yes hostname foo) # ProtectHostname=yes can optionally take a hostname. - systemd-run --wait -p ProtectHostnameEx=yes:hoge \ + systemd-run --wait -p ProtectHostname=yes:hoge \ -P bash -xec ' test "$(hostname)" = "hoge" (! hostname foo) @@ -50,10 +50,18 @@ EOF systemd-run --wait -p ProtectHostname=yes -p PrivateMounts=yes \ findmnt --mountpoint /proc/sys/kernel/hostname + + # Check that ProtectHostnameEx=… also works. + systemd-run --wait -p ProtectHostnameEx=yes:hoge \ + -P bash -xec ' + test "$(hostname)" = "hoge" + (! hostname foo) + test "$(hostname)" = "hoge" + ' } testcase_private() { - systemd-run --wait -p ProtectHostnameEx=private \ + systemd-run --wait -p ProtectHostname=private \ -P bash -xec ' hostname foo test "$(hostname)" = "foo" @@ -64,7 +72,7 @@ testcase_private() { test "$(hostnamectl hostname)" = "$HOSTNAME_FROM_SYSTEMD" # ProtectHostname=private can optionally take a hostname. - systemd-run --wait -p ProtectHostnameEx=private:hoge \ + systemd-run --wait -p ProtectHostname=private:hoge \ -P bash -xec ' test "$(hostname)" = "hoge" hostname foo @@ -91,7 +99,7 @@ EOF test "$(hostnamectl hostname)" = "$HOSTNAME_FROM_SYSTEMD" # Verify /proc/sys/kernel/hostname is not bind mounted from host read-only. - (! systemd-run --wait -p ProtectHostnameEx=private -p PrivateMounts=yes \ + (! systemd-run --wait -p ProtectHostname=private -p PrivateMounts=yes \ findmnt --mountpoint /proc/sys/kernel/hostname) } diff --git a/test/units/TEST-07-PID1.transient-unit-container.sh b/test/units/TEST-07-PID1.transient-unit-container.sh index f18e9ff112..60316bf2fa 100755 --- a/test/units/TEST-07-PID1.transient-unit-container.sh +++ b/test/units/TEST-07-PID1.transient-unit-container.sh @@ -157,7 +157,7 @@ testcase_transient_unit_container_file_write() { -p RootDirectory="$CONTAINER_ROOT_FS" \ -p PrivatePIDs=yes \ -p PrivateUsersEx=full \ - -p ProtectHostnameEx=private \ + -p ProtectHostname=private \ -p ProtectControlGroupsEx=private \ -p PrivateMounts=yes \ -p PrivateNetwork=yes \ From 7a5eb9d03de6be39bab15e9ddfca7ff9d7d90df3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Fri, 27 Jun 2025 16:05:33 +0200 Subject: [PATCH 46/64] shared/bus-unit-util: define helper for Paths property --- src/shared/bus-unit-util.c | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c index c7fce7e77f..0fdf946f97 100644 --- a/src/shared/bus-unit-util.c +++ b/src/shared/bus-unit-util.c @@ -2069,6 +2069,19 @@ static int bus_append_protect_hostname(sd_bus_message *m, const char *field, con return 1; } +static int bus_append_paths(sd_bus_message *m, const char *field, const char *eq) { + int r; + + if (isempty(eq)) + r = sd_bus_message_append(m, "(sv)", "Paths", "a(ss)", 0); + else + r = sd_bus_message_append(m, "(sv)", "Paths", "a(ss)", 1, field, eq); + if (r < 0) + return bus_log_create_error(r); + + return 1; +} + static int bus_append_cgroup_property(sd_bus_message *m, const char *field, const char *eq) { if (STR_IN_SET(field, "DevicePolicy", "Slice", @@ -2492,16 +2505,8 @@ static int bus_append_path_property(sd_bus_message *m, const char *field, const "PathExistsGlob", "PathChanged", "PathModified", - "DirectoryNotEmpty")) { - if (isempty(eq)) - r = sd_bus_message_append(m, "(sv)", "Paths", "a(ss)", 0); - else - r = sd_bus_message_append(m, "(sv)", "Paths", "a(ss)", 1, field, eq); - if (r < 0) - return bus_log_create_error(r); - - return 1; - } + "DirectoryNotEmpty")) + return bus_append_paths(m, field, eq); if (STR_IN_SET(field, "TriggerLimitBurst", "PollLimitBurst")) return bus_append_safe_atou(m, field, eq); From 7673abfc2b31598bdeac78f0125b73cdc7d1c98a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Fri, 27 Jun 2025 16:08:52 +0200 Subject: [PATCH 47/64] shared/bus-unit-util: define helper for SuccessExitStatus= and friends --- src/shared/bus-unit-util.c | 160 +++++++++++++++++++------------------ 1 file changed, 81 insertions(+), 79 deletions(-) diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c index 0fdf946f97..30da646461 100644 --- a/src/shared/bus-unit-util.c +++ b/src/shared/bus-unit-util.c @@ -2082,6 +2082,85 @@ static int bus_append_paths(sd_bus_message *m, const char *field, const char *eq return 1; } +static int bus_append_exit_status(sd_bus_message *m, const char *field, const char *eq) { + _cleanup_free_ int *status = NULL, *signal = NULL; + size_t n_status = 0, n_signal = 0; + int r; + + for (const char *p = eq;;) { + _cleanup_free_ char *word = NULL; + + r = extract_first_word(&p, &word, NULL, EXTRACT_UNQUOTE); + if (r == 0) + break; + if (r == -ENOMEM) + return log_oom(); + if (r < 0) + return log_error_errno(r, "Invalid syntax in %s: %s", field, eq); + + /* We need to call exit_status_from_string() first, because we want + * to parse numbers as exit statuses, not signals. */ + + r = exit_status_from_string(word); + if (r >= 0) { + assert(r >= 0 && r < 256); + + if (!GREEDY_REALLOC(status, n_status + 1)) + return log_oom(); + + status[n_status++] = r; + + } else if ((r = signal_from_string(word)) >= 0) { + if (!GREEDY_REALLOC(signal, n_signal + 1)) + return log_oom(); + + signal[n_signal++] = r; + + } else + /* original r from exit_status_to_string() */ + return log_error_errno(r, "Invalid status or signal %s in %s: %m", + word, field); + } + + r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv"); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_open_container(m, 'v', "(aiai)"); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_open_container(m, 'r', "aiai"); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_append_array(m, 'i', status, n_status * sizeof(int)); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_append_array(m, 'i', signal, n_signal * sizeof(int)); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_close_container(m); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_close_container(m); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_close_container(m); + if (r < 0) + return bus_log_create_error(r); + + return 1; +} + static int bus_append_cgroup_property(sd_bus_message *m, const char *field, const char *eq) { if (STR_IN_SET(field, "DevicePolicy", "Slice", @@ -2493,7 +2572,6 @@ static int bus_append_mount_property(sd_bus_message *m, const char *field, const } static int bus_append_path_property(sd_bus_message *m, const char *field, const char *eq) { - int r; if (streq(field, "MakeDirectory")) return bus_append_parse_boolean(m, field, eq); @@ -2602,84 +2680,8 @@ static int bus_append_service_property(sd_bus_message *m, const char *field, con if (STR_IN_SET(field, "RestartPreventExitStatus", "RestartForceExitStatus", - "SuccessExitStatus")) { - _cleanup_free_ int *status = NULL, *signal = NULL; - size_t n_status = 0, n_signal = 0; - const char *p; - - for (p = eq;;) { - _cleanup_free_ char *word = NULL; - - r = extract_first_word(&p, &word, NULL, EXTRACT_UNQUOTE); - if (r == 0) - break; - if (r == -ENOMEM) - return log_oom(); - if (r < 0) - return log_error_errno(r, "Invalid syntax in %s: %s", field, eq); - - /* We need to call exit_status_from_string() first, because we want - * to parse numbers as exit statuses, not signals. */ - - r = exit_status_from_string(word); - if (r >= 0) { - assert(r >= 0 && r < 256); - - if (!GREEDY_REALLOC(status, n_status + 1)) - return log_oom(); - - status[n_status++] = r; - - } else if ((r = signal_from_string(word)) >= 0) { - if (!GREEDY_REALLOC(signal, n_signal + 1)) - return log_oom(); - - signal[n_signal++] = r; - - } else - /* original r from exit_status_to_string() */ - return log_error_errno(r, "Invalid status or signal %s in %s: %m", - word, field); - } - - r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv"); - if (r < 0) - return bus_log_create_error(r); - - r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field); - if (r < 0) - return bus_log_create_error(r); - - r = sd_bus_message_open_container(m, 'v', "(aiai)"); - if (r < 0) - return bus_log_create_error(r); - - r = sd_bus_message_open_container(m, 'r', "aiai"); - if (r < 0) - return bus_log_create_error(r); - - r = sd_bus_message_append_array(m, 'i', status, n_status * sizeof(int)); - if (r < 0) - return bus_log_create_error(r); - - r = sd_bus_message_append_array(m, 'i', signal, n_signal * sizeof(int)); - if (r < 0) - return bus_log_create_error(r); - - r = sd_bus_message_close_container(m); - if (r < 0) - return bus_log_create_error(r); - - r = sd_bus_message_close_container(m); - if (r < 0) - return bus_log_create_error(r); - - r = sd_bus_message_close_container(m); - if (r < 0) - return bus_log_create_error(r); - - return 1; - } + "SuccessExitStatus")) + return bus_append_exit_status(m, field, eq); if (streq(field, "OpenFile")) return bus_append_open_file(m, field, eq); From 65ebd48e6f99f7cb167ce31ad520966a62f9ca2c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Fri, 27 Jun 2025 16:10:30 +0200 Subject: [PATCH 48/64] shared/bus-unit-util: use common helper for various strv properties --- src/shared/bus-unit-util.c | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c index 30da646461..bf204e6d78 100644 --- a/src/shared/bus-unit-util.c +++ b/src/shared/bus-unit-util.c @@ -149,7 +149,7 @@ static int bus_append_string(sd_bus_message *m, const char *field, const char *e return 1; } -static int bus_append_strv(sd_bus_message *m, const char *field, const char *eq, const char *separator, ExtractFlags flags) { +static int bus_append_strv_full(sd_bus_message *m, const char *field, const char *eq, ExtractFlags flags) { int r; assert(m); @@ -174,7 +174,7 @@ static int bus_append_strv(sd_bus_message *m, const char *field, const char *eq, for (const char *p = eq;;) { _cleanup_free_ char *word = NULL; - r = extract_first_word(&p, &word, separator, flags); + r = extract_first_word(&p, &word, /* separators= */ NULL, flags); if (r == -ENOMEM) return log_oom(); if (r < 0) @@ -202,6 +202,14 @@ static int bus_append_strv(sd_bus_message *m, const char *field, const char *eq, return 1; } +static int bus_append_strv(sd_bus_message *m, const char *field, const char *eq) { + return bus_append_strv_full(m, field, eq, EXTRACT_UNQUOTE); +} + +static int bus_append_strv_cunescape(sd_bus_message *m, const char *field, const char *eq) { + return bus_append_strv_full(m, field, eq, EXTRACT_UNQUOTE | EXTRACT_CUNESCAPE); +} + static int bus_append_byte_array(sd_bus_message *m, const char *field, const void *buf, size_t n) { int r; @@ -306,7 +314,7 @@ static int bus_append_parse_delegate(sd_bus_message *m, const char *field, const r = parse_boolean(eq); if (r < 0) - return bus_append_strv(m, "DelegateControllers", eq, /* separator= */ NULL, EXTRACT_UNQUOTE); + return bus_append_strv(m, "DelegateControllers", eq); r = sd_bus_message_append(m, "(sv)", "Delegate", "b", r); if (r < 0) @@ -2197,7 +2205,7 @@ static int bus_append_cgroup_property(sd_bus_message *m, const char *field, cons return bus_append_parse_cpu_set(m, field, eq); if (streq(field, "DisableControllers")) - return bus_append_strv(m, field, eq, /* separator= */ NULL, EXTRACT_UNQUOTE); + return bus_append_strv(m, field, eq); if (streq(field, "Delegate")) return bus_append_parse_delegate(m, field, eq); @@ -2365,7 +2373,7 @@ static int bus_append_execute_property(sd_bus_message *m, const char *field, con "ConfigurationDirectory", "SupplementaryGroups", "SystemCallArchitectures")) - return bus_append_strv(m, field, eq, /* separator= */ NULL, EXTRACT_UNQUOTE); + return bus_append_strv(m, field, eq); if (STR_IN_SET(field, "SyslogLevel", "LogLevelMax")) @@ -2424,7 +2432,7 @@ static int bus_append_execute_property(sd_bus_message *m, const char *field, con if (STR_IN_SET(field, "Environment", "UnsetEnvironment", "PassEnvironment")) - return bus_append_strv(m, field, eq, /* separator= */ NULL, EXTRACT_UNQUOTE|EXTRACT_CUNESCAPE); + return bus_append_strv_cunescape(m, field, eq); if (streq(field, "EnvironmentFile")) return bus_append_environment_files(m, field, eq); @@ -2769,7 +2777,7 @@ static int bus_append_socket_property(sd_bus_message *m, const char *field, cons return bus_append_string(m, field, eq); if (streq(field, "Symlinks")) - return bus_append_strv(m, field, eq, /* separator= */ NULL, EXTRACT_UNQUOTE); + return bus_append_strv(m, field, eq); if (streq(field, "SocketProtocol")) return bus_append_parse_ip_protocol(m, field, eq); @@ -2904,7 +2912,7 @@ static int bus_append_unit_property(sd_bus_message *m, const char *field, const "RequiresMountsFor", "WantsMountsFor", "Markers")) - return bus_append_strv(m, field, eq, /* separator= */ NULL, EXTRACT_UNQUOTE); + return bus_append_strv(m, field, eq); t = condition_type_from_string(field); if (t >= 0) From d661a540a3b8552e1f7ea93ad29d961a00eb16fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Fri, 27 Jun 2025 16:13:03 +0200 Subject: [PATCH 49/64] shared/bus-unit-util: add helper for Listen property --- src/shared/bus-unit-util.c | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c index bf204e6d78..62df0f5e36 100644 --- a/src/shared/bus-unit-util.c +++ b/src/shared/bus-unit-util.c @@ -2169,6 +2169,21 @@ static int bus_append_exit_status(sd_bus_message *m, const char *field, const ch return 1; } +static int bus_append_listen(sd_bus_message *m, const char *field, const char *eq) { + int r; + + const char *p = ASSERT_PTR(startswith(field, "Listen")); + + if (isempty(eq)) + r = sd_bus_message_append(m, "(sv)", "Listen", "a(ss)", 0); + else + r = sd_bus_message_append(m, "(sv)", "Listen", "a(ss)", 1, p, eq); + if (r < 0) + return bus_log_create_error(r); + + return 1; +} + static int bus_append_cgroup_property(sd_bus_message *m, const char *field, const char *eq) { if (STR_IN_SET(field, "DevicePolicy", "Slice", @@ -2698,8 +2713,6 @@ static int bus_append_service_property(sd_bus_message *m, const char *field, con } static int bus_append_socket_property(sd_bus_message *m, const char *field, const char *eq) { - int r; - if (STR_IN_SET(field, "Accept", "FlushPending", "Writable", @@ -2789,16 +2802,8 @@ static int bus_append_socket_property(sd_bus_message *m, const char *field, cons "ListenSpecial", "ListenMessageQueue", "ListenFIFO", - "ListenUSBFunction")) { - if (isempty(eq)) - r = sd_bus_message_append(m, "(sv)", "Listen", "a(ss)", 0); - else - r = sd_bus_message_append(m, "(sv)", "Listen", "a(ss)", 1, field + STRLEN("Listen"), eq); - if (r < 0) - return bus_log_create_error(r); - - return 1; - } + "ListenUSBFunction")) + return bus_append_listen(m, field, eq); return 0; } From c3c21b2bc4f5b1827957ad8d0f4fd5b1704026f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Fri, 27 Jun 2025 16:14:44 +0200 Subject: [PATCH 50/64] shared/bus-unit-util: add helper for TimersMonotonic property --- src/shared/bus-unit-util.c | 37 +++++++++++++++++++++---------------- 1 file changed, 21 insertions(+), 16 deletions(-) diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c index 62df0f5e36..424218692f 100644 --- a/src/shared/bus-unit-util.c +++ b/src/shared/bus-unit-util.c @@ -2184,6 +2184,25 @@ static int bus_append_listen(sd_bus_message *m, const char *field, const char *e return 1; } +static int bus_append_timers_monotonic(sd_bus_message *m, const char *field, const char *eq) { + int r; + + if (isempty(eq)) + r = sd_bus_message_append(m, "(sv)", "TimersMonotonic", "a(st)", 0); + else { + usec_t t; + r = parse_sec(eq, &t); + if (r < 0) + return log_error_errno(r, "Failed to parse %s=%s: %m", field, eq); + + r = sd_bus_message_append(m, "(sv)", "TimersMonotonic", "a(st)", 1, field, t); + } + if (r < 0) + return bus_log_create_error(r); + + return 1; +} + static int bus_append_cgroup_property(sd_bus_message *m, const char *field, const char *eq) { if (STR_IN_SET(field, "DevicePolicy", "Slice", @@ -2828,22 +2847,8 @@ static int bus_append_timer_property(sd_bus_message *m, const char *field, const "OnBootSec", "OnStartupSec", "OnUnitActiveSec", - "OnUnitInactiveSec")) { - if (isempty(eq)) - r = sd_bus_message_append(m, "(sv)", "TimersMonotonic", "a(st)", 0); - else { - usec_t t; - r = parse_sec(eq, &t); - if (r < 0) - return log_error_errno(r, "Failed to parse %s=%s: %m", field, eq); - - r = sd_bus_message_append(m, "(sv)", "TimersMonotonic", "a(st)", 1, field, t); - } - if (r < 0) - return bus_log_create_error(r); - - return 1; - } + "OnUnitInactiveSec")) + return bus_append_timers_monotonic(m, field, eq); if (streq(field, "OnCalendar")) { if (isempty(eq)) From bfa7d82661a3114b8aace3893b3993c40b0129f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Fri, 27 Jun 2025 16:16:04 +0200 Subject: [PATCH 51/64] shared/bus-unit-util: add helper for TimersCalendar property --- src/shared/bus-unit-util.c | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c index 424218692f..1cd1063222 100644 --- a/src/shared/bus-unit-util.c +++ b/src/shared/bus-unit-util.c @@ -2203,6 +2203,19 @@ static int bus_append_timers_monotonic(sd_bus_message *m, const char *field, con return 1; } +static int bus_append_timers_calendar(sd_bus_message *m, const char *field, const char *eq) { + int r; + + if (isempty(eq)) + r = sd_bus_message_append(m, "(sv)", "TimersCalendar", "a(ss)", 0); + else + r = sd_bus_message_append(m, "(sv)", "TimersCalendar", "a(ss)", 1, field, eq); + if (r < 0) + return bus_log_create_error(r); + + return 1; +} + static int bus_append_cgroup_property(sd_bus_message *m, const char *field, const char *eq) { if (STR_IN_SET(field, "DevicePolicy", "Slice", @@ -2827,8 +2840,6 @@ static int bus_append_socket_property(sd_bus_message *m, const char *field, cons return 0; } static int bus_append_timer_property(sd_bus_message *m, const char *field, const char *eq) { - int r; - if (STR_IN_SET(field, "WakeSystem", "RemainAfterElapse", "Persistent", @@ -2850,16 +2861,8 @@ static int bus_append_timer_property(sd_bus_message *m, const char *field, const "OnUnitInactiveSec")) return bus_append_timers_monotonic(m, field, eq); - if (streq(field, "OnCalendar")) { - if (isempty(eq)) - r = sd_bus_message_append(m, "(sv)", "TimersCalendar", "a(ss)", 0); - else - r = sd_bus_message_append(m, "(sv)", "TimersCalendar", "a(ss)", 1, field, eq); - if (r < 0) - return bus_log_create_error(r); - - return 1; - } + if (streq(field, "OnCalendar")) + return bus_append_timers_calendar(m, field, eq); return 0; } From 9806468ea41e0ff002b610d5cdb6d6aeb9d7cb33 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Fri, 27 Jun 2025 16:23:31 +0200 Subject: [PATCH 52/64] shared/bus-unit-util: define helper for SuccessActionExitStatus= and friend --- src/shared/bus-unit-util.c | 39 +++++++++++++++++++++----------------- 1 file changed, 22 insertions(+), 17 deletions(-) diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c index 1cd1063222..bb49982457 100644 --- a/src/shared/bus-unit-util.c +++ b/src/shared/bus-unit-util.c @@ -2169,6 +2169,26 @@ static int bus_append_exit_status(sd_bus_message *m, const char *field, const ch return 1; } +static int bus_append_action_exit_status(sd_bus_message *m, const char *field, const char *eq) { + int r; + + if (isempty(eq)) + r = sd_bus_message_append(m, "(sv)", field, "i", -1); + else { + uint8_t u; + + r = safe_atou8(eq, &u); + if (r < 0) + return log_error_errno(r, "Failed to parse %s=%s", field, eq); + + r = sd_bus_message_append(m, "(sv)", field, "i", (int) u); + } + if (r < 0) + return bus_log_create_error(r); + + return 1; +} + static int bus_append_listen(sd_bus_message *m, const char *field, const char *eq) { int r; @@ -2902,23 +2922,8 @@ static int bus_append_unit_property(sd_bus_message *m, const char *field, const return bus_append_safe_atou(m, field, eq); if (STR_IN_SET(field, "SuccessActionExitStatus", - "FailureActionExitStatus")) { - if (isempty(eq)) - r = sd_bus_message_append(m, "(sv)", field, "i", -1); - else { - uint8_t u; - - r = safe_atou8(eq, &u); - if (r < 0) - return log_error_errno(r, "Failed to parse %s=%s", field, eq); - - r = sd_bus_message_append(m, "(sv)", field, "i", (int) u); - } - if (r < 0) - return bus_log_create_error(r); - - return 1; - } + "FailureActionExitStatus")) + return bus_append_action_exit_status(m, field, eq); if (unit_dependency_from_string(field) >= 0 || STR_IN_SET(field, "Documentation", From a90d205af5aff9571d2476b3237952a18e4d8573 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Fri, 27 Jun 2025 16:37:24 +0200 Subject: [PATCH 53/64] shared/bus-unit-util: define helper for conditions and asserts The function has "try" in the name because it dynamically checks if the field name matches. --- src/shared/bus-unit-util.c | 70 ++++++++++++++++++++------------------ 1 file changed, 36 insertions(+), 34 deletions(-) diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c index bb49982457..189500c09f 100644 --- a/src/shared/bus-unit-util.c +++ b/src/shared/bus-unit-util.c @@ -2236,6 +2236,41 @@ static int bus_append_timers_calendar(sd_bus_message *m, const char *field, cons return 1; } +static int bus_try_append_condition(sd_bus_message *m, const char *field, const char *eq) { + bool is_condition = false; + int r; + + ConditionType t = condition_type_from_string(field); + if (t >= 0) + is_condition = true; + else + t = assert_type_from_string(field); + if (t >= 0) { + if (isempty(eq)) + r = sd_bus_message_append(m, "(sv)", is_condition ? "Conditions" : "Asserts", "a(sbbs)", 0); + else { + const char *p = eq; + + int trigger = *p == '|'; + if (trigger) + p++; + + int negate = *p == '!'; + if (negate) + p++; + + r = sd_bus_message_append(m, "(sv)", is_condition ? "Conditions" : "Asserts", "a(sbbs)", 1, + field, trigger, negate, p); + } + if (r < 0) + return bus_log_create_error(r); + + return 1; + } + + return 0; +} + static int bus_append_cgroup_property(sd_bus_message *m, const char *field, const char *eq) { if (STR_IN_SET(field, "DevicePolicy", "Slice", @@ -2888,10 +2923,6 @@ static int bus_append_timer_property(sd_bus_message *m, const char *field, const } static int bus_append_unit_property(sd_bus_message *m, const char *field, const char *eq) { - ConditionType t = _CONDITION_TYPE_INVALID; - bool is_condition = false; - int r; - if (STR_IN_SET(field, "Description", "SourcePath", "OnFailureJobMode", @@ -2932,36 +2963,7 @@ static int bus_append_unit_property(sd_bus_message *m, const char *field, const "Markers")) return bus_append_strv(m, field, eq); - t = condition_type_from_string(field); - if (t >= 0) - is_condition = true; - else - t = assert_type_from_string(field); - if (t >= 0) { - if (isempty(eq)) - r = sd_bus_message_append(m, "(sv)", is_condition ? "Conditions" : "Asserts", "a(sbbs)", 0); - else { - const char *p = eq; - int trigger, negate; - - trigger = *p == '|'; - if (trigger) - p++; - - negate = *p == '!'; - if (negate) - p++; - - r = sd_bus_message_append(m, "(sv)", is_condition ? "Conditions" : "Asserts", "a(sbbs)", 1, - field, trigger, negate, p); - } - if (r < 0) - return bus_log_create_error(r); - - return 1; - } - - return 0; + return bus_try_append_condition(m, field, eq); } int bus_append_unit_property_assignment(sd_bus_message *m, UnitType t, const char *assignment) { From 5e18038da213d30c2c62e6317479921409c94bb0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Fri, 27 Jun 2025 16:41:29 +0200 Subject: [PATCH 54/64] shared/bus-unit-util: add helper for unit deps --- src/shared/bus-unit-util.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c index 189500c09f..a40c0e9e73 100644 --- a/src/shared/bus-unit-util.c +++ b/src/shared/bus-unit-util.c @@ -2271,6 +2271,13 @@ static int bus_try_append_condition(sd_bus_message *m, const char *field, const return 0; } +static int bus_try_append_unit_dependency(sd_bus_message *m, const char *field, const char *eq) { + if (unit_dependency_from_string(field) < 0) + return 0; + + return bus_append_strv(m, field, eq); +} + static int bus_append_cgroup_property(sd_bus_message *m, const char *field, const char *eq) { if (STR_IN_SET(field, "DevicePolicy", "Slice", @@ -2923,6 +2930,8 @@ static int bus_append_timer_property(sd_bus_message *m, const char *field, const } static int bus_append_unit_property(sd_bus_message *m, const char *field, const char *eq) { + int r; + if (STR_IN_SET(field, "Description", "SourcePath", "OnFailureJobMode", @@ -2956,13 +2965,16 @@ static int bus_append_unit_property(sd_bus_message *m, const char *field, const "FailureActionExitStatus")) return bus_append_action_exit_status(m, field, eq); - if (unit_dependency_from_string(field) >= 0 || - STR_IN_SET(field, "Documentation", + if (STR_IN_SET(field, "Documentation", "RequiresMountsFor", "WantsMountsFor", "Markers")) return bus_append_strv(m, field, eq); + r = bus_try_append_unit_dependency(m, field, eq); + if (r != 0) + return r; + return bus_try_append_condition(m, field, eq); } From dbd4d4cc43ddfb6fc287786e130bcb192670c34b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Fri, 27 Jun 2025 16:44:01 +0200 Subject: [PATCH 55/64] shared/bus-unit-util: add helper for CPUQuotaPeriodSec=ManagedOOMMemoryPressureDurationSec= --- src/shared/bus-unit-util.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c index a40c0e9e73..c03c8f375c 100644 --- a/src/shared/bus-unit-util.c +++ b/src/shared/bus-unit-util.c @@ -262,6 +262,10 @@ static int bus_append_parse_sec_rename(sd_bus_message *m, const char *field, con return 1; } +static int bus_append_parse_sec_rename_infinity(sd_bus_message *m, const char *field, const char *eq) { + return bus_append_parse_sec_rename(m, field, isempty(eq) ? "infinity" : eq); +} + static int bus_append_parse_size(sd_bus_message *m, const char *field, const char *eq, uint64_t base) { uint64_t v; int r; @@ -2334,7 +2338,7 @@ static int bus_append_cgroup_property(sd_bus_message *m, const char *field, cons return bus_append_parse_cpu_quota(m, field, eq); if (streq(field, "CPUQuotaPeriodSec")) - return bus_append_parse_sec_rename(m, field, isempty(eq) ? "infinity" : eq); + return bus_append_parse_sec_rename_infinity(m, field, eq); if (streq(field, "DeviceAllow")) return bus_append_parse_device_allow(m, field, eq); @@ -2372,7 +2376,7 @@ static int bus_append_cgroup_property(sd_bus_message *m, const char *field, cons if (streq(field, "ManagedOOMMemoryPressureDurationSec")) /* While infinity is disallowed in unit file, infinity is allowed in D-Bus API which * means use the default memory pressure duration from oomd.conf. */ - return bus_append_parse_sec_rename(m, field, isempty(eq) ? "infinity" : eq); + return bus_append_parse_sec_rename_infinity(m, field, eq); if (STR_IN_SET(field, "MemoryLimit", From 472a1faae8359da533418eaa8229e142ce63e4a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Fri, 27 Jun 2025 16:46:32 +0200 Subject: [PATCH 56/64] shared/bus-unit-util: add helper for AppArmorProfile=/SmackProcessLabel= --- src/shared/bus-unit-util.c | 36 +++++++++++++++++++----------------- 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c index c03c8f375c..22cdffa020 100644 --- a/src/shared/bus-unit-util.c +++ b/src/shared/bus-unit-util.c @@ -1304,6 +1304,23 @@ static int bus_append_resource_limit(sd_bus_message *m, const char *field, const return 1; } +static int bus_append_string_with_ignore(sd_bus_message *m, const char *field, const char *eq) { + int ignore = 0; + const char *s = eq; + int r; + + if (eq[0] == '-') { + ignore = 1; + s = eq + 1; + } + + r = sd_bus_message_append(m, "(sv)", field, "(bs)", ignore, s); + if (r < 0) + return bus_log_create_error(r); + + return 1; +} + static int bus_append_capabilities(sd_bus_message *m, const char *field, const char *eq) { uint64_t sum = 0; bool invert = false; @@ -2409,8 +2426,6 @@ static int bus_append_automount_property(sd_bus_message *m, const char *field, c } static int bus_append_execute_property(sd_bus_message *m, const char *field, const char *eq) { - int r; - if (STR_IN_SET(field, "User", "Group", "UtmpIdentifier", @@ -2580,21 +2595,8 @@ static int bus_append_execute_property(sd_bus_message *m, const char *field, con return bus_append_resource_limit(m, field, eq); if (STR_IN_SET(field, "AppArmorProfile", - "SmackProcessLabel")) { - int ignore = 0; - const char *s = eq; - - if (eq[0] == '-') { - ignore = 1; - s = eq + 1; - } - - r = sd_bus_message_append(m, "(sv)", field, "(bs)", ignore, s); - if (r < 0) - return bus_log_create_error(r); - - return 1; - } + "SmackProcessLabel")) + return bus_append_string_with_ignore(m, field, eq); if (STR_IN_SET(field, "CapabilityBoundingSet", "AmbientCapabilities")) From 73ac906becc1adaa562c59b5a39d1b881a53653e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Fri, 27 Jun 2025 17:18:28 +0200 Subject: [PATCH 57/64] shared/bus-unit-util: add define to shorten common append pattern --- src/shared/bus-unit-util.c | 123 +++++++++++++------------------------ 1 file changed, 43 insertions(+), 80 deletions(-) diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c index 22cdffa020..70439f2df8 100644 --- a/src/shared/bus-unit-util.c +++ b/src/shared/bus-unit-util.c @@ -882,17 +882,20 @@ static int bus_append_parse_ip_address_filter(sd_bus_message *m, const char *fie return 1; } +#define bus_append_trivial_array(m, field, eq, types, ...) \ + ({ \ + int r; \ + \ + if (isempty(eq)) \ + r = sd_bus_message_append(m, "(sv)", field, types, 0); \ + else \ + r = sd_bus_message_append(m, "(sv)", field, types, 1, __VA_ARGS__); \ + r < 0 ? bus_log_create_error(r) : 1; \ + }) + static int bus_append_ip_filter_path(sd_bus_message *m, const char *field, const char *eq) { - int r; - - if (isempty(eq)) - r = sd_bus_message_append(m, "(sv)", field, "as", 0); - else - r = sd_bus_message_append(m, "(sv)", field, "as", 1, eq); - if (r < 0) - return bus_log_create_error(r); - - return 1; + return bus_append_trivial_array(m, field, eq, + "as", eq); } static int bus_append_nft_set(sd_bus_message *m, const char *field, const char *eq) { @@ -981,18 +984,10 @@ static int bus_append_nft_set(sd_bus_message *m, const char *field, const char * } static int bus_append_environment_files(sd_bus_message *m, const char *field, const char *eq) { - int r; - - if (isempty(eq)) - r = sd_bus_message_append(m, "(sv)", "EnvironmentFiles", "a(sb)", 0); - else - r = sd_bus_message_append(m, "(sv)", "EnvironmentFiles", "a(sb)", 1, - eq[0] == '-' ? eq + 1 : eq, - eq[0] == '-'); - if (r < 0) - return bus_log_create_error(r); - - return 1; + return bus_append_trivial_array(m, "EnvironmentFiles", eq, + "a(sb)", + eq[0] == '-' ? eq + 1 : eq, + eq[0] == '-'); } static int bus_append_set_credential(sd_bus_message *m, const char *field, const char *eq) { @@ -2099,16 +2094,8 @@ static int bus_append_protect_hostname(sd_bus_message *m, const char *field, con } static int bus_append_paths(sd_bus_message *m, const char *field, const char *eq) { - int r; - - if (isempty(eq)) - r = sd_bus_message_append(m, "(sv)", "Paths", "a(ss)", 0); - else - r = sd_bus_message_append(m, "(sv)", "Paths", "a(ss)", 1, field, eq); - if (r < 0) - return bus_log_create_error(r); - - return 1; + return bus_append_trivial_array(m, "Paths", eq, + "a(ss)", field, eq); } static int bus_append_exit_status(sd_bus_message *m, const char *field, const char *eq) { @@ -2211,18 +2198,10 @@ static int bus_append_action_exit_status(sd_bus_message *m, const char *field, c } static int bus_append_listen(sd_bus_message *m, const char *field, const char *eq) { - int r; - const char *p = ASSERT_PTR(startswith(field, "Listen")); - if (isempty(eq)) - r = sd_bus_message_append(m, "(sv)", "Listen", "a(ss)", 0); - else - r = sd_bus_message_append(m, "(sv)", "Listen", "a(ss)", 1, p, eq); - if (r < 0) - return bus_log_create_error(r); - - return 1; + return bus_append_trivial_array(m, "Listen", eq, + "a(ss)", p, eq); } static int bus_append_timers_monotonic(sd_bus_message *m, const char *field, const char *eq) { @@ -2245,51 +2224,35 @@ static int bus_append_timers_monotonic(sd_bus_message *m, const char *field, con } static int bus_append_timers_calendar(sd_bus_message *m, const char *field, const char *eq) { - int r; - - if (isempty(eq)) - r = sd_bus_message_append(m, "(sv)", "TimersCalendar", "a(ss)", 0); - else - r = sd_bus_message_append(m, "(sv)", "TimersCalendar", "a(ss)", 1, field, eq); - if (r < 0) - return bus_log_create_error(r); - - return 1; + return bus_append_trivial_array(m, "TimersCalendar", eq, + "a(ss)", field, eq); } static int bus_try_append_condition(sd_bus_message *m, const char *field, const char *eq) { - bool is_condition = false; - int r; - ConditionType t = condition_type_from_string(field); - if (t >= 0) - is_condition = true; - else + bool is_condition = t >= 0; + + if (!is_condition) { t = assert_type_from_string(field); - if (t >= 0) { - if (isempty(eq)) - r = sd_bus_message_append(m, "(sv)", is_condition ? "Conditions" : "Asserts", "a(sbbs)", 0); - else { - const char *p = eq; - - int trigger = *p == '|'; - if (trigger) - p++; - - int negate = *p == '!'; - if (negate) - p++; - - r = sd_bus_message_append(m, "(sv)", is_condition ? "Conditions" : "Asserts", "a(sbbs)", 1, - field, trigger, negate, p); - } - if (r < 0) - return bus_log_create_error(r); - - return 1; + if (t < 0) + return 0; } - return 0; + const char *p = eq; + + int trigger = p && *p == '|'; + if (trigger) + p++; + + int negate = p && *p == '!'; + if (negate) + p++; + + return bus_append_trivial_array(m, + is_condition ? "Conditions" : "Asserts", + eq, + "a(sbbs)", + field, trigger, negate, p); } static int bus_try_append_unit_dependency(sd_bus_message *m, const char *field, const char *eq) { From b77e4fc6cebc819ee33a86cd47679115cad14881 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Fri, 27 Jun 2025 18:11:57 +0200 Subject: [PATCH 58/64] shared/bus-unit-util: add helper for TimeoutSec= --- src/shared/bus-unit-util.c | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c index 70439f2df8..fd268782eb 100644 --- a/src/shared/bus-unit-util.c +++ b/src/shared/bus-unit-util.c @@ -2228,6 +2228,16 @@ static int bus_append_timers_calendar(sd_bus_message *m, const char *field, cons "a(ss)", field, eq); } +static int bus_append_timeout_sec(sd_bus_message *m, const char *field, const char *eq) { + int r; + + r = bus_append_parse_sec_rename(m, "TimeoutStartSec", eq); + if (r < 0) + return r; + + return bus_append_parse_sec_rename(m, "TimeoutStopSec", eq); +} + static int bus_try_append_condition(sd_bus_message *m, const char *field, const char *eq) { ConditionType t = condition_type_from_string(field); bool is_condition = t >= 0; @@ -2703,8 +2713,6 @@ static int bus_append_scope_property(sd_bus_message *m, const char *field, const } static int bus_append_service_property(sd_bus_message *m, const char *field, const char *eq) { - int r; - if (STR_IN_SET(field, "PIDFile", "Type", "ExitType", @@ -2736,13 +2744,8 @@ static int bus_append_service_property(sd_bus_message *m, const char *field, con "WatchdogSec")) return bus_append_parse_sec_rename(m, field, eq); - if (streq(field, "TimeoutSec")) { - r = bus_append_parse_sec_rename(m, "TimeoutStartSec", eq); - if (r < 0) - return r; - - return bus_append_parse_sec_rename(m, "TimeoutStopSec", eq); - } + if (streq(field, "TimeoutSec")) + return bus_append_timeout_sec(m, field, eq); if (STR_IN_SET(field, "FileDescriptorStoreMax", "RestartSteps")) From c133545430897ece77a2066bc740c4a8f7b781e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Fri, 27 Jun 2025 19:29:51 +0200 Subject: [PATCH 59/64] shared/bus-unit-util: convert to a table --- src/shared/bus-unit-util.c | 1314 +++++++++++++++--------------------- 1 file changed, 539 insertions(+), 775 deletions(-) diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c index fd268782eb..6811c8fc41 100644 --- a/src/shared/bus-unit-util.c +++ b/src/shared/bus-unit-util.c @@ -71,7 +71,7 @@ int bus_parse_unit_info(sd_bus_message *message, UnitInfo *u) { &u->job_path); } -static int warn_deprecated(const char *field, const char *eq) { +static int warn_deprecated(_unused_ sd_bus_message *m, const char *field, const char *eq) { log_warning("D-Bus property %s is deprecated, ignoring assignment: %s=%s", field, field, eq); return 1; } @@ -266,11 +266,11 @@ static int bus_append_parse_sec_rename_infinity(sd_bus_message *m, const char *f return bus_append_parse_sec_rename(m, field, isempty(eq) ? "infinity" : eq); } -static int bus_append_parse_size(sd_bus_message *m, const char *field, const char *eq, uint64_t base) { +static int bus_append_parse_size(sd_bus_message *m, const char *field, const char *eq) { uint64_t v; int r; - r = parse_size(eq, base, &v); + r = parse_size(eq, /* base= */ 1024, &v); if (r < 0) return log_error_errno(r, "Failed to parse %s=%s: %m", field, eq); @@ -364,7 +364,7 @@ static int bus_append_parse_resource_limit(sd_bus_message *m, const char *field, if (streq(field, "TasksMax")) return bus_append_safe_atou64(m, field, eq); - return bus_append_parse_size(m, field, eq, 1024); + return bus_append_parse_size(m, field, eq); } static int bus_append_parse_cpu_quota(sd_bus_message *m, const char *field, const char *eq) { @@ -411,9 +411,12 @@ static int bus_append_parse_device_allow(sd_bus_message *m, const char *field, c return 1; } -static int bus_append_parse_cgroup_io_limit(sd_bus_message *m, const char *field, const char *eq) { +static int bus_try_append_parse_cgroup_io_limit(sd_bus_message *m, const char *field, const char *eq) { int r; + if (cgroup_io_limit_type_from_string(field) < 0) + return 0; + if (isempty(eq)) r = sd_bus_message_append(m, "(sv)", field, "a(st)", 0); else { @@ -1274,11 +1277,14 @@ static int bus_append_standard_input_data(sd_bus_message *m, const char *field, return bus_append_byte_array(m, field, decoded, sz); } -static int bus_append_resource_limit(sd_bus_message *m, const char *field, const char *eq) { - const char *suffix = ASSERT_PTR(startswith(field, "Limit")); - int rl, r; +static int bus_try_append_resource_limit(sd_bus_message *m, const char *field, const char *eq) { + int r; - rl = rlimit_from_string(suffix); + const char *suffix = startswith(field, "Limit"); + if (!suffix) + return 0; + + int rl = rlimit_from_string(suffix); if (rl < 0) return log_error_errno(rl, "Unknown setting '%s'.", field); @@ -2272,683 +2278,536 @@ static int bus_try_append_unit_dependency(sd_bus_message *m, const char *field, return bus_append_strv(m, field, eq); } -static int bus_append_cgroup_property(sd_bus_message *m, const char *field, const char *eq) { - if (STR_IN_SET(field, "DevicePolicy", - "Slice", - "ManagedOOMSwap", - "ManagedOOMMemoryPressure", - "ManagedOOMPreference", - "MemoryPressureWatch", - "DelegateSubgroup")) - return bus_append_string(m, field, eq); - - if (STR_IN_SET(field, "ManagedOOMMemoryPressureLimit")) - return bus_append_parse_permyriad(m, field, eq); - - if (STR_IN_SET(field, "MemoryAccounting", - "MemoryZSwapWriteback", - "IOAccounting", - "TasksAccounting", - "IPAccounting", - "CoredumpReceive")) - return bus_append_parse_boolean(m, field, eq); - - if (STR_IN_SET(field, "CPUWeight", - "StartupCPUWeight")) - return bus_append_cg_cpu_weight_parse(m, field, eq); - - if (STR_IN_SET(field, "IOWeight", - "StartupIOWeight")) - return bus_append_cg_weight_parse(m, field, eq); - - if (STR_IN_SET(field, "AllowedCPUs", - "StartupAllowedCPUs", - "AllowedMemoryNodes", - "StartupAllowedMemoryNodes")) - return bus_append_parse_cpu_set(m, field, eq); - - if (streq(field, "DisableControllers")) - return bus_append_strv(m, field, eq); - - if (streq(field, "Delegate")) - return bus_append_parse_delegate(m, field, eq); - - if (STR_IN_SET(field, "MemoryMin", - "DefaultMemoryLow", - "DefaultMemoryMin", - "MemoryLow", - "MemoryHigh", - "MemoryMax", - "MemorySwapMax", - "MemoryZSwapMax", - "TasksMax")) - return bus_append_parse_resource_limit(m, field, eq); - - if (streq(field, "CPUQuota")) - return bus_append_parse_cpu_quota(m, field, eq); - - if (streq(field, "CPUQuotaPeriodSec")) - return bus_append_parse_sec_rename_infinity(m, field, eq); - - if (streq(field, "DeviceAllow")) - return bus_append_parse_device_allow(m, field, eq); - - if (cgroup_io_limit_type_from_string(field) >= 0) - return bus_append_parse_cgroup_io_limit(m, field, eq); - - if (streq(field, "IODeviceWeight")) - return bus_append_parse_io_device_weight(m, field, eq); - - if (streq(field, "IODeviceLatencyTargetSec")) - return bus_append_parse_io_device_latency(m, field, eq); - - if (STR_IN_SET(field, "IPAddressAllow", - "IPAddressDeny")) - return bus_append_parse_ip_address_filter(m, field, eq); - - if (STR_IN_SET(field, "IPIngressFilterPath", - "IPEgressFilterPath")) - return bus_append_ip_filter_path(m, field, eq); - - if (streq(field, "BPFProgram")) - return bus_append_bpf_program(m, field, eq); - - if (STR_IN_SET(field, "SocketBindAllow", - "SocketBindDeny")) - return bus_append_socket_filter(m, field, eq); - - if (streq(field, "MemoryPressureThresholdSec")) - return bus_append_parse_sec_rename(m, field, eq); - - if (streq(field, "NFTSet")) - return bus_append_nft_set(m, field, eq); - - if (streq(field, "ManagedOOMMemoryPressureDurationSec")) - /* While infinity is disallowed in unit file, infinity is allowed in D-Bus API which - * means use the default memory pressure duration from oomd.conf. */ - return bus_append_parse_sec_rename_infinity(m, field, eq); - - if (STR_IN_SET(field, - "MemoryLimit", - "CPUShares", - "StartupCPUShares", - "BlockIOAccounting", - "BlockIOWeight", - "StartupBlockIOWeight", - "BlockIODeviceWeight", - "BlockIOReadBandwidth", - "BlockIOWriteBandwidth", - "CPUAccounting")) - return warn_deprecated(field, eq); - - return 0; -} - -static int bus_append_automount_property(sd_bus_message *m, const char *field, const char *eq) { - if (STR_IN_SET(field, "Where", - "ExtraOptions")) - return bus_append_string(m, field, eq); - - if (streq(field, "DirectoryMode")) - return bus_append_parse_mode(m, field, eq); - - if (streq(field, "TimeoutIdleSec")) - return bus_append_parse_sec_rename(m, field, eq); - - return 0; -} - -static int bus_append_execute_property(sd_bus_message *m, const char *field, const char *eq) { - if (STR_IN_SET(field, "User", - "Group", - "UtmpIdentifier", - "UtmpMode", - "PAMName", - "TTYPath", - "WorkingDirectory", - "RootDirectory", - "SyslogIdentifier", - "ProtectSystem", - "ProtectHome", - "PrivateTmpEx", - "PrivateUsersEx", - "ProtectControlGroupsEx", - "SELinuxContext", - "RootImage", - "RootVerity", - "RuntimeDirectoryPreserve", - "Personality", - "KeyringMode", - "ProtectProc", - "ProcSubset", - "NetworkNamespacePath", - "IPCNamespacePath", - "LogNamespace", - "RootImagePolicy", - "MountImagePolicy", - "ExtensionImagePolicy", - "PrivatePIDs")) - return bus_append_string(m, field, eq); - - if (STR_IN_SET(field, "IgnoreSIGPIPE", - "TTYVHangup", - "TTYReset", - "TTYVTDisallocate", - "PrivateTmp", - "PrivateDevices", - "PrivateNetwork", - "PrivateUsers", - "PrivateMounts", - "PrivateIPC", - "NoNewPrivileges", - "SyslogLevelPrefix", - "MemoryDenyWriteExecute", - "RestrictRealtime", - "DynamicUser", - "RemoveIPC", - "ProtectKernelTunables", - "ProtectKernelModules", - "ProtectKernelLogs", - "ProtectClock", - "ProtectControlGroups", - "MountAPIVFS", - "BindLogSockets", - "CPUSchedulingResetOnFork", - "LockPersonality", - "MemoryKSM", - "RestrictSUIDSGID", - "RootEphemeral", - "SetLoginEnvironment")) - return bus_append_parse_boolean(m, field, eq); - - if (STR_IN_SET(field, "ReadWriteDirectories", - "ReadOnlyDirectories", - "InaccessibleDirectories", - "ReadWritePaths", - "ReadOnlyPaths", - "InaccessiblePaths", - "ExecPaths", - "NoExecPaths", - "ExecSearchPath", - "ExtensionDirectories", - "ConfigurationDirectory", - "SupplementaryGroups", - "SystemCallArchitectures")) - return bus_append_strv(m, field, eq); - - if (STR_IN_SET(field, "SyslogLevel", - "LogLevelMax")) - return bus_append_log_level_from_string(m, field, eq); - - if (streq(field, "SyslogFacility")) - return bus_append_log_facility_unshifted_from_string(m, field, eq); - - if (streq(field, "SecureBits")) - return bus_append_secure_bits_from_string(m, field, eq); - - if (streq(field, "CPUSchedulingPolicy")) - return bus_append_sched_policy_from_string(m, field, eq); - - if (STR_IN_SET(field, "CPUSchedulingPriority", - "OOMScoreAdjust")) - return bus_append_safe_atoi(m, field, eq); - - if (streq(field, "CoredumpFilter")) - return bus_append_coredump_filter_mask_from_string(m, field, eq); - - if (streq(field, "Nice")) - return bus_append_parse_nice(m, field, eq); - - if (streq(field, "SystemCallErrorNumber")) - return bus_append_seccomp_parse_errno_or_action(m, field, eq); - - if (streq(field, "IOSchedulingClass")) - return bus_append_ioprio_class_from_string(m, field, eq); - - if (streq(field, "IOSchedulingPriority")) - return bus_append_ioprio_parse_priority(m, field, eq); - - if (STR_IN_SET(field, "RuntimeDirectoryMode", - "StateDirectoryMode", - "CacheDirectoryMode", - "LogsDirectoryMode", - "ConfigurationDirectoryMode", - "UMask")) - return bus_append_parse_mode(m, field, eq); - - if (streq(field, "TimerSlackNSec")) - return bus_append_parse_nsec(m, field, eq); - - if (streq(field, "LogRateLimitIntervalSec")) - return bus_append_parse_sec_rename(m, field, eq); - - if (STR_IN_SET(field, "LogRateLimitBurst", - "TTYRows", - "TTYColumns")) - return bus_append_safe_atou(m, field, eq); - - if (streq(field, "MountFlags")) - return bus_append_mount_propagation_flag_from_string(m, field, eq); - - if (STR_IN_SET(field, "Environment", - "UnsetEnvironment", - "PassEnvironment")) - return bus_append_strv_cunescape(m, field, eq); - - if (streq(field, "EnvironmentFile")) - return bus_append_environment_files(m, field, eq); - - if (STR_IN_SET(field, "SetCredential", "SetCredentialEncrypted")) - return bus_append_set_credential(m, field, eq); - - if (STR_IN_SET(field, "LoadCredential", "LoadCredentialEncrypted")) - return bus_append_load_credential(m, field, eq); - - if (STR_IN_SET(field, "ImportCredential", "ImportCredentialEx")) - return bus_append_import_credential(m, field, eq); - - if (streq(field, "LogExtraFields")) - return bus_append_log_extra_fields(m, field, eq); - - if (streq(field, "LogFilterPatterns")) - return bus_append_log_filter_patterns(m, field, eq); - - if (STR_IN_SET(field, "StandardInput", - "StandardOutput", - "StandardError")) - return bus_append_standard_inputs(m, field, eq); - - if (streq(field, "StandardInputText")) - return bus_append_standard_input_text(m, field, eq); - - if (streq(field, "StandardInputData")) - return bus_append_standard_input_data(m, field, eq); - - if (startswith(field, "Limit")) - return bus_append_resource_limit(m, field, eq); - - if (STR_IN_SET(field, "AppArmorProfile", - "SmackProcessLabel")) - return bus_append_string_with_ignore(m, field, eq); - - if (STR_IN_SET(field, "CapabilityBoundingSet", - "AmbientCapabilities")) - return bus_append_capabilities(m, field, eq); - - if (streq(field, "CPUAffinity")) - return bus_append_cpu_affinity(m, field, eq); - - if (streq(field, "NUMAPolicy")) - return bus_append_mpol_from_string(m, field, eq); - - if (streq(field, "NUMAMask")) - return bus_append_numa_mask(m, field, eq); - - if (STR_IN_SET(field, "RestrictAddressFamilies", - "RestrictFileSystems", - "SystemCallFilter", - "SystemCallLog", - "RestrictNetworkInterfaces")) - return bus_append_filter_list(m, field, eq); - - if (STR_IN_SET(field, "RestrictNamespaces", - "DelegateNamespaces")) - return bus_append_namespace_list(m, field, eq); - - if (STR_IN_SET(field, "BindPaths", - "BindReadOnlyPaths")) - return bus_append_bind_paths(m, field, eq); - - if (streq(field, "TemporaryFileSystem")) - return bus_append_temporary_file_system(m, field, eq); - - if (streq(field, "RootHash")) - return bus_append_root_hash(m, field, eq); - - if (streq(field, "RootHashSignature")) - return bus_append_root_hash_signature(m, field, eq); - - if (streq(field, "RootImageOptions")) - return bus_append_root_image_options(m, field, eq); - - if (streq(field, "MountImages")) - return bus_append_mount_images(m, field, eq); - - if (streq(field, "ExtensionImages")) - return bus_append_extension_images(m, field, eq); - - if (STR_IN_SET(field, "StateDirectory", "RuntimeDirectory", "CacheDirectory", "LogsDirectory")) - return bus_append_directory(m, field, eq); - - if (STR_IN_SET(field, "ProtectHostname", "ProtectHostnameEx")) - return bus_append_protect_hostname(m, field, eq); - - return 0; -} - -static int bus_append_kill_property(sd_bus_message *m, const char *field, const char *eq) { - if (streq(field, "KillMode")) - return bus_append_string(m, field, eq); - - if (STR_IN_SET(field, "SendSIGHUP", - "SendSIGKILL")) - return bus_append_parse_boolean(m, field, eq); - - if (STR_IN_SET(field, "KillSignal", - "RestartKillSignal", - "FinalKillSignal", - "WatchdogSignal", - "ReloadSignal")) - return bus_append_signal_from_string(m, field, eq); - - return 0; -} - -static int bus_append_mount_property(sd_bus_message *m, const char *field, const char *eq) { - - if (STR_IN_SET(field, "What", - "Where", - "Options", - "Type")) - return bus_append_string(m, field, eq); - - if (streq(field, "TimeoutSec")) - return bus_append_parse_sec_rename(m, field, eq); - - if (streq(field, "DirectoryMode")) - return bus_append_parse_mode(m, field, eq); - - if (STR_IN_SET(field, "SloppyOptions", - "LazyUnmount", - "ForceUnmount", - "ReadwriteOnly")) - return bus_append_parse_boolean(m, field, eq); - - return 0; -} - -static int bus_append_path_property(sd_bus_message *m, const char *field, const char *eq) { - - if (streq(field, "MakeDirectory")) - return bus_append_parse_boolean(m, field, eq); - - if (streq(field, "DirectoryMode")) - return bus_append_parse_mode(m, field, eq); - - if (STR_IN_SET(field, "PathExists", - "PathExistsGlob", - "PathChanged", - "PathModified", - "DirectoryNotEmpty")) - return bus_append_paths(m, field, eq); - - if (STR_IN_SET(field, "TriggerLimitBurst", "PollLimitBurst")) - return bus_append_safe_atou(m, field, eq); - - if (STR_IN_SET(field, "TriggerLimitIntervalSec", "PollLimitIntervalSec")) - return bus_append_parse_sec_rename(m, field, eq); - - return 0; -} - -static int bus_append_scope_property(sd_bus_message *m, const char *field, const char *eq) { - if (streq(field, "RuntimeMaxSec")) - return bus_append_parse_sec_rename(m, field, eq); - - if (streq(field, "RuntimeRandomizedExtraSec")) - return bus_append_parse_sec_rename(m, field, eq); - - if (streq(field, "TimeoutStopSec")) - return bus_append_parse_sec_rename(m, field, eq); +typedef struct BusProperty { + const char *name; + int (*convert)(sd_bus_message *m, const char *field, const char *eq); +} BusProperty; + +static const BusProperty cgroup_properties[] = { + { "DevicePolicy", bus_append_string }, + { "Slice", bus_append_string }, + { "ManagedOOMSwap", bus_append_string }, + { "ManagedOOMMemoryPressure", bus_append_string }, + { "ManagedOOMPreference", bus_append_string }, + { "MemoryPressureWatch", bus_append_string }, + { "DelegateSubgroup", bus_append_string }, + { "ManagedOOMMemoryPressureLimit", bus_append_parse_permyriad }, + { "MemoryAccounting", bus_append_parse_boolean }, + { "MemoryZSwapWriteback", bus_append_parse_boolean }, + { "IOAccounting", bus_append_parse_boolean }, + { "TasksAccounting", bus_append_parse_boolean }, + { "IPAccounting", bus_append_parse_boolean }, + { "CoredumpReceive", bus_append_parse_boolean }, + { "CPUWeight", bus_append_cg_cpu_weight_parse }, + { "StartupCPUWeight", bus_append_cg_cpu_weight_parse }, + { "IOWeight", bus_append_cg_weight_parse }, + { "StartupIOWeight", bus_append_cg_weight_parse }, + { "AllowedCPUs", bus_append_parse_cpu_set }, + { "StartupAllowedCPUs", bus_append_parse_cpu_set }, + { "AllowedMemoryNodes", bus_append_parse_cpu_set }, + { "StartupAllowedMemoryNodes", bus_append_parse_cpu_set }, + { "DisableControllers", bus_append_strv }, + { "Delegate", bus_append_parse_delegate }, + { "MemoryMin", bus_append_parse_resource_limit }, + { "DefaultMemoryLow", bus_append_parse_resource_limit }, + { "DefaultMemoryMin", bus_append_parse_resource_limit }, + { "MemoryLow", bus_append_parse_resource_limit }, + { "MemoryHigh", bus_append_parse_resource_limit }, + { "MemoryMax", bus_append_parse_resource_limit }, + { "MemorySwapMax", bus_append_parse_resource_limit }, + { "MemoryZSwapMax", bus_append_parse_resource_limit }, + { "TasksMax", bus_append_parse_resource_limit }, + { "CPUQuota", bus_append_parse_cpu_quota }, + { "CPUQuotaPeriodSec", bus_append_parse_sec_rename_infinity }, + { "DeviceAllow", bus_append_parse_device_allow }, + { "IODeviceWeight", bus_append_parse_io_device_weight }, + { "IODeviceLatencyTargetSec", bus_append_parse_io_device_latency }, + { "IPAddressAllow", bus_append_parse_ip_address_filter }, + { "IPAddressDeny", bus_append_parse_ip_address_filter }, + { "IPIngressFilterPath", bus_append_ip_filter_path }, + { "IPEgressFilterPath", bus_append_ip_filter_path }, + { "BPFProgram", bus_append_bpf_program }, + { "SocketBindAllow", bus_append_socket_filter }, + { "SocketBindDeny", bus_append_socket_filter }, + { "MemoryPressureThresholdSec", bus_append_parse_sec_rename }, + { "NFTSet", bus_append_nft_set }, + + /* While infinity is disallowed in unit file, infinity is allowed in D-Bus API which + * means use the default memory pressure duration from oomd.conf. */ + { "ManagedOOMMemoryPressureDurationSec", bus_append_parse_sec_rename_infinity }, + + { "MemoryLimit", warn_deprecated }, + { "CPUShares", warn_deprecated }, + { "StartupCPUShares", warn_deprecated }, + { "BlockIOAccounting", warn_deprecated }, + { "BlockIOWeight", warn_deprecated }, + { "StartupBlockIOWeight", warn_deprecated }, + { "BlockIODeviceWeight", warn_deprecated }, + { "BlockIOReadBandwidth", warn_deprecated }, + { "BlockIOWriteBandwidth", warn_deprecated }, + { "CPUAccounting", warn_deprecated }, + + { NULL, bus_try_append_parse_cgroup_io_limit }, + {} +}; + +static const BusProperty automount_properties[] = { + { "Where", bus_append_string }, + { "ExtraOptions", bus_append_string }, + { "DirectoryMode", bus_append_parse_mode }, + { "TimeoutIdleSec", bus_append_parse_sec_rename }, + {} +}; + +static const BusProperty execute_properties[] = { + { "User", bus_append_string }, + { "Group", bus_append_string }, + { "UtmpIdentifier", bus_append_string }, + { "UtmpMode", bus_append_string }, + { "PAMName", bus_append_string }, + { "TTYPath", bus_append_string }, + { "WorkingDirectory", bus_append_string }, + { "RootDirectory", bus_append_string }, + { "SyslogIdentifier", bus_append_string }, + { "ProtectSystem", bus_append_string }, + { "ProtectHome", bus_append_string }, + { "PrivateTmpEx", bus_append_string }, + { "PrivateUsersEx", bus_append_string }, + { "ProtectControlGroupsEx", bus_append_string }, + { "SELinuxContext", bus_append_string }, + { "RootImage", bus_append_string }, + { "RootVerity", bus_append_string }, + { "RuntimeDirectoryPreserve", bus_append_string }, + { "Personality", bus_append_string }, + { "KeyringMode", bus_append_string }, + { "ProtectProc", bus_append_string }, + { "ProcSubset", bus_append_string }, + { "NetworkNamespacePath", bus_append_string }, + { "IPCNamespacePath", bus_append_string }, + { "LogNamespace", bus_append_string }, + { "RootImagePolicy", bus_append_string }, + { "MountImagePolicy", bus_append_string }, + { "ExtensionImagePolicy", bus_append_string }, + { "PrivatePIDs", bus_append_string }, + { "IgnoreSIGPIPE", bus_append_parse_boolean }, + { "TTYVHangup", bus_append_parse_boolean }, + { "TTYReset", bus_append_parse_boolean }, + { "TTYVTDisallocate", bus_append_parse_boolean }, + { "PrivateTmp", bus_append_parse_boolean }, + { "PrivateDevices", bus_append_parse_boolean }, + { "PrivateNetwork", bus_append_parse_boolean }, + { "PrivateUsers", bus_append_parse_boolean }, + { "PrivateMounts", bus_append_parse_boolean }, + { "PrivateIPC", bus_append_parse_boolean }, + { "NoNewPrivileges", bus_append_parse_boolean }, + { "SyslogLevelPrefix", bus_append_parse_boolean }, + { "MemoryDenyWriteExecute", bus_append_parse_boolean }, + { "RestrictRealtime", bus_append_parse_boolean }, + { "DynamicUser", bus_append_parse_boolean }, + { "RemoveIPC", bus_append_parse_boolean }, + { "ProtectKernelTunables", bus_append_parse_boolean }, + { "ProtectKernelModules", bus_append_parse_boolean }, + { "ProtectKernelLogs", bus_append_parse_boolean }, + { "ProtectClock", bus_append_parse_boolean }, + { "ProtectControlGroups", bus_append_parse_boolean }, + { "MountAPIVFS", bus_append_parse_boolean }, + { "BindLogSockets", bus_append_parse_boolean }, + { "CPUSchedulingResetOnFork", bus_append_parse_boolean }, + { "LockPersonality", bus_append_parse_boolean }, + { "MemoryKSM", bus_append_parse_boolean }, + { "RestrictSUIDSGID", bus_append_parse_boolean }, + { "RootEphemeral", bus_append_parse_boolean }, + { "SetLoginEnvironment", bus_append_parse_boolean }, + { "ReadWriteDirectories", bus_append_strv }, + { "ReadOnlyDirectories", bus_append_strv }, + { "InaccessibleDirectories", bus_append_strv }, + { "ReadWritePaths", bus_append_strv }, + { "ReadOnlyPaths", bus_append_strv }, + { "InaccessiblePaths", bus_append_strv }, + { "ExecPaths", bus_append_strv }, + { "NoExecPaths", bus_append_strv }, + { "ExecSearchPath", bus_append_strv }, + { "ExtensionDirectories", bus_append_strv }, + { "ConfigurationDirectory", bus_append_strv }, + { "SupplementaryGroups", bus_append_strv }, + { "SystemCallArchitectures", bus_append_strv }, + { "SyslogLevel", bus_append_log_level_from_string }, + { "LogLevelMax", bus_append_log_level_from_string }, + { "SyslogFacility", bus_append_log_facility_unshifted_from_string }, + { "SecureBits", bus_append_secure_bits_from_string }, + { "CPUSchedulingPolicy", bus_append_sched_policy_from_string }, + { "CPUSchedulingPriority", bus_append_safe_atoi }, + { "OOMScoreAdjust", bus_append_safe_atoi }, + { "CoredumpFilter", bus_append_coredump_filter_mask_from_string }, + { "Nice", bus_append_parse_nice }, + { "SystemCallErrorNumber", bus_append_seccomp_parse_errno_or_action }, + { "IOSchedulingClass", bus_append_ioprio_class_from_string }, + { "IOSchedulingPriority", bus_append_ioprio_parse_priority }, + { "RuntimeDirectoryMode", bus_append_parse_mode }, + { "StateDirectoryMode", bus_append_parse_mode }, + { "CacheDirectoryMode", bus_append_parse_mode }, + { "LogsDirectoryMode", bus_append_parse_mode }, + { "ConfigurationDirectoryMode", bus_append_parse_mode }, + { "UMask", bus_append_parse_mode }, + { "TimerSlackNSec", bus_append_parse_nsec }, + { "LogRateLimitIntervalSec", bus_append_parse_sec_rename }, + { "LogRateLimitBurst", bus_append_safe_atou }, + { "TTYRows", bus_append_safe_atou }, + { "TTYColumns", bus_append_safe_atou }, + { "MountFlags", bus_append_mount_propagation_flag_from_string }, + { "Environment", bus_append_strv_cunescape }, + { "UnsetEnvironment", bus_append_strv_cunescape }, + { "PassEnvironment", bus_append_strv_cunescape }, + { "EnvironmentFile", bus_append_environment_files }, + { "SetCredential", bus_append_set_credential }, + { "SetCredentialEncrypted", bus_append_set_credential }, + { "LoadCredential", bus_append_load_credential }, + { "LoadCredentialEncrypted", bus_append_load_credential }, + { "ImportCredential", bus_append_import_credential }, + { "ImportCredentialEx", bus_append_import_credential }, + { "LogExtraFields", bus_append_log_extra_fields }, + { "LogFilterPatterns", bus_append_log_filter_patterns }, + { "StandardInput", bus_append_standard_inputs }, + { "StandardOutput", bus_append_standard_inputs }, + { "StandardError", bus_append_standard_inputs }, + { "StandardInputText", bus_append_standard_input_text }, + { "StandardInputData", bus_append_standard_input_data }, + { "AppArmorProfile", bus_append_string_with_ignore }, + { "SmackProcessLabel", bus_append_string_with_ignore }, + { "CapabilityBoundingSet", bus_append_capabilities }, + { "AmbientCapabilities", bus_append_capabilities }, + { "CPUAffinity", bus_append_cpu_affinity }, + { "NUMAPolicy", bus_append_mpol_from_string }, + { "NUMAMask", bus_append_numa_mask }, + { "RestrictAddressFamilies", bus_append_filter_list }, + { "RestrictFileSystems", bus_append_filter_list }, + { "SystemCallFilter", bus_append_filter_list }, + { "SystemCallLog", bus_append_filter_list }, + { "RestrictNetworkInterfaces", bus_append_filter_list }, + { "RestrictNamespaces", bus_append_namespace_list }, + { "DelegateNamespaces", bus_append_namespace_list }, + { "BindPaths", bus_append_bind_paths }, + { "BindReadOnlyPaths", bus_append_bind_paths }, + { "TemporaryFileSystem", bus_append_temporary_file_system }, + { "RootHash", bus_append_root_hash }, + { "RootHashSignature", bus_append_root_hash_signature }, + { "RootImageOptions", bus_append_root_image_options }, + { "MountImages", bus_append_mount_images }, + { "ExtensionImages", bus_append_extension_images }, + { "StateDirectory", bus_append_directory }, + { "RuntimeDirectory", bus_append_directory }, + { "CacheDirectory", bus_append_directory }, + { "LogsDirectory", bus_append_directory }, + { "ProtectHostname", bus_append_protect_hostname }, + { "ProtectHostnameEx", bus_append_protect_hostname }, + + { NULL, bus_try_append_resource_limit }, + {} +}; + +static const BusProperty kill_properties[] = { + { "KillMode", bus_append_string }, + { "SendSIGHUP", bus_append_parse_boolean }, + { "SendSIGKILL", bus_append_parse_boolean }, + { "KillSignal", bus_append_signal_from_string }, + { "RestartKillSignal", bus_append_signal_from_string }, + { "FinalKillSignal", bus_append_signal_from_string }, + { "WatchdogSignal", bus_append_signal_from_string }, + { "ReloadSignal", bus_append_signal_from_string }, + {} +}; + +static const BusProperty mount_properties[] = { + { "What", bus_append_string }, + { "Where", bus_append_string }, + { "Options", bus_append_string }, + { "Type", bus_append_string }, + { "TimeoutSec", bus_append_parse_sec_rename }, + { "DirectoryMode", bus_append_parse_mode }, + { "SloppyOptions", bus_append_parse_boolean }, + { "LazyUnmount", bus_append_parse_boolean }, + { "ForceUnmount", bus_append_parse_boolean }, + { "ReadwriteOnly", bus_append_parse_boolean }, + {} +}; + +static const BusProperty path_properties[] = { + { "MakeDirectory", bus_append_parse_boolean }, + { "DirectoryMode", bus_append_parse_mode }, + { "PathExists", bus_append_paths }, + { "PathExistsGlob", bus_append_paths }, + { "PathChanged", bus_append_paths }, + { "PathModified", bus_append_paths }, + { "DirectoryNotEmpty", bus_append_paths }, + { "TriggerLimitBurst", bus_append_safe_atou }, + { "PollLimitBurst", bus_append_safe_atou }, + { "TriggerLimitIntervalSec", bus_append_parse_sec_rename }, + { "PollLimitIntervalSec", bus_append_parse_sec_rename }, + {} +}; + +static const BusProperty scope_properties[] = { + { "RuntimeMaxSec", bus_append_parse_sec_rename }, + { "RuntimeRandomizedExtraSec", bus_append_parse_sec_rename }, + { "TimeoutStopSec", bus_append_parse_sec_rename }, + { "OOMPolicy", bus_append_string }, /* Scope units don't have execution context but we still want to allow setting these two, * so let's handle them separately. */ - if (STR_IN_SET(field, "User", "Group")) - return bus_append_string(m, field, eq); + { "User", bus_append_string }, + { "Group", bus_append_string }, + {} +}; - if (streq(field, "OOMPolicy")) - return bus_append_string(m, field, eq); +static const BusProperty service_properties[] = { + { "PIDFile", bus_append_string }, + { "Type", bus_append_string }, + { "ExitType", bus_append_string }, + { "Restart", bus_append_string }, + { "RestartMode", bus_append_string }, + { "BusName", bus_append_string }, + { "NotifyAccess", bus_append_string }, + { "USBFunctionDescriptors", bus_append_string }, + { "USBFunctionStrings", bus_append_string }, + { "OOMPolicy", bus_append_string }, + { "TimeoutStartFailureMode", bus_append_string }, + { "TimeoutStopFailureMode", bus_append_string }, + { "FileDescriptorStorePreserve", bus_append_string }, + { "PermissionsStartOnly", bus_append_parse_boolean }, + { "RootDirectoryStartOnly", bus_append_parse_boolean }, + { "RemainAfterExit", bus_append_parse_boolean }, + { "GuessMainPID", bus_append_parse_boolean }, + { "RestartSec", bus_append_parse_sec_rename }, + { "RestartMaxDelaySec", bus_append_parse_sec_rename }, + { "TimeoutStartSec", bus_append_parse_sec_rename }, + { "TimeoutStopSec", bus_append_parse_sec_rename }, + { "TimeoutAbortSec", bus_append_parse_sec_rename }, + { "RuntimeMaxSec", bus_append_parse_sec_rename }, + { "RuntimeRandomizedExtraSec", bus_append_parse_sec_rename }, + { "WatchdogSec", bus_append_parse_sec_rename }, + { "TimeoutSec", bus_append_timeout_sec }, + { "FileDescriptorStoreMax", bus_append_safe_atou }, + { "RestartSteps", bus_append_safe_atou }, + { "ExecCondition", bus_append_exec_command }, + { "ExecStartPre", bus_append_exec_command }, + { "ExecStart", bus_append_exec_command }, + { "ExecStartPost", bus_append_exec_command }, + { "ExecConditionEx", bus_append_exec_command }, + { "ExecStartPreEx", bus_append_exec_command }, + { "ExecStartEx", bus_append_exec_command }, + { "ExecStartPostEx", bus_append_exec_command }, + { "ExecReload", bus_append_exec_command }, + { "ExecStop", bus_append_exec_command }, + { "ExecStopPost", bus_append_exec_command }, + { "ExecReloadEx", bus_append_exec_command }, + { "ExecStopEx", bus_append_exec_command }, + { "ExecStopPostEx", bus_append_exec_command }, + { "RestartPreventExitStatus", bus_append_exit_status }, + { "RestartForceExitStatus", bus_append_exit_status }, + { "SuccessExitStatus", bus_append_exit_status }, + { "OpenFile", bus_append_open_file }, + {} +}; - return 0; -} +static const BusProperty socket_properties[] = { + { "Accept", bus_append_parse_boolean }, + { "FlushPending", bus_append_parse_boolean }, + { "Writable", bus_append_parse_boolean }, + { "KeepAlive", bus_append_parse_boolean }, + { "NoDelay", bus_append_parse_boolean }, + { "FreeBind", bus_append_parse_boolean }, + { "Transparent", bus_append_parse_boolean }, + { "Broadcast", bus_append_parse_boolean }, + { "PassCredentials", bus_append_parse_boolean }, + { "PassFileDescriptorsToExec", bus_append_parse_boolean }, + { "PassSecurity", bus_append_parse_boolean }, + { "PassPacketInfo", bus_append_parse_boolean }, + { "ReusePort", bus_append_parse_boolean }, + { "RemoveOnStop", bus_append_parse_boolean }, + { "SELinuxContextFromNet", bus_append_parse_boolean }, + { "Priority", bus_append_safe_atoi }, + { "IPTTL", bus_append_safe_atoi }, + { "Mark", bus_append_safe_atoi }, + { "IPTOS", bus_append_ip_tos_from_string }, + { "Backlog", bus_append_safe_atou }, + { "MaxConnections", bus_append_safe_atou }, + { "MaxConnectionsPerSource", bus_append_safe_atou }, + { "KeepAliveProbes", bus_append_safe_atou }, + { "TriggerLimitBurst", bus_append_safe_atou }, + { "PollLimitBurst", bus_append_safe_atou }, + { "SocketMode", bus_append_parse_mode }, + { "DirectoryMode", bus_append_parse_mode }, + { "MessageQueueMaxMessages", bus_append_safe_atoi64 }, + { "MessageQueueMessageSize", bus_append_safe_atoi64 }, + { "TimeoutSec", bus_append_parse_sec_rename }, + { "KeepAliveTimeSec", bus_append_parse_sec_rename }, + { "KeepAliveIntervalSec", bus_append_parse_sec_rename }, + { "DeferAcceptSec", bus_append_parse_sec_rename }, + { "TriggerLimitIntervalSec", bus_append_parse_sec_rename }, + { "PollLimitIntervalSec", bus_append_parse_sec_rename }, + { "DeferTriggerMaxSec", bus_append_parse_sec_rename }, + { "ReceiveBuffer", bus_append_parse_size }, + { "SendBuffer", bus_append_parse_size }, + { "PipeSize", bus_append_parse_size }, + { "ExecStartPre", bus_append_exec_command }, + { "ExecStartPost", bus_append_exec_command }, + { "ExecReload", bus_append_exec_command }, + { "ExecStopPost", bus_append_exec_command }, + { "SmackLabel", bus_append_string }, + { "SmackLabelIPIn", bus_append_string }, + { "SmackLabelIPOut", bus_append_string }, + { "TCPCongestion", bus_append_string }, + { "BindToDevice", bus_append_string }, + { "BindIPv6Only", bus_append_string }, + { "FileDescriptorName", bus_append_string }, + { "SocketUser", bus_append_string }, + { "SocketGroup", bus_append_string }, + { "Timestamping", bus_append_string }, + { "DeferTrigger", bus_append_string }, + { "Symlinks", bus_append_strv }, + { "SocketProtocol", bus_append_parse_ip_protocol }, + { "ListenStream", bus_append_listen }, + { "ListenDatagram", bus_append_listen }, + { "ListenSequentialPacket", bus_append_listen }, + { "ListenNetlink", bus_append_listen }, + { "ListenSpecial", bus_append_listen }, + { "ListenMessageQueue", bus_append_listen }, + { "ListenFIFO", bus_append_listen }, + { "ListenUSBFunction", bus_append_listen }, + {} +}; -static int bus_append_service_property(sd_bus_message *m, const char *field, const char *eq) { - if (STR_IN_SET(field, "PIDFile", - "Type", - "ExitType", - "Restart", - "RestartMode", - "BusName", - "NotifyAccess", - "USBFunctionDescriptors", - "USBFunctionStrings", - "OOMPolicy", - "TimeoutStartFailureMode", - "TimeoutStopFailureMode", - "FileDescriptorStorePreserve")) - return bus_append_string(m, field, eq); +static const BusProperty timer_properties[] = { + { "WakeSystem", bus_append_parse_boolean }, + { "RemainAfterElapse", bus_append_parse_boolean }, + { "Persistent", bus_append_parse_boolean }, + { "OnTimezoneChange", bus_append_parse_boolean }, + { "OnClockChange", bus_append_parse_boolean }, + { "FixedRandomDelay", bus_append_parse_boolean }, + { "DeferReactivation", bus_append_parse_boolean }, + { "AccuracySec", bus_append_parse_sec_rename }, + { "RandomizedDelaySec", bus_append_parse_sec_rename }, + { "RandomizedOffsetSec", bus_append_parse_sec_rename }, + { "OnActiveSec", bus_append_timers_monotonic }, + { "OnBootSec", bus_append_timers_monotonic }, + { "OnStartupSec", bus_append_timers_monotonic }, + { "OnUnitActiveSec", bus_append_timers_monotonic }, + { "OnUnitInactiveSec", bus_append_timers_monotonic }, + { "OnCalendar", bus_append_timers_calendar }, + {} +}; - if (STR_IN_SET(field, "PermissionsStartOnly", - "RootDirectoryStartOnly", - "RemainAfterExit", - "GuessMainPID")) - return bus_append_parse_boolean(m, field, eq); +static const BusProperty unit_properties[] = { + { "Description", bus_append_string }, + { "SourcePath", bus_append_string }, + { "OnFailureJobMode", bus_append_string }, + { "JobTimeoutAction", bus_append_string }, + { "JobTimeoutRebootArgument", bus_append_string }, + { "StartLimitAction", bus_append_string }, + { "FailureAction", bus_append_string }, + { "SuccessAction", bus_append_string }, + { "RebootArgument", bus_append_string }, + { "CollectMode", bus_append_string }, + { "StopWhenUnneeded", bus_append_parse_boolean }, + { "RefuseManualStart", bus_append_parse_boolean }, + { "RefuseManualStop", bus_append_parse_boolean }, + { "AllowIsolate", bus_append_parse_boolean }, + { "IgnoreOnIsolate", bus_append_parse_boolean }, + { "SurviveFinalKillSignal", bus_append_parse_boolean }, + { "DefaultDependencies", bus_append_parse_boolean }, + { "JobTimeoutSec", bus_append_parse_sec_rename }, + { "JobRunningTimeoutSec", bus_append_parse_sec_rename }, + { "StartLimitIntervalSec", bus_append_parse_sec_rename }, + { "StartLimitBurst", bus_append_safe_atou }, + { "SuccessActionExitStatus", bus_append_action_exit_status }, + { "FailureActionExitStatus", bus_append_action_exit_status }, + { "Documentation", bus_append_strv }, + { "RequiresMountsFor", bus_append_strv }, + { "WantsMountsFor", bus_append_strv }, + { "Markers", bus_append_strv }, - if (STR_IN_SET(field, "RestartSec", - "RestartMaxDelaySec", - "TimeoutStartSec", - "TimeoutStopSec", - "TimeoutAbortSec", - "RuntimeMaxSec", - "RuntimeRandomizedExtraSec", - "WatchdogSec")) - return bus_append_parse_sec_rename(m, field, eq); + { NULL, bus_try_append_unit_dependency }, + { NULL, bus_try_append_condition }, + {} +}; - if (streq(field, "TimeoutSec")) - return bus_append_timeout_sec(m, field, eq); +static const BusProperty* service_unit_properties[] = { + cgroup_properties, + execute_properties, + kill_properties, + service_properties, + unit_properties, + NULL, +}; - if (STR_IN_SET(field, "FileDescriptorStoreMax", - "RestartSteps")) - return bus_append_safe_atou(m, field, eq); +static const BusProperty* socket_unit_properties[] = { + cgroup_properties, + execute_properties, + kill_properties, + socket_properties, + unit_properties, + NULL, +}; - if (STR_IN_SET(field, "ExecCondition", - "ExecStartPre", - "ExecStart", - "ExecStartPost", - "ExecConditionEx", - "ExecStartPreEx", - "ExecStartEx", - "ExecStartPostEx", - "ExecReload", - "ExecStop", - "ExecStopPost", - "ExecReloadEx", - "ExecStopEx", - "ExecStopPostEx")) - return bus_append_exec_command(m, field, eq); +static const BusProperty* timer_unit_properties[] = { + timer_properties, + unit_properties, + NULL, +}; - if (STR_IN_SET(field, "RestartPreventExitStatus", - "RestartForceExitStatus", - "SuccessExitStatus")) - return bus_append_exit_status(m, field, eq); +static const BusProperty* path_unit_properties[] = { + path_properties, + unit_properties, + NULL, +}; - if (streq(field, "OpenFile")) - return bus_append_open_file(m, field, eq); +static const BusProperty* slice_unit_properties[] = { + cgroup_properties, + unit_properties, + NULL, +}; - return 0; -} +static const BusProperty* scope_unit_properties[] = { + cgroup_properties, + kill_properties, + scope_properties, + unit_properties, + NULL, +}; -static int bus_append_socket_property(sd_bus_message *m, const char *field, const char *eq) { - if (STR_IN_SET(field, "Accept", - "FlushPending", - "Writable", - "KeepAlive", - "NoDelay", - "FreeBind", - "Transparent", - "Broadcast", - "PassCredentials", - "PassPIDFD", - "PassSecurity", - "PassPacketInfo", - "AcceptFileDescriptors", - "ReusePort", - "RemoveOnStop", - "PassFileDescriptorsToExec", - "SELinuxContextFromNet")) - return bus_append_parse_boolean(m, field, eq); +static const BusProperty* mount_unit_properties[] = { + cgroup_properties, + execute_properties, + kill_properties, + mount_properties, + unit_properties, + NULL, +}; - if (STR_IN_SET(field, "Priority", - "IPTTL", - "Mark")) - return bus_append_safe_atoi(m, field, eq); +static const BusProperty* automount_unit_properties[] = { + automount_properties, + unit_properties, + NULL, +}; - if (streq(field, "IPTOS")) - return bus_append_ip_tos_from_string(m, field, eq); +static const BusProperty* other_unit_properties[] = { + unit_properties, + NULL, +}; - if (STR_IN_SET(field, "Backlog", - "MaxConnections", - "MaxConnectionsPerSource", - "KeepAliveProbes", - "TriggerLimitBurst", - "PollLimitBurst")) - return bus_append_safe_atou(m, field, eq); - - if (STR_IN_SET(field, "SocketMode", - "DirectoryMode")) - return bus_append_parse_mode(m, field, eq); - - if (STR_IN_SET(field, "MessageQueueMaxMessages", - "MessageQueueMessageSize")) - return bus_append_safe_atoi64(m, field, eq); - - if (STR_IN_SET(field, "TimeoutSec", - "KeepAliveTimeSec", - "KeepAliveIntervalSec", - "DeferAcceptSec", - "TriggerLimitIntervalSec", - "PollLimitIntervalSec", - "DeferTriggerMaxSec")) - return bus_append_parse_sec_rename(m, field, eq); - - if (STR_IN_SET(field, "ReceiveBuffer", - "SendBuffer", - "PipeSize")) - return bus_append_parse_size(m, field, eq, 1024); - - if (STR_IN_SET(field, "ExecStartPre", - "ExecStartPost", - "ExecReload", - "ExecStopPost")) - return bus_append_exec_command(m, field, eq); - - if (STR_IN_SET(field, "SmackLabel", - "SmackLabelIPIn", - "SmackLabelIPOut", - "TCPCongestion", - "BindToDevice", - "BindIPv6Only", - "FileDescriptorName", - "SocketUser", - "SocketGroup", - "Timestamping", - "DeferTrigger")) - return bus_append_string(m, field, eq); - - if (streq(field, "Symlinks")) - return bus_append_strv(m, field, eq); - - if (streq(field, "SocketProtocol")) - return bus_append_parse_ip_protocol(m, field, eq); - - if (STR_IN_SET(field, "ListenStream", - "ListenDatagram", - "ListenSequentialPacket", - "ListenNetlink", - "ListenSpecial", - "ListenMessageQueue", - "ListenFIFO", - "ListenUSBFunction")) - return bus_append_listen(m, field, eq); - - return 0; -} -static int bus_append_timer_property(sd_bus_message *m, const char *field, const char *eq) { - if (STR_IN_SET(field, "WakeSystem", - "RemainAfterElapse", - "Persistent", - "OnTimezoneChange", - "OnClockChange", - "FixedRandomDelay", - "DeferReactivation")) - return bus_append_parse_boolean(m, field, eq); - - if (STR_IN_SET(field, "AccuracySec", - "RandomizedDelaySec", - "RandomizedOffsetSec")) - return bus_append_parse_sec_rename(m, field, eq); - - if (STR_IN_SET(field, "OnActiveSec", - "OnBootSec", - "OnStartupSec", - "OnUnitActiveSec", - "OnUnitInactiveSec")) - return bus_append_timers_monotonic(m, field, eq); - - if (streq(field, "OnCalendar")) - return bus_append_timers_calendar(m, field, eq); - - return 0; -} - -static int bus_append_unit_property(sd_bus_message *m, const char *field, const char *eq) { - int r; - - if (STR_IN_SET(field, "Description", - "SourcePath", - "OnFailureJobMode", - "JobTimeoutAction", - "JobTimeoutRebootArgument", - "StartLimitAction", - "FailureAction", - "SuccessAction", - "RebootArgument", - "CollectMode")) - return bus_append_string(m, field, eq); - - if (STR_IN_SET(field, "StopWhenUnneeded", - "RefuseManualStart", - "RefuseManualStop", - "AllowIsolate", - "IgnoreOnIsolate", - "SurviveFinalKillSignal", - "DefaultDependencies")) - return bus_append_parse_boolean(m, field, eq); - - if (STR_IN_SET(field, "JobTimeoutSec", - "JobRunningTimeoutSec", - "StartLimitIntervalSec")) - return bus_append_parse_sec_rename(m, field, eq); - - if (streq(field, "StartLimitBurst")) - return bus_append_safe_atou(m, field, eq); - - if (STR_IN_SET(field, "SuccessActionExitStatus", - "FailureActionExitStatus")) - return bus_append_action_exit_status(m, field, eq); - - if (STR_IN_SET(field, "Documentation", - "RequiresMountsFor", - "WantsMountsFor", - "Markers")) - return bus_append_strv(m, field, eq); - - r = bus_try_append_unit_dependency(m, field, eq); - if (r != 0) - return r; - - return bus_try_append_condition(m, field, eq); -} +static const BusProperty** unit_type_properties[_UNIT_TYPE_MAX] = { + [UNIT_SERVICE] = service_unit_properties, + [UNIT_SOCKET] = socket_unit_properties, + [UNIT_TIMER] = timer_unit_properties, + [UNIT_PATH] = path_unit_properties, + [UNIT_SLICE] = slice_unit_properties, + [UNIT_SCOPE] = scope_unit_properties, + [UNIT_MOUNT] = mount_unit_properties, + [UNIT_AUTOMOUNT] = automount_unit_properties, + [UNIT_TARGET] = other_unit_properties, + [UNIT_DEVICE] = other_unit_properties, + [UNIT_SWAP] = other_unit_properties, +}; int bus_append_unit_property_assignment(sd_bus_message *m, UnitType t, const char *assignment) { const char *eq, *field; @@ -2956,6 +2815,7 @@ int bus_append_unit_property_assignment(sd_bus_message *m, UnitType t, const cha assert(m); assert(assignment); + assert(t >= 0 && t < _UNIT_TYPE_MAX); eq = strchr(assignment, '='); if (!eq) @@ -2965,113 +2825,17 @@ int bus_append_unit_property_assignment(sd_bus_message *m, UnitType t, const cha field = strndupa_safe(assignment, eq - assignment); eq++; - switch (t) { - case UNIT_SERVICE: - r = bus_append_cgroup_property(m, field, eq); - if (r != 0) - return r; - - r = bus_append_execute_property(m, field, eq); - if (r != 0) - return r; - - r = bus_append_kill_property(m, field, eq); - if (r != 0) - return r; - - r = bus_append_service_property(m, field, eq); - if (r != 0) - return r; - break; - - case UNIT_SOCKET: - r = bus_append_cgroup_property(m, field, eq); - if (r != 0) - return r; - - r = bus_append_execute_property(m, field, eq); - if (r != 0) - return r; - - r = bus_append_kill_property(m, field, eq); - if (r != 0) - return r; - - r = bus_append_socket_property(m, field, eq); - if (r != 0) - return r; - break; - - case UNIT_TIMER: - r = bus_append_timer_property(m, field, eq); - if (r != 0) - return r; - break; - - case UNIT_PATH: - r = bus_append_path_property(m, field, eq); - if (r != 0) - return r; - break; - - case UNIT_SLICE: - r = bus_append_cgroup_property(m, field, eq); - if (r != 0) - return r; - break; - - case UNIT_SCOPE: - r = bus_append_cgroup_property(m, field, eq); - if (r != 0) - return r; - - r = bus_append_kill_property(m, field, eq); - if (r != 0) - return r; - - r = bus_append_scope_property(m, field, eq); - if (r != 0) - return r; - break; - - case UNIT_MOUNT: - r = bus_append_cgroup_property(m, field, eq); - if (r != 0) - return r; - - r = bus_append_execute_property(m, field, eq); - if (r != 0) - return r; - - r = bus_append_kill_property(m, field, eq); - if (r != 0) - return r; - - r = bus_append_mount_property(m, field, eq); - if (r != 0) - return r; - - break; - - case UNIT_AUTOMOUNT: - r = bus_append_automount_property(m, field, eq); - if (r != 0) - return r; - - break; - - case UNIT_TARGET: - case UNIT_DEVICE: - case UNIT_SWAP: - break; - - default: - assert_not_reached(); - } - - r = bus_append_unit_property(m, field, eq); - if (r != 0) - return r; + for (const BusProperty** tables = ASSERT_PTR(unit_type_properties[t]); *tables; tables++) + for (const BusProperty *item = *tables; item->convert; item++) + if (item->name) { + if (streq(item->name, field)) + return item->convert(m, field, eq); + } else { + /* If .name is not set, the function must be a "try" helper */ + r = item->convert(m, field, eq); + if (r != 0) + return r; + } return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Unknown assignment: %s", assignment); From 1c1626e06319dd9682712726c5cbef045402cd69 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Thu, 29 May 2025 14:37:30 +0200 Subject: [PATCH 60/64] shared/bus-unit-util: add bus_dump_transient_settings() helper bus_append_unit_property() and associated functions accept a long list of properties. But the specific names are only available through code. But it is useful to be able to know the specific list of properties that is supported, in particular for shell completions. Thus, add a way to list the properties that are supported by the code. In the future we could also turn this into a test for the documentation. For various reasons, the list of properties listed in the docs is a partially overlapping set. E.g. for service type, the pull request https://github.com/systemd/systemd/pull/37661 creates a list with 212 entries, and this code generates 7 entries less and 184 more. I didn't check all the differences, but in the few cases I did, the list generated here was actually correctly supported by 'systemd-run -p'. A smoke test is added. --- src/basic/cgroup-util.c | 4 ++++ src/basic/cgroup-util.h | 1 + src/basic/rlimit-util.c | 5 +++++ src/basic/rlimit-util.h | 1 + src/basic/unit-def.c | 6 ++++++ src/basic/unit-def.h | 1 + src/shared/bus-unit-util.c | 36 +++++++++++++++++++++++++++++++---- src/shared/bus-unit-util.h | 2 ++ src/shared/condition.c | 8 ++++++++ src/shared/condition.h | 2 ++ src/test/meson.build | 1 + src/test/test-bus-unit-util.c | 15 +++++++++++++++ 12 files changed, 78 insertions(+), 4 deletions(-) create mode 100644 src/test/test-bus-unit-util.c diff --git a/src/basic/cgroup-util.c b/src/basic/cgroup-util.c index c0ba6b9401..54d845a87b 100644 --- a/src/basic/cgroup-util.c +++ b/src/basic/cgroup-util.c @@ -2063,6 +2063,10 @@ static const char* const cgroup_io_limit_type_table[_CGROUP_IO_LIMIT_TYPE_MAX] = DEFINE_STRING_TABLE_LOOKUP(cgroup_io_limit_type, CGroupIOLimitType); +void cgroup_io_limits_list(void) { + DUMP_STRING_TABLE(cgroup_io_limit_type, CGroupIOLimitType, _CGROUP_IO_LIMIT_TYPE_MAX); +} + static const char *const cgroup_controller_table[_CGROUP_CONTROLLER_MAX] = { [CGROUP_CONTROLLER_CPU] = "cpu", [CGROUP_CONTROLLER_CPUACCT] = "cpuacct", diff --git a/src/basic/cgroup-util.h b/src/basic/cgroup-util.h index 2dea0ebdc4..ac0c7d8c41 100644 --- a/src/basic/cgroup-util.h +++ b/src/basic/cgroup-util.h @@ -97,6 +97,7 @@ extern const uint64_t cgroup_io_limit_defaults[_CGROUP_IO_LIMIT_TYPE_MAX]; const char* cgroup_io_limit_type_to_string(CGroupIOLimitType t) _const_; CGroupIOLimitType cgroup_io_limit_type_from_string(const char *s) _pure_; +void cgroup_io_limits_list(void); /* Special values for the io.bfq.weight attribute */ #define CGROUP_BFQ_WEIGHT_INVALID UINT64_MAX diff --git a/src/basic/rlimit-util.c b/src/basic/rlimit-util.c index 803eaa09b2..22fd86301c 100644 --- a/src/basic/rlimit-util.c +++ b/src/basic/rlimit-util.c @@ -343,6 +343,11 @@ static const char* const rlimit_table[_RLIMIT_MAX] = { DEFINE_STRING_TABLE_LOOKUP(rlimit, int); +void rlimits_list(const char *prefix) { + FOREACH_ELEMENT(field, rlimit_table) + printf("%s%s\n", strempty(prefix), *field); +} + int rlimit_from_string_harder(const char *s) { const char *suffix; diff --git a/src/basic/rlimit-util.h b/src/basic/rlimit-util.h index 52ec8bd320..8b600fe1d2 100644 --- a/src/basic/rlimit-util.h +++ b/src/basic/rlimit-util.h @@ -10,6 +10,7 @@ const char* rlimit_to_string(int i) _const_; int rlimit_from_string(const char *s) _pure_; int rlimit_from_string_harder(const char *s) _pure_; +void rlimits_list(const char *prefix); int setrlimit_closest(int resource, const struct rlimit *rlim); int setrlimit_closest_all(const struct rlimit * const *rlim, int *which_failed); diff --git a/src/basic/unit-def.c b/src/basic/unit-def.c index 8bc5f56532..f98cfd4ae1 100644 --- a/src/basic/unit-def.c +++ b/src/basic/unit-def.c @@ -1,5 +1,7 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ +#include + #include "alloc-util.h" #include "bus-label.h" #include "glyph-util.h" @@ -331,6 +333,10 @@ static const char* const unit_dependency_table[_UNIT_DEPENDENCY_MAX] = { DEFINE_STRING_TABLE_LOOKUP(unit_dependency, UnitDependency); +void unit_types_list(void) { + DUMP_STRING_TABLE(unit_dependency, UnitDependency, _UNIT_DEPENDENCY_MAX); +} + static const char* const notify_access_table[_NOTIFY_ACCESS_MAX] = { [NOTIFY_NONE] = "none", [NOTIFY_MAIN] = "main", diff --git a/src/basic/unit-def.h b/src/basic/unit-def.h index fd55950ea6..7664f2881a 100644 --- a/src/basic/unit-def.h +++ b/src/basic/unit-def.h @@ -304,6 +304,7 @@ const char* unit_dbus_interface_from_name(const char *name); const char* unit_type_to_string(UnitType i) _const_; UnitType unit_type_from_string(const char *s) _pure_; +void unit_types_list(void); const char* unit_load_state_to_string(UnitLoadState i) _const_; UnitLoadState unit_load_state_from_string(const char *s) _pure_; diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c index 6811c8fc41..dafe652b56 100644 --- a/src/shared/bus-unit-util.c +++ b/src/shared/bus-unit-util.c @@ -1305,6 +1305,10 @@ static int bus_try_append_resource_limit(sd_bus_message *m, const char *field, c return 1; } +static void dump_resource_limits(void) { + rlimits_list("Limit"); +} + static int bus_append_string_with_ignore(sd_bus_message *m, const char *field, const char *eq) { int ignore = 0; const char *s = eq; @@ -2271,6 +2275,11 @@ static int bus_try_append_condition(sd_bus_message *m, const char *field, const field, trigger, negate, p); } +static void dump_conditions(void) { + condition_types_list(); + assert_types_list(); +} + static int bus_try_append_unit_dependency(sd_bus_message *m, const char *field, const char *eq) { if (unit_dependency_from_string(field) < 0) return 0; @@ -2281,6 +2290,7 @@ static int bus_try_append_unit_dependency(sd_bus_message *m, const char *field, typedef struct BusProperty { const char *name; int (*convert)(sd_bus_message *m, const char *field, const char *eq); + void (*dump)(void); } BusProperty; static const BusProperty cgroup_properties[] = { @@ -2347,7 +2357,7 @@ static const BusProperty cgroup_properties[] = { { "BlockIOWriteBandwidth", warn_deprecated }, { "CPUAccounting", warn_deprecated }, - { NULL, bus_try_append_parse_cgroup_io_limit }, + { NULL, bus_try_append_parse_cgroup_io_limit, cgroup_io_limits_list }, {} }; @@ -2501,7 +2511,7 @@ static const BusProperty execute_properties[] = { { "ProtectHostname", bus_append_protect_hostname }, { "ProtectHostnameEx", bus_append_protect_hostname }, - { NULL, bus_try_append_resource_limit }, + { NULL, bus_try_append_resource_limit, dump_resource_limits }, {} }; @@ -2726,8 +2736,8 @@ static const BusProperty unit_properties[] = { { "WantsMountsFor", bus_append_strv }, { "Markers", bus_append_strv }, - { NULL, bus_try_append_unit_dependency }, - { NULL, bus_try_append_condition }, + { NULL, bus_try_append_unit_dependency, unit_types_list }, + { NULL, bus_try_append_condition, dump_conditions }, {} }; @@ -2855,6 +2865,24 @@ int bus_append_unit_property_assignment_many(sd_bus_message *m, UnitType t, char return 0; } +void bus_dump_transient_settings(UnitType t) { + assert(t >= 0 && t < _UNIT_TYPE_MAX); + + for (const BusProperty** tables = ASSERT_PTR(unit_type_properties[t]); *tables; tables++) + for (const BusProperty *item = *tables; item->convert; item++) { + assert(item->name || item->dump); + + /* Do not print deprecated names */ + if (item->convert == warn_deprecated) + continue; + + if (item->name) + puts(item->name); + else + item->dump(); + } +} + int bus_append_scope_pidref(sd_bus_message *m, const PidRef *pidref, bool allow_pidfd) { assert(m); diff --git a/src/shared/bus-unit-util.h b/src/shared/bus-unit-util.h index c6e02a01b4..c07a704414 100644 --- a/src/shared/bus-unit-util.h +++ b/src/shared/bus-unit-util.h @@ -51,3 +51,5 @@ int unit_freezer_new(const char *name, UnitFreezer **ret); int unit_freezer_freeze(UnitFreezer *f); int unit_freezer_thaw(UnitFreezer *f); + +void bus_dump_transient_settings(UnitType t); diff --git a/src/shared/condition.c b/src/shared/condition.c index 14318667ec..25c38f374b 100644 --- a/src/shared/condition.c +++ b/src/shared/condition.c @@ -1402,6 +1402,10 @@ ConditionType condition_type_from_string(const char *s) { return _condition_type_from_string(s); } +void condition_types_list(void) { + DUMP_STRING_TABLE(_condition_type, ConditionType, _CONDITION_TYPE_MAX); +} + static const char* const _assert_type_table[_CONDITION_TYPE_MAX] = { [CONDITION_ARCHITECTURE] = "AssertArchitecture", [CONDITION_FIRMWARE] = "AssertFirmware", @@ -1453,6 +1457,10 @@ ConditionType assert_type_from_string(const char *s) { return _assert_type_from_string(s); } +void assert_types_list(void) { + DUMP_STRING_TABLE(_assert_type, ConditionType, _CONDITION_TYPE_MAX); +} + static const char* const condition_result_table[_CONDITION_RESULT_MAX] = { [CONDITION_UNTESTED] = "untested", [CONDITION_SUCCEEDED] = "succeeded", diff --git a/src/shared/condition.h b/src/shared/condition.h index a06d2a89d1..c25b9643b9 100644 --- a/src/shared/condition.h +++ b/src/shared/condition.h @@ -88,9 +88,11 @@ void condition_dump_list(Condition *c, FILE *f, const char *prefix, condition_to const char* condition_type_to_string(ConditionType t) _const_; ConditionType condition_type_from_string(const char *s) _pure_; +void condition_types_list(void); const char* assert_type_to_string(ConditionType t) _const_; ConditionType assert_type_from_string(const char *s) _pure_; +void assert_types_list(void); const char* condition_result_to_string(ConditionResult r) _const_; ConditionResult condition_result_from_string(const char *s) _pure_; diff --git a/src/test/meson.build b/src/test/meson.build index 6bb9e3f40d..286fcac5c7 100644 --- a/src/test/meson.build +++ b/src/test/meson.build @@ -56,6 +56,7 @@ simple_tests += files( 'test-blockdev-util.c', 'test-bootspec.c', 'test-build-path.c', + 'test-bus-unit-util.c', 'test-bus-util.c', 'test-calendarspec.c', 'test-cgroup-util.c', diff --git a/src/test/test-bus-unit-util.c b/src/test/test-bus-unit-util.c new file mode 100644 index 0000000000..a1f0104bc0 --- /dev/null +++ b/src/test/test-bus-unit-util.c @@ -0,0 +1,15 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ + +#include "bus-unit-util.h" +#include "unit-def.h" +#include "tests.h" + +TEST(bus_dump_transient_settings) { + /* -1 is for generic unit, natural numbers are for specific unit types */ + for (UnitType t = 0; t < _UNIT_TYPE_MAX; t++) { + log_info("==================== %s ====================", t < 0 ? "unit" : unit_type_to_string(t)); + bus_dump_transient_settings(t); + } +} + +DEFINE_TEST_MAIN(LOG_DEBUG); From a839c4b7b7b5ddfd2187d1c3975ed6a203d37f90 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Fri, 30 May 2025 12:15:13 +0200 Subject: [PATCH 61/64] analyze: add transient-settings verb Related to https://github.com/systemd/systemd/pull/37641. The name "transient settings" was used in docs/TRANSIENT-SETTINGS.md. Using "setting" helps distinguish this from D-Bus "properties", which are a much larger set, partially overlapping. --- man/systemd-analyze.xml | 39 +++++++++++++ src/analyze/analyze.c | 105 +++++++++++++++++++++------------- test/units/TEST-65-ANALYZE.sh | 11 ++++ 3 files changed, 116 insertions(+), 39 deletions(-) diff --git a/man/systemd-analyze.xml b/man/systemd-analyze.xml index 7bdf850c60..e1c575757b 100644 --- a/man/systemd-analyze.xml +++ b/man/systemd-analyze.xml @@ -210,6 +210,12 @@ OPTIONS chid + + systemd-analyze + OPTIONS + transient-settings + TYPE + @@ -1121,6 +1127,39 @@ LEGEND: M → sys_vendor (LENOVO) ┄ F → product_family (ThinkPad X1 Carbon G + + <command>systemd-analyze transient-settings <replaceable>TYPE</replaceable>...</command> + + Lists properties that can be set for various unit types via command line interfaces, in + particular + systemctl1 + set-property and / + options in + systemd-run1, + systemd-nspawn1, and + systemd-mount1. + Those assignments are possible for a subset of the properties that can be set in config files, see + systemd.unit5, + systemd.exec5, + systemd.resource-control5, + and the other unit-type-specific pages. The TYPE argument must be a unit + type ("service", "socket", …). The properties that apply to the specific types are listed. + + Note: D-Bus properties documented in + org.freedesktop.systemd15 + form a partially overlapping set with the lists generated by this command. Many D-Bus properties and + transient settings share the same names, but for example, LogRateLimitIntervalSec= + is described in + systemd.exec5 and + would be listed by this command, but the corresponding D-Bus property described in + systemd.exec5 is + LogRateLimitIntervalUSec. + + + This verb is intended primarily for programatic generation of shell completions. + + + diff --git a/src/analyze/analyze.c b/src/analyze/analyze.c index bb5855ecc6..8745db63f5 100644 --- a/src/analyze/analyze.c +++ b/src/analyze/analyze.c @@ -12,7 +12,6 @@ #include "sd-json.h" #include "alloc-util.h" -#include "analyze-verify-util.h" #include "analyze.h" #include "analyze-architectures.h" #include "analyze-blame.h" @@ -46,8 +45,10 @@ #include "analyze-unit-files.h" #include "analyze-unit-paths.h" #include "analyze-verify.h" +#include "analyze-verify-util.h" #include "build.h" #include "bus-error.h" +#include "bus-unit-util.h" #include "bus-util.h" #include "calendarspec.h" #include "dissect-image.h" @@ -66,6 +67,7 @@ #include "string-util.h" #include "strv.h" #include "time-util.h" +#include "unit-def.h" #include "unit-name.h" #include "verbs.h" @@ -159,6 +161,29 @@ void time_parsing_hint(const char *p, bool calendar, bool timestamp, bool timesp "Use 'systemd-analyze timespan \"%s\"' instead?", p); } +static int verb_transient_settings(int argc, char *argv[], void *userdata) { + assert(argc >= 2); + + pager_open(arg_pager_flags); + + bool first = true; + STRV_FOREACH(arg, strv_skip(argv, 1)) { + UnitType t; + + t = unit_type_from_string(*arg); + if (t < 0) + return log_error_errno(t, "Invalid unit type '%s'.", *arg); + + if (!first) + puts(""); + + bus_dump_transient_settings(t); + first = false; + } + + return 0; +} + static int help(int argc, char *argv[], void *userdata) { _cleanup_free_ char *link = NULL, *dot_link = NULL; int r; @@ -200,6 +225,7 @@ static int help(int argc, char *argv[], void *userdata) { " architectures [NAME...] List known architectures\n" " smbios11 List strings passed via SMBIOS Type #11\n" " chid List local CHIDs\n" + " transient-settings TYPE... List transient settings for unit TYPE\n" "\n%3$sExpression Evaluation:%4$s\n" " condition CONDITION... Evaluate conditions and asserts\n" " compare-versions VERSION1 [OP] VERSION2\n" @@ -639,46 +665,47 @@ static int run(int argc, char *argv[]) { _cleanup_(umount_and_freep) char *mounted_dir = NULL; static const Verb verbs[] = { - { "help", VERB_ANY, VERB_ANY, 0, help }, - { "time", VERB_ANY, 1, VERB_DEFAULT, verb_time }, - { "blame", VERB_ANY, 1, 0, verb_blame }, - { "critical-chain", VERB_ANY, VERB_ANY, 0, verb_critical_chain }, - { "plot", VERB_ANY, 1, 0, verb_plot }, - { "dot", VERB_ANY, VERB_ANY, 0, verb_dot }, + { "help", VERB_ANY, VERB_ANY, 0, help }, + { "time", VERB_ANY, 1, VERB_DEFAULT, verb_time }, + { "blame", VERB_ANY, 1, 0, verb_blame }, + { "critical-chain", VERB_ANY, VERB_ANY, 0, verb_critical_chain }, + { "plot", VERB_ANY, 1, 0, verb_plot }, + { "dot", VERB_ANY, VERB_ANY, 0, verb_dot }, /* ↓ The following seven verbs are deprecated, from here … ↓ */ - { "log-level", VERB_ANY, 2, 0, verb_log_control }, - { "log-target", VERB_ANY, 2, 0, verb_log_control }, - { "set-log-level", 2, 2, 0, verb_log_control }, - { "get-log-level", VERB_ANY, 1, 0, verb_log_control }, - { "set-log-target", 2, 2, 0, verb_log_control }, - { "get-log-target", VERB_ANY, 1, 0, verb_log_control }, - { "service-watchdogs", VERB_ANY, 2, 0, verb_service_watchdogs }, + { "log-level", VERB_ANY, 2, 0, verb_log_control }, + { "log-target", VERB_ANY, 2, 0, verb_log_control }, + { "set-log-level", 2, 2, 0, verb_log_control }, + { "get-log-level", VERB_ANY, 1, 0, verb_log_control }, + { "set-log-target", 2, 2, 0, verb_log_control }, + { "get-log-target", VERB_ANY, 1, 0, verb_log_control }, + { "service-watchdogs", VERB_ANY, 2, 0, verb_service_watchdogs }, /* ↑ … until here ↑ */ - { "dump", VERB_ANY, VERB_ANY, 0, verb_dump }, - { "cat-config", 2, VERB_ANY, 0, verb_cat_config }, - { "unit-files", VERB_ANY, VERB_ANY, 0, verb_unit_files }, - { "unit-paths", 1, 1, 0, verb_unit_paths }, - { "exit-status", VERB_ANY, VERB_ANY, 0, verb_exit_status }, - { "syscall-filter", VERB_ANY, VERB_ANY, 0, verb_syscall_filters }, - { "capability", VERB_ANY, VERB_ANY, 0, verb_capabilities }, - { "filesystems", VERB_ANY, VERB_ANY, 0, verb_filesystems }, - { "condition", VERB_ANY, VERB_ANY, 0, verb_condition }, - { "compare-versions", 3, 4, 0, verb_compare_versions }, - { "verify", 2, VERB_ANY, 0, verb_verify }, - { "calendar", 2, VERB_ANY, 0, verb_calendar }, - { "timestamp", 2, VERB_ANY, 0, verb_timestamp }, - { "timespan", 2, VERB_ANY, 0, verb_timespan }, - { "security", VERB_ANY, VERB_ANY, 0, verb_security }, - { "inspect-elf", 2, VERB_ANY, 0, verb_elf_inspection }, - { "malloc", VERB_ANY, VERB_ANY, 0, verb_malloc }, - { "fdstore", 2, VERB_ANY, 0, verb_fdstore }, - { "image-policy", 2, 2, 0, verb_image_policy }, - { "has-tpm2", VERB_ANY, 1, 0, verb_has_tpm2 }, - { "pcrs", VERB_ANY, VERB_ANY, 0, verb_pcrs }, - { "srk", VERB_ANY, 1, 0, verb_srk }, - { "architectures", VERB_ANY, VERB_ANY, 0, verb_architectures }, - { "smbios11", VERB_ANY, 1, 0, verb_smbios11 }, - { "chid", VERB_ANY, VERB_ANY, 0, verb_chid }, + { "dump", VERB_ANY, VERB_ANY, 0, verb_dump }, + { "cat-config", 2, VERB_ANY, 0, verb_cat_config }, + { "unit-files", VERB_ANY, VERB_ANY, 0, verb_unit_files }, + { "unit-paths", 1, 1, 0, verb_unit_paths }, + { "exit-status", VERB_ANY, VERB_ANY, 0, verb_exit_status }, + { "syscall-filter", VERB_ANY, VERB_ANY, 0, verb_syscall_filters }, + { "capability", VERB_ANY, VERB_ANY, 0, verb_capabilities }, + { "filesystems", VERB_ANY, VERB_ANY, 0, verb_filesystems }, + { "condition", VERB_ANY, VERB_ANY, 0, verb_condition }, + { "compare-versions", 3, 4, 0, verb_compare_versions }, + { "verify", 2, VERB_ANY, 0, verb_verify }, + { "calendar", 2, VERB_ANY, 0, verb_calendar }, + { "timestamp", 2, VERB_ANY, 0, verb_timestamp }, + { "timespan", 2, VERB_ANY, 0, verb_timespan }, + { "security", VERB_ANY, VERB_ANY, 0, verb_security }, + { "inspect-elf", 2, VERB_ANY, 0, verb_elf_inspection }, + { "malloc", VERB_ANY, VERB_ANY, 0, verb_malloc }, + { "fdstore", 2, VERB_ANY, 0, verb_fdstore }, + { "image-policy", 2, 2, 0, verb_image_policy }, + { "has-tpm2", VERB_ANY, 1, 0, verb_has_tpm2 }, + { "pcrs", VERB_ANY, VERB_ANY, 0, verb_pcrs }, + { "srk", VERB_ANY, 1, 0, verb_srk }, + { "architectures", VERB_ANY, VERB_ANY, 0, verb_architectures }, + { "smbios11", VERB_ANY, 1, 0, verb_smbios11 }, + { "chid", VERB_ANY, VERB_ANY, 0, verb_chid }, + { "transient-settings", 2, VERB_ANY, 0, verb_transient_settings }, {} }; diff --git a/test/units/TEST-65-ANALYZE.sh b/test/units/TEST-65-ANALYZE.sh index ac4b220ed9..468c9ed093 100755 --- a/test/units/TEST-65-ANALYZE.sh +++ b/test/units/TEST-65-ANALYZE.sh @@ -1105,6 +1105,17 @@ else echo "have no tpm2" fi +# Test "transient-settings" verb + +# shellcheck disable=SC2046 +systemd-analyze --no-pager transient-settings $(systemctl --no-legend --no-pager -t help) +systemd-analyze transient-settings service | grep NoNewPrivileges +systemd-analyze transient-settings mount | grep CPUQuotaPeriodSec +# make sure deprecated names are not printed +(! systemd-analyze transient-settings service | grep CPUAccounting ) +(! systemd-analyze transient-settings service | grep ConditionKernelVersion ) +(! systemd-analyze transient-settings service | grep AssertKernelVersion ) + systemd-analyze log-level info touch /testok From 773cb7aa7ea2c930cd85ee128a8439cfd14ebb0d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Mon, 2 Jun 2025 15:15:38 +0200 Subject: [PATCH 62/64] docs/TRANSIENT-SETTINGS: update lists Those lists were partially wrong and partially outdated. We should generate this document automatically, but let's revisit this topic after the conversion to sphinx. For now, as a stop-gap solution, I generated the lists from the new 'systemd-analyze transient-settings' command. --- docs/TRANSIENT-SETTINGS.md | 403 ++++++++++++++++++++++--------------- 1 file changed, 238 insertions(+), 165 deletions(-) diff --git a/docs/TRANSIENT-SETTINGS.md b/docs/TRANSIENT-SETTINGS.md index 4992acbf67..d5c9a33df8 100644 --- a/docs/TRANSIENT-SETTINGS.md +++ b/docs/TRANSIENT-SETTINGS.md @@ -21,88 +21,131 @@ Most generic unit settings are available for transient units. ``` ✓ Description= -✓ Documentation= ✓ SourcePath= -✓ Requires= -✓ Requisite= -✓ Wants= -✓ BindsTo= -✓ Conflicts= -✓ Before= -✓ After= -✓ OnFailure= -✓ PropagatesReloadTo= -✓ ReloadPropagatedFrom= -✓ PartOf= -✓ Upholds= -✓ JoinsNamespaceOf= -✓ RequiresMountsFor= +✓ OnFailureJobMode= +✓ JobTimeoutAction= +✓ JobTimeoutRebootArgument= +✓ StartLimitAction= +✓ FailureAction= +✓ SuccessAction= +✓ RebootArgument= +✓ CollectMode= ✓ StopWhenUnneeded= ✓ RefuseManualStart= ✓ RefuseManualStop= ✓ AllowIsolate= -✓ DefaultDependencies= -✓ OnFailureJobMode= ✓ IgnoreOnIsolate= +✓ SurviveFinalKillSignal= +✓ DefaultDependencies= ✓ JobTimeoutSec= ✓ JobRunningTimeoutSec= -✓ JobTimeoutAction= -✓ JobTimeoutRebootArgument= ✓ StartLimitIntervalSec= ✓ StartLimitBurst= -✓ StartLimitAction= -✓ FailureAction= -✓ SuccessAction= -✓ FailureActionExitStatus= ✓ SuccessActionExitStatus= -✓ RebootArgument= +✓ FailureActionExitStatus= +✓ Documentation= +✓ RequiresMountsFor= +✓ WantsMountsFor= +✓ Markers= +✓ Requires= +✓ Requisite= +✓ Wants= +✓ BindsTo= +✓ PartOf= +✓ Upholds= +✓ RequiredBy= +✓ RequisiteOf= +✓ WantedBy= +✓ BoundBy= +✓ UpheldBy= +✓ ConsistsOf= +✓ Conflicts= +✓ ConflictedBy= +✓ Before= +✓ After= +✓ OnSuccess= +✓ OnSuccessOf= +✓ OnFailure= +✓ OnFailureOf= +✓ Triggers= +✓ TriggeredBy= +✓ PropagatesReloadTo= +✓ ReloadPropagatedFrom= +✓ PropagatesStopTo= +✓ StopPropagatedFrom= +✓ JoinsNamespaceOf= +✓ References= +✓ ReferencedBy= +✓ InSlice= +✓ SliceOf= +✓ ConditionArchitecture= +✓ ConditionFirmware= +✓ ConditionVirtualization= +✓ ConditionHost= +✓ ConditionKernelCommandLine= +✓ ConditionVersion= +✓ ConditionCredential= +✓ ConditionSecurity= +✓ ConditionCapability= +✓ ConditionACPower= +✓ ConditionNeedsUpdate= +✓ ConditionFirstBoot= ✓ ConditionPathExists= ✓ ConditionPathExistsGlob= ✓ ConditionPathIsDirectory= ✓ ConditionPathIsSymbolicLink= ✓ ConditionPathIsMountPoint= ✓ ConditionPathIsReadWrite= +✓ ConditionPathIsEncrypted= ✓ ConditionDirectoryNotEmpty= ✓ ConditionFileNotEmpty= ✓ ConditionFileIsExecutable= -✓ ConditionNeedsUpdate= -✓ ConditionFirstBoot= -✓ ConditionKernelCommandLine= -✓ ConditionKernelVersion= -✓ ConditionVersion= -✓ ConditionArchitecture= -✓ ConditionFirmware= -✓ ConditionVirtualization= -✓ ConditionSecurity= -✓ ConditionCapability= -✓ ConditionHost= -✓ ConditionACPower= ✓ ConditionUser= ✓ ConditionGroup= ✓ ConditionControlGroupController= +✓ ConditionCPUs= +✓ ConditionMemory= +✓ ConditionEnvironment= +✓ ConditionCPUFeature= +✓ ConditionOSRelease= +✓ ConditionMemoryPressure= +✓ ConditionCPUPressure= +✓ ConditionIOPressure= +✓ ConditionKernelModuleLoaded= +✓ AssertArchitecture= +✓ AssertFirmware= +✓ AssertVirtualization= +✓ AssertHost= +✓ AssertKernelCommandLine= +✓ AssertVersion= +✓ AssertCredential= +✓ AssertSecurity= +✓ AssertCapability= +✓ AssertACPower= +✓ AssertNeedsUpdate= +✓ AssertFirstBoot= ✓ AssertPathExists= ✓ AssertPathExistsGlob= ✓ AssertPathIsDirectory= ✓ AssertPathIsSymbolicLink= ✓ AssertPathIsMountPoint= ✓ AssertPathIsReadWrite= +✓ AssertPathIsEncrypted= ✓ AssertDirectoryNotEmpty= ✓ AssertFileNotEmpty= ✓ AssertFileIsExecutable= -✓ AssertNeedsUpdate= -✓ AssertFirstBoot= -✓ AssertKernelCommandLine= -✓ AssertKernelVersion= -✓ AssertArchitecture= -✓ AssertVirtualization= -✓ AssertSecurity= -✓ AssertCapability= -✓ AssertHost= -✓ AssertACPower= ✓ AssertUser= ✓ AssertGroup= ✓ AssertControlGroupController= -✓ CollectMode= +✓ AssertCPUs= +✓ AssertMemory= +✓ AssertEnvironment= +✓ AssertCPUFeature= +✓ AssertOSRelease= +✓ AssertMemoryPressure= +✓ AssertCPUPressure= +✓ AssertIOPressure= +✓ AssertKernelModuleLoaded= ``` ## Execution-Related Settings @@ -236,55 +279,58 @@ All execution-related settings are available for transient units. All cgroup/resource control settings are available for transient units ``` -✓ CPUAccounting= +✓ DevicePolicy= +✓ Slice= +✓ ManagedOOMSwap= +✓ ManagedOOMMemoryPressure= +✓ ManagedOOMPreference= +✓ MemoryPressureWatch= +✓ DelegateSubgroup= +✓ ManagedOOMMemoryPressureLimit= +✓ MemoryAccounting= +✓ MemoryZSwapWriteback= +✓ IOAccounting= +✓ TasksAccounting= +✓ IPAccounting= +✓ CoredumpReceive= ✓ CPUWeight= ✓ StartupCPUWeight= -✓ CPUShares= -✓ StartupCPUShares= -✓ CPUQuota= -✓ CPUQuotaPeriodSec= +✓ IOWeight= +✓ StartupIOWeight= ✓ AllowedCPUs= ✓ StartupAllowedCPUs= ✓ AllowedMemoryNodes= ✓ StartupAllowedMemoryNodes= -✓ MemoryAccounting= -✓ DefaultMemoryMin= +✓ DisableControllers= +✓ Delegate= ✓ MemoryMin= ✓ DefaultMemoryLow= +✓ DefaultMemoryMin= ✓ MemoryLow= ✓ MemoryHigh= ✓ MemoryMax= ✓ MemorySwapMax= -✓ MemoryLimit= +✓ MemoryZSwapMax= +✓ TasksMax= +✓ CPUQuota= +✓ CPUQuotaPeriodSec= ✓ DeviceAllow= -✓ DevicePolicy= -✓ IOAccounting= -✓ IOWeight= -✓ StartupIOWeight= ✓ IODeviceWeight= +✓ IODeviceLatencyTargetSec= +✓ IPAddressAllow= +✓ IPAddressDeny= +✓ IPIngressFilterPath= +✓ IPEgressFilterPath= +✓ BPFProgram= +✓ SocketBindAllow= +✓ SocketBindDeny= +✓ MemoryPressureThresholdSec= +✓ NFTSet= +✓ ManagedOOMMemoryPressureDurationSec= ✓ IOReadBandwidthMax= ✓ IOWriteBandwidthMax= ✓ IOReadIOPSMax= ✓ IOWriteIOPSMax= -✓ BlockIOAccounting= -✓ BlockIOWeight= -✓ StartupBlockIOWeight= -✓ BlockIODeviceWeight= -✓ BlockIOReadBandwidth= -✓ BlockIOWriteBandwidth= -✓ TasksAccounting= -✓ TasksMax= -✓ Delegate= -✓ DisableControllers= -✓ IPAccounting= -✓ IPAddressAllow= -✓ IPAddressDeny= -✓ ManagedOOMSwap= -✓ ManagedOOMMemoryPressure= -✓ ManagedOOMMemoryPressureLimit= -✓ ManagedOOMMemoryPressureDurationSec= -✓ ManagedOOMPreference= -✓ CoredumpReceive= ``` ## Process Killing Settings @@ -292,13 +338,14 @@ All cgroup/resource control settings are available for transient units All process killing settings are available for transient units: ``` -✓ SendSIGKILL= -✓ SendSIGHUP= ✓ KillMode= +✓ SendSIGHUP= +✓ SendSIGKILL= ✓ KillSignal= ✓ RestartKillSignal= ✓ FinalKillSignal= ✓ WatchdogSignal= +✓ ReloadSignal= ``` ## Service Unit Settings @@ -306,41 +353,53 @@ All process killing settings are available for transient units: Most service unit settings are available for transient units. ``` -✓ BusName= -✓ ExecCondition= -✓ ExecReload= -✓ ExecStart= -✓ ExecStartPost= -✓ ExecStartPre= -✓ ExecStop= -✓ ExecStopPost= -✓ ExitType= -✓ FileDescriptorStoreMax= -✓ GuessMainPID= -✓ NonBlocking= -✓ NotifyAccess= -✓ OOMPolicy= ✓ PIDFile= -✓ RemainAfterExit= -✓ Restart= -✓ RestartForceExitStatus= -✓ RestartPreventExitStatus= -✓ RestartSec= -✓ RootDirectoryStartOnly= -✓ RuntimeMaxSec= -✓ RuntimeRandomizedExtraSec= - Sockets= -✓ SuccessExitStatus= -✓ TimeoutAbortSec= -✓ TimeoutSec= -✓ TimeoutStartFailureMode= -✓ TimeoutStartSec= -✓ TimeoutStopFailureMode= -✓ TimeoutStopSec= ✓ Type= +✓ ExitType= +✓ Restart= +✓ RestartMode= +✓ BusName= +✓ NotifyAccess= ✓ USBFunctionDescriptors= ✓ USBFunctionStrings= +✓ OOMPolicy= +✓ TimeoutStartFailureMode= +✓ TimeoutStopFailureMode= +✓ FileDescriptorStorePreserve= +✓ PermissionsStartOnly= +✓ RootDirectoryStartOnly= +✓ RemainAfterExit= +✓ GuessMainPID= +✓ RestartSec= +✓ RestartMaxDelaySec= +✓ TimeoutStartSec= +✓ TimeoutStopSec= +✓ TimeoutAbortSec= +✓ RuntimeMaxSec= +✓ RuntimeRandomizedExtraSec= ✓ WatchdogSec= +✓ TimeoutSec= +✓ FileDescriptorStoreMax= +✓ RestartSteps= +✓ ExecCondition= +✓ ExecStartPre= +✓ ExecStart= +✓ ExecStartPost= +✓ ExecConditionEx= +✓ ExecStartPreEx= +✓ ExecStartEx= +✓ ExecStartPostEx= +✓ ExecReload= +✓ ExecStop= +✓ ExecStopPost= +✓ ExecReloadEx= +✓ ExecStopEx= +✓ ExecStopPostEx= +✓ RestartPreventExitStatus= +✓ RestartForceExitStatus= +✓ SuccessExitStatus= +✓ OpenFile= + Socket= ``` ## Mount Unit Settings @@ -357,7 +416,7 @@ All mount unit settings are available to transient units: ✓ SloppyOptions= ✓ LazyUnmount= ✓ ForceUnmount= -✓ ReadWriteOnly= +✓ ReadwriteOnly= ``` ## Automount Unit Settings @@ -366,6 +425,7 @@ All automount unit setting is available to transient units: ``` ✓ Where= +✓ ExtraOptions= ✓ DirectoryMode= ✓ TimeoutIdleSec= ``` @@ -375,21 +435,21 @@ All automount unit setting is available to transient units: Most timer unit settings are available to transient units. ``` -✓ OnActiveSec= -✓ OnBootSec= -✓ OnCalendar= -✓ OnClockChange= -✓ OnStartupSec= -✓ OnTimezoneChange= -✓ OnUnitActiveSec= -✓ OnUnitInactiveSec= -✓ Persistent= ✓ WakeSystem= ✓ RemainAfterElapse= -✓ AccuracySec= -✓ RandomizedDelaySec= +✓ Persistent= +✓ OnTimezoneChange= +✓ OnClockChange= ✓ FixedRandomDelay= ✓ DeferReactivation= +✓ AccuracySec= +✓ RandomizedDelaySec= +✓ OnActiveSec= +✓ OnBootSec= +✓ OnStartupSec= +✓ OnUnitActiveSec= +✓ OnUnitInactiveSec= +✓ OnCalendar= Unit= ``` @@ -407,6 +467,9 @@ such). ✓ RuntimeMaxSec= ✓ RuntimeRandomizedExtraSec= ✓ TimeoutStopSec= +✓ User= +✓ Group= +✓ OOMPolicy= ``` ## Socket Unit Settings @@ -414,65 +477,71 @@ such). Most socket unit settings are available to transient units. ``` -✓ ListenStream= -✓ ListenDatagram= -✓ ListenSequentialPacket= -✓ ListenFIFO= -✓ ListenNetlink= -✓ ListenSpecial= -✓ ListenMessageQueue= -✓ ListenUSBFunction= -✓ SocketProtocol= -✓ BindIPv6Only= -✓ Backlog= -✓ BindToDevice= -✓ ExecStartPre= -✓ ExecStartPost= -✓ ExecStopPre= -✓ ExecStopPost= -✓ TimeoutSec= -✓ SocketUser= -✓ SocketGroup= -✓ SocketMode= -✓ DirectoryMode= ✓ Accept= ✓ FlushPending= ✓ Writable= -✓ MaxConnections= -✓ MaxConnectionsPerSource= ✓ KeepAlive= -✓ KeepAliveTimeSec= -✓ KeepAliveIntervalSec= -✓ KeepAliveProbes= -✓ DeferAcceptSec= ✓ NoDelay= -✓ Priority= -✓ ReceiveBuffer= -✓ SendBuffer= -✓ IPTOS= -✓ IPTTL= -✓ Mark= -✓ PipeSize= ✓ FreeBind= ✓ Transparent= ✓ Broadcast= ✓ PassCredentials= +✓ PassFileDescriptorsToExec= ✓ PassSecurity= ✓ PassPacketInfo= -✓ TCPCongestion= ✓ ReusePort= +✓ RemoveOnStop= +✓ SELinuxContextFromNet= +✓ Priority= +✓ IPTTL= +✓ Mark= +✓ IPTOS= +✓ Backlog= +✓ MaxConnections= +✓ MaxConnectionsPerSource= +✓ KeepAliveProbes= +✓ TriggerLimitBurst= +✓ PollLimitBurst= +✓ SocketMode= +✓ DirectoryMode= ✓ MessageQueueMaxMessages= ✓ MessageQueueMessageSize= -✓ RemoveOnStop= -✓ Symlinks= -✓ FileDescriptorName= - Service= +✓ TimeoutSec= +✓ KeepAliveTimeSec= +✓ KeepAliveIntervalSec= +✓ DeferAcceptSec= +✓ DeferTrigger= +✓ DeferTriggerMaxSec= ✓ TriggerLimitIntervalSec= -✓ TriggerLimitBurst= +✓ PollLimitIntervalSec= +✓ ReceiveBuffer= +✓ SendBuffer= +✓ PipeSize= +✓ ExecStartPre= +✓ ExecStartPost= +✓ ExecReload= +✓ ExecStopPost= ✓ SmackLabel= ✓ SmackLabelIPIn= ✓ SmackLabelIPOut= -✓ SELinuxContextFromNet= +✓ TCPCongestion= +✓ BindToDevice= +✓ BindIPv6Only= +✓ FileDescriptorName= +✓ SocketUser= +✓ SocketGroup= +✓ Timestamping= +✓ Symlinks= +✓ SocketProtocol= +✓ ListenStream= +✓ ListenDatagram= +✓ ListenSequentialPacket= +✓ ListenNetlink= +✓ ListenSpecial= +✓ ListenMessageQueue= +✓ ListenFIFO= +✓ ListenUSBFunction= + Service= ``` ## Swap Unit Settings @@ -491,14 +560,18 @@ Swap units are currently not available at all as transient units: Most path unit settings are available to transient units. ``` +✓ MakeDirectory= +✓ DirectoryMode= ✓ PathExists= ✓ PathExistsGlob= ✓ PathChanged= ✓ PathModified= ✓ DirectoryNotEmpty= +✓ TriggerLimitBurst= +✓ PollLimitBurst= +✓ TriggerLimitIntervalSec= +✓ PollLimitIntervalSec= Unit= -✓ MakeDirectory= -✓ DirectoryMode= ``` ## Install Section From d971936bf4c39259774e363148c80dea5c93243d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Mon, 2 Jun 2025 20:42:54 +0200 Subject: [PATCH 63/64] shell-completions: add systemd-analyze transient-settings The zsh completions only complete one type argument, even though multiple args are allowed. But the same issue occurs with other completions, e.g. for options. I don't know how to solve this. --- shell-completion/bash/systemd-analyze | 8 ++++++++ shell-completion/zsh/_systemd-analyze | 8 ++++++++ 2 files changed, 16 insertions(+) diff --git a/shell-completion/bash/systemd-analyze b/shell-completion/bash/systemd-analyze index 41a2151e12..e4ecafeddc 100644 --- a/shell-completion/bash/systemd-analyze +++ b/shell-completion/bash/systemd-analyze @@ -81,6 +81,7 @@ _systemd_analyze() { [ARCHITECTURES]='architectures' [FDSTORE]='fdstore' [CAPABILITY]='capability' + [TRANSIENT_SETTINGS]='transient-settings' ) local CONFIGS='locale.conf systemd/bootchart.conf systemd/coredump.conf systemd/journald.conf @@ -225,6 +226,13 @@ _systemd_analyze() { if [[ $cur = -* ]]; then comps='--help --version --no-pager --json=off --json=pretty --json=short -m --mask' fi + + elif __contains_word "$verb" ${VERBS[TRANSIENT_SETTINGS]}; then + if [[ $cur = -* ]]; then + comps='--help --version --no-pager' + else + comps="$(systemctl --no-legend --no-pager -t help)" + fi fi COMPREPLY=( $(compgen -W '$comps' -- "$cur") ) diff --git a/shell-completion/zsh/_systemd-analyze b/shell-completion/zsh/_systemd-analyze index 50542b3962..e03ae31afd 100644 --- a/shell-completion/zsh/_systemd-analyze +++ b/shell-completion/zsh/_systemd-analyze @@ -47,6 +47,13 @@ _describe 'plot options' _options } +(( $+functions[_systemd-analyze_transient-settings] )) || + _systemd-analyze_transient-settings() { + local -a _types + _types=( $(systemctl --no-pager --no-legend -t help) ) + _describe -t types 'unit types' _types + } + (( $+functions[_systemd-analyze_commands] )) || _systemd-analyze_commands(){ local -a _systemd_analyze_cmds @@ -74,6 +81,7 @@ JSON or table format' 'security:Analyze security settings of a service' 'inspect-elf:Parse and print ELF package metadata' 'has-tpm2:Report whether TPM2 support is available' + 'transient-settings:List transient settings for unit types' # log-level, log-target, service-watchdogs have been deprecated ) From 01383af1c12bb4b89d24b783ec54dcf1cf4cbb9f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Tue, 1 Jul 2025 09:51:00 +0200 Subject: [PATCH 64/64] shared/bus-unit-util: stop unsing strndupa Those are user-controlled strings, so let's use heap allocations in the usual fashion. (Though, with strndupa_safe, the allocations were bounded anyway, so ultimately this doesn't matter.) --- src/shared/bus-unit-util.c | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c index dafe652b56..c5e02a912f 100644 --- a/src/shared/bus-unit-util.c +++ b/src/shared/bus-unit-util.c @@ -395,11 +395,15 @@ static int bus_append_parse_device_allow(sd_bus_message *m, const char *field, c if (isempty(eq)) r = sd_bus_message_append(m, "(sv)", field, "a(ss)", 0); else { + _cleanup_free_ char *_path = NULL; const char *path = eq, *rwm = NULL, *e; e = strchr(eq, ' '); if (e) { - path = strndupa_safe(eq, e - eq); + path = _path = strndup(eq, e - eq); + if (!path) + return log_oom(); + rwm = e + 1; } @@ -426,8 +430,10 @@ static int bus_try_append_parse_cgroup_io_limit(sd_bus_message *m, const char *f "Failed to parse %s value %s.", field, eq); - const char *path = strndupa_safe(eq, e - eq); const char *bandwidth = e + 1; + _cleanup_free_ char *path = strndup(eq, e - eq); + if (!path) + return log_oom(); uint64_t bytes; if (streq(bandwidth, "infinity")) @@ -458,8 +464,10 @@ static int bus_append_parse_io_device_weight(sd_bus_message *m, const char *fiel "Failed to parse %s value %s.", field, eq); - const char *path = strndupa_safe(eq, e - eq); const char *weight = e + 1; + _cleanup_free_ char *path = strndup(eq, e - eq); + if (!path) + return log_oom(); uint64_t u; r = safe_atou64(weight, &u); @@ -487,8 +495,10 @@ static int bus_append_parse_io_device_latency(sd_bus_message *m, const char *fie "Failed to parse %s value %s.", field, eq); - const char *path = strndupa_safe(eq, e - eq); const char *target = e + 1; + _cleanup_free_ char *path = strndup(eq, e - eq); + if (!path) + return log_oom(); usec_t usec; r = parse_sec(target, &usec); @@ -2820,7 +2830,8 @@ static const BusProperty** unit_type_properties[_UNIT_TYPE_MAX] = { }; int bus_append_unit_property_assignment(sd_bus_message *m, UnitType t, const char *assignment) { - const char *eq, *field; + _cleanup_free_ char *field = NULL; + const char *eq; int r; assert(m); @@ -2832,7 +2843,10 @@ int bus_append_unit_property_assignment(sd_bus_message *m, UnitType t, const cha return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Not an assignment: %s", assignment); - field = strndupa_safe(assignment, eq - assignment); + + field = strndup(assignment, eq - assignment); + if (!field) + return log_oom(); eq++; for (const BusProperty** tables = ASSERT_PTR(unit_type_properties[t]); *tables; tables++)