Compare commits

...
Sign in to create a new pull request.

15 commits

Author SHA1 Message Date
Andreas Schneider
28bbd2db44 userdb: Omit empty parameters field in JSON messages
Details: https://github.com/systemd/systemd/issues/40252
2026-01-05 11:00:02 +01:00
Zbigniew Jędrzejewski-Szmek
9dd9d14abb Add patches for ssh-generator vsock issue 2025-12-17 16:21:00 +01:00
Zbigniew Jędrzejewski-Szmek
a0d8dd5606 Version 258.3
- 148 patches, for all kinds of small issues.
- Includes a hwdb update.
2025-12-13 11:52:43 +01:00
Zbigniew Jędrzejewski-Szmek
34636ff018 Version 258.2
- A bunch of fixes in many components.
- Stop creating user namespace for system services (rhbz#2391343)
- Systemd trigger scriptlets are updated

(cherry picked from commit 1a7506a105)
2025-11-10 18:31:49 +01:00
Zbigniew Jędrzejewski-Szmek
430d0a6784 Restore runlevelX.target units
... (rhbz#2411195)

(cherry picked from commit 256463d690)
2025-11-10 18:31:45 +01:00
Zbigniew Jędrzejewski-Szmek
6c95e54d3d Use %autosetup -C
This is supported since rpm 4.20 but not advertised much.

(cherry picked from commit b17d9c3474)
2025-11-10 18:31:13 +01:00
Daan De Meyer
2aa97060d3 Remove hack to stop systemd-networkd-resolve-hook.socket
This didn't end up working, so drop the hack as we have a better
fix coming up in https://github.com/systemd/systemd/pull/39415.

(cherry picked from commit fe18084a05)
2025-11-10 18:31:13 +01:00
Zbigniew Jędrzejewski-Szmek
45a98a2ed1 Automatically figure out the name of the top-level tar dir
(cherry picked from commit 8e2833a5b6)
2025-11-10 18:31:13 +01:00
Daan De Meyer
1eeea644a2 Make sure fallback source is listed first
2ace9416e8 broke packit as the fallback
url wasn't listed first anymore. Make sure the fallback URL is listed
first again as clearly documented just above the conditionals.

(cherry picked from commit dffbf2beba)
2025-11-10 18:31:13 +01:00
Zbigniew Jędrzejewski-Szmek
d92c2318d0 Enable sysupdate and sysupdated
The files will land in the -udev subpackage.

(cherry picked from commit 1d3b892105)
2025-11-10 18:31:13 +01:00
Daan De Meyer
9fbc554780 Add missing networkd socket units
systemd-networkd-resolve-hook.socket will be introduced by
https://github.com/systemd/systemd/pull/39293 but we need the spec
to handle the socket for the upgrade/downgrade test to pass so adding
it early behind the upstream bcond.

(cherry picked from commit ea1d871ecd)
2025-11-10 18:31:13 +01:00
Daan De Meyer
c5d4c8ac29 Drop backwards compat logic from integration tests script
(cherry picked from commit f8932309d9)
2025-11-10 18:31:13 +01:00
Zbigniew Jędrzejewski-Szmek
2eec25c1e6 Require systemd-rpm-macros for build
We use our own macros. They get pulled into the buildroot in Fedora
builds, but we shouldn't rely on this. In OBS builds, they are not
pulled in and the build fails.

(cherry picked from commit 7208fa2b1b)
2025-11-10 18:31:13 +01:00
Lukáš Zaoral
c0a7192ccf Require python3-zstandard in ELN
Related: https://issues.redhat.com/browse/RHEL-103523
(cherry picked from commit 2e1a6c7474)
2025-11-10 18:31:13 +01:00
Zbigniew Jędrzejewski-Szmek
75240e80fc Require systemd-libs and systemd-shared to be in the same version
... (rhbz#2404143)

(cherry picked from commit 79c9db1bc8)
2025-10-15 13:55:46 +02:00
10 changed files with 1181 additions and 78 deletions

View file

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

View file

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

View file

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

View file

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

733
38922.patch Normal file
View file

@ -0,0 +1,733 @@
From 993e877cdbd5cc12dcee563e6f4a004c6beac95a Mon Sep 17 00:00:00 2001
From: gvenugo3 <gvenugo3@asu.edu>
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 <gvenugo3@asu.edu>
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(&parameters);
+ r = varlink_sanitize_incoming_parameters(&parameters);
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(&parameters);
+ r = varlink_sanitize_incoming_parameters(&parameters);
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(&parameters);
- 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(&parameters);
- 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(&parameters);
- 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(&parameters);
- 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(&parameters);
- 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(&parameters);
- 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(&parameters);
- 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(&parameters);
- 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 <gvenugo3@asu.edu>
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 <gvenugo3@asu.edu>
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 <gvenugo3@asu.edu>
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 <gvenugo3@asu.edu>
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 @@
<citerefentry><refentrytitle>sd-json</refentrytitle><manvolnum>3</manvolnum></citerefentry> API for JSON
serialization, deserialization and manipulation.</para>
+ <para>Canonical encoding rules: sd-varlink omits the <literal>"parameters"</literal> 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 <literal>"parameters"</literal> key (preferred), a JSON <literal>null</literal>
+ value, or an empty object <literal>{}</literal>. When decoding, sd-varlink treats JSON <literal>null</literal>
+ as if the member was omitted.</para>
+
<para>The <citerefentry><refentrytitle>varlinkctl</refentrytitle><manvolnum>1</manvolnum></citerefentry> tool
makes the functionality implemented by sd-varlink available from the command line.</para>
</refsect1>
From 420241fdd4143818712ef78559db725f3d9f9d3f Mon Sep 17 00:00:00 2001
From: gvenugo3 <gvenugo3@asu.edu>
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 @@
<citerefentry><refentrytitle>sd-json</refentrytitle><manvolnum>3</manvolnum></citerefentry> API for JSON
serialization, deserialization and manipulation.</para>
- <para>Canonical encoding rules: sd-varlink omits the <literal>"parameters"</literal> member in replies,
+ <para>Canonical encoding rules: sd-varlink omits the <literal>"parameters"</literal> 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 <literal>"parameters"</literal> key (preferred), a JSON <literal>null</literal>
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;

View file

@ -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" <<EOF
tee mkosi/mkosi.local.conf <<EOF
[Distribution]
Distribution=${MKOSI_DISTRIBUTION:-$ID}
Release=${MKOSI_RELEASE:-${VERSION_ID:-rawhide}}
@ -97,17 +82,6 @@ KernelCommandLineExtra=systemd.setenv=TEST_SELINUX_CHECK_AVCS=$TEST_SELINUX_CHEC
EOF
fi
# Create missing mountpoint for mkosi sandbox.
mkdir -p /etc/pacman.d/gnupg
# We don't bother with this change if the mkosi configuration is
# in mkosi/ as if that's the case then we know for sure that the
# upstream has this fix as well.
# TODO: drop once BTRFS regression is fixed.
if [[ -f mkosi.repart/10-root.conf ]]; then
sed -i "s/Format=btrfs/Format=ext4/" mkosi.repart/10-root.conf
fi
# If we don't have KVM, skip running in qemu, as it's too slow. But try to load the module first.
modprobe kvm || true
if [[ ! -e /dev/kvm ]]; then
@ -128,23 +102,17 @@ export TEST_SKIP="TEST-21-DFUZZER"
mkosi genkey
mkosi summary
mkosi -f sandbox -- true
if [[ -d integration-tests/standalone ]]; then
mkosi sandbox -- meson setup build integration-tests/standalone
elif [[ -d test/integration-tests/standalone ]]; then
mkosi sandbox -- meson setup build test/integration-tests/standalone
else
mkosi sandbox -- meson setup -Dintegration-tests=true build
fi
mkosi -f box -- true
mkosi box -- meson setup build integration-tests/standalone
mkosi -f
mkosi sandbox -- \
mkosi box -- \
meson test \
-C build \
--no-rebuild \
--suite integration-tests \
--print-errorlogs \
--no-stdsplit \
--num-processes "$NPROC" && EC=0 || EC=$?
-C build \
--setup=integration \
--print-errorlogs \
--no-stdsplit \
--max-lines 300 \
--num-processes "$NPROC" && EC=0 || EC=$?
[[ -d build/meson-logs ]] && find build/meson-logs -type f -exec mv {} "$TMT_TEST_DATA" \;
[[ -d build/test/journal ]] && find build/test/journal -type f -exec mv {} "$TMT_TEST_DATA" \;

View file

@ -1 +1 @@
SHA512 (systemd-258.1.tar.gz) = 0fd62724d4b9cc0789445f3072a7052f52533e2a928cb4a6c3d7375169d087f9cc3941f37c9f208c870042f4e32d90a17cfbb96930a31ac875b41aa7efac8f53
SHA512 (systemd-258.3.tar.gz) = 9f4261e1703efd1f38c90e4166e6d85fa9379c99ac7f3c66caa62955c3cbe8a43ab259c261ab20bce0dd84dd682258192ace66b4dee0390bf3740c32f4569fed

View file

@ -245,6 +245,7 @@ for file in files(buildroot):
sysctl|
coredump|
homed|home1|
sysupdate|updatctl|
oomd|
portabled|portable1
''', n, re.X): # coredumpctl, homectl, portablectl are included in the main package because

View file

@ -68,7 +68,7 @@ Url: https://systemd.io
# But don't do that on OBS, otherwise the version subst fails, and will be
# like 257-123-gabcd257.1 instead of 257-123-gabcd
%if %{without obs}
Version: %{?version_override}%{!?version_override:258.1}
Version: %{?version_override}%{!?version_override:258.3}
%else
Version: %{?version_override}%{!?version_override:%(cat meson.version)}
%endif
@ -82,15 +82,15 @@ Summary: System and Service Manager
# download tarballs with "spectool -g systemd.spec"
# packit will always rewrite the first Source0 it finds, ignoring any conditionals so list
# the fallback source that's used if neither %%branch nor %%commit are defined first.
%if %{with obs}
Source0: https://github.com/systemd/systemd/archive/v%{version_no_tilde}/%{name}-%{version}.tar.xz
%elif %{undefined branch} && %{undefined commit}
# the fallback source that's used if neither %%branch, %%commit or %%obs are defined first.
%if %{undefined branch} && %{undefined commit} && %{without obs}
Source0: https://github.com/systemd/systemd/archive/v%{version_no_tilde}/%{name}-%{version_no_tilde}.tar.gz
%elif %{defined branch}
Source0: https://github.com/systemd/systemd/archive/refs/heads/%{branch}.tar.gz
%elif %{defined commit}
Source0: https://github.com/systemd/systemd/archive/%{commit}/%{name}-%{commit}.tar.gz
%elif %{with obs}
Source0: https://github.com/systemd/systemd/archive/v%{version_no_tilde}/%{name}-%{version}.tar.xz
%endif
# This file must be available before %%prep.
# It is generated during systemd build and can be found at build/src/rpm/triggers.systemd.sh.
@ -145,9 +145,20 @@ Patch: https://github.com/systemd/systemd/pull/30846.patch
# Workaround for a kernel issue. Fixed in kernel-core-6.17.0-0.rc3.31.fc44.x86_64.
Patch: https://github.com/systemd/systemd/pull/38724.patch
# Again create runlevelX.target. Dropping those files breaks upgrades.
# https://bugzilla.redhat.com/show_bug.cgi?id=2411195
Patch: 0001-Revert-units-drop-runlevel-0-6-.target.patch
# userdb: create userdb root directory with correct label
# We can drop this after SELinux policy is updated to handle the transition.
Patch: https://github.com/systemd/systemd/pull/38769.patch
# https://github.com/systemd/systemd/pull/40124
Patch: 0001-ssh-generator-split-out-common-helper-function.patch
Patch: 0002-ssh-generator-split-out-one-more-helper-function.patch
Patch: 0003-ssh-generator-suppress-error-message-for-vsock-EADDR.patch
# userdb: omit empty parameters field in JSON messages
Patch: https://github.com/systemd/systemd/pull/38922.patch
%endif
%ifarch %{ix86} x86_64 aarch64 riscv64
@ -169,6 +180,9 @@ BuildRequires: libselinux-devel
BuildRequires: audit-libs-devel
%if %{without bootstrap}
BuildRequires: cryptsetup-devel
# Require (previous version) of our macros package.
# We use the %%systemd_{post,preun,…} macros for various services.
BuildRequires: systemd-rpm-macros
%endif
BuildRequires: dbus-devel
BuildRequires: util-linux
@ -388,6 +402,7 @@ Summary: systemd libraries
License: LGPL-2.1-or-later AND MIT
Provides: nss-myhostname = 0.4
Provides: nss-myhostname%{_isa} = 0.4
Conflicts: systemd-shared < %{version}-%{release}
%description libs
Libraries for systemd and udev.
@ -399,6 +414,7 @@ License: LGPL-2.1-or-later AND MIT
# was moved from package systemd to systemd-shared.
# Add a conflit to allow downgrades across this change.
Conflicts: systemd < 257.3-6
Conflicts: systemd-libs < %{version}-%{release}
%description shared
Internal libraries used by various systemd binaries.
@ -538,9 +554,7 @@ Requires: (systemd-boot if %{shrink:(
filesystem(riscv64)
)})
Requires: python3dist(pefile)
%if 0%{?fedora}
Requires: python3dist(zstandard)
%endif
Requires: python3dist(cryptography)
%if 0%{?fedora}
Recommends: python3dist(pillow)
@ -747,18 +761,13 @@ library or other libraries from systemd-libs. This package conflicts with the
main systemd package and is meant for use in exitrds.
%prep
%if %{defined branch}
%autosetup -n %{name}-%{branch} -p1
%elif %{defined commit}
%autosetup -n %{name}-%{commit} -p1
%elif %{with obs}
%if %{with obs}
# Recipe files in the OBS build are in a distro-specific dir, as they conflict (e.g. with SUSE ones)
mv %{_sourcedir}/%{name}.fedora/* %{_sourcedir}
%autosetup -n %{name}-%{version} -p1
%else
%autosetup -n %{name}-%{version_no_tilde} -p1
%endif
%autosetup -C -p1
# Disable user lockdown until rpm implements it natively.
# https://github.com/rpm-software-management/rpm/issues/3450
sed -r -i 's/^u!/u/' sysusers.d/*.conf*
@ -837,6 +846,8 @@ CONFIGURE_OPTS=(
-Dlibfido2=enabled
-Dxenctrl=%[0%{?have_xen}?"enabled":"disabled"]
-Defi=true
-Dsysupdate=enabled
-Dsysupdated=enabled
-Dtpm=true
-Dtpm2=enabled
-Dhwdb=true
@ -1379,6 +1390,7 @@ fi
%global networkd_services %{shrink:
systemd-networkd.service
systemd-networkd.socket
systemd-networkd-varlink.socket
systemd-networkd-wait-online.service
systemd-network-generator.service
systemd-networkd-persistent-storage.service

View file

@ -9,17 +9,17 @@
#
# Minimum rpm version supported: 4.14.0
%transfiletriggerin -P 900900 -- /usr/lib/systemd/system /etc/systemd/system
%transfiletriggerin -P 900900 -- /usr/lib/systemd/system/ /etc/systemd/system/
# This script will run after any package is initially installed or
# upgraded. We care about the case where a package is initially
# installed, because other cases are covered by the *un scriptlets,
# so sometimes we will reload needlessly.
/usr/lib/systemd/systemd-update-helper system-reload-restart || :
%transfiletriggerin -P 900899 -- /usr/lib/systemd/user /etc/systemd/user
%transfiletriggerin -P 900899 -- /usr/lib/systemd/user/ /etc/systemd/user/
/usr/lib/systemd/systemd-update-helper user-reload-restart || :
%transfiletriggerpostun -P 1000100 -- /usr/lib/systemd/system /etc/systemd/system
%transfiletriggerpostun -P 1000100 -- /usr/lib/systemd/system/ /etc/systemd/system/
# On removal, we need to run daemon-reload after any units have been
# removed.
# On upgrade, we need to run daemon-reload after any new unit files
@ -27,35 +27,35 @@
# executed.
/usr/lib/systemd/systemd-update-helper system-reload || :
%transfiletriggerpostun -P 1000099 -- /usr/lib/systemd/user /etc/systemd/user
%transfiletriggerpostun -P 1000099 -- /usr/lib/systemd/user/ /etc/systemd/user/
# Execute daemon-reload in user managers.
/usr/lib/systemd/systemd-update-helper user-reload || :
%transfiletriggerpostun -P 10000 -- /usr/lib/systemd/system /etc/systemd/system
%transfiletriggerpostun -P 10000 -- /usr/lib/systemd/system/ /etc/systemd/system/
# We restart remaining system services that should be restarted here.
/usr/lib/systemd/systemd-update-helper system-restart || :
%transfiletriggerpostun -P 9999 -- /usr/lib/systemd/user /etc/systemd/user
%transfiletriggerpostun -P 9999 -- /usr/lib/systemd/user/ /etc/systemd/user/
# We restart remaining user services that should be restarted here.
/usr/lib/systemd/systemd-update-helper user-restart || :
%transfiletriggerin -P 1000700 -- /usr/lib/sysusers.d
%transfiletriggerin -P 1000700 -- /usr/lib/sysusers.d/
# This script will process files installed in /usr/lib/sysusers.d to create
# specified users automatically. The priority is set such that it
# will run before the tmpfiles file trigger.
systemd-sysusers || :
%transfiletriggerin -P 1000700 udev -- /usr/lib/udev/hwdb.d
%transfiletriggerin -P 1000700 udev -- /usr/lib/udev/hwdb.d/
# This script will automatically invoke hwdb update if files have been
# installed or updated in /usr/lib/udev/hwdb.d.
systemd-hwdb update || :
%transfiletriggerin -P 1000700 -- /usr/lib/systemd/catalog
%transfiletriggerin -P 1000700 -- /usr/lib/systemd/catalog/
# This script will automatically invoke journal catalog update if files
# have been installed or updated in /usr/lib/systemd/catalog.
journalctl --update-catalog || :
%transfiletriggerin -P 1000700 -- /usr/lib/binfmt.d
%transfiletriggerin -P 1000700 -- /usr/lib/binfmt.d/
# This script will automatically apply binfmt rules if files have been
# installed or updated in /usr/lib/binfmt.d.
if test -d "/run/systemd/system"; then
@ -64,7 +64,7 @@ if test -d "/run/systemd/system"; then
/usr/lib/systemd/systemd-binfmt || :
fi
%transfiletriggerin -P 1000600 -- /usr/lib/tmpfiles.d
%transfiletriggerin -P 1000600 -- /usr/lib/tmpfiles.d/
# This script will process files installed in /usr/lib/tmpfiles.d to create
# tmpfiles automatically. The priority is set such that it will run
# after the sysusers file trigger, but before any other triggers.
@ -72,14 +72,12 @@ if test -d "/run/systemd/system"; then
systemd-tmpfiles --create || :
fi
%transfiletriggerin -P 1000600 udev -- /usr/lib/udev/rules.d
%transfiletriggerin -P 1000600 udev -- /usr/lib/udev/rules.d/
# This script will automatically update udev with new rules if files
# have been installed or updated in /usr/lib/udev/rules.d.
if test -e /run/udev/control; then
udevadm control --reload || :
fi
/usr/lib/systemd/systemd-update-helper mark-reload-system-units systemd-udevd.service || :
%transfiletriggerin -P 1000500 -- /usr/lib/sysctl.d
%transfiletriggerin -P 1000500 -- /usr/lib/sysctl.d/
# This script will automatically apply sysctl rules if files have been
# installed or updated in /usr/lib/sysctl.d.
if test -d "/run/systemd/system"; then