From e0fb180483301883bb80ff53606e9885a3ca3151 Mon Sep 17 00:00:00 2001 From: Mike Yuan Date: Mon, 16 Feb 2026 06:18:09 +0100 Subject: [PATCH 01/30] backlight: update comment to match the new clamp value Follow-up for 4ed1e2ea17e0f29a23d7a3dd65af192def9b3214 --- src/backlight/backlight.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/backlight/backlight.c b/src/backlight/backlight.c index 0ef362813f..15e0d17b8d 100644 --- a/src/backlight/backlight.c +++ b/src/backlight/backlight.c @@ -348,8 +348,8 @@ static int clamp_brightness( assert(brightness); /* Some systems turn the backlight all the way off at the lowest levels. This clamps the saved - * brightness to at least 1 or 5% of max_brightness in case of 'backlight' subsystem. This - * avoids preserving an unreadably dim screen, which would otherwise force the user to disable + * brightness to at least 1 or 1% of max_brightness (whichever is bigger) in case of 'backlight' subsystem. + * This avoids preserving an unreadably dim screen, which would otherwise force the user to disable * state restoration. */ min_brightness = (unsigned) ((double) max_brightness * percent / 100); From 763f615c3aaf8ab89b98186cf3c7c292bf31a54c Mon Sep 17 00:00:00 2001 From: Mike Yuan Date: Sun, 15 Feb 2026 00:39:05 +0100 Subject: [PATCH 02/30] log-context: drop redundant forward decl We consolidated all these into forward.h. --- src/basic/log-context.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/basic/log-context.h b/src/basic/log-context.h index ccff2eb572..ca112fa862 100644 --- a/src/basic/log-context.h +++ b/src/basic/log-context.h @@ -32,8 +32,6 @@ * message. */ -struct iovec; - typedef struct LogContext { unsigned n_ref; /* Depending on which destructor is used (log_context_free() or log_context_detach()) the memory From 36f82366d0fceb1709b04eed000d837fe73591ed Mon Sep 17 00:00:00 2001 From: Mike Yuan Date: Sun, 15 Feb 2026 00:21:34 +0100 Subject: [PATCH 03/30] process-util: group oom_score_adjust_is_valid() with getter/setter --- src/basic/process-util.c | 8 ++++---- src/basic/process-util.h | 3 +-- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/src/basic/process-util.c b/src/basic/process-util.c index 52af6a01c8..640aa77d6c 100644 --- a/src/basic/process-util.c +++ b/src/basic/process-util.c @@ -1128,10 +1128,6 @@ bool is_main_thread(void) { return cached; } -bool oom_score_adjust_is_valid(int oa) { - return oa >= OOM_SCORE_ADJ_MIN && oa <= OOM_SCORE_ADJ_MAX; -} - unsigned long personality_from_string(const char *s) { Architecture architecture; @@ -1887,6 +1883,10 @@ int namespace_fork_full( return 1; } +bool oom_score_adjust_is_valid(int oa) { + return oa >= OOM_SCORE_ADJ_MIN && oa <= OOM_SCORE_ADJ_MAX; +} + int set_oom_score_adjust(int value) { char t[DECIMAL_STR_MAX(int)]; diff --git a/src/basic/process-util.h b/src/basic/process-util.h index 66bb194bac..40ce50d125 100644 --- a/src/basic/process-util.h +++ b/src/basic/process-util.h @@ -87,8 +87,6 @@ int pidref_from_same_root_fs(PidRef *a, PidRef *b); bool is_main_thread(void); -bool oom_score_adjust_is_valid(int oa); - #ifndef PERSONALITY_INVALID /* personality(2) documents that 0xFFFFFFFFUL is used for querying the * current personality, hence let's use that here as error @@ -220,6 +218,7 @@ static inline int namespace_fork( ret); } +bool oom_score_adjust_is_valid(int oa); int set_oom_score_adjust(int value); int get_oom_score_adjust(int *ret); From 3ac675dff369d81df7bbc463ab960c9433608832 Mon Sep 17 00:00:00 2001 From: Mike Yuan Date: Sun, 15 Feb 2026 00:25:42 +0100 Subject: [PATCH 04/30] process-util: drop unused TAKE_PID Follow-up for fbd276cb86a2f0292cc19fd57ee3d72bf73592dc We now track helper processes via PidRef throughout the codebase. --- src/basic/process-util.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/basic/process-util.h b/src/basic/process-util.h index 40ce50d125..85fe81c617 100644 --- a/src/basic/process-util.h +++ b/src/basic/process-util.h @@ -234,9 +234,6 @@ int get_oom_score_adjust(int *ret); assert_cc(TASKS_MAX <= (unsigned long) PID_T_MAX); -/* Like TAKE_PTR() but for pid_t, resetting them to 0 */ -#define TAKE_PID(pid) TAKE_GENERIC(pid, pid_t, 0) - int setpriority_closest(int priority); _noreturn_ void freeze(void); From 89769fb4ad1b101eea6dd2fb2ac940c862dcdb62 Mon Sep 17 00:00:00 2001 From: Mike Yuan Date: Mon, 16 Feb 2026 02:50:29 +0100 Subject: [PATCH 05/30] shared: conditionalize build of apparmor-util.c in meson --- src/shared/apparmor-util.c | 3 --- src/shared/meson.build | 5 ++++- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/shared/apparmor-util.c b/src/shared/apparmor-util.c index 22e7d2d90d..10b57c6090 100644 --- a/src/shared/apparmor-util.c +++ b/src/shared/apparmor-util.c @@ -1,7 +1,5 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ -#if HAVE_APPARMOR - #include #include "alloc-util.h" @@ -67,4 +65,3 @@ bool mac_apparmor_use(void) { return (cached_use = true); } -#endif diff --git a/src/shared/meson.build b/src/shared/meson.build index fea5e22109..b9630bef65 100644 --- a/src/shared/meson.build +++ b/src/shared/meson.build @@ -3,7 +3,6 @@ shared_sources = files( 'acl-util.c', 'acpi-fpdt.c', - 'apparmor-util.c', 'ask-password-agent.c', 'ask-password-api.c', 'async.c', @@ -279,6 +278,10 @@ if conf.get('HAVE_LIBIDN2') == 1 shared_sources += files('idn-util.c') endif +if conf.get('HAVE_APPARMOR') == 1 + shared_sources += files('apparmor-util.c') +endif + generate_ip_protocol_list = files('generate-ip-protocol-list.sh') ip_protocol_list_txt = custom_target( input : [generate_ip_protocol_list, ipproto_sources], From daeb7dd390fc32005c20bb27729d838b68fe1e37 Mon Sep 17 00:00:00 2001 From: Mike Yuan Date: Sun, 15 Feb 2026 01:45:50 +0100 Subject: [PATCH 06/30] sd-json: use FOREACH_ARRAY more --- src/libsystemd/sd-json/sd-json.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/libsystemd/sd-json/sd-json.c b/src/libsystemd/sd-json/sd-json.c index c0067cb40b..3278fba6a8 100644 --- a/src/libsystemd/sd-json/sd-json.c +++ b/src/libsystemd/sd-json/sd-json.c @@ -3370,8 +3370,8 @@ done: r = 0; finish: - for (size_t i = 0; i < n_stack; i++) - json_stack_release(stack + i); + FOREACH_ARRAY(i, stack, n_stack) + json_stack_release(i); free(stack); @@ -5227,8 +5227,8 @@ done: r = 0; finish: - for (size_t i = 0; i < n_stack; i++) - json_stack_release(stack + i); + FOREACH_ARRAY(i, stack, n_stack) + json_stack_release(i); free(stack); From 926ae62a27e09de3d65ee99d424e1597a9c8332a Mon Sep 17 00:00:00 2001 From: Mike Yuan Date: Sun, 8 Feb 2026 17:12:21 +0100 Subject: [PATCH 07/30] json-util: sort includes --- src/libsystemd/sd-json/json-util.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libsystemd/sd-json/json-util.h b/src/libsystemd/sd-json/json-util.h index 334a2506dc..3d7d37a30c 100644 --- a/src/libsystemd/sd-json/json-util.h +++ b/src/libsystemd/sd-json/json-util.h @@ -5,8 +5,8 @@ #include "sd-json.h" -#include "sd-forward.h" #include "log.h" +#include "sd-forward.h" #include "string-util.h" /* IWYU pragma: keep */ #define JSON_VARIANT_REPLACE(v, q) \ From 05d1cfee9009aa46126a92a259e7050f8459397f Mon Sep 17 00:00:00 2001 From: Mike Yuan Date: Sun, 15 Feb 2026 02:06:19 +0100 Subject: [PATCH 08/30] sd-json: unify JSON_BUILD_PAIR_IN?_ADDR_* This also swaps family and address params for plain JSON_BUILD(_PAIR)_IN_ADDR, aligning with _WITH_STRING flavors. --- src/core/varlink-cgroup.c | 2 +- src/libsystemd/sd-json/json-util.h | 32 ++- src/libsystemd/sd-json/sd-json.c | 300 ++++------------------------- src/network/networkd-json.c | 6 +- src/resolve/resolved-dns-server.c | 2 +- 5 files changed, 57 insertions(+), 285 deletions(-) diff --git a/src/core/varlink-cgroup.c b/src/core/varlink-cgroup.c index ffa3b7ca6d..2e0c086f95 100644 --- a/src/core/varlink-cgroup.c +++ b/src/core/varlink-cgroup.c @@ -112,7 +112,7 @@ static int ip_address_access_build_json(sd_json_variant **ret, const char *name, r = sd_json_variant_append_arraybo( &v, SD_JSON_BUILD_PAIR_INTEGER("family", i->family), - JSON_BUILD_PAIR_IN_ADDR("address", &i->address, i->family), + JSON_BUILD_PAIR_IN_ADDR("address", i->family, &i->address), SD_JSON_BUILD_PAIR_UNSIGNED("prefixLength", i->prefixlen)); if (r < 0) return r; diff --git a/src/libsystemd/sd-json/json-util.h b/src/libsystemd/sd-json/json-util.h index 3d7d37a30c..5365eedcae 100644 --- a/src/libsystemd/sd-json/json-util.h +++ b/src/libsystemd/sd-json/json-util.h @@ -175,9 +175,9 @@ enum { _JSON_BUILD_PAIR_VARIANT_NON_EMPTY, /* _SD_JSON_BUILD_PAIR_VARIANT_ARRAY_NON_EMPTY, */ _JSON_BUILD_PAIR_BYTE_ARRAY_NON_EMPTY, - _JSON_BUILD_PAIR_IN4_ADDR_NON_NULL, - _JSON_BUILD_PAIR_IN6_ADDR_NON_NULL, _JSON_BUILD_PAIR_IN_ADDR_NON_NULL, + _JSON_BUILD_PAIR_IN_ADDR_WITH_STRING, + _JSON_BUILD_PAIR_IN_ADDR_WITH_STRING_NON_NULL, _JSON_BUILD_PAIR_ETHER_ADDR_NON_NULL, _JSON_BUILD_PAIR_HW_ADDR_NON_NULL, _JSON_BUILD_PAIR_DUAL_TIMESTAMP_NON_NULL, @@ -190,12 +190,6 @@ enum { _JSON_BUILD_PAIR_TRISTATE_NON_NULL, _JSON_BUILD_PAIR_PIDREF_NON_NULL, _JSON_BUILD_PAIR_DEVNUM, - _JSON_BUILD_PAIR_IN_ADDR_WITH_STRING, - _JSON_BUILD_PAIR_IN6_ADDR_WITH_STRING, - _JSON_BUILD_PAIR_IN4_ADDR_WITH_STRING, - _JSON_BUILD_PAIR_IN_ADDR_WITH_STRING_NON_NULL, - _JSON_BUILD_PAIR_IN6_ADDR_WITH_STRING_NON_NULL, - _JSON_BUILD_PAIR_IN4_ADDR_WITH_STRING_NON_NULL, _SD_JSON_BUILD_REALLYMAX, }; @@ -206,7 +200,7 @@ enum { #define JSON_BUILD_CONST_STRING(s) _SD_JSON_BUILD_VARIANT, JSON_VARIANT_STRING_CONST(s) #define JSON_BUILD_IN4_ADDR(v) SD_JSON_BUILD_BYTE_ARRAY((const struct in_addr*) { v }, sizeof(struct in_addr)) #define JSON_BUILD_IN6_ADDR(v) SD_JSON_BUILD_BYTE_ARRAY((const struct in6_addr*) { v }, sizeof(struct in6_addr)) -#define JSON_BUILD_IN_ADDR(v, f) SD_JSON_BUILD_BYTE_ARRAY(((const union in_addr_union*) { v })->bytes, FAMILY_ADDRESS_SIZE_SAFE(f)) +#define JSON_BUILD_IN_ADDR(f, v) SD_JSON_BUILD_BYTE_ARRAY(((const union in_addr_union*) { v })->bytes, FAMILY_ADDRESS_SIZE_SAFE(f)) #define JSON_BUILD_ETHER_ADDR(v) SD_JSON_BUILD_BYTE_ARRAY(((const struct ether_addr*) { v })->ether_addr_octet, sizeof(struct ether_addr)) #define JSON_BUILD_HW_ADDR(v) _JSON_BUILD_HW_ADDR, (const struct hw_addr_data*) { v } #define JSON_BUILD_STRING_SET(s) _JSON_BUILD_STRING_SET, (Set *) { s } @@ -229,9 +223,15 @@ enum { #define JSON_BUILD_PAIR_VARIANT_NON_NULL(name, v) _JSON_BUILD_PAIR_VARIANT_NON_NULL, (const char*) { name }, (sd_json_variant*) { v } #define JSON_BUILD_PAIR_VARIANT_NON_EMPTY(name, v) _JSON_BUILD_PAIR_VARIANT_NON_EMPTY, (const char*) { name }, (sd_json_variant*) { v } #define JSON_BUILD_PAIR_BYTE_ARRAY_NON_EMPTY(name, v, n) _JSON_BUILD_PAIR_BYTE_ARRAY_NON_EMPTY, (const char*) { name }, (const void*) { v }, (size_t) { n } -#define JSON_BUILD_PAIR_IN4_ADDR_NON_NULL(name, v) _JSON_BUILD_PAIR_IN4_ADDR_NON_NULL, (const char*) { name }, (const struct in_addr*) { v } -#define JSON_BUILD_PAIR_IN6_ADDR_NON_NULL(name, v) _JSON_BUILD_PAIR_IN6_ADDR_NON_NULL, (const char*) { name }, (const struct in6_addr*) { v } -#define JSON_BUILD_PAIR_IN_ADDR_NON_NULL(name, v, f) _JSON_BUILD_PAIR_IN_ADDR_NON_NULL, (const char*) { name }, (const union in_addr_union*) { v }, (int) { f } +#define JSON_BUILD_PAIR_IN_ADDR_NON_NULL(name, f, v) _JSON_BUILD_PAIR_IN_ADDR_NON_NULL, (const char*) { name }, (int) { f }, (const union in_addr_union*) { v } +#define JSON_BUILD_PAIR_IN4_ADDR_NON_NULL(name, v) _JSON_BUILD_PAIR_IN_ADDR_NON_NULL, (const char*) { name }, AF_INET, &(union in_addr_union) { .in = *(v) } +#define JSON_BUILD_PAIR_IN6_ADDR_NON_NULL(name, v) _JSON_BUILD_PAIR_IN_ADDR_NON_NULL, (const char*) { name }, AF_INET6, &(union in_addr_union) { .in6 = *(v) } +#define JSON_BUILD_PAIR_IN_ADDR_WITH_STRING(name, f, v) _JSON_BUILD_PAIR_IN_ADDR_WITH_STRING, (const char*) { name }, (int) { f }, (const union in_addr_union*) { v } +#define JSON_BUILD_PAIR_IN4_ADDR_WITH_STRING(name, v) _JSON_BUILD_PAIR_IN_ADDR_WITH_STRING, (const char*) { name }, AF_INET, &(union in_addr_union) { .in = *(v) } +#define JSON_BUILD_PAIR_IN6_ADDR_WITH_STRING(name, v) _JSON_BUILD_PAIR_IN_ADDR_WITH_STRING, (const char*) { name }, AF_INET6, &(union in_addr_union) { .in6 = *(v) } +#define JSON_BUILD_PAIR_IN_ADDR_WITH_STRING_NON_NULL(name, f, v) _JSON_BUILD_PAIR_IN_ADDR_WITH_STRING_NON_NULL, (const char*) { name }, (int) { f }, (const union in_addr_union*) { v } +#define JSON_BUILD_PAIR_IN4_ADDR_WITH_STRING_NON_NULL(name, v) _JSON_BUILD_PAIR_IN_ADDR_WITH_STRING_NON_NULL, (const char*) { name }, AF_INET, &(union in_addr_union) { .in = *(v) } +#define JSON_BUILD_PAIR_IN6_ADDR_WITH_STRING_NON_NULL(name, v) _JSON_BUILD_PAIR_IN_ADDR_WITH_STRING_NON_NULL, (const char*) { name }, AF_INET6, &(union in_addr_union) { .in6 = *(v) } #define JSON_BUILD_PAIR_ETHER_ADDR_NON_NULL(name, v) _JSON_BUILD_PAIR_ETHER_ADDR_NON_NULL, (const char*) { name }, (const struct ether_addr*) { v } #define JSON_BUILD_PAIR_HW_ADDR_NON_NULL(name, v) _JSON_BUILD_PAIR_HW_ADDR_NON_NULL, (const char*) { name }, (const struct hw_addr_data*) { v } #define JSON_BUILD_PAIR_DUAL_TIMESTAMP_NON_NULL(name, t) _JSON_BUILD_PAIR_DUAL_TIMESTAMP_NON_NULL, (const char*) { name }, (dual_timestamp*) { t } @@ -243,18 +243,12 @@ enum { #define JSON_BUILD_PAIR_OCTESCAPE_NON_EMPTY(name, v, n) _JSON_BUILD_PAIR_HEX_NON_EMPTY, (const char*) { name }, (const void*) { v }, (size_t) { n } #define JSON_BUILD_PAIR_TRISTATE_NON_NULL(name, i) _JSON_BUILD_PAIR_TRISTATE_NON_NULL, (const char*) { name }, (int) { i } #define JSON_BUILD_PAIR_PIDREF_NON_NULL(name, p) _JSON_BUILD_PAIR_PIDREF_NON_NULL, (const char*) { name }, (const PidRef*) { p } -#define JSON_BUILD_PAIR_IN_ADDR_WITH_STRING(name, f, v) _JSON_BUILD_PAIR_IN_ADDR_WITH_STRING, (const char*) { name }, (int) { f }, (const union in_addr_union*) { v } -#define JSON_BUILD_PAIR_IN6_ADDR_WITH_STRING(name, v) _JSON_BUILD_PAIR_IN6_ADDR_WITH_STRING, (const char*) { name }, (const struct in6_addr*) { v } -#define JSON_BUILD_PAIR_IN4_ADDR_WITH_STRING(name, v) _JSON_BUILD_PAIR_IN4_ADDR_WITH_STRING, (const char*) { name }, (const struct in_addr*) { v } -#define JSON_BUILD_PAIR_IN_ADDR_WITH_STRING_NON_NULL(name, f, v) _JSON_BUILD_PAIR_IN_ADDR_WITH_STRING_NON_NULL, (const char*) { name }, (int) { f }, (const union in_addr_union*) { v } -#define JSON_BUILD_PAIR_IN6_ADDR_WITH_STRING_NON_NULL(name, v) _JSON_BUILD_PAIR_IN6_ADDR_WITH_STRING_NON_NULL, (const char*) { name }, (const struct in6_addr*) { v } -#define JSON_BUILD_PAIR_IN4_ADDR_WITH_STRING_NON_NULL(name, v) _JSON_BUILD_PAIR_IN4_ADDR_WITH_STRING_NON_NULL, (const char*) { name }, (const struct in_addr*) { v } #define JSON_BUILD_PAIR_IOVEC_BASE64(name, iov) SD_JSON_BUILD_PAIR(name, JSON_BUILD_IOVEC_BASE64(iov)) #define JSON_BUILD_PAIR_IOVEC_HEX(name, iov) SD_JSON_BUILD_PAIR(name, JSON_BUILD_IOVEC_HEX(iov)) #define JSON_BUILD_PAIR_IN4_ADDR(name, v) SD_JSON_BUILD_PAIR(name, JSON_BUILD_IN4_ADDR(v)) #define JSON_BUILD_PAIR_IN6_ADDR(name, v) SD_JSON_BUILD_PAIR(name, JSON_BUILD_IN6_ADDR(v)) -#define JSON_BUILD_PAIR_IN_ADDR(name, v, f) SD_JSON_BUILD_PAIR(name, JSON_BUILD_IN_ADDR(v, f)) +#define JSON_BUILD_PAIR_IN_ADDR(name, f, v) SD_JSON_BUILD_PAIR(name, JSON_BUILD_IN_ADDR(f, v)) #define JSON_BUILD_PAIR_ETHER_ADDR(name, v) SD_JSON_BUILD_PAIR(name, JSON_BUILD_ETHER_ADDR(v)) #define JSON_BUILD_PAIR_HW_ADDR(name, v) SD_JSON_BUILD_PAIR(name, JSON_BUILD_HW_ADDR(v)) #define JSON_BUILD_PAIR_STRING_SET(name, s) SD_JSON_BUILD_PAIR(name, JSON_BUILD_STRING_SET(s)) diff --git a/src/libsystemd/sd-json/sd-json.c b/src/libsystemd/sd-json/sd-json.c index 3278fba6a8..4ac50c20c9 100644 --- a/src/libsystemd/sd-json/sd-json.c +++ b/src/libsystemd/sd-json/sd-json.c @@ -4666,63 +4666,9 @@ _public_ int sd_json_buildv(sd_json_variant **ret, va_list ap) { break; } - case _JSON_BUILD_PAIR_IN4_ADDR_NON_NULL: { - const struct in_addr *a; - const char *n; - - if (current->expect != EXPECT_OBJECT_KEY) { - r = -EINVAL; - goto finish; - } - - n = va_arg(ap, const char *); - a = va_arg(ap, const struct in_addr *); - - if (a && in4_addr_is_set(a) && current->n_suppress == 0) { - r = sd_json_variant_new_string(&add, n); - if (r < 0) - goto finish; - - r = sd_json_variant_new_array_bytes(&add_more, a, sizeof(struct in_addr)); - if (r < 0) - goto finish; - } - - n_subtract = 2; /* we generated two items */ - - current->expect = EXPECT_OBJECT_KEY; - break; - } - - case _JSON_BUILD_PAIR_IN6_ADDR_NON_NULL: { - const struct in6_addr *a; - const char *n; - - if (current->expect != EXPECT_OBJECT_KEY) { - r = -EINVAL; - goto finish; - } - - n = va_arg(ap, const char *); - a = va_arg(ap, const struct in6_addr *); - - if (a && in6_addr_is_set(a) && current->n_suppress == 0) { - r = sd_json_variant_new_string(&add, n); - if (r < 0) - goto finish; - - r = sd_json_variant_new_array_bytes(&add_more, a, sizeof(struct in6_addr)); - if (r < 0) - goto finish; - } - - n_subtract = 2; /* we generated two items */ - - current->expect = EXPECT_OBJECT_KEY; - break; - } - - case _JSON_BUILD_PAIR_IN_ADDR_NON_NULL: { + case _JSON_BUILD_PAIR_IN_ADDR_NON_NULL: + case _JSON_BUILD_PAIR_IN_ADDR_WITH_STRING_NON_NULL: + case _JSON_BUILD_PAIR_IN_ADDR_WITH_STRING: { const union in_addr_union *a; const char *n; int f; @@ -4733,10 +4679,16 @@ _public_ int sd_json_buildv(sd_json_variant **ret, va_list ap) { } n = va_arg(ap, const char *); - a = va_arg(ap, const union in_addr_union *); f = va_arg(ap, int); + a = va_arg(ap, const union in_addr_union *); + + if (current->n_suppress == 0 && + ((a && in_addr_is_set(f, a)) || + command == _JSON_BUILD_PAIR_IN_ADDR_WITH_STRING)) { + + if (!a) + a = &IN_ADDR_NULL; - if (a && in_addr_is_set(f, a) && current->n_suppress == 0) { r = sd_json_variant_new_string(&add, n); if (r < 0) goto finish; @@ -4744,9 +4696,36 @@ _public_ int sd_json_buildv(sd_json_variant **ret, va_list ap) { r = sd_json_variant_new_array_bytes(&add_more, a->bytes, FAMILY_ADDRESS_SIZE_SAFE(f)); if (r < 0) goto finish; + + if (IN_SET(command, _JSON_BUILD_PAIR_IN_ADDR_WITH_STRING, _JSON_BUILD_PAIR_IN_ADDR_WITH_STRING_NON_NULL)) { + _cleanup_free_ char *string_key_name = NULL; + _cleanup_(sd_json_variant_unrefp) sd_json_variant *string_key = NULL, *string_value = NULL; + + string_key_name = strjoin(n, "String"); + if (!string_key_name) { + r = -ENOMEM; + goto finish; + } + + r = sd_json_variant_new_string(&string_key, string_key_name); + if (r < 0) + goto finish; + + r = sd_json_variant_new_string(&string_value, IN_ADDR_TO_STRING(f, a)); + if (r < 0) + goto finish; + + if (!GREEDY_REALLOC(current->elements, current->n_elements + 2)) { + r = -ENOMEM; + goto finish; + } + + current->elements[current->n_elements++] = TAKE_PTR(string_key); + current->elements[current->n_elements++] = TAKE_PTR(string_value); + } } - n_subtract = 2; /* we generated two items */ + n_subtract = command == _JSON_BUILD_PAIR_IN_ADDR_NON_NULL ? 2 : 4; current->expect = EXPECT_OBJECT_KEY; break; @@ -4896,207 +4875,6 @@ _public_ int sd_json_buildv(sd_json_variant **ret, va_list ap) { break; } - case _JSON_BUILD_PAIR_IN_ADDR_WITH_STRING_NON_NULL: - case _JSON_BUILD_PAIR_IN_ADDR_WITH_STRING: { - const union in_addr_union *a; - const char *n; - int f; - - if (current->expect != EXPECT_OBJECT_KEY) { - r = -EINVAL; - goto finish; - } - - n = va_arg(ap, const char *); - f = va_arg(ap, int); - a = va_arg(ap, const union in_addr_union *); - - if (current->n_suppress == 0) { - bool have_address = a && in_addr_is_set(f, a); - - if (have_address || command != _JSON_BUILD_PAIR_IN_ADDR_WITH_STRING_NON_NULL) { - _cleanup_free_ char *addr_str = NULL, *string_key_name = NULL; - _cleanup_(sd_json_variant_unrefp) sd_json_variant *string_key = NULL, *string_value = NULL; - - /* For non-NON_NULL variant, always convert address to string (even if all zeros). - * For NON_NULL variant, we only get here when have_address is true. */ - if (a) { - r = in_addr_to_string(f, a, &addr_str); - if (r < 0) - goto finish; - } - - string_key_name = strjoin(n, "String"); - if (!string_key_name) { - r = -ENOMEM; - goto finish; - } - - r = sd_json_variant_new_string(&add, n); - if (r < 0) - goto finish; - - r = sd_json_variant_new_array_bytes(&add_more, a->bytes, FAMILY_ADDRESS_SIZE_SAFE(f)); - if (r < 0) - goto finish; - - r = sd_json_variant_new_string(&string_key, string_key_name); - if (r < 0) - goto finish; - - r = sd_json_variant_new_string(&string_value, addr_str); - if (r < 0) - goto finish; - - if (!GREEDY_REALLOC(current->elements, current->n_elements + 2)) { - r = -ENOMEM; - goto finish; - } - - current->elements[current->n_elements++] = TAKE_PTR(string_key); - current->elements[current->n_elements++] = TAKE_PTR(string_value); - } - } - - n_subtract = 4; /* we generated two pairs (binary and string) */ - - current->expect = EXPECT_OBJECT_KEY; - break; - } - - case _JSON_BUILD_PAIR_IN6_ADDR_WITH_STRING_NON_NULL: - case _JSON_BUILD_PAIR_IN6_ADDR_WITH_STRING: { - const struct in6_addr *a; - const char *n; - - if (current->expect != EXPECT_OBJECT_KEY) { - r = -EINVAL; - goto finish; - } - - n = va_arg(ap, const char *); - a = va_arg(ap, const struct in6_addr *); - - if (current->n_suppress == 0) { - bool have_address = a && in6_addr_is_set(a); - - if (have_address || command != _JSON_BUILD_PAIR_IN6_ADDR_WITH_STRING_NON_NULL) { - _cleanup_free_ char *addr_str = NULL, *string_key_name = NULL; - _cleanup_(sd_json_variant_unrefp) sd_json_variant *string_key = NULL, *string_value = NULL; - - /* For non-NON_NULL variant, always convert address to string (even if all zeros). - * For NON_NULL variant, we only get here when have_address is true. */ - if (a) { - r = in6_addr_to_string(a, &addr_str); - if (r < 0) - goto finish; - } - - string_key_name = strjoin(n, "String"); - if (!string_key_name) { - r = -ENOMEM; - goto finish; - } - - r = sd_json_variant_new_string(&add, n); - if (r < 0) - goto finish; - - r = sd_json_variant_new_array_bytes(&add_more, a, sizeof(struct in6_addr)); - if (r < 0) - goto finish; - - r = sd_json_variant_new_string(&string_key, string_key_name); - if (r < 0) - goto finish; - - r = sd_json_variant_new_string(&string_value, addr_str); - if (r < 0) - goto finish; - - if (!GREEDY_REALLOC(current->elements, current->n_elements + 2)) { - r = -ENOMEM; - goto finish; - } - - current->elements[current->n_elements++] = TAKE_PTR(string_key); - current->elements[current->n_elements++] = TAKE_PTR(string_value); - } - } - - n_subtract = 4; /* we generated two pairs (binary and string) */ - - current->expect = EXPECT_OBJECT_KEY; - break; - } - - case _JSON_BUILD_PAIR_IN4_ADDR_WITH_STRING_NON_NULL: - case _JSON_BUILD_PAIR_IN4_ADDR_WITH_STRING: { - const struct in_addr *a; - const char *n; - - if (current->expect != EXPECT_OBJECT_KEY) { - r = -EINVAL; - goto finish; - } - - n = va_arg(ap, const char *); - a = va_arg(ap, const struct in_addr *); - - if (current->n_suppress == 0) { - bool have_address = a && !in4_addr_is_null(a); - - if (have_address || command != _JSON_BUILD_PAIR_IN4_ADDR_WITH_STRING_NON_NULL) { - _cleanup_free_ char *addr_str = NULL, *string_key_name = NULL; - _cleanup_(sd_json_variant_unrefp) sd_json_variant *string_key = NULL, *string_value = NULL; - - /* For non-NON_NULL variant, always convert address to string (even if all zeros). - * For NON_NULL variant, we only get here when have_address is true. */ - if (a) { - union in_addr_union addr_union = { .in = *a }; - r = in_addr_to_string(AF_INET, &addr_union, &addr_str); - if (r < 0) - goto finish; - } - - string_key_name = strjoin(n, "String"); - if (!string_key_name) { - r = -ENOMEM; - goto finish; - } - - r = sd_json_variant_new_string(&add, n); - if (r < 0) - goto finish; - - r = sd_json_variant_new_array_bytes(&add_more, a, sizeof(struct in_addr)); - if (r < 0) - goto finish; - - r = sd_json_variant_new_string(&string_key, string_key_name); - if (r < 0) - goto finish; - - r = sd_json_variant_new_string(&string_value, addr_str); - if (r < 0) - goto finish; - - if (!GREEDY_REALLOC(current->elements, current->n_elements + 2)) { - r = -ENOMEM; - goto finish; - } - - current->elements[current->n_elements++] = TAKE_PTR(string_key); - current->elements[current->n_elements++] = TAKE_PTR(string_value); - } - } - - n_subtract = 4; /* we generated two pairs (binary and string) */ - - current->expect = EXPECT_OBJECT_KEY; - break; - } - case _JSON_BUILD_PAIR_CALLBACK_NON_NULL: { sd_json_build_callback_t cb; void *userdata; diff --git a/src/network/networkd-json.c b/src/network/networkd-json.c index 123594179c..de1a8829ee 100644 --- a/src/network/networkd-json.c +++ b/src/network/networkd-json.c @@ -623,7 +623,7 @@ static int dnr_append_json_one(Link *link, const struct sd_dns_resolver *res, Ne FOREACH_ARRAY(addr, res->addrs, res->n_addrs) { r = sd_json_variant_append_arrayb( &addrs_array, - JSON_BUILD_IN_ADDR(addr, res->family)); + JSON_BUILD_IN_ADDR(res->family, addr)); if (r < 0) return r; } @@ -644,7 +644,7 @@ static int dnr_append_json_one(Link *link, const struct sd_dns_resolver *res, Ne JSON_BUILD_PAIR_STRING_NON_EMPTY("DoHPath", res->dohpath), JSON_BUILD_PAIR_STRV_NON_EMPTY("Transports", transports), SD_JSON_BUILD_PAIR_STRING("ConfigSource", network_config_source_to_string(s)), - JSON_BUILD_PAIR_IN_ADDR_NON_NULL("ConfigProvider", p, res->family))); + JSON_BUILD_PAIR_IN_ADDR_NON_NULL("ConfigProvider", res->family, p))); } static int dnr_append_json(Link *link, sd_json_variant **v) { @@ -733,7 +733,7 @@ static int server_append_json_one_addr(int family, const union in_addr_union *a, return sd_json_variant_append_arraybo( array, SD_JSON_BUILD_PAIR_INTEGER("Family", family), - JSON_BUILD_PAIR_IN_ADDR("Address", a, family), + JSON_BUILD_PAIR_IN_ADDR("Address", family, a), SD_JSON_BUILD_PAIR_STRING("AddressString", address_str), SD_JSON_BUILD_PAIR_STRING("ConfigSource", network_config_source_to_string(s)), JSON_BUILD_PAIR_IN_ADDR_WITH_STRING_NON_NULL("ConfigProvider", family, p)); diff --git a/src/resolve/resolved-dns-server.c b/src/resolve/resolved-dns-server.c index 83082631f7..4f04476f2d 100644 --- a/src/resolve/resolved-dns-server.c +++ b/src/resolve/resolved-dns-server.c @@ -1374,7 +1374,7 @@ int dns_server_dump_configuration_to_json(DnsServer *server, sd_json_variant **r return sd_json_buildo( ret, JSON_BUILD_PAIR_STRING_NON_EMPTY("addressString", dns_server_string(server)), - JSON_BUILD_PAIR_IN_ADDR("address", &server->address, server->family), + JSON_BUILD_PAIR_IN_ADDR("address", server->family, &server->address), SD_JSON_BUILD_PAIR_INTEGER("family", server->family), SD_JSON_BUILD_PAIR_UNSIGNED("port", dns_server_port(server)), SD_JSON_BUILD_PAIR_CONDITION(ifindex > 0, "ifindex", SD_JSON_BUILD_UNSIGNED(ifindex)), From 42ed373294aa79c9a26a9db3122c944aa77f838e Mon Sep 17 00:00:00 2001 From: Mike Yuan Date: Wed, 4 Feb 2026 19:51:28 +0100 Subject: [PATCH 09/30] varlink-io.systemd.Network: minor coding style cleanups Follow-up for cf27c70d70f5912078f68b66869d16198aaa36a5 --- src/shared/varlink-io.systemd.Network.c | 58 ++++++++++++------------- 1 file changed, 29 insertions(+), 29 deletions(-) diff --git a/src/shared/varlink-io.systemd.Network.c b/src/shared/varlink-io.systemd.Network.c index f7d29521b0..b80070ee5f 100644 --- a/src/shared/varlink-io.systemd.Network.c +++ b/src/shared/varlink-io.systemd.Network.c @@ -4,11 +4,11 @@ #include "varlink-io.systemd.Network.h" /* Helper macro to define address fields with both binary and string representation */ -#define SD_VARLINK_DEFINE_IN_ADDR_WITH_STRING_FIELD(field_name, comment, flags) \ - SD_VARLINK_FIELD_COMMENT(comment), \ - SD_VARLINK_DEFINE_FIELD(field_name, SD_VARLINK_INT, SD_VARLINK_ARRAY | (flags)), \ - SD_VARLINK_FIELD_COMMENT(comment " (human-readable format)"), \ - SD_VARLINK_DEFINE_FIELD(field_name##String, SD_VARLINK_STRING, (flags)) +#define VARLINK_DEFINE_IN_ADDR_WITH_STRING_FIELD(field_name, comment, flags) \ + SD_VARLINK_FIELD_COMMENT(comment), \ + SD_VARLINK_DEFINE_FIELD(field_name, SD_VARLINK_INT, SD_VARLINK_ARRAY | (flags)), \ + SD_VARLINK_FIELD_COMMENT(comment " (human-readable format)"), \ + SD_VARLINK_DEFINE_FIELD(field_name##String, SD_VARLINK_STRING, (flags)) static SD_VARLINK_DEFINE_ENUM_TYPE( LinkState, @@ -43,10 +43,10 @@ static SD_VARLINK_DEFINE_STRUCT_TYPE( RoutingPolicyRule, SD_VARLINK_FIELD_COMMENT("Address family (AF_INET or AF_INET6)"), SD_VARLINK_DEFINE_FIELD(Family, SD_VARLINK_INT, 0), - SD_VARLINK_DEFINE_IN_ADDR_WITH_STRING_FIELD(FromPrefix, "Source address prefix to match", SD_VARLINK_NULLABLE), + VARLINK_DEFINE_IN_ADDR_WITH_STRING_FIELD(FromPrefix, "Source address prefix to match", SD_VARLINK_NULLABLE), SD_VARLINK_FIELD_COMMENT("Length of source prefix in bits"), SD_VARLINK_DEFINE_FIELD(FromPrefixLength, SD_VARLINK_INT, SD_VARLINK_NULLABLE), - SD_VARLINK_DEFINE_IN_ADDR_WITH_STRING_FIELD(ToPrefix, "Destination address prefix to match", SD_VARLINK_NULLABLE), + VARLINK_DEFINE_IN_ADDR_WITH_STRING_FIELD(ToPrefix, "Destination address prefix to match", SD_VARLINK_NULLABLE), SD_VARLINK_FIELD_COMMENT("Length of destination prefix in bits"), SD_VARLINK_DEFINE_FIELD(ToPrefixLength, SD_VARLINK_INT, SD_VARLINK_NULLABLE), SD_VARLINK_FIELD_COMMENT("Routing protocol identifier"), @@ -98,14 +98,14 @@ static SD_VARLINK_DEFINE_STRUCT_TYPE( Route, SD_VARLINK_FIELD_COMMENT("Address family (AF_INET or AF_INET6)"), SD_VARLINK_DEFINE_FIELD(Family, SD_VARLINK_INT, 0), - SD_VARLINK_DEFINE_IN_ADDR_WITH_STRING_FIELD(Destination, "Destination network address", 0), + VARLINK_DEFINE_IN_ADDR_WITH_STRING_FIELD(Destination, "Destination network address", 0), SD_VARLINK_FIELD_COMMENT("Destination network prefix length"), SD_VARLINK_DEFINE_FIELD(DestinationPrefixLength, SD_VARLINK_INT, 0), - SD_VARLINK_DEFINE_IN_ADDR_WITH_STRING_FIELD(Gateway, "Gateway address for this route", SD_VARLINK_NULLABLE), - SD_VARLINK_DEFINE_IN_ADDR_WITH_STRING_FIELD(Source, "Source address prefix for route selection", SD_VARLINK_NULLABLE), + VARLINK_DEFINE_IN_ADDR_WITH_STRING_FIELD(Gateway, "Gateway address for this route", SD_VARLINK_NULLABLE), + VARLINK_DEFINE_IN_ADDR_WITH_STRING_FIELD(Source, "Source address prefix for route selection", SD_VARLINK_NULLABLE), SD_VARLINK_FIELD_COMMENT("Source prefix length"), SD_VARLINK_DEFINE_FIELD(SourcePrefixLength, SD_VARLINK_INT, SD_VARLINK_NULLABLE), - SD_VARLINK_DEFINE_IN_ADDR_WITH_STRING_FIELD(PreferredSource, "Preferred source address for outgoing packets", SD_VARLINK_NULLABLE), + VARLINK_DEFINE_IN_ADDR_WITH_STRING_FIELD(PreferredSource, "Preferred source address for outgoing packets", SD_VARLINK_NULLABLE), SD_VARLINK_FIELD_COMMENT("Type of Service (TOS) field"), SD_VARLINK_DEFINE_FIELD(TOS, SD_VARLINK_INT, 0), SD_VARLINK_FIELD_COMMENT("Route scope (RT_SCOPE_* value)"), @@ -140,7 +140,7 @@ static SD_VARLINK_DEFINE_STRUCT_TYPE( SD_VARLINK_DEFINE_FIELD(LifetimeUSec, SD_VARLINK_INT, SD_VARLINK_NULLABLE), SD_VARLINK_FIELD_COMMENT("Configuration source for this route"), SD_VARLINK_DEFINE_FIELD(ConfigSource, SD_VARLINK_STRING, 0), - SD_VARLINK_DEFINE_IN_ADDR_WITH_STRING_FIELD(ConfigProvider, "Address of the configuration provider", SD_VARLINK_NULLABLE), + VARLINK_DEFINE_IN_ADDR_WITH_STRING_FIELD(ConfigProvider, "Address of the configuration provider", SD_VARLINK_NULLABLE), SD_VARLINK_FIELD_COMMENT("Configuration state of this route"), SD_VARLINK_DEFINE_FIELD(ConfigState, SD_VARLINK_STRING, SD_VARLINK_NULLABLE), SD_VARLINK_FIELD_COMMENT("Interface index for serialization"), @@ -163,7 +163,7 @@ static SD_VARLINK_DEFINE_STRUCT_TYPE( SD_VARLINK_DEFINE_FIELD(ID, SD_VARLINK_INT, 0), SD_VARLINK_FIELD_COMMENT("Address family (AF_INET or AF_INET6)"), SD_VARLINK_DEFINE_FIELD(Family, SD_VARLINK_INT, 0), - SD_VARLINK_DEFINE_IN_ADDR_WITH_STRING_FIELD(Gateway, "Gateway address for this next hop", SD_VARLINK_NULLABLE), + VARLINK_DEFINE_IN_ADDR_WITH_STRING_FIELD(Gateway, "Gateway address for this next hop", SD_VARLINK_NULLABLE), SD_VARLINK_FIELD_COMMENT("Next hop flags (RTNH_F_* values)"), SD_VARLINK_DEFINE_FIELD(Flags, SD_VARLINK_INT, SD_VARLINK_NULLABLE), SD_VARLINK_FIELD_COMMENT("Human-readable flags string"), @@ -178,7 +178,7 @@ static SD_VARLINK_DEFINE_STRUCT_TYPE( SD_VARLINK_DEFINE_FIELD_BY_TYPE(Group, NextHopGroup, SD_VARLINK_ARRAY|SD_VARLINK_NULLABLE), SD_VARLINK_FIELD_COMMENT("Configuration source for this next hop"), SD_VARLINK_DEFINE_FIELD(ConfigSource, SD_VARLINK_STRING, 0), - SD_VARLINK_DEFINE_IN_ADDR_WITH_STRING_FIELD(ConfigProvider, "Address of the configuration provider", SD_VARLINK_NULLABLE), + VARLINK_DEFINE_IN_ADDR_WITH_STRING_FIELD(ConfigProvider, "Address of the configuration provider", SD_VARLINK_NULLABLE), SD_VARLINK_FIELD_COMMENT("Configuration state of this next hop"), SD_VARLINK_DEFINE_FIELD(ConfigState, SD_VARLINK_STRING, SD_VARLINK_NULLABLE)); @@ -209,7 +209,7 @@ static SD_VARLINK_DEFINE_STRUCT_TYPE( DNS, SD_VARLINK_FIELD_COMMENT("Address family (AF_INET or AF_INET6)"), SD_VARLINK_DEFINE_FIELD(Family, SD_VARLINK_INT, 0), - SD_VARLINK_DEFINE_IN_ADDR_WITH_STRING_FIELD(Address, "DNS server IP address", 0), + VARLINK_DEFINE_IN_ADDR_WITH_STRING_FIELD(Address, "DNS server IP address", 0), SD_VARLINK_FIELD_COMMENT("DNS server port number"), SD_VARLINK_DEFINE_FIELD(Port, SD_VARLINK_INT, SD_VARLINK_NULLABLE), SD_VARLINK_FIELD_COMMENT("Interface index for link-local DNS servers"), @@ -218,29 +218,29 @@ static SD_VARLINK_DEFINE_STRUCT_TYPE( SD_VARLINK_DEFINE_FIELD(ServerName, SD_VARLINK_STRING, SD_VARLINK_NULLABLE), SD_VARLINK_FIELD_COMMENT("Configuration source for this DNS server"), SD_VARLINK_DEFINE_FIELD(ConfigSource, SD_VARLINK_STRING, 0), - SD_VARLINK_DEFINE_IN_ADDR_WITH_STRING_FIELD(ConfigProvider, "Address of the configuration provider", SD_VARLINK_NULLABLE)); + VARLINK_DEFINE_IN_ADDR_WITH_STRING_FIELD(ConfigProvider, "Address of the configuration provider", SD_VARLINK_NULLABLE)); static SD_VARLINK_DEFINE_STRUCT_TYPE( NTP, SD_VARLINK_FIELD_COMMENT("Address family (AF_INET or AF_INET6) for address-based servers"), SD_VARLINK_DEFINE_FIELD(Family, SD_VARLINK_INT, SD_VARLINK_NULLABLE), - SD_VARLINK_DEFINE_IN_ADDR_WITH_STRING_FIELD(Address, "NTP server IP address", SD_VARLINK_NULLABLE), + VARLINK_DEFINE_IN_ADDR_WITH_STRING_FIELD(Address, "NTP server IP address", SD_VARLINK_NULLABLE), SD_VARLINK_FIELD_COMMENT("NTP server"), SD_VARLINK_DEFINE_FIELD(Server, SD_VARLINK_STRING, SD_VARLINK_NULLABLE), SD_VARLINK_FIELD_COMMENT("Configuration source for this NTP server"), SD_VARLINK_DEFINE_FIELD(ConfigSource, SD_VARLINK_STRING, 0), - SD_VARLINK_DEFINE_IN_ADDR_WITH_STRING_FIELD(ConfigProvider, "Address of the configuration provider", SD_VARLINK_NULLABLE)); + VARLINK_DEFINE_IN_ADDR_WITH_STRING_FIELD(ConfigProvider, "Address of the configuration provider", SD_VARLINK_NULLABLE)); static SD_VARLINK_DEFINE_STRUCT_TYPE( SIP, SD_VARLINK_FIELD_COMMENT("Address family (AF_INET or AF_INET6) for address-based servers"), SD_VARLINK_DEFINE_FIELD(Family, SD_VARLINK_INT, SD_VARLINK_NULLABLE), - SD_VARLINK_DEFINE_IN_ADDR_WITH_STRING_FIELD(Address, "SIP server IP address", SD_VARLINK_NULLABLE), + VARLINK_DEFINE_IN_ADDR_WITH_STRING_FIELD(Address, "SIP server IP address", SD_VARLINK_NULLABLE), SD_VARLINK_FIELD_COMMENT("SIP server domain name"), SD_VARLINK_DEFINE_FIELD(Domain, SD_VARLINK_STRING, SD_VARLINK_NULLABLE), SD_VARLINK_FIELD_COMMENT("Configuration source for this SIP server"), SD_VARLINK_DEFINE_FIELD(ConfigSource, SD_VARLINK_STRING, 0), - SD_VARLINK_DEFINE_IN_ADDR_WITH_STRING_FIELD(ConfigProvider, "Address of the configuration provider", SD_VARLINK_NULLABLE)); + VARLINK_DEFINE_IN_ADDR_WITH_STRING_FIELD(ConfigProvider, "Address of the configuration provider", SD_VARLINK_NULLABLE)); static SD_VARLINK_DEFINE_STRUCT_TYPE( Domain, @@ -248,7 +248,7 @@ static SD_VARLINK_DEFINE_STRUCT_TYPE( SD_VARLINK_DEFINE_FIELD(Domain, SD_VARLINK_STRING, 0), SD_VARLINK_FIELD_COMMENT("Configuration source for this domain"), SD_VARLINK_DEFINE_FIELD(ConfigSource, SD_VARLINK_STRING, 0), - SD_VARLINK_DEFINE_IN_ADDR_WITH_STRING_FIELD(ConfigProvider, "Address of the configuration provider", SD_VARLINK_NULLABLE)); + VARLINK_DEFINE_IN_ADDR_WITH_STRING_FIELD(ConfigProvider, "Address of the configuration provider", SD_VARLINK_NULLABLE)); static SD_VARLINK_DEFINE_STRUCT_TYPE( DNSSECNegativeTrustAnchor, @@ -280,7 +280,7 @@ static SD_VARLINK_DEFINE_STRUCT_TYPE( SD_VARLINK_DEFINE_FIELD(PrefixLength, SD_VARLINK_INT, 0), SD_VARLINK_FIELD_COMMENT("Lifetime of the prefix in microseconds"), SD_VARLINK_DEFINE_FIELD(LifetimeUSec, SD_VARLINK_INT, SD_VARLINK_NULLABLE), - SD_VARLINK_DEFINE_IN_ADDR_WITH_STRING_FIELD(ConfigProvider, "Address of router that provided this prefix", SD_VARLINK_NULLABLE)); + VARLINK_DEFINE_IN_ADDR_WITH_STRING_FIELD(ConfigProvider, "Address of router that provided this prefix", SD_VARLINK_NULLABLE)); static SD_VARLINK_DEFINE_STRUCT_TYPE( NDisc, @@ -291,14 +291,14 @@ static SD_VARLINK_DEFINE_STRUCT_TYPE( Address, SD_VARLINK_FIELD_COMMENT("Address family (AF_INET or AF_INET6)"), SD_VARLINK_DEFINE_FIELD(Family, SD_VARLINK_INT, 0), - SD_VARLINK_DEFINE_IN_ADDR_WITH_STRING_FIELD(Address, "IP address", 0), - SD_VARLINK_DEFINE_IN_ADDR_WITH_STRING_FIELD(Peer, "Peer address for point-to-point interfaces", SD_VARLINK_NULLABLE), + VARLINK_DEFINE_IN_ADDR_WITH_STRING_FIELD(Address, "IP address", 0), + VARLINK_DEFINE_IN_ADDR_WITH_STRING_FIELD(Peer, "Peer address for point-to-point interfaces", SD_VARLINK_NULLABLE), SD_VARLINK_FIELD_COMMENT("Network prefix length"), SD_VARLINK_DEFINE_FIELD(PrefixLength, SD_VARLINK_INT, 0), SD_VARLINK_FIELD_COMMENT("Configuration source for this address"), SD_VARLINK_DEFINE_FIELD(ConfigSource, SD_VARLINK_STRING, 0), - SD_VARLINK_DEFINE_IN_ADDR_WITH_STRING_FIELD(ConfigProvider, "Address of the configuration provider (DHCP server, router, etc.)", SD_VARLINK_NULLABLE), - SD_VARLINK_DEFINE_IN_ADDR_WITH_STRING_FIELD(Broadcast, "Broadcast address for IPv4 networks", SD_VARLINK_NULLABLE), + VARLINK_DEFINE_IN_ADDR_WITH_STRING_FIELD(ConfigProvider, "Address of the configuration provider (DHCP server, router, etc.)", SD_VARLINK_NULLABLE), + VARLINK_DEFINE_IN_ADDR_WITH_STRING_FIELD(Broadcast, "Broadcast address for IPv4 networks", SD_VARLINK_NULLABLE), SD_VARLINK_FIELD_COMMENT("Address scope (RT_SCOPE_* value)"), SD_VARLINK_DEFINE_FIELD(Scope, SD_VARLINK_INT, SD_VARLINK_NULLABLE), SD_VARLINK_FIELD_COMMENT("Human-readable scope string"), @@ -324,7 +324,7 @@ static SD_VARLINK_DEFINE_STRUCT_TYPE( Neighbor, SD_VARLINK_FIELD_COMMENT("Address family (AF_INET or AF_INET6)"), SD_VARLINK_DEFINE_FIELD(Family, SD_VARLINK_INT, 0), - SD_VARLINK_DEFINE_IN_ADDR_WITH_STRING_FIELD(Destination, "IP address of the neighbor", 0), + VARLINK_DEFINE_IN_ADDR_WITH_STRING_FIELD(Destination, "IP address of the neighbor", 0), SD_VARLINK_FIELD_COMMENT("Link layer (MAC) address of the neighbor"), SD_VARLINK_DEFINE_FIELD(LinkLayerAddress, SD_VARLINK_INT, SD_VARLINK_ARRAY), SD_VARLINK_FIELD_COMMENT("Configuration source for this neighbor entry"), @@ -387,7 +387,7 @@ static SD_VARLINK_DEFINE_STRUCT_TYPE( DHCPServerLease, SD_VARLINK_FIELD_COMMENT("DHCP client identifier"), SD_VARLINK_DEFINE_FIELD(ClientId, SD_VARLINK_INT, SD_VARLINK_ARRAY|SD_VARLINK_NULLABLE), - SD_VARLINK_DEFINE_IN_ADDR_WITH_STRING_FIELD(Address, "Address assigned to the client", SD_VARLINK_NULLABLE), + VARLINK_DEFINE_IN_ADDR_WITH_STRING_FIELD(Address, "Address assigned to the client", SD_VARLINK_NULLABLE), SD_VARLINK_FIELD_COMMENT("Hostname provided by the DHCP client"), SD_VARLINK_DEFINE_FIELD(Hostname, SD_VARLINK_STRING, SD_VARLINK_NULLABLE), SD_VARLINK_FIELD_COMMENT("Hardware address type (ARPHRD_* value)"), @@ -448,7 +448,7 @@ static SD_VARLINK_DEFINE_STRUCT_TYPE( SD_VARLINK_DEFINE_FIELD(PermanentHardwareAddress, SD_VARLINK_INT, SD_VARLINK_ARRAY|SD_VARLINK_NULLABLE), SD_VARLINK_FIELD_COMMENT("Broadcast address for Ethernet interfaces"), SD_VARLINK_DEFINE_FIELD(BroadcastAddress, SD_VARLINK_INT, SD_VARLINK_ARRAY|SD_VARLINK_NULLABLE), - SD_VARLINK_DEFINE_IN_ADDR_WITH_STRING_FIELD(IPv6LinkLocalAddress, "IPv6 link-local address", SD_VARLINK_NULLABLE), + VARLINK_DEFINE_IN_ADDR_WITH_STRING_FIELD(IPv6LinkLocalAddress, "IPv6 link-local address", SD_VARLINK_NULLABLE), SD_VARLINK_FIELD_COMMENT("Wireless LAN interface type (NL80211_IFTYPE_* value)"), SD_VARLINK_DEFINE_FIELD(WirelessLanInterfaceType, SD_VARLINK_INT, SD_VARLINK_NULLABLE), SD_VARLINK_FIELD_COMMENT("Human-readable wireless LAN interface type"), From 09388a6b9e471c817f00b8f4f59b514810670a71 Mon Sep 17 00:00:00 2001 From: Mike Yuan Date: Sun, 8 Feb 2026 21:47:38 +0100 Subject: [PATCH 10/30] tree-wide: drop redundant check for SD_VARLINK_METHOD_MORE flag If the IDL declares the method requires 'more' yet the call doesn't have it set, varlink_idl_validate_method_call() should have rejected it and the callback shouldn't be reached. --- src/bootctl/bootctl-status.c | 4 +--- src/import/importd.c | 4 +--- src/pcrlock/pcrlock.c | 1 + src/resolve/resolved-varlink.c | 8 ++------ src/shared/metrics.c | 8 ++------ src/sysext/sysext.c | 1 + 6 files changed, 8 insertions(+), 18 deletions(-) diff --git a/src/bootctl/bootctl-status.c b/src/bootctl/bootctl-status.c index 9c53522594..67b590b76f 100644 --- a/src/bootctl/bootctl-status.c +++ b/src/bootctl/bootctl-status.c @@ -642,14 +642,12 @@ int vl_method_list_boot_entries(sd_varlink *link, sd_json_variant *parameters, s int r; assert(link); + assert(FLAGS_SET(flags, SD_VARLINK_METHOD_MORE)); r = sd_varlink_dispatch(link, parameters, /* dispatch_table= */ NULL, /* userdata= */ NULL); if (r != 0) return r; - if (!FLAGS_SET(flags, SD_VARLINK_METHOD_MORE)) - return sd_varlink_error(link, SD_VARLINK_ERROR_EXPECTED_MORE, NULL); - r = acquire_esp(/* unprivileged_mode= */ false, /* graceful= */ false, /* ret_part= */ NULL, diff --git a/src/import/importd.c b/src/import/importd.c index 549bbe712f..280aa88d46 100644 --- a/src/import/importd.c +++ b/src/import/importd.c @@ -1793,14 +1793,12 @@ static int vl_method_list_transfers(sd_varlink *link, sd_json_variant *parameter assert(link); assert(parameters); + assert(FLAGS_SET(flags, SD_VARLINK_METHOD_MORE)); r = sd_varlink_dispatch(link, parameters, dispatch_table, &p); if (r != 0) return r; - if (!FLAGS_SET(flags, SD_VARLINK_METHOD_MORE)) - return sd_varlink_error(link, SD_VARLINK_ERROR_EXPECTED_MORE, NULL); - r = varlink_set_sentinel(link, "io.systemd.Import.NoTransfers"); if (r < 0) return r; diff --git a/src/pcrlock/pcrlock.c b/src/pcrlock/pcrlock.c index 396785280c..138841f31c 100644 --- a/src/pcrlock/pcrlock.c +++ b/src/pcrlock/pcrlock.c @@ -5404,6 +5404,7 @@ static int vl_method_read_event_log(sd_varlink *link, sd_json_variant *parameter int r; assert(link); + assert(FLAGS_SET(flags, SD_VARLINK_METHOD_MORE)); r = sd_varlink_dispatch(link, parameters, /* dispatch_table= */ NULL, /* userdata= */ NULL); if (r != 0) diff --git a/src/resolve/resolved-varlink.c b/src/resolve/resolved-varlink.c index 760e890426..e99a69cabd 100644 --- a/src/resolve/resolved-varlink.c +++ b/src/resolve/resolved-varlink.c @@ -1239,9 +1239,7 @@ static int vl_method_subscribe_query_results(sd_varlink *link, sd_json_variant * Manager *m = ASSERT_PTR(sd_varlink_get_userdata(ASSERT_PTR(link))); int r; - /* if the client didn't set the more flag, it is using us incorrectly */ - if (!FLAGS_SET(flags, SD_VARLINK_METHOD_MORE)) - return sd_varlink_error(link, SD_VARLINK_ERROR_EXPECTED_MORE, NULL); + assert(FLAGS_SET(flags, SD_VARLINK_METHOD_MORE)); r = verify_polkit(link, parameters, "org.freedesktop.resolve1.subscribe-query-results"); if (r <= 0) @@ -1382,9 +1380,7 @@ static int vl_method_subscribe_dns_configuration(sd_varlink *link, sd_json_varia Manager *m = ASSERT_PTR(sd_varlink_get_userdata(ASSERT_PTR(link))); int r; - /* if the client didn't set the more flag, it is using us incorrectly */ - if (!FLAGS_SET(flags, SD_VARLINK_METHOD_MORE)) - return sd_varlink_error(link, SD_VARLINK_ERROR_EXPECTED_MORE, NULL); + assert(FLAGS_SET(flags, SD_VARLINK_METHOD_MORE)); r = verify_polkit(link, parameters, "org.freedesktop.resolve1.subscribe-dns-configuration"); if (r <= 0) diff --git a/src/shared/metrics.c b/src/shared/metrics.c index 9c70f1129b..9c7cf282cb 100644 --- a/src/shared/metrics.c +++ b/src/shared/metrics.c @@ -84,14 +84,12 @@ int metrics_method_describe( assert(metric_family_table); assert(link); assert(parameters); + assert(FLAGS_SET(flags, SD_VARLINK_METHOD_MORE)); r = sd_varlink_dispatch(link, parameters, /* dispatch_table= */ NULL, /* userdata= */ NULL); if (r != 0) return r; - if (!FLAGS_SET(flags, SD_VARLINK_METHOD_MORE)) - return sd_varlink_error(link, SD_VARLINK_ERROR_EXPECTED_MORE, NULL); - r = varlink_set_sentinel(link, "io.systemd.Metrics.NoSuchMetric"); if (r < 0) return r; @@ -123,14 +121,12 @@ int metrics_method_list( assert(metric_family_table); assert(link); assert(parameters); + assert(FLAGS_SET(flags, SD_VARLINK_METHOD_MORE)); r = sd_varlink_dispatch(link, parameters, /* dispatch_table= */ NULL, /* userdata= */ NULL); if (r != 0) return r; - if (!FLAGS_SET(flags, SD_VARLINK_METHOD_MORE)) - return sd_varlink_error(link, SD_VARLINK_ERROR_EXPECTED_MORE, NULL); - r = varlink_set_sentinel(link, "io.systemd.Metrics.NoSuchMetric"); if (r < 0) return r; diff --git a/src/sysext/sysext.c b/src/sysext/sysext.c index 5e16ace9f9..3661457d26 100644 --- a/src/sysext/sysext.c +++ b/src/sysext/sysext.c @@ -2749,6 +2749,7 @@ static int vl_method_list(sd_varlink *link, sd_json_variant *parameters, sd_varl int r; assert(link); + assert(FLAGS_SET(flags, SD_VARLINK_METHOD_MORE)); const char *class = NULL; r = sd_varlink_dispatch(link, parameters, dispatch_table, &class); From 41e675996d56b478a359abfbc395e598b6bd4f94 Mon Sep 17 00:00:00 2001 From: Mike Yuan Date: Sun, 8 Feb 2026 21:57:01 +0100 Subject: [PATCH 11/30] mute-console: io.systemd.MuteConsole requires 'more' --- src/mute-console/mute-console.c | 4 +--- src/shared/varlink-io.systemd.MuteConsole.c | 3 ++- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/mute-console/mute-console.c b/src/mute-console/mute-console.c index 40c0839367..b18e79d622 100644 --- a/src/mute-console/mute-console.c +++ b/src/mute-console/mute-console.c @@ -273,6 +273,7 @@ static int vl_method_mute( int r; assert(link); + assert(FLAGS_SET(flags, SD_VARLINK_METHOD_MORE)); _cleanup_free_ Context *nc = new(Context, 1); if (!nc) @@ -294,9 +295,6 @@ static int vl_method_mute( if (r != 0) return r; - if (!FLAGS_SET(flags, SD_VARLINK_METHOD_MORE)) - return sd_varlink_error(link, SD_VARLINK_ERROR_EXPECTED_MORE, NULL); - r = sd_varlink_server_bind_disconnect(sd_varlink_get_server(link), vl_on_disconnect); if (r < 0) return r; diff --git a/src/shared/varlink-io.systemd.MuteConsole.c b/src/shared/varlink-io.systemd.MuteConsole.c index 0cea5b8554..723b19985e 100644 --- a/src/shared/varlink-io.systemd.MuteConsole.c +++ b/src/shared/varlink-io.systemd.MuteConsole.c @@ -4,8 +4,9 @@ #include "varlink-io.systemd.MuteConsole.h" -static SD_VARLINK_DEFINE_METHOD( +static SD_VARLINK_DEFINE_METHOD_FULL( Mute, + SD_VARLINK_REQUIRES_MORE, SD_VARLINK_FIELD_COMMENT("Whether to mute the kernel's output to the console (defaults to true)."), SD_VARLINK_DEFINE_INPUT(kernel, SD_VARLINK_BOOL, SD_VARLINK_NULLABLE), SD_VARLINK_FIELD_COMMENT("Whether to mute PID1's output to the console (defaults to true)."), From 03023fd12cc48043a13b519ed6e146bd0a845267 Mon Sep 17 00:00:00 2001 From: Mike Yuan Date: Sun, 15 Feb 2026 03:04:28 +0100 Subject: [PATCH 12/30] resolve: io.systemd.Resolve.BrowseServices requires 'more' --- src/resolve/resolved-varlink.c | 5 +---- src/shared/varlink-io.systemd.Resolve.c | 2 +- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/src/resolve/resolved-varlink.c b/src/resolve/resolved-varlink.c index e99a69cabd..bb0100b046 100644 --- a/src/resolve/resolved-varlink.c +++ b/src/resolve/resolved-varlink.c @@ -1214,10 +1214,7 @@ static int vl_method_browse_services(sd_varlink* link, sd_json_variant* paramete int r = 0; assert(link); - - /* if the client didn't set the more flag, it is using us incorrectly */ - if (!FLAGS_SET(flags, SD_VARLINK_METHOD_MORE)) - return sd_varlink_error(link, SD_VARLINK_ERROR_EXPECTED_MORE, NULL); + assert(FLAGS_SET(flags, SD_VARLINK_METHOD_MORE)); m = ASSERT_PTR(sd_varlink_server_get_userdata(sd_varlink_get_server(link))); diff --git a/src/shared/varlink-io.systemd.Resolve.c b/src/shared/varlink-io.systemd.Resolve.c index c84453851b..33398a62f7 100644 --- a/src/shared/varlink-io.systemd.Resolve.c +++ b/src/shared/varlink-io.systemd.Resolve.c @@ -300,7 +300,7 @@ static SD_VARLINK_DEFINE_METHOD( static SD_VARLINK_DEFINE_METHOD_FULL( BrowseServices, - SD_VARLINK_SUPPORTS_MORE, + SD_VARLINK_REQUIRES_MORE, SD_VARLINK_FIELD_COMMENT("The domain to browse for services. If null, the default browsing domain local is used."), SD_VARLINK_DEFINE_INPUT(domain, SD_VARLINK_STRING, SD_VARLINK_NULLABLE), SD_VARLINK_FIELD_COMMENT("The service type to browse for (e.g., '_http._tcp')."), From 097243cc30dd850a61be30d183dd75e403a8e986 Mon Sep 17 00:00:00 2001 From: Mike Yuan Date: Sun, 15 Feb 2026 03:08:12 +0100 Subject: [PATCH 13/30] repart: io.systemd.Repart.ListCandidateDevices requires 'more' --- src/repart/repart.c | 4 +--- src/shared/varlink-io.systemd.Repart.c | 3 ++- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/repart/repart.c b/src/repart/repart.c index ac6cccbcba..3d1846b7e8 100644 --- a/src/repart/repart.c +++ b/src/repart/repart.c @@ -10324,14 +10324,12 @@ static int vl_method_list_candidate_devices( int r; assert(link); + assert(FLAGS_SET(flags, SD_VARLINK_METHOD_MORE)); r = sd_varlink_dispatch(link, parameters, dispatch_table, &p); if (r != 0) return r; - if (!FLAGS_SET(flags, SD_VARLINK_METHOD_MORE)) - return sd_varlink_error(link, SD_VARLINK_ERROR_EXPECTED_MORE, NULL); - BlockDevice *l = NULL; size_t n = 0; CLEANUP_ARRAY(l, n, block_device_array_free); diff --git a/src/shared/varlink-io.systemd.Repart.c b/src/shared/varlink-io.systemd.Repart.c index 35b860db9e..8d50454595 100644 --- a/src/shared/varlink-io.systemd.Repart.c +++ b/src/shared/varlink-io.systemd.Repart.c @@ -59,8 +59,9 @@ static SD_VARLINK_DEFINE_METHOD_FULL( SD_VARLINK_FIELD_COMMENT("If used with the 'more' flag, a progress percentrage (specific to the work done for the specified phase+object is sent in progress updates."), SD_VARLINK_DEFINE_OUTPUT(progress, SD_VARLINK_INT, SD_VARLINK_NULLABLE)); -static SD_VARLINK_DEFINE_METHOD( +static SD_VARLINK_DEFINE_METHOD_FULL( ListCandidateDevices, + SD_VARLINK_REQUIRES_MORE, SD_VARLINK_FIELD_COMMENT("Control whether to include the root disk of the currently booted OS in the list. Defaults to false, i.e. the root disk is included."), SD_VARLINK_DEFINE_INPUT(ignoreRoot, SD_VARLINK_BOOL, SD_VARLINK_NULLABLE), SD_VARLINK_FIELD_COMMENT("Control whether to include block devices with zero size in the list, i.e. typically block devices without any inserted medium. Defaults to false, i.e. empty block devices are included."), From e2fb041564a3c19fff5108f6af0209053583cd6b Mon Sep 17 00:00:00 2001 From: Mike Yuan Date: Sun, 15 Feb 2026 05:56:50 +0100 Subject: [PATCH 14/30] sd-varlink: shorten the code a bit --- src/libsystemd/sd-varlink/sd-varlink.c | 23 +++++------------------ 1 file changed, 5 insertions(+), 18 deletions(-) diff --git a/src/libsystemd/sd-varlink/sd-varlink.c b/src/libsystemd/sd-varlink/sd-varlink.c index eecc3c8865..4c6787ea3b 100644 --- a/src/libsystemd/sd-varlink/sd-varlink.c +++ b/src/libsystemd/sd-varlink/sd-varlink.c @@ -1857,19 +1857,10 @@ _public_ int sd_varlink_wait(sd_varlink *v, uint64_t timeout) { r = sd_varlink_get_timeout(v, &t); if (r < 0) return r; - if (t != USEC_INFINITY) { - usec_t n; + if (t != USEC_INFINITY) + t = usec_sub_unsigned(t, now(CLOCK_MONOTONIC)); - n = now(CLOCK_MONOTONIC); - if (t < n) - t = 0; - else - t = usec_sub_unsigned(t, n); - } - - if (timeout != USEC_INFINITY && - (t == USEC_INFINITY || timeout < t)) - t = timeout; + t = MIN(t, timeout); events = sd_varlink_get_events(v); if (events < 0) @@ -4293,20 +4284,16 @@ _public_ int sd_varlink_server_add_interface_many_internal(sd_varlink_server *s, } _public_ unsigned sd_varlink_server_connections_max(sd_varlink_server *s) { - int dts; /* If a server is specified, return the setting for that server, otherwise the default value */ if (s) return s->connections_max; - dts = getdtablesize(); + int dts = getdtablesize(); assert_se(dts > 0); /* Make sure we never use up more than ¾th of RLIMIT_NOFILE for IPC */ - if (VARLINK_DEFAULT_CONNECTIONS_MAX > (unsigned) dts / 4 * 3) - return dts / 4 * 3; - - return VARLINK_DEFAULT_CONNECTIONS_MAX; + return MIN(VARLINK_DEFAULT_CONNECTIONS_MAX, (unsigned) dts / 4 * 3); } _public_ unsigned sd_varlink_server_connections_per_uid_max(sd_varlink_server *s) { From 3482e4dd7067f855f51f6a19ed5200cdcdec3e8b Mon Sep 17 00:00:00 2001 From: Mike Yuan Date: Sun, 15 Feb 2026 05:36:56 +0100 Subject: [PATCH 15/30] sd-varlink: log about client uid that hit connection limit --- src/libsystemd/sd-varlink/sd-varlink.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libsystemd/sd-varlink/sd-varlink.c b/src/libsystemd/sd-varlink/sd-varlink.c index 4c6787ea3b..b04a43a35c 100644 --- a/src/libsystemd/sd-varlink/sd-varlink.c +++ b/src/libsystemd/sd-varlink/sd-varlink.c @@ -3547,8 +3547,8 @@ static int validate_connection(sd_varlink_server *server, const struct ucred *uc c = PTR_TO_UINT(hashmap_get(server->by_uid, UID_TO_PTR(ucred->uid))); if (c >= server->connections_per_uid_max) { - varlink_server_log(server, "Per-UID connection limit of %u reached, refusing.", - server->connections_per_uid_max); + varlink_server_log(server, "Per-UID connection limit of %u for '" UID_FMT "' reached, refusing.", + server->connections_per_uid_max, ucred->uid); return 0; } } From 122bde2c457095cb57b2b4fedc58b133777a5787 Mon Sep 17 00:00:00 2001 From: Mike Yuan Date: Sun, 15 Feb 2026 05:24:56 +0100 Subject: [PATCH 16/30] sd-varlink: also validate peer ucred for SD_VARLINK_SERVER_MYSELF_ONLY --- src/libsystemd/sd-varlink/sd-varlink.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libsystemd/sd-varlink/sd-varlink.c b/src/libsystemd/sd-varlink/sd-varlink.c index b04a43a35c..c7f6074617 100644 --- a/src/libsystemd/sd-varlink/sd-varlink.c +++ b/src/libsystemd/sd-varlink/sd-varlink.c @@ -3601,7 +3601,7 @@ _public_ int sd_varlink_server_add_connection_pair( assert_return(input_fd >= 0, -EBADF); assert_return(output_fd >= 0, -EBADF); - if ((server->flags & (SD_VARLINK_SERVER_ROOT_ONLY|SD_VARLINK_SERVER_ACCOUNT_UID)) != 0) { + if ((server->flags & (SD_VARLINK_SERVER_ROOT_ONLY|SD_VARLINK_SERVER_MYSELF_ONLY|SD_VARLINK_SERVER_ACCOUNT_UID)) != 0) { if (override_ucred) ucred = *override_ucred; From 9257690859cddb0e5a0842b2b694076986e61886 Mon Sep 17 00:00:00 2001 From: Mike Yuan Date: Sun, 15 Feb 2026 03:45:26 +0100 Subject: [PATCH 17/30] sd-varlink: replace manual move_fd() with FORK_PACK_FDS + FORK_CLOEXEC_OFF Note that this actually matters: we might otherwise clobber the logging fds reopened when rearranging fd '3'. While at it, avoid logging from library functions. --- src/libsystemd/sd-varlink/sd-varlink.c | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/src/libsystemd/sd-varlink/sd-varlink.c b/src/libsystemd/sd-varlink/sd-varlink.c index c7f6074617..198713d440 100644 --- a/src/libsystemd/sd-varlink/sd-varlink.c +++ b/src/libsystemd/sd-varlink/sd-varlink.c @@ -247,28 +247,20 @@ _public_ int sd_varlink_connect_exec(sd_varlink **ret, const char *_command, cha /* stdio_fds= */ NULL, /* except_fds= */ (int[]) { pair[1] }, /* n_except_fds= */ 1, - FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_DEATHSIG_SIGTERM|FORK_REOPEN_LOG|FORK_LOG|FORK_RLIMIT_NOFILE_SAFE, + FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_PACK_FDS|FORK_CLOEXEC_OFF|FORK_REOPEN_LOG|FORK_DEATHSIG_SIGTERM|FORK_RLIMIT_NOFILE_SAFE, &pidref); if (r < 0) return log_debug_errno(r, "Failed to spawn process: %m"); if (r == 0) { char spid[DECIMAL_STR_MAX(pid_t)+1]; const char *setenv_list[] = { - "LISTEN_FDS", "1", "LISTEN_PID", spid, + "LISTEN_FDS", "1", "LISTEN_FDNAMES", "varlink", NULL, NULL, }; /* Child */ - pair[0] = -EBADF; - - r = move_fd(pair[1], 3, /* cloexec= */ false); - if (r < 0) { - log_debug_errno(r, "Failed to move file descriptor to 3: %m"); - _exit(EXIT_FAILURE); - } - xsprintf(spid, PID_FMT, pidref.pid); uint64_t pidfdid; @@ -364,7 +356,7 @@ static int varlink_connect_ssh_unix(sd_varlink **ret, const char *where) { /* stdio_fds= */ (int[]) { pair[1], pair[1], STDERR_FILENO }, /* except_fds= */ NULL, /* n_except_fds= */ 0, - FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_DEATHSIG_SIGTERM|FORK_REOPEN_LOG|FORK_LOG|FORK_RLIMIT_NOFILE_SAFE|FORK_REARRANGE_STDIO, + FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_DEATHSIG_SIGTERM|FORK_REOPEN_LOG|FORK_RLIMIT_NOFILE_SAFE|FORK_REARRANGE_STDIO, &pidref); if (r < 0) return log_debug_errno(r, "Failed to spawn process: %m"); @@ -448,7 +440,7 @@ static int varlink_connect_ssh_exec(sd_varlink **ret, const char *where) { /* stdio_fds= */ (int[]) { input_pipe[0], output_pipe[1], STDERR_FILENO }, /* except_fds= */ NULL, /* n_except_fds= */ 0, - FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_DEATHSIG_SIGTERM|FORK_REOPEN_LOG|FORK_LOG|FORK_RLIMIT_NOFILE_SAFE|FORK_REARRANGE_STDIO, + FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_DEATHSIG_SIGTERM|FORK_REOPEN_LOG|FORK_RLIMIT_NOFILE_SAFE|FORK_REARRANGE_STDIO, &pidref); if (r < 0) return log_debug_errno(r, "Failed to spawn process: %m"); From 959f6923e50098650724f9c5d132f19e9e40dc9c Mon Sep 17 00:00:00 2001 From: Mike Yuan Date: Wed, 11 Feb 2026 16:29:37 +0100 Subject: [PATCH 18/30] sd-varlink: use free_and_replace at one more place --- src/libsystemd/sd-varlink/sd-varlink.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/libsystemd/sd-varlink/sd-varlink.c b/src/libsystemd/sd-varlink/sd-varlink.c index 198713d440..d6d3b5bcb9 100644 --- a/src/libsystemd/sd-varlink/sd-varlink.c +++ b/src/libsystemd/sd-varlink/sd-varlink.c @@ -1381,15 +1381,14 @@ static int varlink_format_queue(sd_varlink *v) { * would not corrupt our fd message boundaries */ while (v->output_queue) { - _cleanup_free_ int *array = NULL; - assert(v->n_output_queue > 0); - VarlinkJsonQueueItem *q = v->output_queue; - if (v->n_output_fds > 0) /* unwritten fds? if we'd add more we'd corrupt the fd message boundaries, hence wait */ return 0; + VarlinkJsonQueueItem *q = v->output_queue; + _cleanup_free_ int *array = NULL; + if (q->n_fds > 0) { array = newdup(int, q->fds, q->n_fds); if (!array) @@ -1401,8 +1400,7 @@ static int varlink_format_queue(sd_varlink *v) { return r; /* Take possession of the queue element's fds */ - free(v->output_fds); - v->output_fds = TAKE_PTR(array); + free_and_replace(v->output_fds, array); v->n_output_fds = q->n_fds; q->n_fds = 0; From 86ac1083c9b5db3fb71f27a543660449b5e234e5 Mon Sep 17 00:00:00 2001 From: Mike Yuan Date: Wed, 11 Feb 2026 18:02:04 +0100 Subject: [PATCH 19/30] sd-varlink: _reset_fds() should reset fds for the reply being constructed ... (aka pushed_fds), not what's already enqueued to be sent out. --- src/libsystemd/sd-varlink/sd-varlink.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libsystemd/sd-varlink/sd-varlink.c b/src/libsystemd/sd-varlink/sd-varlink.c index d6d3b5bcb9..faa56d9d3a 100644 --- a/src/libsystemd/sd-varlink/sd-varlink.c +++ b/src/libsystemd/sd-varlink/sd-varlink.c @@ -2662,8 +2662,8 @@ _public_ int sd_varlink_reset_fds(sd_varlink *v) { * rollback the fds. Note that this is implicitly called whenever an error reply is sent, see * below. */ - close_many(v->output_fds, v->n_output_fds); - v->n_output_fds = 0; + close_many(v->pushed_fds, v->n_pushed_fds); + v->n_pushed_fds = 0; return 0; } From 1f9ba6ba73aed7f96cc0399ae479e39b286d317e Mon Sep 17 00:00:00 2001 From: Mike Yuan Date: Thu, 12 Feb 2026 01:11:30 +0100 Subject: [PATCH 20/30] sd-varlink: take output queue into account in sd_varlink_flush() --- src/libsystemd/sd-varlink/sd-varlink.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libsystemd/sd-varlink/sd-varlink.c b/src/libsystemd/sd-varlink/sd-varlink.c index faa56d9d3a..1217d1f7cf 100644 --- a/src/libsystemd/sd-varlink/sd-varlink.c +++ b/src/libsystemd/sd-varlink/sd-varlink.c @@ -2000,7 +2000,7 @@ _public_ int sd_varlink_flush(sd_varlink *v) { return varlink_log_errno(v, SYNTHETIC_ERRNO(ENOTCONN), "Not connected."); for (;;) { - if (v->output_buffer_size == 0) + if (v->output_buffer_size == 0 && !v->output_queue) break; if (v->write_disconnected) return -ECONNRESET; From eeead6e1774a3022ed2983d3488d6d6f34d8a0d4 Mon Sep 17 00:00:00 2001 From: Mike Yuan Date: Thu, 12 Feb 2026 01:09:49 +0100 Subject: [PATCH 21/30] sd-varlink: fail if a method call wasn't replied to and the callback didn't store it --- src/libsystemd/sd-varlink/sd-varlink.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/libsystemd/sd-varlink/sd-varlink.c b/src/libsystemd/sd-varlink/sd-varlink.c index 1217d1f7cf..4e7467e6d0 100644 --- a/src/libsystemd/sd-varlink/sd-varlink.c +++ b/src/libsystemd/sd-varlink/sd-varlink.c @@ -1583,7 +1583,7 @@ static int varlink_dispatch_method(sd_varlink *v) { r = callback(v, parameters, flags, v->userdata); if (VARLINK_STATE_WANTS_REPLY(v->state)) { if (r < 0) { - varlink_log_errno(v, r, "Callback for %s returned error: %m", method); + varlink_log_errno(v, r, "Callback for '%s' returned error: %m", method); /* We got an error back from the callback. Propagate it to the client * if the method call remains unanswered. */ @@ -1612,6 +1612,16 @@ static int varlink_dispatch_method(sd_varlink *v) { varlink_log_errno(v, r, "Failed to process sentinel for method '%s': %m", method); } else { assert(!v->previous); + + /* We're at the bare minimum referenced by sd_varlink_server and + * sd_varlink_process() */ + if (v->n_ref <= 2) { + r = varlink_log_errno(v, SYNTHETIC_ERRNO(EPROTO), + "Callback for method '%s' returned without enqueuing a reply or stashing connection, failing.", + method); + goto fail; + } + r = 0; } From fe48347ce63e48445f1e9e69a3047a29cc034b7f Mon Sep 17 00:00:00 2001 From: Mike Yuan Date: Sun, 15 Feb 2026 02:05:07 +0100 Subject: [PATCH 22/30] core/varlink-cgroup: add BindNetworkInterface to varlink CGContext Follow-up for c1c787651b34c0a0f1082b9d32cf47ea3abe0af2 --- src/core/varlink-cgroup.c | 1 + src/shared/varlink-io.systemd.Unit.c | 2 ++ 2 files changed, 3 insertions(+) diff --git a/src/core/varlink-cgroup.c b/src/core/varlink-cgroup.c index 2e0c086f95..65c07ecfad 100644 --- a/src/core/varlink-cgroup.c +++ b/src/core/varlink-cgroup.c @@ -299,6 +299,7 @@ int unit_cgroup_context_build_json(sd_json_variant **ret, const char *name, void SD_JSON_BUILD_OBJECT( SD_JSON_BUILD_PAIR_BOOLEAN("isAllowList", c->restrict_network_interfaces_is_allow_list), JSON_BUILD_PAIR_STRING_SET("interfaces", c->restrict_network_interfaces))), + JSON_BUILD_PAIR_STRING_NON_EMPTY("BindNetworkInterface", c->bind_network_interface), JSON_BUILD_PAIR_CALLBACK_NON_NULL("NFTSet", nft_set_build_json, &c->nft_set_context), /* BPF programs */ diff --git a/src/shared/varlink-io.systemd.Unit.c b/src/shared/varlink-io.systemd.Unit.c index 19d384dd91..7ea6a7bc54 100644 --- a/src/shared/varlink-io.systemd.Unit.c +++ b/src/shared/varlink-io.systemd.Unit.c @@ -179,6 +179,8 @@ static SD_VARLINK_DEFINE_STRUCT_TYPE( SD_VARLINK_DEFINE_FIELD_BY_TYPE(SocketBindDeny, CGroupSocketBind, SD_VARLINK_ARRAY|SD_VARLINK_NULLABLE), SD_VARLINK_FIELD_COMMENT("https://www.freedesktop.org/software/systemd/man/"PROJECT_VERSION_STR"/systemd.resource-control.html#RestrictNetworkInterfaces="), SD_VARLINK_DEFINE_FIELD_BY_TYPE(RestrictNetworkInterfaces, CGroupRestrictNetworkInterfaces, SD_VARLINK_NULLABLE), + SD_VARLINK_FIELD_COMMENT("https://www.freedesktop.org/software/systemd/man/"PROJECT_VERSION_STR"/systemd.resource-control.html#BindNetworkInterface="), + SD_VARLINK_DEFINE_FIELD(BindNetworkInterface, SD_VARLINK_STRING, SD_VARLINK_NULLABLE), SD_VARLINK_FIELD_COMMENT("https://www.freedesktop.org/software/systemd/man/"PROJECT_VERSION_STR"/systemd.resource-control.html#NFTSet=family:table:set"), SD_VARLINK_DEFINE_FIELD_BY_TYPE(NFTSet, CGroupNFTSet, SD_VARLINK_ARRAY|SD_VARLINK_NULLABLE), From 3cfd35eef9eb162f1b3e0ebcc693f5c43892dee1 Mon Sep 17 00:00:00 2001 From: Mike Yuan Date: Fri, 13 Feb 2026 17:48:15 +0100 Subject: [PATCH 23/30] core/varlink-metrics: include core-forward.h --- src/core/varlink-metrics.c | 3 +++ src/core/varlink-metrics.h | 3 +-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/core/varlink-metrics.c b/src/core/varlink-metrics.c index 15bd1f154c..69eff4ef8a 100644 --- a/src/core/varlink-metrics.c +++ b/src/core/varlink-metrics.c @@ -1,5 +1,8 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ +#include "sd-json.h" +#include "sd-varlink.h" + #include "hashmap.h" #include "manager.h" #include "metrics.h" diff --git a/src/core/varlink-metrics.h b/src/core/varlink-metrics.h index 92e7d81cf8..782a3641c3 100644 --- a/src/core/varlink-metrics.h +++ b/src/core/varlink-metrics.h @@ -1,8 +1,7 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once -#include "sd-varlink.h" -#include "sd-json.h" +#include "core-forward.h" #define METRIC_IO_SYSTEMD_MANAGER_PREFIX "io.systemd.Manager." From ba5bd88db3bc9f4eaad2aa50bd1795b5dfa0a355 Mon Sep 17 00:00:00 2001 From: Mike Yuan Date: Fri, 13 Feb 2026 18:14:34 +0100 Subject: [PATCH 24/30] core/varlink-metrics: suffix metrics methods with _metrics This is not even the prominent "Describe" method in pid1, as typically one would be looking for _describe_manager(). --- src/core/varlink-metrics.c | 4 ++-- src/core/varlink-metrics.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/core/varlink-metrics.c b/src/core/varlink-metrics.c index 69eff4ef8a..1bfdb1f5d7 100644 --- a/src/core/varlink-metrics.c +++ b/src/core/varlink-metrics.c @@ -178,10 +178,10 @@ const MetricFamily metric_family_table[] = { {} }; -int vl_method_describe(sd_varlink *link, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata) { +int vl_method_describe_metrics(sd_varlink *link, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata) { return metrics_method_describe(metric_family_table, link, parameters, flags, userdata); } -int vl_method_list(sd_varlink *link, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata) { +int vl_method_list_metrics(sd_varlink *link, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata) { return metrics_method_list(metric_family_table, link, parameters, flags, userdata); } diff --git a/src/core/varlink-metrics.h b/src/core/varlink-metrics.h index 782a3641c3..5347774f2d 100644 --- a/src/core/varlink-metrics.h +++ b/src/core/varlink-metrics.h @@ -5,5 +5,5 @@ #define METRIC_IO_SYSTEMD_MANAGER_PREFIX "io.systemd.Manager." -int vl_method_list(sd_varlink *link, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata); -int vl_method_describe(sd_varlink *link, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata); +int vl_method_list_metrics(sd_varlink *link, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata); +int vl_method_describe_metrics(sd_varlink *link, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata); From 702db03034aeef264d9af0b76cc39ee0fb1ec9aa Mon Sep 17 00:00:00 2001 From: Mike Yuan Date: Fri, 13 Feb 2026 17:31:33 +0100 Subject: [PATCH 25/30] shared/metrics: name the sd_varlink_server in our usual fashion This is used for internal reference, in debug logging and such, hence let's do nothing fancy but instead make it identifiable. --- src/shared/metrics.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/shared/metrics.c b/src/shared/metrics.c index 9c7cf282cb..0fc25ea7b5 100644 --- a/src/shared/metrics.c +++ b/src/shared/metrics.c @@ -41,7 +41,7 @@ int metrics_setup_varlink_server( if (r < 0) return log_debug_errno(r, "Failed to register varlink metrics methods: %m"); - r = sd_varlink_server_set_description(s, "systemd varlink metrics server"); + r = sd_varlink_server_set_description(s, "varlink-metrics"); if (r < 0) return log_debug_errno(r, "Failed to set varlink metrics server description: %m"); From ba08fa3230adb20159e3260e01db8f8f38f933e7 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Mon, 16 Feb 2026 15:26:21 +0900 Subject: [PATCH 26/30] shared/metrics: add two more assertions --- src/shared/metrics.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/shared/metrics.c b/src/shared/metrics.c index 0fc25ea7b5..5e0b0a1158 100644 --- a/src/shared/metrics.c +++ b/src/shared/metrics.c @@ -20,6 +20,8 @@ int metrics_setup_varlink_server( assert(server); assert(event); + assert(vl_method_list_cb); + assert(vl_method_describe_cb); if (*server) return 0; @@ -34,10 +36,8 @@ int metrics_setup_varlink_server( r = sd_varlink_server_bind_method_many( s, - "io.systemd.Metrics.List", - vl_method_list_cb, - "io.systemd.Metrics.Describe", - vl_method_describe_cb); + "io.systemd.Metrics.List", vl_method_list_cb, + "io.systemd.Metrics.Describe", vl_method_describe_cb); if (r < 0) return log_debug_errno(r, "Failed to register varlink metrics methods: %m"); From 9676845efa8b3d4140ab7bb8e567d22717c66b9e Mon Sep 17 00:00:00 2001 From: Mike Yuan Date: Fri, 13 Feb 2026 17:37:10 +0100 Subject: [PATCH 27/30] core/varlink: several cleanups for metrics varlink server Follow-up for bb1ef2edf7d62de35291702635067ee85f09bad5 The commit introduced a new "metrics" varlink server, but for user scope stuff it is not bound anywhere. The copy-pasted "fresh" handling for deserialization is also essentially meaningless as metrics_setup_varlink_server() doesn't even report whether the varlink server is fresh (let alone that no serialization is being done at all right now). Moreover, currently the event priority is hardcoded, while event loop and associated priority assignment ought to be subject to each daemon. While fixing the mentioned issues I took the chance to restructure the existing code a bit for readability. Note that serialization for the metrics server is still missing - it will be tackled in subsequent commits. --- src/core/varlink.c | 155 +++++++++++++++++++++++++++---------------- src/core/varlink.h | 1 + src/shared/metrics.c | 6 +- src/shared/metrics.h | 1 + 4 files changed, 102 insertions(+), 61 deletions(-) diff --git a/src/core/varlink.c b/src/core/varlink.c index b5b00cdf74..76beeba434 100644 --- a/src/core/varlink.c +++ b/src/core/varlink.c @@ -9,7 +9,6 @@ #include "path-util.h" #include "pidref.h" #include "string-util.h" -#include "strv.h" #include "unit.h" #include "varlink.h" #include "varlink-dynamic-user.h" @@ -375,6 +374,8 @@ int manager_setup_varlink_server(Manager *m) { if (r < 0) return log_debug_errno(r, "Failed to allocate Varlink server: %m"); + (void) sd_varlink_server_set_description(s, "varlink-api"); + r = sd_varlink_server_add_interface_many( s, &vl_interface_io_systemd_Manager, @@ -425,26 +426,64 @@ int manager_setup_varlink_server(Manager *m) { return 1; } -static int manager_setup_varlink_metrics_server(Manager *m) { - sd_varlink_server_flags_t flags = SD_VARLINK_SERVER_INHERIT_USERDATA; - int r; - +int manager_setup_varlink_metrics_server(Manager *m) { assert(m); + sd_varlink_server_flags_t flags = SD_VARLINK_SERVER_INHERIT_USERDATA; if (MANAGER_IS_SYSTEM(m)) flags |= SD_VARLINK_SERVER_ACCOUNT_UID; - r = metrics_setup_varlink_server( - &m->metrics_varlink_server, flags, m->event, vl_method_list, vl_method_describe, m); - if (r < 0) - return r; - - return 0; + return metrics_setup_varlink_server(&m->metrics_varlink_server, flags, + m->event, EVENT_PRIORITY_IPC, + vl_method_list_metrics, vl_method_describe_metrics, + m); } -static int manager_varlink_init_system(Manager *m) { +static int varlink_server_listen_many_idempotent_sentinel( + sd_varlink_server *s, + bool known_fresh, + const char *prefix, + ...) { + + va_list ap; + int r = 0; + + assert(s); + + va_start(ap, prefix); + for (const char *address; (address = va_arg(ap, const char*)); ) { + _cleanup_free_ char *p = NULL; + + if (prefix) { + p = path_join(prefix, address); + if (!p) { + r = log_oom(); + break; + } + + address = p; + } + + /* We might have got sockets through deserialization. Do not bind to them twice. */ + if (!known_fresh && varlink_server_contains_socket(s, address)) + continue; + + r = sd_varlink_server_listen_address(s, address, 0666 | SD_VARLINK_SERVER_MODE_MKDIR_0755); + if (r < 0) { + log_error_errno(r, "Failed to bind to varlink socket '%s': %m", address); + break; + } + } + va_end(ap); + + return r; +} + +#define varlink_server_listen_many_idempotent(s, known_fresh, prefix, ...) \ + varlink_server_listen_many_idempotent_sentinel((s), (known_fresh), (prefix), __VA_ARGS__, NULL) + +static int manager_varlink_init_system_api(Manager *m) { int r; - _cleanup_free_ char *metrics_address = NULL; assert(m); @@ -453,38 +492,21 @@ static int manager_varlink_init_system(Manager *m) { return log_error_errno(r, "Failed to set up varlink server: %m"); bool fresh = r > 0; - r = manager_setup_varlink_metrics_server(m); - if (r < 0) - return log_error_errno(r, "Failed to set up metrics varlink server: %m"); - bool metrics_fresh = r > 0; - - r = runtime_directory_generic(m->runtime_scope, "systemd/report/io.systemd.Manager", &metrics_address); - if (r < 0) - return r; - if (!MANAGER_IS_TEST_RUN(m)) { - FOREACH_STRING(address, - "/run/systemd/userdb/io.systemd.DynamicUser", - VARLINK_PATH_MANAGED_OOM_SYSTEM, - "/run/systemd/io.systemd.Manager", - metrics_address) { - - sd_varlink_server *server = streq(address, metrics_address) ? m->metrics_varlink_server : m->varlink_server; - fresh = streq(address, metrics_address) ? metrics_fresh : fresh; - /* We might have got sockets through deserialization. Do not bind to them twice. */ - if (!fresh && varlink_server_contains_socket(server, address)) - continue; - - r = sd_varlink_server_listen_address(server, address, 0666 | SD_VARLINK_SERVER_MODE_MKDIR_0755); - if (r < 0) - return log_error_errno(r, "Failed to bind to varlink socket '%s': %m", address); - } + r = varlink_server_listen_many_idempotent( + m->varlink_server, fresh, + /* prefix = */ NULL, + "/run/systemd/io.systemd.Manager", + "/run/systemd/userdb/io.systemd.DynamicUser", + VARLINK_PATH_MANAGED_OOM_SYSTEM); + if (r < 0) + return r; } - return 1; + return 0; } -static int manager_varlink_init_user(Manager *m) { +static int manager_varlink_init_user_api(Manager *m) { int r; assert(m); @@ -497,30 +519,46 @@ static int manager_varlink_init_user(Manager *m) { return log_error_errno(r, "Failed to set up varlink server: %m"); bool fresh = r > 0; - FOREACH_STRING(a, - "systemd/io.systemd.Manager") { - _cleanup_free_ char *address = NULL; - address = path_join(m->prefix[EXEC_DIRECTORY_RUNTIME], a); - if (!address) - return -ENOMEM; - /* We might have got sockets through deserialization. Do not bind to them twice. */ - if (!fresh && varlink_server_contains_socket(m->varlink_server, address)) - continue; - - r = sd_varlink_server_listen_address(m->varlink_server, address, 0666 | SD_VARLINK_SERVER_MODE_MKDIR_0755); - if (r < 0) - return log_error_errno(r, "Failed to bind to varlink socket '%s': %m", address); - } - - r = manager_setup_varlink_metrics_server(m); + r = varlink_server_listen_many_idempotent( + m->varlink_server, fresh, + m->prefix[EXEC_DIRECTORY_RUNTIME], + "systemd/io.systemd.Manager"); if (r < 0) - return log_error_errno(r, "Failed to set up metrics varlink server: %m"); + return r; return manager_varlink_managed_oom_connect(m); } +static int manager_varlink_init_metrics(Manager *m) { + int r; + + assert(m); + + if (MANAGER_IS_TEST_RUN(m)) + return 0; + + r = manager_setup_varlink_metrics_server(m); + if (r < 0) + return log_error_errno(r, "Failed to set up metrics varlink server: %m"); + bool fresh = r > 0; + + return varlink_server_listen_many_idempotent( + m->metrics_varlink_server, fresh, + m->prefix[EXEC_DIRECTORY_RUNTIME], + "systemd/report/io.systemd.Manager"); +} + int manager_varlink_init(Manager *m) { - return MANAGER_IS_SYSTEM(m) ? manager_varlink_init_system(m) : manager_varlink_init_user(m); + int r; + + if (MANAGER_IS_SYSTEM(m)) + r = manager_varlink_init_system_api(m); + else + r = manager_varlink_init_user_api(m); + if (r < 0) + return r; + + return manager_varlink_init_metrics(m); } void manager_varlink_done(Manager *m) { @@ -534,6 +572,7 @@ void manager_varlink_done(Manager *m) { m->varlink_server = sd_varlink_server_unref(m->varlink_server); m->managed_oom_varlink = sd_varlink_close_unref(m->managed_oom_varlink); + m->metrics_varlink_server = sd_varlink_server_unref(m->metrics_varlink_server); } diff --git a/src/core/varlink.h b/src/core/varlink.h index f959cf8a67..119394386b 100644 --- a/src/core/varlink.h +++ b/src/core/varlink.h @@ -4,6 +4,7 @@ #include "core-forward.h" int manager_setup_varlink_server(Manager *m); +int manager_setup_varlink_metrics_server(Manager *m); int manager_varlink_init(Manager *m); void manager_varlink_done(Manager *m); diff --git a/src/shared/metrics.c b/src/shared/metrics.c index 5e0b0a1158..3b8965dbdc 100644 --- a/src/shared/metrics.c +++ b/src/shared/metrics.c @@ -11,6 +11,7 @@ int metrics_setup_varlink_server( sd_varlink_server **server, /* in and out param */ sd_varlink_server_flags_t flags, sd_event *event, + int64_t priority, sd_varlink_method_t vl_method_list_cb, sd_varlink_method_t vl_method_describe_cb, void *userdata) { @@ -45,13 +46,12 @@ int metrics_setup_varlink_server( if (r < 0) return log_debug_errno(r, "Failed to set varlink metrics server description: %m"); - r = sd_varlink_server_attach_event(s, event, SD_EVENT_PRIORITY_NORMAL); + r = sd_varlink_server_attach_event(s, event, priority); if (r < 0) return log_debug_errno(r, "Failed to attach varlink metrics server to event loop: %m"); *server = TAKE_PTR(s); - - return 0; + return 1; } static const char * const metric_family_type_table[_METRIC_FAMILY_TYPE_MAX] = { diff --git a/src/shared/metrics.h b/src/shared/metrics.h index cec0153e68..ffc28cb0a9 100644 --- a/src/shared/metrics.h +++ b/src/shared/metrics.h @@ -31,6 +31,7 @@ int metrics_setup_varlink_server( sd_varlink_server **server, /* in and out param */ sd_varlink_server_flags_t flags, sd_event *event, + int64_t priority, sd_varlink_method_t vl_method_list_cb, sd_varlink_method_t vl_method_describe_cb, void *userdata); From b166461f82ee68a43897bd0a0babb26fd5d57aa6 Mon Sep 17 00:00:00 2001 From: Mike Yuan Date: Sun, 15 Feb 2026 03:21:01 +0100 Subject: [PATCH 28/30] varlink-serialize: deserialize to correct event priority --- src/libsystemd/sd-varlink/sd-varlink.c | 16 +++++++--------- src/libsystemd/sd-varlink/varlink-internal.h | 2 +- src/shared/varlink-serialize.c | 2 +- 3 files changed, 9 insertions(+), 11 deletions(-) diff --git a/src/libsystemd/sd-varlink/sd-varlink.c b/src/libsystemd/sd-varlink/sd-varlink.c index 4e7467e6d0..bcb16af89f 100644 --- a/src/libsystemd/sd-varlink/sd-varlink.c +++ b/src/libsystemd/sd-varlink/sd-varlink.c @@ -3743,11 +3743,7 @@ static int varlink_server_create_listen_fd_socket(sd_varlink_server *s, int fd, }; if (s->event) { - r = sd_event_add_io(s->event, &ss->event_source, fd, EPOLLIN, connect_callback, ss); - if (r < 0) - return r; - - r = sd_event_source_set_priority(ss->event_source, s->event_priority); + r = varlink_server_add_socket_event_source(s, ss); if (r < 0) return r; } @@ -4071,13 +4067,14 @@ _public_ int sd_varlink_server_set_exit_on_idle(sd_varlink_server *s, int b) { return 0; } -int varlink_server_add_socket_event_source(sd_varlink_server *s, VarlinkServerSocket *ss, int64_t priority) { +int varlink_server_add_socket_event_source(sd_varlink_server *s, VarlinkServerSocket *ss) { _cleanup_(sd_event_source_unrefp) sd_event_source *es = NULL; int r; assert(s); assert(s->event); assert(ss); + assert(ss->server == s); assert(ss->fd >= 0); assert(!ss->event_source); @@ -4085,7 +4082,7 @@ int varlink_server_add_socket_event_source(sd_varlink_server *s, VarlinkServerSo if (r < 0) return r; - r = sd_event_source_set_priority(es, priority); + r = sd_event_source_set_priority(es, s->event_priority); if (r < 0) return r; @@ -4107,13 +4104,14 @@ _public_ int sd_varlink_server_attach_event(sd_varlink_server *s, sd_event *e, i return r; } + s->event_priority = priority; + LIST_FOREACH(sockets, ss, s->sockets) { - r = varlink_server_add_socket_event_source(s, ss, priority); + r = varlink_server_add_socket_event_source(s, ss); if (r < 0) goto fail; } - s->event_priority = priority; return 0; fail: diff --git a/src/libsystemd/sd-varlink/varlink-internal.h b/src/libsystemd/sd-varlink/varlink-internal.h index 6486851424..39b15e12a1 100644 --- a/src/libsystemd/sd-varlink/varlink-internal.h +++ b/src/libsystemd/sd-varlink/varlink-internal.h @@ -262,4 +262,4 @@ static inline const char* varlink_server_description(sd_varlink_server *s) { VarlinkServerSocket* varlink_server_socket_free(VarlinkServerSocket *ss); DEFINE_TRIVIAL_CLEANUP_FUNC(VarlinkServerSocket *, varlink_server_socket_free); -int varlink_server_add_socket_event_source(sd_varlink_server *s, VarlinkServerSocket *ss, int64_t priority); +int varlink_server_add_socket_event_source(sd_varlink_server *s, VarlinkServerSocket *ss); diff --git a/src/shared/varlink-serialize.c b/src/shared/varlink-serialize.c index 906a1020de..d9199f2869 100644 --- a/src/shared/varlink-serialize.c +++ b/src/shared/varlink-serialize.c @@ -83,7 +83,7 @@ int varlink_server_deserialize_one(sd_varlink_server *s, const char *value, FDSe .fd = fdset_remove(fds, fd), }; - r = varlink_server_add_socket_event_source(s, ss, SD_EVENT_PRIORITY_NORMAL); + r = varlink_server_add_socket_event_source(s, ss); if (r < 0) return varlink_server_log_errno(s, r, "Failed to add VarlinkServerSocket event source to the event loop: %m"); From 5561623ef474fff77d66009feebe7099b5a2b1df Mon Sep 17 00:00:00 2001 From: Mike Yuan Date: Fri, 13 Feb 2026 20:36:39 +0100 Subject: [PATCH 29/30] core/manager-serialize: discern daemon-reload/reexec via objective --- src/core/manager-serialize.c | 23 ++++++++--------------- 1 file changed, 8 insertions(+), 15 deletions(-) diff --git a/src/core/manager-serialize.c b/src/core/manager-serialize.c index 9318d02f9a..f40df69764 100644 --- a/src/core/manager-serialize.c +++ b/src/core/manager-serialize.c @@ -282,7 +282,6 @@ static void manager_deserialize_gid_refs_one(Manager *m, const char *value) { } int manager_deserialize(Manager *m, FILE *f, FDSet *fds) { - bool deserialize_varlink_sockets = false; int r; assert(m); @@ -491,22 +490,16 @@ int manager_deserialize(Manager *m, FILE *f, FDSet *fds) { if (r < 0) return r; } else if ((val = startswith(l, "varlink-server-socket-address="))) { - if (!m->varlink_server) { - r = manager_setup_varlink_server(m); - if (r < 0) { - log_warning_errno(r, "Failed to setup varlink server, ignoring: %m"); - continue; - } + if (m->objective == MANAGER_RELOAD) + /* We don't destroy varlink server on daemon-reload (in contrast to reexec) -> skip! */ + continue; - deserialize_varlink_sockets = true; - } - - /* To avoid unnecessary deserialization (i.e. during reload vs. reexec) we only deserialize - * the FDs if we had to create a new m->varlink_server. The deserialize_varlink_sockets flag - * is initialized outside of the loop, is flipped after the VarlinkServer is setup, and - * remains set until all serialized contents are handled. */ - if (deserialize_varlink_sockets) + r = manager_setup_varlink_server(m); + if (r < 0) + log_warning_errno(r, "Failed to setup varlink server, ignoring: %m"); + else (void) varlink_server_deserialize_one(m->varlink_server, val, fds); + } else if ((val = startswith(l, "dump-ratelimit="))) deserialize_ratelimit(&m->dump_ratelimit, "dump-ratelimit", val); else if ((val = startswith(l, "reload-reexec-ratelimit="))) From 389cd296ecad9969df46063604197c19bb3f7620 Mon Sep 17 00:00:00 2001 From: Mike Yuan Date: Fri, 13 Feb 2026 20:22:13 +0100 Subject: [PATCH 30/30] core: serialize metrics varlink server as well --- src/core/manager-serialize.c | 19 ++++++++- src/shared/varlink-serialize.c | 71 ++++++++++++++++------------------ src/shared/varlink-serialize.h | 2 +- 3 files changed, 52 insertions(+), 40 deletions(-) diff --git a/src/core/manager-serialize.c b/src/core/manager-serialize.c index f40df69764..2357b9277c 100644 --- a/src/core/manager-serialize.c +++ b/src/core/manager-serialize.c @@ -171,7 +171,11 @@ int manager_serialize( if (r < 0) return r; - r = varlink_server_serialize(m->varlink_server, f, fds); + r = varlink_server_serialize(m->varlink_server, /* name = */ NULL, f, fds); + if (r < 0) + return r; + + r = varlink_server_serialize(m->metrics_varlink_server, "metrics", f, fds); if (r < 0) return r; @@ -489,7 +493,18 @@ int manager_deserialize(Manager *m, FILE *f, FDSet *fds) { r = strv_extend(&m->subscribed_as_strv, val); if (r < 0) return r; - } else if ((val = startswith(l, "varlink-server-socket-address="))) { + } else if ((val = startswith(l, "varlink-server-metrics-"))) { + if (m->objective == MANAGER_RELOAD) + /* We don't destroy varlink server on daemon-reload (in contrast to reexec) -> skip! */ + continue; + + r = manager_setup_varlink_metrics_server(m); + if (r < 0) + log_warning_errno(r, "Failed to setup metrics varlink server, ignoring: %m"); + else + (void) varlink_server_deserialize_one(m->metrics_varlink_server, val, fds); + + } else if ((val = startswith(l, "varlink-server-"))) { if (m->objective == MANAGER_RELOAD) /* We don't destroy varlink server on daemon-reload (in contrast to reexec) -> skip! */ continue; diff --git a/src/shared/varlink-serialize.c b/src/shared/varlink-serialize.c index d9199f2869..7ea8ca7552 100644 --- a/src/shared/varlink-serialize.c +++ b/src/shared/varlink-serialize.c @@ -1,78 +1,73 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ -#include "sd-event.h" - #include "alloc-util.h" +#include "extract-word.h" +#include "fd-util.h" #include "fdset.h" #include "log.h" -#include "parse-util.h" +#include "serialize.h" #include "socket-util.h" #include "string-util.h" #include "varlink-internal.h" #include "varlink-serialize.h" -int varlink_server_serialize(sd_varlink_server *s, FILE *f, FDSet *fds) { +int varlink_server_serialize(sd_varlink_server *s, const char *name, FILE *f, FDSet *fds) { assert(f); assert(fds); if (!s) return 0; - LIST_FOREACH(sockets, ss, s->sockets) { - int copy; + const char *prefix = name ? strjoina("varlink-server-", name) : "varlink-server"; + LIST_FOREACH(sockets, ss, s->sockets) { assert(ss->address); assert(ss->fd >= 0); - fprintf(f, "varlink-server-socket-address=%s", ss->address); - /* If we fail to serialize the fd, it will be considered an error during deserialization */ - copy = fdset_put_dup(fds, ss->fd); + int copy = fdset_put_dup(fds, ss->fd); if (copy < 0) return copy; - fprintf(f, " varlink-server-socket-fd=%i", copy); - - fputc('\n', f); + fprintf(f, "%s-socket-address=%s varlink-server-socket-fd=%d\n", prefix, ss->address, copy); } return 0; } int varlink_server_deserialize_one(sd_varlink_server *s, const char *value, FDSet *fds) { - _cleanup_(varlink_server_socket_freep) VarlinkServerSocket *ss = NULL; _cleanup_free_ char *address = NULL; - const char *v = ASSERT_PTR(value); - int r, fd = -EBADF; - char *buf; - size_t n; + _cleanup_close_ int fd = -EBADF; + const char *v; + int r; + + /* This function expects a serialization line with "varlink-server(-name)-" prefix stripped! */ assert(s); + assert(value); assert(fds); - n = strcspn(v, " "); - address = strndup(v, n); - if (!address) - return log_oom_debug(); - - if (v[n] != ' ') - return varlink_server_log_errno(s, SYNTHETIC_ERRNO(EINVAL), - "Failed to deserialize sd_varlink_server_socket: %s", value); - v = startswith(v + n + 1, "varlink-server-socket-fd="); + v = startswith(value, "socket-address="); if (!v) - return varlink_server_log_errno(s, SYNTHETIC_ERRNO(EINVAL), - "Failed to deserialize VarlinkServerSocket fd: %s", value); + return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), + "Invalid varlink server serialization entry: %s", value); - n = strcspn(v, " "); - buf = strndupa_safe(v, n); - - fd = parse_fd(buf); - if (fd < 0) - return varlink_server_log_errno(s, fd, "Unable to parse VarlinkServerSocket varlink-server-socket-fd=%s: %m", buf); - if (!fdset_contains(fds, fd)) + r = extract_first_word(&v, &address, " ", /* flags = */ 0); + if (r <= 0) + return varlink_server_log_errno(s, r < 0 ? r : SYNTHETIC_ERRNO(ENODATA), + "Failed to extract socket address from varlink serialization: %s", value); + if (v) + v = startswith(v, "varlink-server-socket-fd="); + if (!v) return varlink_server_log_errno(s, SYNTHETIC_ERRNO(EBADF), - "VarlinkServerSocket varlink-server-socket-fd= has unknown fd: %d", fd); + "Got varlink serialization without socket fd, refusing."); + fd = deserialize_fd(fds, v); + if (fd < 0) + return varlink_server_log_errno(s, fd, "Failed to deserialize varlink socket fd: %m"); + + /* NB: varlink_server_socket_free() does not close the fd! */ + _cleanup_(varlink_server_socket_freep) VarlinkServerSocket *ss = NULL; ss = new(VarlinkServerSocket, 1); if (!ss) return log_oom_debug(); @@ -80,7 +75,7 @@ int varlink_server_deserialize_one(sd_varlink_server *s, const char *value, FDSe *ss = (VarlinkServerSocket) { .server = s, .address = TAKE_PTR(address), - .fd = fdset_remove(fds, fd), + .fd = fd, }; r = varlink_server_add_socket_event_source(s, ss); @@ -88,6 +83,8 @@ int varlink_server_deserialize_one(sd_varlink_server *s, const char *value, FDSe return varlink_server_log_errno(s, r, "Failed to add VarlinkServerSocket event source to the event loop: %m"); LIST_PREPEND(sockets, s->sockets, TAKE_PTR(ss)); + TAKE_FD(fd); /* ownership is now transferred to varlink server */ + return 0; } diff --git a/src/shared/varlink-serialize.h b/src/shared/varlink-serialize.h index db5de52161..99bf046f04 100644 --- a/src/shared/varlink-serialize.h +++ b/src/shared/varlink-serialize.h @@ -3,7 +3,7 @@ #include "shared-forward.h" -int varlink_server_serialize(sd_varlink_server *s, FILE *f, FDSet *fds); +int varlink_server_serialize(sd_varlink_server *s, const char *name, FILE *f, FDSet *fds); int varlink_server_deserialize_one(sd_varlink_server *s, const char *value, FDSet *fds); bool varlink_server_contains_socket(sd_varlink_server *s, const char *address);