From 75240e80fc00ee9967808a38051dca0786876138 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Wed, 15 Oct 2025 13:54:29 +0200 Subject: [PATCH 01/15] Require systemd-libs and systemd-shared to be in the same version ... (rhbz#2404143) (cherry picked from commit 79c9db1bc8f2f0c95cc8af38c5b495c815778b2e) --- systemd.spec | 2 ++ 1 file changed, 2 insertions(+) diff --git a/systemd.spec b/systemd.spec index 1387788..0c56c7b 100644 --- a/systemd.spec +++ b/systemd.spec @@ -388,6 +388,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 +400,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. From c0a7192ccf198f4ac3e1ea9937b0c594ed712723 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Zaoral?= Date: Mon, 20 Oct 2025 16:00:31 +0200 Subject: [PATCH 02/15] Require python3-zstandard in ELN Related: https://issues.redhat.com/browse/RHEL-103523 (cherry picked from commit 2e1a6c7474502ca63c677cd7070b6e13e6329057) --- systemd.spec | 2 -- 1 file changed, 2 deletions(-) diff --git a/systemd.spec b/systemd.spec index 0c56c7b..0f28184 100644 --- a/systemd.spec +++ b/systemd.spec @@ -540,9 +540,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) From 2eec25c1e6a1dae92d1e960d84fa22d0b6cb8ae4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Thu, 23 Oct 2025 20:40:58 +0200 Subject: [PATCH 03/15] 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 7208fa2b1b2afbf93fe05d285e8db8e09d795fad) --- systemd.spec | 3 +++ 1 file changed, 3 insertions(+) diff --git a/systemd.spec b/systemd.spec index 0f28184..e177a51 100644 --- a/systemd.spec +++ b/systemd.spec @@ -169,6 +169,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 From c5d4c8ac29b83d1fd392c1a3478625be8a5588e3 Mon Sep 17 00:00:00 2001 From: Daan De Meyer Date: Tue, 21 Oct 2025 13:06:49 +0200 Subject: [PATCH 04/15] Drop backwards compat logic from integration tests script (cherry picked from commit f8932309d95f37b0f81c54a8d38010ced60ae99b) --- plans/run-integration-tests.sh | 60 ++++++++-------------------------- 1 file changed, 14 insertions(+), 46 deletions(-) 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" < Date: Wed, 29 Oct 2025 10:32:12 +0100 Subject: [PATCH 05/15] 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 ea1d871ecd6c2fe063523840c1e4cf9bcf200e32) --- systemd.spec | 2 ++ 1 file changed, 2 insertions(+) diff --git a/systemd.spec b/systemd.spec index e177a51..4842e92 100644 --- a/systemd.spec +++ b/systemd.spec @@ -1382,6 +1382,8 @@ fi %global networkd_services %{shrink: systemd-networkd.service systemd-networkd.socket + systemd-networkd-varlink.socket + %[%{with upstream}?"systemd-networkd-resolve-hook.socket":""] systemd-networkd-wait-online.service systemd-network-generator.service systemd-networkd-persistent-storage.service From d92c2318d0039c70b3eb96174db2fe1d2aff67e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Thu, 23 Oct 2025 23:36:16 +0200 Subject: [PATCH 06/15] Enable sysupdate and sysupdated The files will land in the -udev subpackage. (cherry picked from commit 1d3b89210552dcc25f89519045fb54439176ac25) --- split-files.py | 1 + systemd.spec | 2 ++ 2 files changed, 3 insertions(+) diff --git a/split-files.py b/split-files.py index 8405956..38bde60 100644 --- a/split-files.py +++ b/split-files.py @@ -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 diff --git a/systemd.spec b/systemd.spec index 4842e92..a4c329d 100644 --- a/systemd.spec +++ b/systemd.spec @@ -840,6 +840,8 @@ CONFIGURE_OPTS=( -Dlibfido2=enabled -Dxenctrl=%[0%{?have_xen}?"enabled":"disabled"] -Defi=true + -Dsysupdate=enabled + -Dsysupdated=enabled -Dtpm=true -Dtpm2=enabled -Dhwdb=true From 1eeea644a2afaf5cdd4402a5739b094583c9f07f Mon Sep 17 00:00:00 2001 From: Daan De Meyer Date: Mon, 3 Nov 2025 11:17:40 +0100 Subject: [PATCH 07/15] Make sure fallback source is listed first 2ace9416e85dd4759f7c0db4bb79d2bc9302dd77 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 dffbf2beba916ad79eeb2ccff9768ab48855a2eb) --- systemd.spec | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/systemd.spec b/systemd.spec index a4c329d..4e8ee72 100644 --- a/systemd.spec +++ b/systemd.spec @@ -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. From 45a98a2ed1a2ac0c41dc42655a524b4f527cec83 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Mon, 3 Nov 2025 12:08:50 +0100 Subject: [PATCH 08/15] Automatically figure out the name of the top-level tar dir (cherry picked from commit 8e2833a5b64f7e2ce62ea0a2d0ec9e393e718dfa) --- systemd.spec | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/systemd.spec b/systemd.spec index 4e8ee72..13aabfb 100644 --- a/systemd.spec +++ b/systemd.spec @@ -750,18 +750,15 @@ 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 +# Automatically figure out the name of the top-level directory. +# rpm really should do this automatically. +%autosetup -n %(tar -tf %{SOURCE0} | head -n1) -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* From 2aa97060d3e5a865993b1eb2ea8c23ca0c603582 Mon Sep 17 00:00:00 2001 From: Daan De Meyer Date: Mon, 3 Nov 2025 14:33:02 +0100 Subject: [PATCH 09/15] 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 fe18084a0583d134e424d70acb341860e69e8540) --- systemd.spec | 1 - 1 file changed, 1 deletion(-) diff --git a/systemd.spec b/systemd.spec index 13aabfb..e9685e3 100644 --- a/systemd.spec +++ b/systemd.spec @@ -1382,7 +1382,6 @@ fi systemd-networkd.service systemd-networkd.socket systemd-networkd-varlink.socket - %[%{with upstream}?"systemd-networkd-resolve-hook.socket":""] systemd-networkd-wait-online.service systemd-network-generator.service systemd-networkd-persistent-storage.service From 6c95e54d3dc7eacd3fcd48ee52419a0b1752e032 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Tue, 4 Nov 2025 16:18:12 +0100 Subject: [PATCH 10/15] Use %autosetup -C This is supported since rpm 4.20 but not advertised much. (cherry picked from commit b17d9c3474f6cd4c07e01ffdfedf6a93c157d859) --- systemd.spec | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/systemd.spec b/systemd.spec index e9685e3..9d72bb2 100644 --- a/systemd.spec +++ b/systemd.spec @@ -755,9 +755,7 @@ main systemd package and is meant for use in exitrds. mv %{_sourcedir}/%{name}.fedora/* %{_sourcedir} %endif -# Automatically figure out the name of the top-level directory. -# rpm really should do this automatically. -%autosetup -n %(tar -tf %{SOURCE0} | head -n1) -p1 +%autosetup -C -p1 # Disable user lockdown until rpm implements it natively. # https://github.com/rpm-software-management/rpm/issues/3450 From 430d0a6784d41c640572e634d0c42362ca5769e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Wed, 5 Nov 2025 17:55:32 +0100 Subject: [PATCH 11/15] Restore runlevelX.target units ... (rhbz#2411195) (cherry picked from commit 256463d69051665ea25d584a35ea817f94e18a41) --- ...vert-units-drop-runlevel-0-6-.target.patch | 87 +++++++++++++++++++ systemd.spec | 4 + 2 files changed, 91 insertions(+) create mode 100644 0001-Revert-units-drop-runlevel-0-6-.target.patch 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/systemd.spec b/systemd.spec index 9d72bb2..a414aa1 100644 --- a/systemd.spec +++ b/systemd.spec @@ -145,6 +145,10 @@ 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 From 34636ff018d1425930cb1f37d26ef9652ca4be5a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Fri, 7 Nov 2025 14:02:48 +0100 Subject: [PATCH 12/15] 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 1a7506a1051c8361714463825b83febcb04b5639) --- sources | 2 +- systemd.spec | 2 +- triggers.systemd | 30 ++++++++++++++---------------- 3 files changed, 16 insertions(+), 18 deletions(-) diff --git a/sources b/sources index 6b4fe22..a9f4297 100644 --- a/sources +++ b/sources @@ -1 +1 @@ -SHA512 (systemd-258.1.tar.gz) = 0fd62724d4b9cc0789445f3072a7052f52533e2a928cb4a6c3d7375169d087f9cc3941f37c9f208c870042f4e32d90a17cfbb96930a31ac875b41aa7efac8f53 +SHA512 (systemd-258.2.tar.gz) = 1dc016a5a037aec2682e08d2add0dcf8d03db15b45ce8c6b677898f734aefd4694ce18e588d579e42514071fc4c167b2bf53808478b2bd3856b257c9fbcde45d diff --git a/systemd.spec b/systemd.spec index a414aa1..54f7de6 100644 --- a/systemd.spec +++ b/systemd.spec @@ -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.2} %else Version: %{?version_override}%{!?version_override:%(cat meson.version)} %endif diff --git a/triggers.systemd b/triggers.systemd index f8bb078..28ddc1f 100644 --- a/triggers.systemd +++ b/triggers.systemd @@ -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 From a0d8dd56066bc01e65c7b8b59f192ac526711a46 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Sat, 13 Dec 2025 11:52:43 +0100 Subject: [PATCH 13/15] Version 258.3 - 148 patches, for all kinds of small issues. - Includes a hwdb update. --- sources | 2 +- systemd.spec | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/sources b/sources index a9f4297..9523ae5 100644 --- a/sources +++ b/sources @@ -1 +1 @@ -SHA512 (systemd-258.2.tar.gz) = 1dc016a5a037aec2682e08d2add0dcf8d03db15b45ce8c6b677898f734aefd4694ce18e588d579e42514071fc4c167b2bf53808478b2bd3856b257c9fbcde45d +SHA512 (systemd-258.3.tar.gz) = 9f4261e1703efd1f38c90e4166e6d85fa9379c99ac7f3c66caa62955c3cbe8a43ab259c261ab20bce0dd84dd682258192ace66b4dee0390bf3740c32f4569fed diff --git a/systemd.spec b/systemd.spec index 54f7de6..a482a2e 100644 --- a/systemd.spec +++ b/systemd.spec @@ -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.2} +Version: %{?version_override}%{!?version_override:258.3} %else Version: %{?version_override}%{!?version_override:%(cat meson.version)} %endif From 9dd9d14abb5b260f3b860bb11f4c68f169c0e0f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Wed, 17 Dec 2025 16:21:00 +0100 Subject: [PATCH 14/15] Add patches for ssh-generator vsock issue --- ...tor-split-out-common-helper-function.patch | 155 ++++++++++++++++++ ...r-split-out-one-more-helper-function.patch | 110 +++++++++++++ ...ppress-error-message-for-vsock-EADDR.patch | 39 +++++ systemd.spec | 5 + 4 files changed, 309 insertions(+) create mode 100644 0001-ssh-generator-split-out-common-helper-function.patch create mode 100644 0002-ssh-generator-split-out-one-more-helper-function.patch create mode 100644 0003-ssh-generator-suppress-error-message-for-vsock-EADDR.patch 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/systemd.spec b/systemd.spec index a482a2e..1605bcc 100644 --- a/systemd.spec +++ b/systemd.spec @@ -152,6 +152,11 @@ 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 %endif %ifarch %{ix86} x86_64 aarch64 riscv64 From 28bbd2db447c95707529d365fb721f2f01905b78 Mon Sep 17 00:00:00 2001 From: Andreas Schneider Date: Mon, 5 Jan 2026 10:57:12 +0100 Subject: [PATCH 15/15] userdb: Omit empty parameters field in JSON messages Details: https://github.com/systemd/systemd/issues/40252 --- 38922.patch | 733 +++++++++++++++++++++++++++++++++++++++++++++++++++ systemd.spec | 2 + 2 files changed, 735 insertions(+) create mode 100644 38922.patch 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/systemd.spec b/systemd.spec index 1605bcc..e6d0eb4 100644 --- a/systemd.spec +++ b/systemd.spec @@ -157,6 +157,8 @@ Patch: https://github.com/systemd/systemd/pull/38769.patch 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