diff --git a/0001-Revert-units-drop-runlevel-0-6-.target.patch b/0001-Revert-units-drop-runlevel-0-6-.target.patch new file mode 100644 index 0000000..4180211 --- /dev/null +++ b/0001-Revert-units-drop-runlevel-0-6-.target.patch @@ -0,0 +1,87 @@ +From 27f4f96c4e56744ecbffec0595236e1441278804 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Wed, 5 Nov 2025 17:52:16 +0100 +Subject: [PATCH] Revert "units: drop runlevel[0-6].target" + +This partially reverts commit e58ba80a40fb6e96543d56774a5bc5aa9cdadbf3. +The unit are still needed for compat. +--- + units/meson.build | 27 ++++++++++++++++++++++----- + 1 file changed, 22 insertions(+), 5 deletions(-) + +diff --git a/units/meson.build b/units/meson.build +index 4f47a3b2bd..34b3222f11 100644 +--- a/units/meson.build ++++ b/units/meson.build +@@ -1,5 +1,7 @@ + # SPDX-License-Identifier: LGPL-2.1-or-later + ++with_runlevels = conf.get('HAVE_SYSV_COMPAT') == 1 ++ + units = [ + { 'file' : 'basic.target' }, + { 'file' : 'blockdev@.target' }, +@@ -49,7 +51,7 @@ units = [ + }, + { + 'file' : 'graphical.target', +- 'symlinks' : ['default.target'], ++ 'symlinks' : ['default.target'] + (with_runlevels ? ['runlevel5.target'] : []), + }, + { 'file' : 'halt.target' }, + { +@@ -142,14 +144,20 @@ units = [ + 'conditions' : ['ENABLE_MACHINED'], + }, + { 'file' : 'modprobe@.service' }, +- { 'file' : 'multi-user.target' }, ++ { ++ 'file' : 'multi-user.target', ++ 'symlinks' : with_runlevels ? ['runlevel2.target', 'runlevel3.target', 'runlevel4.target'] : [], ++ }, + { 'file' : 'network-online.target' }, + { 'file' : 'network-pre.target' }, + { 'file' : 'network.target' }, + { 'file' : 'nss-lookup.target' }, + { 'file' : 'nss-user-lookup.target' }, + { 'file' : 'paths.target' }, +- { 'file' : 'poweroff.target' }, ++ { ++ 'file' : 'poweroff.target', ++ 'symlinks' : with_runlevels ? ['runlevel0.target'] : [], ++ }, + { 'file' : 'printer.target' }, + { + 'file' : 'proc-sys-fs-binfmt_misc.automount', +@@ -174,7 +182,7 @@ units = [ + }, + { + 'file' : 'reboot.target', +- 'symlinks' : ['ctrl-alt-del.target'], ++ 'symlinks' : ['ctrl-alt-del.target'] + (with_runlevels ? ['runlevel6.target'] : []), + }, + { + 'file' : 'remote-cryptsetup.target', +@@ -194,7 +202,10 @@ units = [ + 'symlinks' : ['initrd-root-device.target.wants/'], + }, + { 'file' : 'rescue.service.in' }, +- { 'file' : 'rescue.target' }, ++ { ++ 'file' : 'rescue.target', ++ 'symlinks' : with_runlevels ? ['runlevel1.target'] : [], ++ }, + { 'file' : 'rpcbind.target' }, + { 'file' : 'serial-getty@.service.in' }, + { 'file' : 'shutdown.target' }, +@@ -972,4 +983,10 @@ else + dbussessionservicedir / 'org.freedesktop.systemd1.service')) + endif + ++if conf.get('HAVE_SYSV_COMPAT') == 1 ++ foreach i : [1, 2, 3, 4, 5] ++ install_emptydir(systemunitdir / 'runlevel@0@.target.wants'.format(i)) ++ endforeach ++endif ++ + subdir('user') diff --git a/0001-ssh-generator-split-out-common-helper-function.patch b/0001-ssh-generator-split-out-common-helper-function.patch new file mode 100644 index 0000000..0399535 --- /dev/null +++ b/0001-ssh-generator-split-out-common-helper-function.patch @@ -0,0 +1,155 @@ +From cf18131f96868cd92bf923a4d953b7bbd6e32541 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Tue, 18 Nov 2025 11:19:41 +0100 +Subject: [PATCH 1/3] ssh-generator: split out common helper function + +(cherry picked from commit 7e8fe8e29f31e2c35d16ab10b8d7a5d582b38b8c) +--- + src/ssh-generator/meson.build | 17 ++++++++++++++--- + src/ssh-generator/ssh-generator.c | 15 ++++----------- + src/ssh-generator/ssh-issue.c | 16 ++++------------ + src/ssh-generator/ssh-util.c | 23 +++++++++++++++++++++++ + src/ssh-generator/ssh-util.h | 3 +++ + 5 files changed, 48 insertions(+), 26 deletions(-) + create mode 100644 src/ssh-generator/ssh-util.c + create mode 100644 src/ssh-generator/ssh-util.h + +diff --git a/src/ssh-generator/meson.build b/src/ssh-generator/meson.build +index f281a25184..a7162e9b86 100644 +--- a/src/ssh-generator/meson.build ++++ b/src/ssh-generator/meson.build +@@ -3,15 +3,26 @@ + executables += [ + generator_template + { + 'name' : 'systemd-ssh-generator', +- 'sources' : files('ssh-generator.c'), ++ 'sources' : files( ++ 'ssh-generator.c', ++ 'ssh-util.c', ++ ), ++ 'extract' : files( ++ 'ssh-util.c', ++ ), + }, + libexec_template + { + 'name' : 'systemd-ssh-proxy', +- 'sources' : files('ssh-proxy.c'), ++ 'sources' : files( ++ 'ssh-proxy.c', ++ ), + }, + libexec_template + { + 'name' : 'systemd-ssh-issue', +- 'sources' : files('ssh-issue.c'), ++ 'sources' : files( ++ 'ssh-issue.c', ++ ), ++ 'objects' : ['systemd-ssh-generator'], + }, + ] + +diff --git a/src/ssh-generator/ssh-generator.c b/src/ssh-generator/ssh-generator.c +index 778807938b..bf807196ee 100644 +--- a/src/ssh-generator/ssh-generator.c ++++ b/src/ssh-generator/ssh-generator.c +@@ -17,6 +17,7 @@ + #include "socket-netlink.h" + #include "socket-util.h" + #include "special.h" ++#include "ssh-util.h" + #include "string-util.h" + #include "strv.h" + #include "virt.h" +@@ -211,17 +212,9 @@ static int add_vsock_socket( + return 0; + } + +- _cleanup_close_ int vsock_fd = socket(AF_VSOCK, SOCK_STREAM|SOCK_CLOEXEC, 0); +- if (vsock_fd < 0) { +- if (ERRNO_IS_NOT_SUPPORTED(errno)) { +- log_debug("Not creating AF_VSOCK ssh listener, since AF_VSOCK is not available."); +- return 0; +- } +- +- return log_error_errno(errno, "Unable to test if AF_VSOCK is available: %m"); +- } +- +- vsock_fd = safe_close(vsock_fd); ++ r = vsock_open_or_warn(/* ret= */ NULL); ++ if (r <= 0) ++ return r; + + /* Determine the local CID so that we can log it to help users to connect to this VM */ + unsigned local_cid; +diff --git a/src/ssh-generator/ssh-issue.c b/src/ssh-generator/ssh-issue.c +index 68ad66bfd0..9ad9a997bd 100644 +--- a/src/ssh-generator/ssh-issue.c ++++ b/src/ssh-generator/ssh-issue.c +@@ -16,6 +16,7 @@ + #include "parse-argument.h" + #include "pretty-print.h" + #include "socket-util.h" ++#include "ssh-util.h" + #include "string-util.h" + #include "tmpfile-util.h" + #include "virt.h" +@@ -135,18 +136,9 @@ static int acquire_cid(unsigned *ret_cid) { + return 0; + } + +- _cleanup_close_ int vsock_fd = socket(AF_VSOCK, SOCK_STREAM|SOCK_CLOEXEC, 0); +- if (vsock_fd < 0) { +- if (ERRNO_IS_NOT_SUPPORTED(errno)) { +- log_debug("Not creating issue file, since AF_VSOCK is not available."); +- *ret_cid = 0; +- return 0; +- } +- +- return log_error_errno(errno, "Unable to test if AF_VSOCK is available: %m"); +- } +- +- vsock_fd = safe_close(vsock_fd); ++ r = vsock_open_or_warn(/* ret= */ NULL); ++ if (r <= 0) ++ return r; + + unsigned local_cid; + r = vsock_get_local_cid(&local_cid); +diff --git a/src/ssh-generator/ssh-util.c b/src/ssh-generator/ssh-util.c +new file mode 100644 +index 0000000000..5723a2bf2a +--- /dev/null ++++ b/src/ssh-generator/ssh-util.c +@@ -0,0 +1,23 @@ ++/* SPDX-License-Identifier: LGPL-2.1-or-later */ ++ ++#include ++#include ++ ++#include "errno-util.h" ++#include "log.h" ++#include "ssh-util.h" ++ ++int vsock_open_or_warn(int *ret) { ++ int fd = RET_NERRNO(socket(AF_VSOCK, SOCK_STREAM|SOCK_CLOEXEC, 0)); ++ if (ERRNO_IS_NEG_NOT_SUPPORTED(fd)) ++ log_debug_errno(fd, "AF_VSOCK is not available, ignoring: %m"); ++ else if (fd < 0) ++ return log_error_errno(fd, "Unable to test if AF_VSOCK is available: %m"); ++ ++ if (ret) ++ *ret = fd; ++ else ++ close(fd); ++ ++ return fd >= 0; ++} +diff --git a/src/ssh-generator/ssh-util.h b/src/ssh-generator/ssh-util.h +new file mode 100644 +index 0000000000..60984a5401 +--- /dev/null ++++ b/src/ssh-generator/ssh-util.h +@@ -0,0 +1,3 @@ ++/* SPDX-License-Identifier: LGPL-2.1-or-later */ ++ ++int vsock_open_or_warn(int *ret); diff --git a/0002-ssh-generator-split-out-one-more-helper-function.patch b/0002-ssh-generator-split-out-one-more-helper-function.patch new file mode 100644 index 0000000..a69ab47 --- /dev/null +++ b/0002-ssh-generator-split-out-one-more-helper-function.patch @@ -0,0 +1,110 @@ +From df5380c79fde84a39069c9dc4489103d94a9458f Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Tue, 18 Nov 2025 11:34:37 +0100 +Subject: [PATCH 2/3] ssh-generator: split out one more helper function + +(cherry picked from commit 8c019224a1ad7dd325da9fd2a4b9ab519534f659) +--- + src/ssh-generator/ssh-generator.c | 12 +++--------- + src/ssh-generator/ssh-issue.c | 16 +--------------- + src/ssh-generator/ssh-util.c | 16 ++++++++++++++++ + src/ssh-generator/ssh-util.h | 1 + + 4 files changed, 21 insertions(+), 24 deletions(-) + +diff --git a/src/ssh-generator/ssh-generator.c b/src/ssh-generator/ssh-generator.c +index bf807196ee..0820ab2de7 100644 +--- a/src/ssh-generator/ssh-generator.c ++++ b/src/ssh-generator/ssh-generator.c +@@ -218,15 +218,9 @@ static int add_vsock_socket( + + /* Determine the local CID so that we can log it to help users to connect to this VM */ + unsigned local_cid; +- r = vsock_get_local_cid(&local_cid); +- if (r < 0) { +- if (ERRNO_IS_DEVICE_ABSENT(r)) { +- log_debug("Not creating AF_VSOCK ssh listener, since /dev/vsock is not available (even though AF_VSOCK is)."); +- return 0; +- } +- +- return log_error_errno(r, "Failed to query local AF_VSOCK CID: %m"); +- } ++ r = vsock_get_local_cid_or_warn(&local_cid); ++ if (r <= 0) ++ return r; + + r = make_sshd_template_unit( + dest, +diff --git a/src/ssh-generator/ssh-issue.c b/src/ssh-generator/ssh-issue.c +index 9ad9a997bd..4ad83924f0 100644 +--- a/src/ssh-generator/ssh-issue.c ++++ b/src/ssh-generator/ssh-issue.c +@@ -15,7 +15,6 @@ + #include "mkdir.h" + #include "parse-argument.h" + #include "pretty-print.h" +-#include "socket-util.h" + #include "ssh-util.h" + #include "string-util.h" + #include "tmpfile-util.h" +@@ -140,20 +139,7 @@ static int acquire_cid(unsigned *ret_cid) { + if (r <= 0) + return r; + +- unsigned local_cid; +- r = vsock_get_local_cid(&local_cid); +- if (r < 0) { +- if (ERRNO_IS_DEVICE_ABSENT(r)) { +- log_debug("Not creating issue file, since /dev/vsock is not available (even though AF_VSOCK is)."); +- *ret_cid = 0; +- return 0; +- } +- +- return log_error_errno(r, "Failed to query local AF_VSOCK CID: %m"); +- } +- +- *ret_cid = local_cid; +- return 1; ++ return vsock_get_local_cid_or_warn(ret_cid); + } + + static int run(int argc, char* argv[]) { +diff --git a/src/ssh-generator/ssh-util.c b/src/ssh-generator/ssh-util.c +index 5723a2bf2a..d414713486 100644 +--- a/src/ssh-generator/ssh-util.c ++++ b/src/ssh-generator/ssh-util.c +@@ -5,6 +5,7 @@ + + #include "errno-util.h" + #include "log.h" ++#include "socket-util.h" + #include "ssh-util.h" + + int vsock_open_or_warn(int *ret) { +@@ -21,3 +22,18 @@ int vsock_open_or_warn(int *ret) { + + return fd >= 0; + } ++ ++int vsock_get_local_cid_or_warn(unsigned *ret) { ++ int r; ++ ++ r = vsock_get_local_cid(ret); ++ if (ERRNO_IS_NEG_DEVICE_ABSENT(r)) { ++ log_debug_errno(r, "/dev/vsock is not available (even though AF_VSOCK is), ignoring: %m"); ++ if (ret) ++ *ret = 0; /* bogus value */ ++ return 0; ++ } ++ if (r < 0) ++ return log_error_errno(r, "Failed to query local AF_VSOCK CID: %m"); ++ return 1; ++} +diff --git a/src/ssh-generator/ssh-util.h b/src/ssh-generator/ssh-util.h +index 60984a5401..2a38e1955e 100644 +--- a/src/ssh-generator/ssh-util.h ++++ b/src/ssh-generator/ssh-util.h +@@ -1,3 +1,4 @@ + /* SPDX-License-Identifier: LGPL-2.1-or-later */ + + int vsock_open_or_warn(int *ret); ++int vsock_get_local_cid_or_warn(unsigned *ret); diff --git a/0003-ssh-generator-suppress-error-message-for-vsock-EADDR.patch b/0003-ssh-generator-suppress-error-message-for-vsock-EADDR.patch new file mode 100644 index 0000000..edb0b0a --- /dev/null +++ b/0003-ssh-generator-suppress-error-message-for-vsock-EADDR.patch @@ -0,0 +1,39 @@ +From 5f97faffa0b5d16be17d2f3f571fcf8312fe4aa9 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Tue, 18 Nov 2025 11:37:59 +0100 +Subject: [PATCH 3/3] ssh-generator: suppress error message for vsock + EADDRNOTAVAIL + +In logs in the Fedora OpenQA CI: +Nov 17 22:20:06 fedora systemd-ssh-generator[4117]: Failed to query local AF_VSOCK CID: Cannot assign requested address +Nov 17 22:20:06 fedora (generato[4088]: /usr/lib/systemd/system-generators/systemd-ssh-generator failed with exit status 1. +Nov 17 22:20:06 fedora systemd[1]: sshd-vsock.socket: Unit configuration changed while unit was running, and no socket file descriptors are open. Unit not functional until restarted. + +AF_VSOCK is not configured there and systemd-ssh-generator should just exit +quietly. vsock_get_local_cid() already does some logging at debug level, so we +don't need to. + +There is also a second bug, we report modifications to the unit have just +created. I think we have an issue open for this somewhere, but cannot find it. + +(cherry picked from commit 8c3acba63b40cd0ebcb9863804e598744eda0b80) +--- + src/ssh-generator/ssh-util.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/src/ssh-generator/ssh-util.c b/src/ssh-generator/ssh-util.c +index d414713486..48cb662b71 100644 +--- a/src/ssh-generator/ssh-util.c ++++ b/src/ssh-generator/ssh-util.c +@@ -27,8 +27,9 @@ int vsock_get_local_cid_or_warn(unsigned *ret) { + int r; + + r = vsock_get_local_cid(ret); +- if (ERRNO_IS_NEG_DEVICE_ABSENT(r)) { +- log_debug_errno(r, "/dev/vsock is not available (even though AF_VSOCK is), ignoring: %m"); ++ if (ERRNO_IS_NEG_DEVICE_ABSENT(r) || r == -EADDRNOTAVAIL) { ++ if (ERRNO_IS_NEG_DEVICE_ABSENT(r)) ++ log_debug_errno(r, "/dev/vsock is not available (even though AF_VSOCK is), ignoring: %m"); + if (ret) + *ret = 0; /* bogus value */ + return 0; diff --git a/38922.patch b/38922.patch new file mode 100644 index 0000000..f15a013 --- /dev/null +++ b/38922.patch @@ -0,0 +1,733 @@ +From 993e877cdbd5cc12dcee563e6f4a004c6beac95a Mon Sep 17 00:00:00 2001 +From: gvenugo3 +Date: Tue, 23 Sep 2025 21:16:24 -0700 +Subject: [PATCH 1/7] json: add JSON_BUILD_PAIR_VARIANT_NON_EMPTY macro and fix + typos + +- Add JSON_BUILD_PAIR_VARIANT_NON_EMPTY macro to skip empty JSON objects in output +- Fix comment typos changing "two item" to "two items" throughout +--- + src/libsystemd/sd-json/json-util.h | 2 + + src/libsystemd/sd-json/sd-json.c | 60 +++++++++++++++++++++--------- + 2 files changed, 45 insertions(+), 17 deletions(-) + +diff --git a/src/libsystemd/sd-json/json-util.h b/src/libsystemd/sd-json/json-util.h +index 1b244722b8a3d..47eb7401fef83 100644 +--- a/src/libsystemd/sd-json/json-util.h ++++ b/src/libsystemd/sd-json/json-util.h +@@ -167,6 +167,7 @@ enum { + _JSON_BUILD_PAIR_STRV_NON_EMPTY, + _JSON_BUILD_PAIR_STRV_ENV_PAIR_NON_EMPTY, + _JSON_BUILD_PAIR_VARIANT_NON_NULL, ++ _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, +@@ -215,6 +216,7 @@ enum { + #define JSON_BUILD_PAIR_STRV_NON_EMPTY(name, l) _JSON_BUILD_PAIR_STRV_NON_EMPTY, (const char*) { name }, (char**) { l } + #define JSON_BUILD_PAIR_STRV_ENV_PAIR_NON_EMPTY(name, l) _JSON_BUILD_PAIR_STRV_ENV_PAIR_NON_EMPTY, (const char*) { name }, (char**) { l } + #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 } +diff --git a/src/libsystemd/sd-json/sd-json.c b/src/libsystemd/sd-json/sd-json.c +index 9add7be9a881e..5587e03f7dceb 100644 +--- a/src/libsystemd/sd-json/sd-json.c ++++ b/src/libsystemd/sd-json/sd-json.c +@@ -4434,7 +4434,7 @@ _public_ int sd_json_buildv(sd_json_variant **ret, va_list ap) { + goto finish; + } + +- n_subtract = 2; /* we generated two item */ ++ n_subtract = 2; /* we generated two items */ + + current->expect = EXPECT_OBJECT_KEY; + break; +@@ -4464,7 +4464,7 @@ _public_ int sd_json_buildv(sd_json_variant **ret, va_list ap) { + goto finish; + } + +- n_subtract = 2; /* we generated two item */ ++ n_subtract = 2; /* we generated two items */ + + current->expect = EXPECT_OBJECT_KEY; + break; +@@ -4492,7 +4492,7 @@ _public_ int sd_json_buildv(sd_json_variant **ret, va_list ap) { + goto finish; + } + +- n_subtract = 2; /* we generated two item */ ++ n_subtract = 2; /* we generated two items */ + + current->expect = EXPECT_OBJECT_KEY; + break; +@@ -4519,7 +4519,7 @@ _public_ int sd_json_buildv(sd_json_variant **ret, va_list ap) { + goto finish; + } + +- n_subtract = 2; /* we generated two item */ ++ n_subtract = 2; /* we generated two items */ + + current->expect = EXPECT_OBJECT_KEY; + break; +@@ -4556,7 +4556,7 @@ _public_ int sd_json_buildv(sd_json_variant **ret, va_list ap) { + goto finish; + } + +- n_subtract = 2; /* we generated two item */ ++ n_subtract = 2; /* we generated two items */ + + current->expect = EXPECT_OBJECT_KEY; + break; +@@ -4582,7 +4582,33 @@ _public_ int sd_json_buildv(sd_json_variant **ret, va_list ap) { + add_more = sd_json_variant_ref(v); + } + +- n_subtract = 2; /* we generated two item */ ++ n_subtract = 2; /* we generated two items */ ++ ++ current->expect = EXPECT_OBJECT_KEY; ++ break; ++ } ++ ++ case _JSON_BUILD_PAIR_VARIANT_NON_EMPTY: { ++ sd_json_variant *v; ++ const char *n; ++ ++ if (current->expect != EXPECT_OBJECT_KEY) { ++ r = -EINVAL; ++ goto finish; ++ } ++ ++ n = va_arg(ap, const char *); ++ v = va_arg(ap, sd_json_variant *); ++ ++ if (v && !sd_json_variant_is_blank_object(v) && current->n_suppress == 0) { ++ r = sd_json_variant_new_string(&add, n); ++ if (r < 0) ++ goto finish; ++ ++ add_more = sd_json_variant_ref(v); ++ } ++ ++ n_subtract = 2; /* we generated two items */ + + current->expect = EXPECT_OBJECT_KEY; + break; +@@ -4612,7 +4638,7 @@ _public_ int sd_json_buildv(sd_json_variant **ret, va_list ap) { + goto finish; + } + +- n_subtract = 2; /* we generated two item */ ++ n_subtract = 2; /* we generated two items */ + + current->expect = EXPECT_OBJECT_KEY; + break; +@@ -4640,7 +4666,7 @@ _public_ int sd_json_buildv(sd_json_variant **ret, va_list ap) { + goto finish; + } + +- n_subtract = 2; /* we generated two item */ ++ n_subtract = 2; /* we generated two items */ + + current->expect = EXPECT_OBJECT_KEY; + break; +@@ -4668,7 +4694,7 @@ _public_ int sd_json_buildv(sd_json_variant **ret, va_list ap) { + goto finish; + } + +- n_subtract = 2; /* we generated two item */ ++ n_subtract = 2; /* we generated two items */ + + current->expect = EXPECT_OBJECT_KEY; + break; +@@ -4698,7 +4724,7 @@ _public_ int sd_json_buildv(sd_json_variant **ret, va_list ap) { + goto finish; + } + +- n_subtract = 2; /* we generated two item */ ++ n_subtract = 2; /* we generated two items */ + + current->expect = EXPECT_OBJECT_KEY; + break; +@@ -4726,7 +4752,7 @@ _public_ int sd_json_buildv(sd_json_variant **ret, va_list ap) { + goto finish; + } + +- n_subtract = 2; /* we generated two item */ ++ n_subtract = 2; /* we generated two items */ + + current->expect = EXPECT_OBJECT_KEY; + break; +@@ -4754,7 +4780,7 @@ _public_ int sd_json_buildv(sd_json_variant **ret, va_list ap) { + goto finish; + } + +- n_subtract = 2; /* we generated two item */ ++ n_subtract = 2; /* we generated two items */ + + current->expect = EXPECT_OBJECT_KEY; + break; +@@ -4784,7 +4810,7 @@ _public_ int sd_json_buildv(sd_json_variant **ret, va_list ap) { + goto finish; + } + +- n_subtract = 2; /* we generated two item */ ++ n_subtract = 2; /* we generated two items */ + + current->expect = EXPECT_OBJECT_KEY; + break; +@@ -4814,7 +4840,7 @@ _public_ int sd_json_buildv(sd_json_variant **ret, va_list ap) { + goto finish; + } + +- n_subtract = 2; /* we generated two item */ ++ n_subtract = 2; /* we generated two items */ + + current->expect = EXPECT_OBJECT_KEY; + break; +@@ -4876,7 +4902,7 @@ _public_ int sd_json_buildv(sd_json_variant **ret, va_list ap) { + } + } + +- n_subtract = 2; /* we generated two item */ ++ n_subtract = 2; /* we generated two items */ + + current->expect = EXPECT_OBJECT_KEY; + break; +@@ -4912,7 +4938,7 @@ _public_ int sd_json_buildv(sd_json_variant **ret, va_list ap) { + goto finish; + } + +- n_subtract = 2; /* we generated two item */ ++ n_subtract = 2; /* we generated two items */ + + current->expect = EXPECT_OBJECT_KEY; + break; +@@ -4940,7 +4966,7 @@ _public_ int sd_json_buildv(sd_json_variant **ret, va_list ap) { + goto finish; + } + +- n_subtract = 2; /* we generated two item */ ++ n_subtract = 2; /* we generated two items */ + + current->expect = EXPECT_OBJECT_KEY; + break; + +From c58327a9060855369f68922b9f718d078a13e0c5 Mon Sep 17 00:00:00 2001 +From: gvenugo3 +Date: Thu, 25 Sep 2025 11:23:31 -0700 +Subject: [PATCH 2/7] varlink: refactor parameter handling with asymmetric + encoding + +Rename varlink_sanitize_parameters to varlink_sanitize_incoming_parameters +to clarify its role in handling incoming messages. + +Implement canonical empty parameter encoding where: +- Incoming: NULL/null/empty object all become empty object for compatibility +- Outgoing: Empty parameters omitted entirely via JSON build system + +This avoids modifying caller parameters while maintaining wire format +optimization. +--- + src/libsystemd/sd-varlink/sd-varlink-idl.c | 9 +- + src/libsystemd/sd-varlink/sd-varlink.c | 116 ++++++++------------- + 2 files changed, 48 insertions(+), 77 deletions(-) + +diff --git a/src/libsystemd/sd-varlink/sd-varlink-idl.c b/src/libsystemd/sd-varlink/sd-varlink-idl.c +index 7e6680e0e6052..03ed52f1720b7 100644 +--- a/src/libsystemd/sd-varlink/sd-varlink-idl.c ++++ b/src/libsystemd/sd-varlink/sd-varlink-idl.c +@@ -5,6 +5,7 @@ + #include "alloc-util.h" + #include "ansi-color.h" + #include "extract-word.h" ++#include "json-internal.h" + #include "json-util.h" + #include "log.h" + #include "memstream-util.h" +@@ -1793,11 +1794,9 @@ static int varlink_idl_validate_symbol(const sd_varlink_symbol *symbol, sd_json_ + assert(symbol); + assert(!IN_SET(symbol->symbol_type, _SD_VARLINK_SYMBOL_COMMENT, _SD_VARLINK_INTERFACE_COMMENT)); + +- if (!v) { +- if (reterr_bad_field) +- *reterr_bad_field = NULL; +- return varlink_idl_log(SYNTHETIC_ERRNO(EMEDIUMTYPE), "Null object passed, refusing."); +- } ++ /* Consider a NULL pointer equivalent to an empty object */ ++ if (!v) ++ v = JSON_VARIANT_MAGIC_EMPTY_OBJECT; + + switch (symbol->symbol_type) { + +diff --git a/src/libsystemd/sd-varlink/sd-varlink.c b/src/libsystemd/sd-varlink/sd-varlink.c +index 1666162e89059..dda7a9503b612 100644 +--- a/src/libsystemd/sd-varlink/sd-varlink.c ++++ b/src/libsystemd/sd-varlink/sd-varlink.c +@@ -1061,31 +1061,30 @@ static int varlink_dispatch_disconnect(sd_varlink *v) { + return 1; + } + +-static int varlink_sanitize_parameters(sd_json_variant **v) { ++static int varlink_sanitize_incoming_parameters(sd_json_variant **v) { + int r; +- + assert(v); + +- /* Varlink always wants a parameters list, hence make one if the caller doesn't want any */ +- if (!*v) +- return sd_json_variant_new_object(v, NULL, 0); +- if (sd_json_variant_is_null(*v)) { +- sd_json_variant *empty; +- ++ /* Convert NULL or JSON null to empty object for method handlers (backward compatibility) */ ++ if (!*v || sd_json_variant_is_null(*v)) { ++ _cleanup_(sd_json_variant_unrefp) sd_json_variant *empty = NULL; + r = sd_json_variant_new_object(&empty, NULL, 0); + if (r < 0) + return r; +- ++ /* sd_json_variant_unref() is a NOP if *v is NULL */ + sd_json_variant_unref(*v); +- *v = empty; ++ *v = TAKE_PTR(empty); + return 0; + } ++ ++ /* Ensure we have an object */ + if (!sd_json_variant_is_object(*v)) + return -EINVAL; + + return 0; + } + ++ + static int varlink_dispatch_reply(sd_varlink *v) { + _cleanup_(sd_json_variant_unrefp) sd_json_variant *parameters = NULL; + sd_varlink_reply_flags_t flags = 0; +@@ -1146,7 +1145,7 @@ static int varlink_dispatch_reply(sd_varlink *v) { + if (error && FLAGS_SET(flags, SD_VARLINK_REPLY_CONTINUES)) + goto invalid; + +- r = varlink_sanitize_parameters(¶meters); ++ r = varlink_sanitize_incoming_parameters(¶meters); + if (r < 0) + goto invalid; + +@@ -1327,7 +1326,7 @@ static int varlink_dispatch_method(sd_varlink *v) { + if (!method) + goto invalid; + +- r = varlink_sanitize_parameters(¶meters); ++ r = varlink_sanitize_incoming_parameters(¶meters); + if (r < 0) + goto fail; + +@@ -1575,13 +1574,14 @@ _public_ int sd_varlink_get_current_parameters(sd_varlink *v, sd_json_variant ** + if (!v->current) + return -ENODATA; + +- p = sd_json_variant_by_key(v->current, "parameters"); +- if (!p) +- return -ENODATA; ++ if (!ret) ++ return 0; + +- if (ret) +- *ret = sd_json_variant_ref(p); ++ p = sd_json_variant_by_key(v->current, "parameters"); ++ if (!p || sd_json_variant_is_null(p)) ++ return sd_json_variant_new_object(ret, NULL, 0); + ++ *ret = sd_json_variant_ref(p); + return 0; + } + +@@ -2024,14 +2024,10 @@ _public_ int sd_varlink_send(sd_varlink *v, const char *method, sd_json_variant + if (!IN_SET(v->state, VARLINK_IDLE_CLIENT, VARLINK_AWAITING_REPLY)) + return varlink_log_errno(v, SYNTHETIC_ERRNO(EBUSY), "Connection busy."); + +- r = varlink_sanitize_parameters(¶meters); +- if (r < 0) +- return varlink_log_errno(v, r, "Failed to sanitize parameters: %m"); +- + r = sd_json_buildo( + &m, + SD_JSON_BUILD_PAIR("method", SD_JSON_BUILD_STRING(method)), +- SD_JSON_BUILD_PAIR("parameters", SD_JSON_BUILD_VARIANT(parameters)), ++ JSON_BUILD_PAIR_VARIANT_NON_EMPTY("parameters", parameters), + SD_JSON_BUILD_PAIR("oneway", SD_JSON_BUILD_BOOLEAN(true))); + if (r < 0) + return varlink_log_errno(v, r, "Failed to build json message: %m"); +@@ -2076,14 +2072,10 @@ _public_ int sd_varlink_invoke(sd_varlink *v, const char *method, sd_json_varian + if (!IN_SET(v->state, VARLINK_IDLE_CLIENT, VARLINK_AWAITING_REPLY)) + return varlink_log_errno(v, SYNTHETIC_ERRNO(EBUSY), "Connection busy."); + +- r = varlink_sanitize_parameters(¶meters); +- if (r < 0) +- return varlink_log_errno(v, r, "Failed to sanitize parameters: %m"); +- + r = sd_json_buildo( + &m, + SD_JSON_BUILD_PAIR("method", SD_JSON_BUILD_STRING(method)), +- SD_JSON_BUILD_PAIR("parameters", SD_JSON_BUILD_VARIANT(parameters))); ++ JSON_BUILD_PAIR_VARIANT_NON_EMPTY("parameters", parameters)); + if (r < 0) + return varlink_log_errno(v, r, "Failed to build json message: %m"); + +@@ -2130,14 +2122,10 @@ _public_ int sd_varlink_observe(sd_varlink *v, const char *method, sd_json_varia + if (v->state != VARLINK_IDLE_CLIENT) + return varlink_log_errno(v, SYNTHETIC_ERRNO(EBUSY), "Connection busy."); + +- r = varlink_sanitize_parameters(¶meters); +- if (r < 0) +- return varlink_log_errno(v, r, "Failed to sanitize parameters: %m"); +- + r = sd_json_buildo( + &m, + SD_JSON_BUILD_PAIR("method", SD_JSON_BUILD_STRING(method)), +- SD_JSON_BUILD_PAIR("parameters", SD_JSON_BUILD_VARIANT(parameters)), ++ JSON_BUILD_PAIR_VARIANT_NON_EMPTY("parameters", parameters), + SD_JSON_BUILD_PAIR("more", SD_JSON_BUILD_BOOLEAN(true))); + if (r < 0) + return varlink_log_errno(v, r, "Failed to build json message: %m"); +@@ -2195,14 +2183,10 @@ _public_ int sd_varlink_call_full( + * that we can assign a new reply shortly. */ + varlink_clear_current(v); + +- r = varlink_sanitize_parameters(¶meters); +- if (r < 0) +- return varlink_log_errno(v, r, "Failed to sanitize parameters: %m"); +- + r = sd_json_buildo( + &m, + SD_JSON_BUILD_PAIR("method", SD_JSON_BUILD_STRING(method)), +- SD_JSON_BUILD_PAIR("parameters", SD_JSON_BUILD_VARIANT(parameters))); ++ JSON_BUILD_PAIR_VARIANT_NON_EMPTY("parameters", parameters)); + if (r < 0) + return varlink_log_errno(v, r, "Failed to build json message: %m"); + +@@ -2353,14 +2337,10 @@ _public_ int sd_varlink_collect_full( + * that we can assign a new reply shortly. */ + varlink_clear_current(v); + +- r = varlink_sanitize_parameters(¶meters); +- if (r < 0) +- return varlink_log_errno(v, r, "Failed to sanitize parameters: %m"); +- + r = sd_json_buildo( + &m, + SD_JSON_BUILD_PAIR("method", SD_JSON_BUILD_STRING(method)), +- SD_JSON_BUILD_PAIR("parameters", SD_JSON_BUILD_VARIANT(parameters)), ++ JSON_BUILD_PAIR_VARIANT_NON_EMPTY("parameters", parameters), + SD_JSON_BUILD_PAIR("more", SD_JSON_BUILD_BOOLEAN(true))); + if (r < 0) + return varlink_log_errno(v, r, "Failed to build json message: %m"); +@@ -2501,14 +2481,7 @@ _public_ int sd_varlink_reply(sd_varlink *v, sd_json_variant *parameters) { + VARLINK_PENDING_METHOD, VARLINK_PENDING_METHOD_MORE)) + return -EBUSY; + +- r = varlink_sanitize_parameters(¶meters); +- if (r < 0) +- return varlink_log_errno(v, r, "Failed to sanitize parameters: %m"); +- +- r = sd_json_buildo(&m, SD_JSON_BUILD_PAIR("parameters", SD_JSON_BUILD_VARIANT(parameters))); +- if (r < 0) +- return varlink_log_errno(v, r, "Failed to build json message: %m"); +- ++ /* Validate parameters BEFORE sanitization */ + if (v->current_method) { + const char *bad_field = NULL; + +@@ -2519,6 +2492,10 @@ _public_ int sd_varlink_reply(sd_varlink *v, sd_json_variant *parameters) { + v->current_method->name, strna(bad_field)); + } + ++ r = sd_json_buildo(&m, JSON_BUILD_PAIR_VARIANT_NON_EMPTY("parameters", parameters)); ++ if (r < 0) ++ return varlink_log_errno(v, r, "Failed to build json message: %m"); ++ + r = varlink_enqueue_json(v, m); + if (r < 0) + return varlink_log_errno(v, r, "Failed to enqueue json message: %m"); +@@ -2588,17 +2565,7 @@ _public_ int sd_varlink_error(sd_varlink *v, const char *error_id, sd_json_varia + * the callers don't need to do this explicitly. */ + sd_varlink_reset_fds(v); + +- r = varlink_sanitize_parameters(¶meters); +- if (r < 0) +- return varlink_log_errno(v, r, "Failed to sanitize parameters: %m"); +- +- r = sd_json_buildo( +- &m, +- SD_JSON_BUILD_PAIR("error", SD_JSON_BUILD_STRING(error_id)), +- SD_JSON_BUILD_PAIR("parameters", SD_JSON_BUILD_VARIANT(parameters))); +- if (r < 0) +- return varlink_log_errno(v, r, "Failed to build json message: %m"); +- ++ /* Validate parameters BEFORE sanitization */ + sd_varlink_symbol *symbol = hashmap_get(v->server->symbols, error_id); + if (!symbol) + varlink_log(v, "No interface description defined for error '%s', not validating.", error_id); +@@ -2612,6 +2579,13 @@ _public_ int sd_varlink_error(sd_varlink *v, const char *error_id, sd_json_varia + error_id, strna(bad_field)); + } + ++ r = sd_json_buildo( ++ &m, ++ SD_JSON_BUILD_PAIR("error", SD_JSON_BUILD_STRING(error_id)), ++ JSON_BUILD_PAIR_VARIANT_NON_EMPTY("parameters", parameters)); ++ if (r < 0) ++ return varlink_log_errno(v, r, "Failed to build json message: %m"); ++ + r = varlink_enqueue_json(v, m); + if (r < 0) + return varlink_log_errno(v, r, "Failed to enqueue json message: %m"); +@@ -2726,17 +2700,7 @@ _public_ int sd_varlink_notify(sd_varlink *v, sd_json_variant *parameters) { + if (!IN_SET(v->state, VARLINK_PROCESSING_METHOD_MORE, VARLINK_PENDING_METHOD_MORE)) + return varlink_log_errno(v, SYNTHETIC_ERRNO(EBUSY), "Connection busy."); + +- r = varlink_sanitize_parameters(¶meters); +- if (r < 0) +- return varlink_log_errno(v, r, "Failed to sanitize parameters: %m"); +- +- r = sd_json_buildo( +- &m, +- SD_JSON_BUILD_PAIR("parameters", SD_JSON_BUILD_VARIANT(parameters)), +- SD_JSON_BUILD_PAIR("continues", SD_JSON_BUILD_BOOLEAN(true))); +- if (r < 0) +- return varlink_log_errno(v, r, "Failed to build json message: %m"); +- ++ /* Validate parameters BEFORE sanitization */ + if (v->current_method) { + const char *bad_field = NULL; + +@@ -2750,6 +2714,13 @@ _public_ int sd_varlink_notify(sd_varlink *v, sd_json_variant *parameters) { + v->current_method->name, strna(bad_field)); + } + ++ r = sd_json_buildo( ++ &m, ++ JSON_BUILD_PAIR_VARIANT_NON_EMPTY("parameters", parameters), ++ SD_JSON_BUILD_PAIR("continues", SD_JSON_BUILD_BOOLEAN(true))); ++ if (r < 0) ++ return varlink_log_errno(v, r, "Failed to build json message: %m"); ++ + r = varlink_enqueue_json(v, m); + if (r < 0) + return varlink_log_errno(v, r, "Failed to enqueue json message: %m"); +@@ -2783,6 +2754,7 @@ _public_ int sd_varlink_dispatch(sd_varlink *v, sd_json_variant *parameters, con + + /* A wrapper around json_dispatch_full() that returns a nice InvalidParameter error if we hit a problem with some field. */ + ++ /* sd_json_dispatch_full() now handles NULL parameters gracefully */ + r = sd_json_dispatch_full(parameters, dispatch_table, /* bad= */ NULL, /* flags= */ 0, userdata, &bad_field); + if (r < 0) { + if (bad_field) + +From dfe8fe44ee427aaffd82daae960c7c4090d47858 Mon Sep 17 00:00:00 2001 +From: gvenugo3 +Date: Thu, 25 Sep 2025 11:23:42 -0700 +Subject: [PATCH 3/7] varlink: add parameter validation to systemd service + handler + +Add assertion in systemd service handler to ensure parameters are +non-null after sanitization, providing early detection of invalid +parameter handling. +--- + src/shared/varlink-io.systemd.service.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/src/shared/varlink-io.systemd.service.c b/src/shared/varlink-io.systemd.service.c +index d130f0df51a5e..8cbf299e07baa 100644 +--- a/src/shared/varlink-io.systemd.service.c ++++ b/src/shared/varlink-io.systemd.service.c +@@ -47,6 +47,7 @@ int varlink_method_ping(sd_varlink *link, sd_json_variant *parameters, sd_varlin + int r; + + assert(link); ++ assert(parameters); + + r = sd_varlink_dispatch(link, parameters, /* dispatch_table= */ NULL, /* userdata= */ NULL); + if (r != 0) + +From 9fa2f9ebf3d9c1c9f317afbd5e94d8f7c17991ed Mon Sep 17 00:00:00 2001 +From: gvenugo3 +Date: Thu, 25 Sep 2025 11:23:54 -0700 +Subject: [PATCH 4/7] varlink: update tests for canonical empty parameter + handling + +Update test overload handling to verify NULL parameters are properly +handled for disconnect errors, ensuring test coverage of the new +canonical encoding behavior. +--- + src/test/test-varlink.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/src/test/test-varlink.c b/src/test/test-varlink.c +index b298b9cfbfed7..c853eb41d0afe 100644 +--- a/src/test/test-varlink.c ++++ b/src/test/test-varlink.c +@@ -205,6 +205,9 @@ static int overload_reply(sd_varlink *link, sd_json_variant *parameters, const c + + log_debug("Over reply triggered with error: %s", strna(error_id)); + ASSERT_STREQ(error_id, SD_VARLINK_ERROR_DISCONNECTED); ++ /* Local disconnect errors carry no parameters. Ensure we propagate ++ * absence as NULL rather than an empty object. */ ++ ASSERT_TRUE(!parameters); + sd_event_exit(sd_varlink_get_event(link), 0); + + return 0; + +From dfb11f713e5a742868e64810e969dc8938c6b52d Mon Sep 17 00:00:00 2001 +From: gvenugo3 +Date: Thu, 25 Sep 2025 11:24:04 -0700 +Subject: [PATCH 5/7] sysext: fix varlink parameter handling + +Update sysext to use proper parameter handling that's compatible with +the new canonical empty parameter encoding. +--- + src/sysext/sysext.c | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/src/sysext/sysext.c b/src/sysext/sysext.c +index c8c75d68bd077..957386890cfd3 100644 +--- a/src/sysext/sysext.c ++++ b/src/sysext/sysext.c +@@ -2219,7 +2219,6 @@ static int parse_merge_parameters(sd_varlink *link, sd_json_variant *parameters, + }; + + assert(link); +- assert(parameters); + assert(p); + + return sd_varlink_dispatch(link, parameters, dispatch_table, p); + +From 0c063940acb06a27fd2fd482ffc6058bab576e0c Mon Sep 17 00:00:00 2001 +From: gvenugo3 +Date: Thu, 25 Sep 2025 11:24:40 -0700 +Subject: [PATCH 6/7] man: document canonical empty parameter encoding behavior + +Document the asymmetric parameter handling where receivers accept +multiple formats (omitted/null/empty) for compatibility while senders +use canonical encoding (omit field entirely) for optimization. +--- + man/sd-varlink.xml | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/man/sd-varlink.xml b/man/sd-varlink.xml +index c7cfceb71252f..c57411d5bd867 100644 +--- a/man/sd-varlink.xml ++++ b/man/sd-varlink.xml +@@ -44,6 +44,13 @@ + sd-json3 API for JSON + serialization, deserialization and manipulation. + ++ Canonical encoding rules: sd-varlink omits the "parameters" member in replies, ++ errors, and notifications when there are no parameters to transmit. This reduces message size and ++ avoids ambiguity. Receivers must be tolerant and accept any of the following encodings for the ++ absence of parameters: an omitted "parameters" key (preferred), a JSON null ++ value, or an empty object {}. When decoding, sd-varlink treats JSON null ++ as if the member was omitted. ++ + The varlinkctl1 tool + makes the functionality implemented by sd-varlink available from the command line. + + +From 420241fdd4143818712ef78559db725f3d9f9d3f Mon Sep 17 00:00:00 2001 +From: gvenugo3 +Date: Sun, 28 Sep 2025 21:48:39 -0700 +Subject: [PATCH 7/7] varlink: address reviewer feedback + +- Pass empty object instead of NULL for local errors to ensure + API consistency and allow code to rely on non-null parameters +- Remove spurious empty line +- Restore necessary assertion in sysext parameter validation +- Clarify documentation to specify wire format encoding + +This improves API reliability by guaranteeing parameter objects +are always provided to callbacks, even for local disconnect errors. +--- + man/sd-varlink.xml | 2 +- + src/libsystemd/sd-varlink/sd-varlink.c | 8 ++++++-- + src/sysext/sysext.c | 1 + + src/test/test-varlink.c | 6 +++--- + 4 files changed, 11 insertions(+), 6 deletions(-) + +diff --git a/man/sd-varlink.xml b/man/sd-varlink.xml +index c57411d5bd867..282d6a330ef1f 100644 +--- a/man/sd-varlink.xml ++++ b/man/sd-varlink.xml +@@ -44,7 +44,7 @@ + sd-json3 API for JSON + serialization, deserialization and manipulation. + +- Canonical encoding rules: sd-varlink omits the "parameters" member in replies, ++ Canonical encoding rules: sd-varlink omits the "parameters" member on the wire in replies, + errors, and notifications when there are no parameters to transmit. This reduces message size and + avoids ambiguity. Receivers must be tolerant and accept any of the following encodings for the + absence of parameters: an omitted "parameters" key (preferred), a JSON null +diff --git a/src/libsystemd/sd-varlink/sd-varlink.c b/src/libsystemd/sd-varlink/sd-varlink.c +index dda7a9503b612..e3b9106ac72e7 100644 +--- a/src/libsystemd/sd-varlink/sd-varlink.c ++++ b/src/libsystemd/sd-varlink/sd-varlink.c +@@ -1020,6 +1020,7 @@ static int varlink_test_timeout(sd_varlink *v) { + } + + static int varlink_dispatch_local_error(sd_varlink *v, const char *error) { ++ _cleanup_(sd_json_variant_unrefp) sd_json_variant *empty = NULL; + int r; + + assert(v); +@@ -1028,7 +1029,11 @@ static int varlink_dispatch_local_error(sd_varlink *v, const char *error) { + if (!v->reply_callback) + return 0; + +- r = v->reply_callback(v, NULL, error, SD_VARLINK_REPLY_ERROR|SD_VARLINK_REPLY_LOCAL, v->userdata); ++ r = sd_json_variant_new_object(&empty, NULL, 0); ++ if (r < 0) ++ return r; ++ ++ r = v->reply_callback(v, empty, error, SD_VARLINK_REPLY_ERROR|SD_VARLINK_REPLY_LOCAL, v->userdata); + if (r < 0) + varlink_log_errno(v, r, "Reply callback returned error, ignoring: %m"); + +@@ -1084,7 +1089,6 @@ static int varlink_sanitize_incoming_parameters(sd_json_variant **v) { + return 0; + } + +- + static int varlink_dispatch_reply(sd_varlink *v) { + _cleanup_(sd_json_variant_unrefp) sd_json_variant *parameters = NULL; + sd_varlink_reply_flags_t flags = 0; +diff --git a/src/sysext/sysext.c b/src/sysext/sysext.c +index 957386890cfd3..c8c75d68bd077 100644 +--- a/src/sysext/sysext.c ++++ b/src/sysext/sysext.c +@@ -2219,6 +2219,7 @@ static int parse_merge_parameters(sd_varlink *link, sd_json_variant *parameters, + }; + + assert(link); ++ assert(parameters); + assert(p); + + return sd_varlink_dispatch(link, parameters, dispatch_table, p); +diff --git a/src/test/test-varlink.c b/src/test/test-varlink.c +index c853eb41d0afe..0b834fad17dad 100644 +--- a/src/test/test-varlink.c ++++ b/src/test/test-varlink.c +@@ -205,9 +205,9 @@ static int overload_reply(sd_varlink *link, sd_json_variant *parameters, const c + + log_debug("Over reply triggered with error: %s", strna(error_id)); + ASSERT_STREQ(error_id, SD_VARLINK_ERROR_DISCONNECTED); +- /* Local disconnect errors carry no parameters. Ensure we propagate +- * absence as NULL rather than an empty object. */ +- ASSERT_TRUE(!parameters); ++ /* Local disconnect errors carry empty parameters. Ensure we propagate ++ * a consistent empty object for API reliability. */ ++ ASSERT_TRUE(sd_json_variant_is_blank_object(parameters)); + sd_event_exit(sd_varlink_get_event(link), 0); + + return 0; diff --git a/plans/run-integration-tests.sh b/plans/run-integration-tests.sh index 9a90fa7..46ea433 100755 --- a/plans/run-integration-tests.sh +++ b/plans/run-integration-tests.sh @@ -17,9 +17,9 @@ sysctl fs.inotify.max_user_watches=65536 || true sysctl fs.inotify.max_user_instances=1024 || true if [[ -n "${KOJI_TASK_ID:-}" ]]; then - koji download-task --noprogress --arch="src,noarch,$(rpm --eval '%{_arch}')" "$KOJI_TASK_ID" + koji download-task --noprogress --arch="noarch,$(rpm --eval '%{_arch}')" "$KOJI_TASK_ID" elif [[ -n "${CBS_TASK_ID:-}" ]]; then - cbs download-task --noprogress --arch="src,noarch,$(rpm --eval '%{_arch}')" "$CBS_TASK_ID" + cbs download-task --noprogress --arch="noarch,$(rpm --eval '%{_arch}')" "$CBS_TASK_ID" elif [[ -n "${PACKIT_SRPM_URL:-}" ]]; then COPR_BUILD_ID="$(basename "$(dirname "$PACKIT_SRPM_URL")")" COPR_CHROOT="$(basename "$(dirname "$(dirname "$PACKIT_BUILD_LOG_URL")")")" @@ -32,21 +32,12 @@ fi PACKAGEDIR="$PWD" -# TODO: Remove fallback once v257.6 is released. Also stop downloading source rpms then. - # This will match both the regular and the debuginfo rpm so make sure we select only the # non-debuginfo rpm. RPMS=(systemd-tests-*.rpm) rpm2cpio "${RPMS[0]}" | cpio --make-directories --extract -if [[ -d usr/lib/systemd/tests/mkosi ]]; then - pushd usr/lib/systemd/tests - mkosi_hash="$(grep "MinimumVersion=commit:" mkosi/mkosi.conf | sed "s|MinimumVersion=commit:||g")" -else - mkdir systemd - rpm2cpio systemd-*.src.rpm | cpio --to-stdout --extract './*.tar.gz' | tar xz --strip-components=1 -C systemd - pushd systemd - mkosi_hash="$(grep systemd/mkosi@ .github/workflows/mkosi.yml | sed "s|.*systemd/mkosi@||g")" -fi +pushd usr/lib/systemd/tests +mkosi_hash="$(grep "MinimumVersion=commit:" mkosi/mkosi.conf | sed "s|MinimumVersion=commit:||g")" # Now prepare mkosi at the same version required by the systemd repo. git clone https://github.com/systemd/mkosi /var/tmp/systemd-integration-tests-mkosi @@ -57,13 +48,7 @@ export PATH="/var/tmp/systemd-integration-tests-mkosi/bin:$PATH" # shellcheck source=/dev/null . /etc/os-release || . /usr/lib/os-release -if [[ -d mkosi ]]; then - LOCAL_CONF=mkosi/mkosi.local.conf -else - LOCAL_CONF=mkosi.local.conf -fi - -tee "$LOCAL_CONF" <