]> git.ipfire.org Git - thirdparty/systemd.git/log
thirdparty/systemd.git
3 weeks agologind: add ListInhibitors Varlink method 41561/head
Yaping Li [Sun, 10 May 2026 14:50:13 +0000 (14:50 +0000)] 
logind: add ListInhibitors Varlink method

The Varlink ListInhibitors method is the counterpart of D-Bus
ListInhibitors. Like its D-Bus counterpart it is zero-filter and streams
the full list of currently registered inhibitors using the
SD_VARLINK_METHOD_MORE pattern, returning InhibitorInfo objects with
Id, What, Who, Why, Mode, UID, PID, and Since fields.

There is no D-Bus GetInhibitor getter to fold in, so no unique-key
filter is introduced here.

3 weeks agologind: add ListSeats Varlink method
Yaping Li [Sun, 10 May 2026 14:50:13 +0000 (14:50 +0000)] 
logind: add ListSeats Varlink method

The Varlink ListSeats method accepts an optional Id filter, folding in
the D-Bus GetSeat(s) lookup.

Passing Id yields a single reply on match, or NoSuchSeat on miss.
Passing no Id with the 'more' flag streams the full list; passing no
Id without 'more' resolves to the caller's seat (preserving the
ergonomic default of GetSeat). The Id filter supports the special
names "self" and "auto" which resolve to the caller's seat.

The SeatInfo type in the io.systemd.Login Varlink IDL carries all seat
properties matching the D-Bus org.freedesktop.login1.Seat interface.

3 weeks agologind: add ListUsers Varlink method
Yaping Li [Sun, 10 May 2026 14:50:13 +0000 (14:50 +0000)] 
logind: add ListUsers Varlink method

The Varlink ListUsers method accepts optional UID and PID filters,
folding in the D-Bus GetUser(u) and GetUserByPID(u) lookups.

Passing a unique-key filter (UID and/or PID) yields a single reply on
match, or NoSuchUser on miss. Passing no filter with the 'more' flag
streams the full list; passing no filter without 'more' resolves to
the caller's user (preserving the ergonomic default of GetUser). If
both UID and PID are specified they must reference the same user,
otherwise NoSuchUser is returned.

The UserInfo type in the io.systemd.Login Varlink IDL carries all
user properties matching the D-Bus org.freedesktop.login1.User
interface.

3 weeks agologind: add ListSessions Varlink method
Yaping Li [Sun, 10 May 2026 14:50:12 +0000 (14:50 +0000)] 
logind: add ListSessions Varlink method

The Varlink ListSessions method accepts optional Id and PID filters,
folding in the D-Bus GetSession(s) and GetSessionByPID(u) lookups.

Passing a unique-key filter (Id and/or PID) yields a single reply on
match, or NoSuchSession on miss. Passing no filter streams the full
list (requires the 'more' flag). Specifying both Id and PID acts as a
consistency check: both must refer to the same session, otherwise
NoSuchSession is returned.

The Id filter supports the special names "self" and "auto" which
resolve to the caller's session. The SessionInfo type in the
io.systemd.Login Varlink IDL carries all session properties matching
the D-Bus org.freedesktop.login1.Session interface.

3 weeks agologind: let {session,user,seat}_get_idle_hint() return bool and always set output...
Yaping Li [Sun, 10 May 2026 14:50:12 +0000 (14:50 +0000)] 
logind: let {session,user,seat}_get_idle_hint() return bool and always set output timestamp

These helpers returned int but in practice only ever produced 0/1.
session_get_idle_hint() silently swallowed negative returns from
get_tty_atime()/get_process_ctty_atime() and fell through to
return false; user_get_idle_hint() and seat_get_idle_hint() propagated
errors from session_get_idle_hint() that could no longer occur.

Change all three to return bool and always set *t on non-NULL output.
session_get_idle_hint() previously did not set *t on the
!SESSION_CLASS_CAN_IDLE() early return; fix by defaulting *t at the
top of the function. Callers that read *t after a false return now see
DUAL_TIMESTAMP_NULL rather than uninitialized memory.

Update all callers: drop dead < 0 error checks, drop > 0 coercion,
drop DUAL_TIMESTAMP_NULL pre-init at sites that only pass &t to the
helpers.

3 weeks agosd-varlink: skip IDL validation on synthetic empty terminator
Yaping Li [Tue, 28 Apr 2026 22:45:05 +0000 (15:45 -0700)] 
sd-varlink: skip IDL validation on synthetic empty terminator

When a streaming method's callback returns 0 with no replies enqueued and
sd_varlink_set_sentinel() was passed NULL (POINTER_MAX), the framework
emits an empty parameters reply via sd_varlink_reply(v, NULL) as a clean
stream terminator. That call validated the empty parameters against the
method's output IDL — which always failed when the IDL declared any
mandatory output field, generating a spurious 'didn't pass validation'
warning even though the empty terminator is correct by construction.

Move the body of sd_varlink_reply() into a static varlink_reply_internal()
that takes a skip_validation flag. The public sd_varlink_reply() keeps
its existing behavior (validation enabled). Add a static
varlink_reply_terminator() helper that wraps
varlink_reply_internal(v, NULL, /* skip_validation= */ true), and route
varlink_dispatch_sentinel() through it for the synthetic empty terminator,
so both the synchronous dispatch path (varlink_dispatch_method()) and the
fiber path (varlink_fiber_entry()) skip validation in one place.

Without this, callers who want 'streaming method, possibly empty result'
semantics had to either fire a logically wrong 'NotFound'-style error
sentinel on empty (sysext.List, BootControl.ListBootEntries pattern) or
mark every output field NULLABLE just to placate the validator (the
io.systemd.Manager.EnqueueMarkedJobs approach), misrepresenting the
contract — exactly the tradeoff the FIXME in pcrlock.c flagged. With
this change, the empty terminator is invisible to the IDL validator and
the FIXME is no longer needed.

Co-developed-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
3 weeks agosd-dhcp-server: use sd_dhcp_message object on sending reply 42240/head
Yu Watanabe [Sun, 10 May 2026 13:17:05 +0000 (22:17 +0900)] 
sd-dhcp-server: use sd_dhcp_message object on sending reply

This also makes the conditions in dhcp_server_send_message() uses
the message that will be sent, rather than we received.

This does not change basic functionality, but changes/fixes several
minor behaviors, e.g.
- fix when the broadcast flag assignment,
- set server identifier in DHCPFORCERENEW.

3 weeks agosd-dhcp-server: use sd_dhcp_message to parse received messages
Yu Watanabe [Thu, 7 May 2026 04:30:00 +0000 (13:30 +0900)] 
sd-dhcp-server: use sd_dhcp_message to parse received messages

This is mostly refactoring. This does not change basic behavior, but
changes/fixes some minor/corner cases, e.g.

- extend the minimum default lease time from 1 second to 30 seconds, as
  1 second is too short and causes the network unstable (though 30
  seconds is stll too short, but hopefully that does not make the
  network unstable).
- error code on broken/malicious message received may be changed.

3 weeks agodhcp-server-request: drop invalid short-cut logic
Yu Watanabe [Mon, 18 May 2026 00:37:27 +0000 (09:37 +0900)] 
dhcp-server-request: drop invalid short-cut logic

Even if no pool is allocated, the server may have a static lease
matching with the DHCPDISCOVER message.

3 weeks agodhcp: move definition of enum DHCPState to dhcp-protocol.[ch]
Yu Watanabe [Sun, 10 May 2026 14:13:07 +0000 (23:13 +0900)] 
dhcp: move definition of enum DHCPState to dhcp-protocol.[ch]

It will be also used in DHCP server, later.

3 weeks agosd-dhcp-relay: use forward declarations
Yu Watanabe [Thu, 21 May 2026 22:10:46 +0000 (07:10 +0900)] 
sd-dhcp-relay: use forward declarations

3 weeks agosd-dhcp-server: several trivial cleanups (#42235)
Yu Watanabe [Thu, 21 May 2026 21:44:07 +0000 (06:44 +0900)] 
sd-dhcp-server: several trivial cleanups (#42235)

This should mostly not change behavior, except for some corner cases.
Just refactoring and preparation for later changes.

3 weeks agoUpdate NEWS
Luca Boccassi [Thu, 21 May 2026 20:59:17 +0000 (21:59 +0100)] 
Update NEWS

3 weeks agobootctl: add A/B fallback for sd-boot updates (#41650)
Luca Boccassi [Thu, 21 May 2026 20:56:05 +0000 (21:56 +0100)] 
bootctl: add A/B fallback for sd-boot updates (#41650)

On `bootctl install`, two EFI boot entries are registered: one for the
primary sd-boot binary and one for a fallback. On `bootctl update`, the
existing primary binary is rotated to the fallback path before the new
version is installed, so the fallback entry always points to the
previous known-good binary.

```
$ sudo bootctl install
...
Created EFI boot entry "Linux Boot Manager".
Created EFI boot entry "Fallback Linux Boot Manager".
$ sudo bootctl update
Copied "/boot/EFI/systemd/systemd-bootaa64.efi" to "/boot/EFI/systemd/systemd-boot-fallbackaa64.efi".
Copied "/usr/lib/systemd/boot/efi/systemd-bootaa64.efi" to "/boot/EFI/systemd/systemd-bootaa64.efi".
$ efibootmgr
...
Boot0004* Linux Boot Manager        HD(...)/\EFI\systemd\systemd-bootaa64.efi
Boot0005* Fallback Linux Boot Manager     HD(...)/\EFI\systemd\systemd-boot-fallbackaa64.efi
```

Fixes: #23805
3 weeks agoUpdate NEWS
Luca Boccassi [Thu, 21 May 2026 20:49:22 +0000 (21:49 +0100)] 
Update NEWS

3 weeks agoboot,stub: explicitly measure select SMBIOS objects (#42233)
Luca Boccassi [Thu, 21 May 2026 20:44:42 +0000 (21:44 +0100)] 
boot,stub: explicitly measure select SMBIOS objects (#42233)

This is supposed to protect our SMBIOS type 11 importing for
credentials. Note that firmwares are supposed to measure SMBIOS anyway
to PCR 1. Alas firmware doesn't really do that in various cases. Hence
let's do so again, for select objects.

This closes a gap where some of the input for OS (i.e. system
credentials places in smbios11) isn't measured properly.

(I really want this to get into v261, because this will fuck up the PCRs
a bit more, and we already have the new separator measurement in v261,
hence there's value in getting this merged at the same time, so that we
don't break the measurements a 2nd time)

3 weeks agoupdate TODO 42233/head
Lennart Poettering [Thu, 21 May 2026 15:13:40 +0000 (17:13 +0200)] 
update TODO

3 weeks agopcrlock: port --help to help-util.[ch] apis
Lennart Poettering [Thu, 21 May 2026 16:16:32 +0000 (18:16 +0200)] 
pcrlock: port --help to help-util.[ch] apis

3 weeks agopcrlock: decode new smbios events
Lennart Poettering [Thu, 21 May 2026 16:16:45 +0000 (18:16 +0200)] 
pcrlock: decode new smbios events

3 weeks agobootctl: show SMBIOS feature flags
Lennart Poettering [Thu, 21 May 2026 15:27:13 +0000 (17:27 +0200)] 
bootctl: show SMBIOS feature flags

3 weeks agodocs: document the new smbios measurements
Lennart Poettering [Thu, 21 May 2026 15:26:20 +0000 (17:26 +0200)] 
docs: document the new smbios measurements

3 weeks agoUpdate NEWS
Luca Boccassi [Thu, 21 May 2026 20:13:10 +0000 (21:13 +0100)] 
Update NEWS

3 weeks agoUse malloc'ed strings instead of static libc buffers for user and group lookup (...
Yu Watanabe [Thu, 21 May 2026 20:09:56 +0000 (05:09 +0900)] 
Use malloc'ed strings instead of static libc buffers for user and group lookup (#42184)

Preparation for other work.

3 weeks agohostnamed,pid1,firstboot: introduce "machine tags" concept (#42223)
Luca Boccassi [Thu, 21 May 2026 19:57:34 +0000 (20:57 +0100)] 
hostnamed,pid1,firstboot: introduce "machine tags" concept (#42223)

Fixes: #38591
3 weeks agoci: ignore failures to chown journal in GHA jobs
Luca Boccassi [Thu, 21 May 2026 18:21:19 +0000 (19:21 +0100)] 
ci: ignore failures to chown journal in GHA jobs

Otherwise when the build fails, this fails, and the GUI jumps to the
chown failure instead of the actual failure

Follow-up for 35bf1c826454bfcaa3c93cae950d36fa216ac3ce

3 weeks agodhcp-server-request: check server address in DHCPDECLINE and DHCPRELEASE 42235/head
Yu Watanabe [Thu, 7 May 2026 03:19:25 +0000 (12:19 +0900)] 
dhcp-server-request: check server address in DHCPDECLINE and DHCPRELEASE

Otherwise, we may do something wrong by messages for another DHCP server.
Let's silently ignore messages with unmatching server identifier.

Also, logs something when we receive DHCPRELEASE but found lease does
not match the reported address.

3 weeks agosd-dhcp-server: store more information in DHCPRequest
Yu Watanabe [Thu, 7 May 2026 02:59:23 +0000 (11:59 +0900)] 
sd-dhcp-server: store more information in DHCPRequest

This makes DHCPRequest stores
- the message type of the received message,
- acquired address,
- found static DHCP lease,

This also moves call of dhcp_request_get_lifetime_timestamp() from
dhcp_server_ack() to dhcp_server_set_lease(), and rename
DHCPRequest.server_id -> .server_address.

No functional change, just refactoring.

3 weeks agosd-dhcp-server: use struct hw_addr_data to manage client hardware address parsed...
Yu Watanabe [Mon, 4 May 2026 19:55:03 +0000 (04:55 +0900)] 
sd-dhcp-server: use struct hw_addr_data to manage client hardware address parsed from DHCP message

Then, this drops garbage in DHCP server lease in DBus and Varlink message.

This also drops fallback to use client ID as hardware address when chaddr
field is not set. In that case, we should broadcast reply.

3 weeks agodhcp-server-send: rework sending DHCP reply message
Yu Watanabe [Mon, 4 May 2026 13:08:40 +0000 (22:08 +0900)] 
dhcp-server-send: rework sending DHCP reply message

This should mostly not change anything, except for some corner cases.
Just refactoring.

3 weeks agosd-dhcp-server: make IP service type (TOS) configurable
Yu Watanabe [Thu, 7 May 2026 03:41:38 +0000 (12:41 +0900)] 
sd-dhcp-server: make IP service type (TOS) configurable

3 weeks agosd-dhcp-server: refactoring for socket fd handling
Yu Watanabe [Mon, 4 May 2026 10:57:49 +0000 (19:57 +0900)] 
sd-dhcp-server: refactoring for socket fd handling

This makes
- UDP socket fd is owned by IO event source,
- open RAW socket fd just before sending first packet,
- set TOS and socket priority,
- use AF_UNIX soxket pair in the unit test and fuzzer, so the unit test
  can now run by unprivileged user.

3 weeks agodhcp-serve-request: move message size check to dhcp_server_handle_message()
Yu Watanabe [Mon, 4 May 2026 21:57:33 +0000 (06:57 +0900)] 
dhcp-serve-request: move message size check to dhcp_server_handle_message()

3 weeks agodhcp-server-request: modernize server_receive_message()
Yu Watanabe [Mon, 4 May 2026 07:59:04 +0000 (16:59 +0900)] 
dhcp-server-request: modernize server_receive_message()

3 weeks agosd-dhcp-server: split into small pieaces
Yu Watanabe [Mon, 4 May 2026 04:24:33 +0000 (13:24 +0900)] 
sd-dhcp-server: split into small pieaces

No functional change, just several functions are moved/split/renamed.

3 weeks agotest-dhcp-server: several cleanups
Yu Watanabe [Mon, 4 May 2026 11:42:27 +0000 (20:42 +0900)] 
test-dhcp-server: several cleanups

No effective change, just rafactoring.

3 weeks agomeson: Add libucontext to libshared_deps
Daan De Meyer [Thu, 21 May 2026 17:51:07 +0000 (17:51 +0000)] 
meson: Add libucontext to libshared_deps

Fixes #42236

3 weeks agobootctl: remove fallback EFI Boot#### variable on uninstall 41650/head
Clayton Craft [Thu, 30 Apr 2026 03:32:19 +0000 (20:32 -0700)] 
bootctl: remove fallback EFI Boot#### variable on uninstall

This cleans up the fallback Boot#### entry that was registered on
install. The logic cleaning up variables was moved from verb_remove into
a new remove_variables function, which mirrors the install side.

3 weeks agobootctl: register fallback EFI Boot#### entry on install
Clayton Craft [Thu, 30 Apr 2026 01:46:13 +0000 (18:46 -0700)] 
bootctl: register fallback EFI Boot#### entry on install

This adds a second install_boot_option call to register a Boot#### entry
pointing at systemd-boot-fallback{arch}.efi, and place it immediately
after the primary entry in BootOrder.

The fallback file does not exist on the ESP on first install and is
only created on first update when the existing primary binary is
rotated to the fallback path. We register the variable anyway, so
that the entry exists in the BootOrder once the fallback file shows up.
Until then, firmware that reaches the fallback entry will fail to
load it and fall through to the next entry in BootOrder, which is
fine. install_boot_option gains a require_existing parameter so the
existing early return on a missing ESP path can be skipped for the
fallback, where a missing path is expected.

This also does a bit of refactoring by splitting the bottom part of
run_install() into a new install_variables() function that handles
registering both the primary and fallback entries.

3 weeks agobootctl: back up sd-boot binary to fallback path on update
Clayton Craft [Thu, 30 Apr 2026 01:24:21 +0000 (18:24 -0700)] 
bootctl: back up sd-boot binary to fallback path on update

When a primary sd-boot binary already exists on the ESP and is being
updated, it is copied to systemd-boot-fallback{arch}.efi before installing
the new version. This gives firmware a fallback Boot#### entry pointing
to the previous binary in case the new one fails to load.

The fallback is preserved (not overwritten) when its product and version
match the currently booted bootloader (read from the LoaderInfo EFI
variable), since that means it already holds the known good binary that
booted this session. In all other cases it is overwritten with the current
primary, when no fallback exists yet, when LoaderInfo is unavailable, or
when the fallback's product or version differs from what booted.

This also moves the version_check() call up so its result determines
both the rotation decision and the main copy, and avoids a duplicate
check (and duplicate "Skipping..." log) when the binary is already
current.

3 weeks agobootctl: add after_slot parameter to insert_into_order()
Clayton Craft [Thu, 30 Apr 2026 00:35:05 +0000 (17:35 -0700)] 
bootctl: add after_slot parameter to insert_into_order()

This adds an after_slot parameter that, when not set to UINT16_MAX,
requests that the new slot be placed immediately after the given slot in
BootOrder. When after_slot is set and the new slot already exists in
BootOrder, it will leave its position alone. This is so that if a user
reorders it, we don't stomp on their changes.

3 weeks agobootctl: add description and ret_slot parameters to install_boot_option()
Clayton Craft [Thu, 30 Apr 2026 00:10:05 +0000 (17:10 -0700)] 
bootctl: add description and ret_slot parameters to install_boot_option()

This moves creation of the EFI boot option description out of
install_boot_option and into the caller, and adds a ret_slot output
parameter for capturing the assigned BootOrder slot. This allows reusing
the function for installing variables with different descriptions.

3 weeks agobootctl: rename install_variables/remove_variables to install/remove_boot_option
Clayton Craft [Tue, 12 May 2026 17:47:17 +0000 (10:47 -0700)] 
bootctl: rename install_variables/remove_variables to install/remove_boot_option

These functions install or remove a single EFI Boot#### entry, not
"all variables," so this renames them to better reflect what they do.

3 weeks agobootctl: fix removing variables on uninstall
Clayton Craft [Thu, 30 Apr 2026 02:33:58 +0000 (19:33 -0700)] 
bootctl: fix removing variables on uninstall

remove_variables looks up the EFI boot entry by matching both the path
and the partition UUID and it wasn't actually removing any entries
because verb_remove was passing SD_ID128_NULL, so the lookup never
matched and Boot#### entries were left behind on uninstall.

Fixes 38433a6

3 weeks agosystemctl: also attempt kexec image extraction on EINVAL
Rocker Zhang [Thu, 21 May 2026 15:47:48 +0000 (23:47 +0800)] 
systemctl: also attempt kexec image extraction on EINVAL

load_kexec_kernel() retries kexec_file_load() with an extracted kernel
(decompressed Image / ZBOOT PE / UKI) when the kernel rejects the image,
but it only does so when kexec_file_load() failed with ENOEXEC. On arm64
that retry never happens: arm64's image_probe()
(arch/arm64/kernel/kexec_image.c) returns -EINVAL on an ARM64_IMAGE_MAGIC
mismatch, whereas x86's bzImage64_probe() and the generic
kexec_image_probe_default() return -ENOEXEC. So `systemctl kexec` of a
UKI on arm64 skips the extraction path and falls back to the
/usr/sbin/kexec binary, which is no longer a dependency since e107c7ead0
("systemctl: replace kexec-tools dependency with direct kexec_file_load()
syscall") -- leaving kexec broken.

Accept EINVAL in addition to ENOEXEC. This is safe: the extraction in
kexec_maybe_decompress_kernel() re-gates on the actual file magic (MZ /
compression headers) and is a no-op returning 0 for anything else, so an
EINVAL that is not a format mismatch just falls through to the existing
fallback as before.

Fixing this in systemd (rather than only in the kernel) is appropriate:
systemd must keep working with already-shipped arm64 kernels whose
kexec_file_load() returns EINVAL for an unrecognized image magic.

Relates to: https://github.com/systemd/systemd/issues/28538

Co-developed-by: Claude Opus 4.7 <noreply@anthropic.com>
3 weeks agonsresourced: Add more debug logging 42224/head
Daan De Meyer [Thu, 21 May 2026 08:37:56 +0000 (08:37 +0000)] 
nsresourced: Add more debug logging

3 weeks agoboot: measure select SMBIOS objects explicitly
Lennart Poettering [Thu, 21 May 2026 15:26:02 +0000 (17:26 +0200)] 
boot: measure select SMBIOS objects explicitly

3 weeks agoupdate TODO 42223/head
Lennart Poettering [Thu, 21 May 2026 06:42:43 +0000 (08:42 +0200)] 
update TODO

3 weeks agoci: add test for new machine-tags concept
Lennart Poettering [Thu, 21 May 2026 07:47:16 +0000 (09:47 +0200)] 
ci: add test for new machine-tags concept

3 weeks agofirstboot: allow configuring machine tags via firstboot
Lennart Poettering [Thu, 21 May 2026 06:39:23 +0000 (08:39 +0200)] 
firstboot: allow configuring machine tags via firstboot

3 weeks agocondition: add a condition that matches against the machine tags
Lennart Poettering [Wed, 20 May 2026 21:23:15 +0000 (23:23 +0200)] 
condition: add a condition that matches against the machine tags

3 weeks agohostnamectl: add support for tagging the machine
Lennart Poettering [Wed, 20 May 2026 16:44:45 +0000 (18:44 +0200)] 
hostnamectl: add support for tagging the machine

3 weeks agohostnamectl: port to new --help API
Lennart Poettering [Wed, 20 May 2026 16:32:59 +0000 (18:32 +0200)] 
hostnamectl: port to new --help API

3 weeks agohostnamed: introduce "machine tags" concept
Lennart Poettering [Wed, 20 May 2026 16:45:12 +0000 (18:45 +0200)] 
hostnamed: introduce "machine tags" concept

For management purposes it's useful to be able to "tag" a machine with
various labels. Let's add a field for that to /etc/machine-info and make
it settable.

Fixes: #38591
3 weeks agohostnamed: port to regular string_is_safe()
Lennart Poettering [Wed, 20 May 2026 15:03:39 +0000 (17:03 +0200)] 
hostnamed: port to regular string_is_safe()

3 weeks agotpm2: add nvpcr allocation priorities (#42227)
Lennart Poettering [Thu, 21 May 2026 16:19:39 +0000 (18:19 +0200)] 
tpm2: add nvpcr allocation priorities (#42227)

nvindex space is very scarce, let's hence introduce "priorities" on
nvpcrs, so that if we haven't got enough space for all we have some
control which ones get dropped and which ones kept.

3 weeks agocore: introduce ConditionFraction= that is true on a certain percantage of the fleet
Lennart Poettering [Thu, 21 May 2026 13:32:24 +0000 (15:32 +0200)] 
core: introduce ConditionFraction= that is true on a certain percantage of the fleet

3 weeks agoTEST-08-INITRD: Set up exitrd on boot rather than including in image
Daan De Meyer [Thu, 21 May 2026 10:25:03 +0000 (10:25 +0000)] 
TEST-08-INITRD: Set up exitrd on boot rather than including in image

Just copy the initramfs from the VM rather than doing it during
the image build.

3 weeks agouser-util: return malloc'ed strings in get_user_creds 42184/head
Zbigniew Jędrzejewski-Szmek [Tue, 19 May 2026 21:22:06 +0000 (23:22 +0200)] 
user-util: return malloc'ed strings in get_user_creds

get_user_creds would use getpwnam() and then returns strings pointing
into the static buffer. This seems very iffy. Let's duplicate the
strings properly

3 weeks agouser-util: stop mangling groupname in get_group_creds
Zbigniew Jędrzejewski-Szmek [Tue, 19 May 2026 15:59:57 +0000 (17:59 +0200)] 
user-util: stop mangling groupname in get_group_creds

The param was input/output, which is unexpected and confusing and
actually made most callers much more complicated than they needed to be.
The function was playing fast and loose with the return value. In some
cases it was returning a static string, which would be completely fine.
But in other case it was returning a pointer into the getgrgid static
buffer, i.e. that return value could be overwritten. AFAICT, this didn't
matter in any of the callers, but we shouldn't do that anyway.

So use a separate output param with an allocated string that the caller
is responsible for.

It turns out that all callers pass NULL (outside of tests) and zero for
flags. So the function _could_ be simplified. But get_user_creds is
called with all the params actually used, and I think having the the
functions so different wouldn't be nice. I first wrote a commit to
drop the unused params, but then I discarded it.

The error message in exec-invoke.c is fixed.

3 weeks agocore/exec-invoke: fix bogus error code
Zbigniew Jędrzejewski-Szmek [Thu, 21 May 2026 16:01:29 +0000 (18:01 +0200)] 
core/exec-invoke: fix bogus error code

r was bogus here. getusername_malloc() can only fail on oom,
so we can simplify this.

3 weeks agoTranslations update from Fedora Weblate (#42231)
Luca Boccassi [Thu, 21 May 2026 15:16:33 +0000 (16:16 +0100)] 
Translations update from Fedora Weblate (#42231)

Translations update from [Fedora
Weblate](https://translate.fedoraproject.org) for
[systemd/main](https://translate.fedoraproject.org/projects/systemd/main/).

Current translation status:

![Weblate translation
status](https://translate.fedoraproject.org/widget/systemd/main/horizontal-auto.svg)

3 weeks agopo: Translated using Weblate (Arabic) 42231/head
joo es [Thu, 21 May 2026 15:01:53 +0000 (15:01 +0000)] 
po: Translated using Weblate (Arabic)

Currently translated at 100.0% (270 of 270 strings)

Co-authored-by: joo es <jonnyse@users.noreply.translate.fedoraproject.org>
Translate-URL: https://translate.fedoraproject.org/projects/systemd/main/ar/
Translation: systemd/main

3 weeks agopo: Translated using Weblate (Korean)
김인수 [Thu, 21 May 2026 15:01:50 +0000 (15:01 +0000)] 
po: Translated using Weblate (Korean)

Currently translated at 100.0% (270 of 270 strings)

Co-authored-by: 김인수 <simmon@nplob.com>
Translate-URL: https://translate.fedoraproject.org/projects/systemd/main/ko/
Translation: systemd/main

3 weeks agoUpdate NEWS
Luca Boccassi [Thu, 21 May 2026 15:05:52 +0000 (16:05 +0100)] 
Update NEWS

3 weeks agotest: cover lingering users surviving a soft-reboot in TEST-82
Rocker Zhang [Thu, 21 May 2026 10:29:24 +0000 (18:29 +0800)] 
test: cover lingering users surviving a soft-reboot in TEST-82

Regression coverage for the soft-reboot linger bug fixed in
9f25feb4ed18 ("logind: keep lingering users at startup-time GC", #41789):
a lingering user's user@.service was started after a hardware reboot but
not after `systemctl soft-reboot`, because logind GC'd the user at
startup before user_start() ran.

On the first boot, enable lingering for the pre-existing testuser and
wait for its user@UID.service to come up. After the first soft-reboot
(which keeps the same persistent rootfs), assert the service is active
again — this is the regression check. Disable lingering again before the
nextroot switch in the second boot so the lingering user doesn't leak
into the later boots' minimal overlay rootfs.

Verified locally in a qemu/KVM VM: passes with the fix present, and with
the fix reverted the second-boot assertion times out (the lingering user
is GC'd in logind startup and user@UID.service never comes back),
confirming the test exercises the bug.

Co-developed-by: Claude Opus 4.7 <noreply@anthropic.com>
3 weeks agoci: add a CI test for nvpcr priorization 42227/head
Lennart Poettering [Thu, 21 May 2026 12:22:29 +0000 (14:22 +0200)] 
ci: add a CI test for nvpcr priorization

3 weeks agodocs: document the .nvpcr file format superficially
Lennart Poettering [Thu, 21 May 2026 12:22:03 +0000 (14:22 +0200)] 
docs: document the .nvpcr file format superficially

3 weeks agotpm2-util: be more graceful with nvindex space exhaustion issues
Lennart Poettering [Thu, 21 May 2026 12:21:28 +0000 (14:21 +0200)] 
tpm2-util: be more graceful with nvindex space exhaustion issues

Let's tone down the language, and say how many we skipped.

3 weeks agonsresourced: Verify user namespace identity on registry lookup
Daan De Meyer [Thu, 21 May 2026 11:34:44 +0000 (11:34 +0000)] 
nsresourced: Verify user namespace identity on registry lookup

When a user namespace dies and its registry entry is torn down, the kernel
can recycle its inode number for a freshly-created namespace. A subsequent
registration or operation request can therefore find a stale registry entry
keyed by the same inode that actually belongs to a different, now-dead user
namespace.

Use NS_GET_ID to compare the kernel-assigned namespace identifier against
the stored one whenever we look up the registry from a live userns fd
(AddMount/AddControlGroup/AddNetworkInterface, plus the two registration
paths). Extract release_userns_by_info()/release_userns_by_inode() into
userns-registry.c so nsresourcework can fully clean up stale entries
(BPF allowlist, fdstore fd, cgroups, netifs, on-disk record) before reusing
the slot, and remove the now-unused userns_registry_inode_exists().

Co-developed-by: Claude Opus 4.7 <noreply@anthropic.com>
3 weeks agosd-dhcp-relay: reimplement DHCP relay agent and drop legacy DHCP relay mode from...
Daan De Meyer [Thu, 21 May 2026 14:23:44 +0000 (16:23 +0200)] 
sd-dhcp-relay: reimplement DHCP relay agent and drop legacy DHCP relay mode from sd-dhcp-server (#42130)

3 weeks agoIntroduce support for running code in fibers (#39771)
Daan De Meyer [Thu, 21 May 2026 14:21:13 +0000 (16:21 +0200)] 
Introduce support for running code in fibers (#39771)

Traditionally, asynchronous programming in systemd has been achieved
using
sd-event along with the asynchronous interfaces of sd-bus and
sd-varlink.
This works well when the system is reacting to events and all code
triggered
by those events can run without blocking. In these scenarios, the global
Manager object is passed as userdata to the callback, and the callback
can
use the stack as usual, declaring local state and ensuring proper
cleanup via
_cleanup_. Control flow structures, such as loops, work as expected, and
everything runs smoothly.

However, challenges arise when the code needs to perform long-running
operations within these callbacks. Since the system cannot block
execution
within the callback, we can't directly invoke a long-running operation
and
wait for its result without introducing complexities. Instead, we need
to
initiate the long-running task, register for completion with sd-event,
sd-bus, or sd-varlink, and provide a callback to be invoked when the
operation completes.

This callback, however, only receives a single userdata pointer, which
forces us to bundle all local variables into a struct and pass it along
as
part of the callback. On top of that, after queuing the asynchronous
operation, the caller continues executing. As the caller's stack unwinds
when the function exits, the resources and state within the local scope
may
be prematurely cleaned up. Therefore, the struct must store copies of
the
local variables or ensure proper reference counting to prevent premature
resource cleanup.

When multiple long-running operations need to be initiated within a
loop,
the complexity grows further. We must introduce additional shared state
to
track the completion of all operations before we can run any code that
depends on their results.

Furthermore, since the daemon may be shut down at any time, we must
track
the lifecycle of each long-running operation in the global Manager
struct,
ensuring proper cleanup even when stack unwinding can no longer manage
the
resources for us.

Fibers, or green threads, provide a more natural way of handling
asynchronous operations. By enabling cooperative multitasking within a
single thread, fibers allow us to write code that looks like it’s
running
synchronously, but with the ability to yield control at predefined
points,
such as when waiting for long-running tasks to complete.

With fibers, we can simplify the control flow by running asynchronous
operations within a fiber, allowing us to "pause" execution while
waiting
for the long-running operation to finish and then "resume" the operation
once
it's complete. This eliminates the need for multiple callback chains,
extensive state tracking, and the potential pitfalls of stack unwinding.

This commit introduces the ability to execute long-running operations in
a
non-blocking manner while maintaining the simplicity and readability of
synchronous code. The fiber-based approach will significantly improve
the
handling of complex workflows, making the code easier to write and
maintain.

The implementation is based on ucontext.h's makecontext() (with a
fallback
to the venerable sigaltstack() approach on musl),
sigsetjmp()/siglongjmp()
and sd-event. ucontext.h provides us with alternate stacks that we can
switch
between. We use sigsetjmp()/siglongjmp() instead of swapcontext()
because the
latter forcibly saves/restores a per context signal mask every time it
is called.
Using sigsetjmp()/siglongjmp(), we can avoid the unnecessary syscall and
maintain
a per thread signal mask, which makes much more sense than having a per
fiber
signal mask.

The default stack size is the same as a regular thread. Because we
use mmap() to allocate the stack, the memory won't actually be used
until it
is paged in by the kernel, so we don't actually use 8MB per fiber.

To integrate fibers with the event loop, each fiber is assigned a
deferred
event source which resumes the fiber when enabled. The deferred event
source
is oneshot by default so the fiber will run immediately until it yields
or
suspends. If it yields, the deferred event source is enabled again
(oneshot)
immediately. If it suspends, before it suspends, one or more event
sources
are registered with sd-event that will enable the deferred event source
(oneshot) to resume the fiber once the operation it is waiting for
completes.

Yielding or suspending the fiber is done by calling sd_fiber_yield() or
sd_fiber_suspend() respectively. Both of these return zero on success or
any
error value from the async operation that caused the fiber to resume.

This is also how fiber cancellation is implemented. When a fiber is
cancelled,
sd_fiber_yield() and sd_fiber_suspend() will return ECANCELED when the
fiber
is resumed, allowing the fiber to unwind its stack (which allows cleanup
to
happen automatically) and finish.

Instead of having applications work directly with fibers, we hide them
behind
a generic futures interface to represent long-running operations,
regardless of
whether those operations are running on a fiber or not. Aside from
fibers, the
futures library (sd-future) will for example allow waiting for sd-event
sources
and doing sd-bus calls in the background as well. Fibers can suspend
until a
future is ready with sd_fiber_await() or by having the future wake up
the fiber
explicitly in its callback. A future always defaults to waking up the
current
fiber.

Each future kind plugs into the library by providing an sd_future_ops
vtable
(alloc, free, cancel, set_priority). The library treats the impl pointer
returned by alloc() as a black box. Future Implementations retrieve it
via
sd_future_get_private().

A future starts in SD_FUTURE_PENDING and transitions exactly once to
SD_FUTURE_RESOLVED, carrying an integer result. Consumers can react to
that
transition either by installing a one-shot callback with
sd_future_set_callback() (callback-style code) or by waiting on it from
a
fiber via sd_fiber_await() (synchronous-looking fiber code).
sd_fiber_await()
is itself built on a "wait future" that resolves when its target
resolves;
sd_future_new_wait() exposes the same primitive directly so non-fiber
callers
can chain futures without involving a fiber.

Cancellation is cooperative: sd_future_cancel() invokes the future
impl's
cancel callback, which is responsible for tearing down its work and
ultimately
resolving the promise with -ECANCELED. For fiber futures this is what
surfaces as the ECANCELED return from
sd_fiber_yield()/sd_fiber_suspend()
mentioned above.

Fire-and-forget fibers — created by passing a NULL ret to sd_fiber_new()

take a self-reference on their future so they outlive the caller's
scope.
The self-ref is dropped when the fiber resolves. This floating mechanism
(sd_fiber_set_floating()) is restricted to fiber futures because they
uniquely guarantee resolution; allowing it for arbitrary future kinds
would
risk silent leaks for kinds that may never resolve.

Note that fiber cleanup depends on the runtime operating normally. Each
fiber's _cleanup_-style cleanups live on the fiber's own stack and run
only when the fiber is resumed and allowed to unwind, which requires a
working event loop to drive it to completion. The exit event source
registered for top-level fibers ensures unwind on a normal
sd_event_exit(),
but if the event loop itself terminates abnormally (e.g. an
unrecoverable
allocation failure mid-dispatch) before all fibers have resolved, their
stacks never unwind and any resources they own leak.

The code lives in libsystemd as sd-future (not exported) for the
following reasons:
- We may want to make this a public libsystemd API in the future
- The code can't live in src/basic as it makes heavy use of sd-event
- The code can't live in src/shared as sd-bus and sd-event make use of
it

The log and log-context headers are updated with functions to allow
fibers to have their own log prefix and log context.

3 weeks agonvpcr: define some reasonable priorities for the nvpcrs we already defined
Lennart Poettering [Thu, 21 May 2026 12:21:02 +0000 (14:21 +0200)] 
nvpcr: define some reasonable priorities for the nvpcrs we already defined

3 weeks agoanalyze: show priority in 'nvpcrs' output
Lennart Poettering [Thu, 21 May 2026 12:20:37 +0000 (14:20 +0200)] 
analyze: show priority in 'nvpcrs' output

3 weeks agotpm2-setup: introduce a 'priority' concept for NvPCRs
Lennart Poettering [Thu, 21 May 2026 12:19:42 +0000 (14:19 +0200)] 
tpm2-setup: introduce a 'priority' concept for NvPCRs

3 weeks agoupdatectl: Apply --no-ask-password argument to polkit agent
Philip Withnall [Thu, 21 May 2026 10:40:19 +0000 (11:40 +0100)] 
updatectl: Apply --no-ask-password argument to polkit agent

Accidentally missed out of commit
8c0f9073c7da808461acfc016cc291e4aba9c1a2.

Signed-off-by: Philip Withnall <pwithnall@gnome.org>
Fixes: 8c0f9073c7da808461acfc016cc291e4aba9c1a2
3 weeks agoinclude/uapi: add linux/openat2.h (#42220)
Zbigniew Jędrzejewski-Szmek [Thu, 21 May 2026 11:29:28 +0000 (13:29 +0200)] 
include/uapi: add linux/openat2.h (#42220)

We include the header through src/include/override/fcntl.h, hence we should
have the latest copy of the header.

(E.g. compilation fails with musl-libc-1.2.5-6.fc44.x86_64 and older kernel
headers.)

3 weeks agocore: add FileDescriptorStorePreserve=on-success option (#42160)
Luca Boccassi [Thu, 21 May 2026 11:08:33 +0000 (12:08 +0100)] 
core: add FileDescriptorStorePreserve=on-success option (#42160)

Currently with FileDescriptorStorePreserve=yes the FD store is kept
around
regardless of what happens to a unit, which is useful in many cases. But
in
some cases, for example when complex services crash horribly, it's hard
to
reason about what was in the intermediate state, and it's better to
start
fresh.

Add a new 'on-success' option for the FileDescriptorStorePreserve=
setting
that keeps it around only for as long as the unit doesn't go to a
persistently
failed state.

This is especially useful in combination with LUO, where we don't want
to
keep around LUO sessions created by units that then proceeded to crash
and
burn, and might be in a bad state afterwards.

3 weeks agotest-btrfs: skip info test when GET_SUBVOL_INFO ioctl is unsupported
Daan De Meyer [Wed, 20 May 2026 20:46:40 +0000 (20:46 +0000)] 
test-btrfs: skip info test when GET_SUBVOL_INFO ioctl is unsupported

On 32-bit userspace running against a 64-bit kernel
BTRFS_IOC_GET_SUBVOL_INFO returns -ENOTTY: struct
btrfs_ioctl_get_subvol_info_args embeds four btrfs_ioctl_timespec
values, and that timespec struct (__u64 sec; __u32 nsec) packs to 12
bytes on i386 but 16 on x86_64 due to differing __u64 alignment.
sizeof(struct) is part of the ioctl cmd number via _IOR(), so the cmd
emitted by 32-bit userspace doesn't match the case label compiled by
the 64-bit kernel and the switch falls through to -ENOTTY.

btrfs already handles this exact class of bug for
BTRFS_IOC_SET_RECEIVED_SUBVOL via a btrfs_ioctl_timespec_32 struct
plus a _32 cmd alias in fs/btrfs/ioctl.c, but GET_SUBVOL_INFO (added
in 2018, four years after that fix) didn't get the same treatment.
Until a kernel patch lands the test can't exercise the ioctl on
32-bit, so convert TEST(info) to TEST_RET(info) and return
EXIT_TEST_SKIP with a clear message when -ENOTTY comes back. The
other tests in the file use ioctls that already have working compat
paths and remain unaffected.

3 weeks agonetwork: several fixlets for NDisc (#42218)
Luca Boccassi [Thu, 21 May 2026 11:05:34 +0000 (12:05 +0100)] 
network: several fixlets for NDisc (#42218)

Unfortunately, previously the path to test-ndisc-send has been wrong, so
some test cases have not been checked in our mkosi CIs. And two test
cases have been broken.

The test case `test_ndisc_redirect` was not updated when the logic in
networkd was changed by 9142bd5a8e9ed94ecbb1e335305e24760b90ad2a. The
change itself should be OK. So, the test case is updated.

The test case `test_ndisc_mtu` was broken when the commit
32417c172383847ec78b672c537594e3efe8f0e0 is merged. The commit is not
correct, as we cannot set IPv6 MTU larger than interface MTU. So, the
offending commit is reverted.

3 weeks agocore: better errors and more fields for io.systemd.Unit.StartTransient (#42161)
Daan De Meyer [Thu, 21 May 2026 11:03:29 +0000 (13:03 +0200)] 
core: better errors and more fields for io.systemd.Unit.StartTransient (#42161)

core: add User,Group,SupplementaryGroups,Nice to varlink
 Unit.StartTransient

This commit adds more writable fields to the
io.systemd.Unit.StartTransient
varlink method. With this its possible to set:
User,Group,SupplementaryGroups,Nice values.

Plus tests for them.

---

core: report unsupported service fields in varlink calls

Just like for the unsupported/bad exec_fields we should show
a message about what field is bad for service parameters. This
commit adds it using the same pattern. The JSON parser works in
fail-fast mode so we only display the first bad field (and
it depends on the parser what it finds first).

3 weeks agomath-util: round to declared FP precision consistently across architectures
Daan De Meyer [Wed, 20 May 2026 12:37:15 +0000 (12:37 +0000)] 
math-util: round to declared FP precision consistently across architectures

Add -fexcess-precision=standard so gcc inserts ISO C99 conformant
rounding at assignments, casts, and returns — without it, double values
on x87 happily stay at 80-bit extended precision across operations and
diverge from the SSE/x86_64 behavior, making strict equality comparisons
architecture-dependent.

The flag doesn't fully cover x87: per gcc PR#323
(https://gcc.gnu.org/bugzilla/show_bug.cgi?id=323), a function return
value carried in ST(0) can arrive at the caller still at 80-bit, so a
double that ought to compare equal to a same-magnitude literal picks up
extra mantissa bits and doesn't. Wrap fp_equal in volatile-double
temporaries to force a memory roundtrip — the only operation that
reliably truncates on x87 — so its callers get consistent results
regardless of how the operands were produced.

Add a TEST(fp_equal) case that exercises the previously-broken pattern:
a runtime 1.0/10.0 computed inside a noinline helper, returned across
the function ABI boundary, then compared against the literal 0.1.
Without the volatile truncation this assertion fails on 32-bit gcc.

3 weeks agosysupdate: Fix a minor typo in the polkit policy 42209/head
Philip Withnall [Wed, 20 May 2026 16:10:06 +0000 (17:10 +0100)] 
sysupdate: Fix a minor typo in the polkit policy

‘cleanup’ is a noun; ‘clean up’ is a verb.

Signed-off-by: Philip Withnall <pwithnall@gnome.org>
3 weeks agosysupdate: Add separate polkit actions for cancellation
Philip Withnall [Wed, 20 May 2026 16:08:03 +0000 (17:08 +0100)] 
sysupdate: Add separate polkit actions for cancellation

This allows us to have a separate, more permissive, policy for
cancelling ongoing sysupdate jobs. The new default policy for
cancellation actions is to allow them for the active user, without admin
authentication, because typically the user can just pull the plug on the
computer to cancel a job anyway.

Signed-off-by: Philip Withnall <pwithnall@gnome.org>
Fixes: https://github.com/systemd/systemd/issues/38568
3 weeks agotest-qmp-client: run mock QMP servers as fibers on the shared event loop 39771/head
Daan De Meyer [Fri, 24 Apr 2026 09:49:10 +0000 (09:49 +0000)] 
test-qmp-client: run mock QMP servers as fibers on the shared event loop

The mock servers used to be driven out-of-band: each test created a
socketpair, forked a child, ran a hand-coded request/response script
against the raw fd, and sent SIGTERM to tear it down. That worked but
required pidref/process-util/signal plumbing in every test, two
distinct execution contexts that couldn't share state, and a JsonStream
attached to the mock side that pretended to be event-loop-driven while
actually being driven manually via blocking reads.

Now that JsonStream suspends when on a fiber, the mocks can live
inside the same process and event loop as the client. Each mock is
rewritten as an sd-fiber that runs alongside the client fiber: so the
mock fiber yields on I/O and the event loop schedules the client in the
meantime. Both sides progress cooperatively, no fork/SIGTERM/PID tracking,
no manual phase tracking.

Two cleanups fall out of the rewrite:

- A QMP_TEST(name, mock_fn) { ... } macro encapsulates the per-test
  scaffolding (event loop, socketpair, mock fiber spawn, exit-on-idle
  shim) and injects an already-connected QmpClient *client into the
  test body. Each test now reads as a flat sequence of
  qmp_client_call() invocations against that client.

- Repeated mock command/reply scripting is factored into
  mock_qmp_expect(), mock_qmp_reply(), mock_qmp_expect_and_reply(),
  mock_qmp_handshake(), and mock_qmp_query_status_running(). The
  greeting JSON is built with sd_json_buildo() instead of being parsed
  from a literal.

The file shrinks from 756 to 494 lines, mostly through deletions.

3 weeks agoqmp-client: add fiber-aware call paths
Daan De Meyer [Fri, 24 Apr 2026 09:49:02 +0000 (09:49 +0000)] 
qmp-client: add fiber-aware call paths

The synchronous qmp_client_call() pumps the event loop until its reply
arrives, pinning the parsed reply on c->current so it can hand out
borrowed pointers to the caller. That model only fits one in-flight
sync call: a second qmp_client_call() on the same client clears
c->current before issuing its own send, invalidating the first
caller's borrowed pointers. On a single-threaded event loop that was
fine, but with fibers two concurrent calls on the same client can
interleave through the pump (json_stream_wait() suspends the running
fiber) and trample each other.

To fix this, make qmp_client_call() detect when it's running on a fiber
whose event loop matches the client and transparently delegate to
qmp_client_call_suspend(), which makes use of a new QmpFuture to allow
multiple concurrent calls to qmp_client_call().

To make this work concurrently, we also change qmp_client_call() to
hand out references and copies of errors so that we don't have to store
the borrowed pointers we hand out in the QmpClient struct.

3 weeks agosd-varlink: make sd-varlink fiber-aware
Daan De Meyer [Tue, 14 Apr 2026 08:54:49 +0000 (08:54 +0000)] 
sd-varlink: make sd-varlink fiber-aware

Add varlink_server_bind_fiber() and varlink_server_bind_fiber_many()
in varlink-util.{c,h} for registering a method handler that should
run on a dedicated fiber per dispatch. The fiber-bound methods live
in a separate s->fiber_methods map alongside the regular s->methods;
bind_internal()/bind_many_internal() are factored out so the regular
and fiber bind variants share their parsing/insertion code.
Registering the same method in both maps is rejected because the
dispatcher consults the regular map first and would otherwise
silently shadow the fiber binding.

varlink_dispatch_fiber() builds a VarlinkFiberData (refs to the
connection, parameters, and method name), spawns a fiber via
sd_fiber_new(), and makes the future floating so the fiber
self-manages its lifetime — neither the dispatcher nor the
connection has to track it. The fiber's priority is set to one
below the connection's quit event source so that on graceful
shutdown the fiber's exit handler fires (and runs its cleanup)
before varlink's quit_callback() closes the connection underneath
it; this is what lets a fiber-bound handler reply or flush its
sentinel on a still-open connection during shutdown.

The connection state transitions are reordered so they happen before
the fiber spawn rather than after the synchronous callback returns:
the fiber runs after dispatch has already moved past PROCESSING, which
matches the behaviour expected for a deferred reply (the fiber may
either reply immediately, or stash the connection and reply later, in
which case the post-callback logic treats it as a PENDING_METHOD).

Note that all the synchronous varlink APIs (sd_varlink_call() and friends)
already behave properly when on a fiber because they call json_stream_wait()
which calls ppoll_usec() which we already fixed to suspend when called from
a fiber.

The client/server varlink tests are migrated to fibers (threads → mock
server fibers on the same event loop) to exercise the new paths.

3 weeks agosd-bus: make sd-bus fiber-aware
Daan De Meyer [Mon, 11 May 2026 14:27:34 +0000 (16:27 +0200)] 
sd-bus: make sd-bus fiber-aware

Two changes to teach sd-bus how to behave when called from a fiber, in
order of increasing depth:

2. sd_bus_call() now redirects to a new bus_call_suspend() helper when
   the caller is a fiber whose event loop is the same one the bus is
   attached to. The plain bus_poll() path serializes all bus traffic on
   the slot's reply (only one method call can be in flight per
   sd_bus*), which would defeat the point of running multiple fibers
   against one bus. bus_call_suspend() builds on the async sd-bus API:
   it wraps the call in a new BusFuture (sd-bus/bus-future.{c,h}) that
   resolves when the reply or method-error arrives, lets the fiber
   await that future, and surfaces the reply to the caller via
   future_get_bus_reply(). Because the futures live on the event loop
   rather than a per-bus slot, multiple fibers can drive concurrent
   method calls against the same bus.

3. A new private SD_BUS_VTABLE_METHOD_FIBER flag dispatches a vtable
   method handler on its own fiber, so handlers are free to use
   sd_bus_call() against the same bus, sd_fiber_sleep(), loop_read(),
   etc. without stalling the event loop for other connections or
   handlers. The flag stays out of sd-bus-vtable.h (its bit value is
   reserved there to prevent collisions) — the fiber runtime is a
   systemd-internal implementation detail.

Lifecycle of fiber-dispatched handlers is tracked on the bus itself: a
new bus->fiber_futures set holds a ref to each in-flight handler.
bus_enter_closing() cancels every entry and process_closing() returns
with the bus still in CLOSING state until the set drains, so we can be
sure no fiber handler outlives the bus. bus_fiber_resolved() removes
the entry on completion. bus_free()'s assert(set_isempty()) makes the
invariant load-bearing.

Note that plain sd_bus_call() already works correctly on a fiber as it
calls ppoll_usec() which has already been modified to suspend when
running on a fiber.

To exercise these changes the existing thread-based client/server
sd-bus tests (test-bus-chat, test-bus-objects, test-bus-peersockaddr,
test-bus-server, test-bus-watch-bind) are migrated to fibers, and a
new test-bus-fiber is added that covers SD_BUS_VTABLE_METHOD_FIBER —
including handlers that issue nested sd_bus_call() on the same bus, the
cancel-on-close path, and concurrent dispatches across multiple fibers.

3 weeks agosd-event: suspend instead of blocking when sd_event_run() runs on a fiber
Daan De Meyer [Mon, 23 Mar 2026 09:15:27 +0000 (10:15 +0100)] 
sd-event: suspend instead of blocking when sd_event_run() runs on a fiber

sd_event_run() blocks the calling thread on the event loop's epoll fd
until something happens. When the caller is a fiber, that's the wrong
behaviour: blocking the thread also stalls every other fiber and the
outer event loop driving them. The most common way to hit this is a
fiber that creates its own inner event loop (e.g. a server-style fiber
that wants to dispatch its own sources independently of whatever loop
the test or supervising fiber is running on) — with the existing
implementation the inner sd_event_run() would hold the thread while the
outer scheduler should be free to advance other fibers.

Add an event_run_suspend() variant in sd-event/event-future.c that
performs the same prepare/wait/dispatch dance, but when the fast path
finds nothing ready it (a) creates an IO future watching the inner
event loop's epoll fd on the *outer* event loop, (b) optionally creates
a time future for the timeout, and (c) suspends the fiber. When either
future fires the fiber is resumed and the prepare/wait/dispatch sequence
runs once more to actually dispatch what's pending. sd_event_run()
checks sd_fiber_is_running() and delegates to this variant when on a
fiber; profile_delays accounting is intentionally skipped on that path
since the underlying prepare/wait/dispatch primitives already account
for themselves.

3 weeks agosd-future: make src/basic blocking helpers fiber-aware
Daan De Meyer [Sat, 25 Apr 2026 20:06:54 +0000 (22:06 +0200)] 
sd-future: make src/basic blocking helpers fiber-aware

Some helpers in src/basic — ppoll_usec_full() (used by fd_wait_for_event()),
loop_read(), loop_read_exact(), loop_write_full() and
pidref_wait_for_terminate_full() — block the calling thread. That's the
right behaviour outside a fiber but not inside one, where blocking the
thread also stalls every other fiber running on the same event loop.
Rewriting every caller to pick a fiber or non-fiber variant explicitly
would be a lot of churn and would split otherwise-shared code paths in
two.

Instead, the helpers detect at runtime whether they're running on a fiber
and dispatch to a suspending variant when they are. FiberOps in
fiber-ops.h holds five function pointers (ppoll, read, write, timeout,
cancel_wait_unref); a fiber_ops global constant is populated whenever we
enter a fiber with functions that delegate to suspending variants of common
syscalls. With this approach, the variants themselves stay in libsystemd
which is required because they make use of sd-event.

- loop_read()/loop_read_exact() take the fiber read hook on a fiber
  unless the caller asked for a non-blocking attempt (do_poll=false) and
  the fd is already non-blocking — in that case we fall through to read()
  to preserve the existing return-EAGAIN-immediately semantic. The hook
  itself suspends on EAGAIN until data is available, so neither the
  do_poll knob nor the explicit fd_wait_for_event() retry loop are
  needed on the fiber path.

- loop_write_full() likewise takes the fiber write hook on a fiber,
  except when timeout=0 with an already-non-blocking fd (preserving the
  fast-return-EAGAIN semantic). The fiber path runs inside a
  FIBER_OPS_TIMEOUT() scope so the caller's timeout is honoured via a
  deadline future, mirroring SD_FIBER_TIMEOUT() but reachable from
  src/basic without pulling in sd-future.h.

- pidref_wait_for_terminate_full() polls the pidfd via fd_wait_for_event()
  before each waitid() when either a finite timeout is set or we're on a
  fiber, and requires pidref->fd >= 0 in those cases (returning
  -ENOMEDIUM otherwise — extending the rule that already applied to
  finite timeouts). The poll suspends the fiber via the ppoll hook above;
  the subsequent waitid() doesn't block because the pidfd is already
  signalled.

3 weeks agosd-future: add fiber-aware non-blocking I/O wrappers
Daan De Meyer [Sat, 25 Apr 2026 20:31:58 +0000 (22:31 +0200)] 
sd-future: add fiber-aware non-blocking I/O wrappers

Add a family of sd_fiber_*() I/O wrappers that, when called from a
fiber, behave like blocking I/O from the caller's perspective but
yield to the event loop instead of blocking the thread:

  sd_fiber_read / sd_fiber_write
  sd_fiber_readv / sd_fiber_writev
  sd_fiber_recv / sd_fiber_send
  sd_fiber_connect
  sd_fiber_recvmsg / sd_fiber_sendmsg
  sd_fiber_recvfrom / sd_fiber_sendto
  sd_fiber_accept
  sd_fiber_ppoll

Most of them share a single helper, fiber_io_operation(), which when
invoked outside a fiber falls through to the underlying syscall
directly, preserving the regular blocking behaviour. Inside a fiber
the helper flips the fd to non-blocking (restoring its original mode
on return), tries the syscall once on the fast path, and on EAGAIN/
EWOULDBLOCK creates an sd-event-backed IO future via future_new_io(),
suspends the fiber, and retries the syscall once the event source
fires.

future_new_io() itself is added to sd-event/event-future.{c,h} as a
new IoFuture kind. It wraps sd_event_add_io() into an sd_future:
oneshot enable, EPOLLERR translated via SO_ERROR (suppressed for
non-sockets), and the fd duplicated with F_DUPFD_CLOEXEC to avoid
EEXIST when multiple sources watch the same descriptor.

Together these let fiber-using code write straight-line socket and
pipe I/O without bundling state into callbacks.

3 weeks agoIntroduce support for running code in fibers
Daan De Meyer [Wed, 12 Nov 2025 16:53:47 +0000 (17:53 +0100)] 
Introduce support for running code in fibers

Traditionally, asynchronous programming in systemd has been achieved using
sd-event along with the asynchronous interfaces of sd-bus and sd-varlink.
This works well when the system is reacting to events and all code triggered
by those events can run without blocking. In these scenarios, the global
Manager object is passed as userdata to the callback, and the callback can
use the stack as usual, declaring local state and ensuring proper cleanup via
_cleanup_. Control flow structures, such as loops, work as expected, and
everything runs smoothly.

However, challenges arise when the code needs to perform long-running
operations within these callbacks. Since the system cannot block execution
within the callback, we can't directly invoke a long-running operation and
wait for its result without introducing complexities. Instead, we need to
initiate the long-running task, register for completion with sd-event,
sd-bus, or sd-varlink, and provide a callback to be invoked when the
operation completes.

This callback, however, only receives a single userdata pointer, which
forces us to bundle all local variables into a struct and pass it along as
part of the callback. On top of that, after queuing the asynchronous
operation, the caller continues executing. As the caller's stack unwinds
when the function exits, the resources and state within the local scope may
be prematurely cleaned up. Therefore, the struct must store copies of the
local variables or ensure proper reference counting to prevent premature
resource cleanup.

When multiple long-running operations need to be initiated within a loop,
the complexity grows further. We must introduce additional shared state to
track the completion of all operations before we can run any code that
depends on their results.

Furthermore, since the daemon may be shut down at any time, we must track
the lifecycle of each long-running operation in the global Manager struct,
ensuring proper cleanup even when stack unwinding can no longer manage the
resources for us.

Fibers, or green threads, provide a more natural way of handling
asynchronous operations. By enabling cooperative multitasking within a
single thread, fibers allow us to write code that looks like it’s running
synchronously, but with the ability to yield control at predefined points,
such as when waiting for long-running tasks to complete.

With fibers, we can simplify the control flow by running asynchronous
operations within a fiber, allowing us to "pause" execution while waiting
for the long-running operation to finish and then "resume" the operation once
it's complete. This eliminates the need for multiple callback chains,
extensive state tracking, and the potential pitfalls of stack unwinding.

This commit introduces the ability to execute long-running operations in a
non-blocking manner while maintaining the simplicity and readability of
synchronous code. The fiber-based approach will significantly improve the
handling of complex workflows, making the code easier to write and maintain.

The implementation is based on ucontext.h's makecontext() (with a fallback
to the venerable sigaltstack() approach on musl), sigsetjmp()/siglongjmp()
and sd-event. ucontext.h provides us with alternate stacks that we can switch
between. We use sigsetjmp()/siglongjmp() instead of swapcontext() because the
latter forcibly saves/restores a per context signal mask every time it is called.
Using sigsetjmp()/siglongjmp(), we can avoid the unnecessary syscall and maintain
a per thread signal mask, which makes much more sense than having a per fiber
signal mask.

The default stack size is the same as a regular thread. Because we
use mmap() to allocate the stack, the memory won't actually be used until it
is paged in by the kernel, so we don't actually use 8MB per fiber.

To integrate fibers with the event loop, each fiber is assigned a deferred
event source which resumes the fiber when enabled. The deferred event source
is oneshot by default so the fiber will run immediately until it yields or
suspends. If it yields, the deferred event source is enabled again (oneshot)
immediately. If it suspends, before it suspends, one or more event sources
are registered with sd-event that will enable the deferred event source
(oneshot) to resume the fiber once the operation it is waiting for completes.

Yielding or suspending the fiber is done by calling sd_fiber_yield() or
sd_fiber_suspend() respectively. Both of these return zero on success or any
error value from the async operation that caused the fiber to resume.

This is also how fiber cancellation is implemented. When a fiber is cancelled,
sd_fiber_yield() and sd_fiber_suspend() will return ECANCELED when the fiber
is resumed, allowing the fiber to unwind its stack (which allows cleanup to
happen automatically) and finish.

Instead of having applications work directly with fibers, we hide them behind
a generic futures interface to represent long-running operations, regardless of
whether those operations are running on a fiber or not. Aside from fibers, the
futures library (sd-future) will for example allow waiting for sd-event sources
and doing sd-bus calls in the background as well. Fibers can suspend until a
future is ready with sd_fiber_await() or by having the future wake up the fiber
explicitly in its callback. A future always defaults to waking up the current
fiber.

Each future kind plugs into the library by providing an sd_future_ops vtable
(alloc, free, cancel, set_priority). The library treats the impl pointer
returned by alloc() as a black box. Future Implementations retrieve it via
sd_future_get_private().

A future starts in SD_FUTURE_PENDING and transitions exactly once to
SD_FUTURE_RESOLVED, carrying an integer result. Consumers can react to that
transition either by installing a one-shot callback with
sd_future_set_callback() (callback-style code) or by waiting on it from a
fiber via sd_fiber_await() (synchronous-looking fiber code). sd_fiber_await()
is itself built on a "wait future" that resolves when its target resolves;
sd_future_new_wait() exposes the same primitive directly so non-fiber callers
can chain futures without involving a fiber.

Cancellation is cooperative: sd_future_cancel() invokes the future impl's
cancel callback, which is responsible for tearing down its work and ultimately
resolving the promise with -ECANCELED. For fiber futures this is what
surfaces as the ECANCELED return from sd_fiber_yield()/sd_fiber_suspend()
mentioned above.

Fire-and-forget fibers — created by passing a NULL ret to sd_fiber_new() —
take a self-reference on their future so they outlive the caller's scope.
The self-ref is dropped when the fiber resolves. This floating mechanism
(sd_fiber_set_floating()) is restricted to fiber futures because they
uniquely guarantee resolution; allowing it for arbitrary future kinds would
risk silent leaks for kinds that may never resolve.

Note that fiber cleanup depends on the runtime operating normally. Each
fiber's _cleanup_-style cleanups live on the fiber's own stack and run
only when the fiber is resumed and allowed to unwind, which requires a
working event loop to drive it to completion. The exit event source
registered for top-level fibers ensures unwind on a normal sd_event_exit(),
but if the event loop itself terminates abnormally (e.g. an unrecoverable
allocation failure mid-dispatch) before all fibers have resolved, their
stacks never unwind and any resources they own leak.

The code lives in libsystemd as sd-future (not exported) for the following reasons:
- We may want to make this a public libsystemd API in the future
- The code can't live in src/basic as it makes heavy use of sd-event
- The code can't live in src/shared as sd-bus and sd-event make use of it

The log and log-context headers are updated with functions to allow
fibers to have their own log prefix and log context.

3 weeks agodocs: extend credentials docs with notes about imds
Lennart Poettering [Thu, 21 May 2026 08:11:53 +0000 (10:11 +0200)] 
docs: extend credentials docs with notes about imds

3 weeks agocore: add FileDescriptorStorePreserve=on-success option 42160/head
Luca Boccassi [Mon, 18 May 2026 14:47:32 +0000 (15:47 +0100)] 
core: add FileDescriptorStorePreserve=on-success option

Currently with FileDescriptorStorePreserve=yes the FD store is kept around
regardless of what happens to a unit, which is useful in many cases. But in
some cases, for example when complex services crash horribly, it's hard to
reason about what was in the intermediate state, and it's better to start
fresh.

Add a new 'on-success' option for the FileDescriptorStorePreserve= setting
that keeps it around only for as long as the unit doesn't go to a persistently
failed state.

This is especially useful in combination with LUO, where we don't want to
keep around LUO sessions created by units that then proceeded to crash and
burn, and might be in a bad state afterwards.

3 weeks agotest: avoid test-fdstore failing units when exiting
Luca Boccassi [Mon, 18 May 2026 14:49:23 +0000 (15:49 +0100)] 
test: avoid test-fdstore failing units when exiting

This is used as payload, so ensure the wrapping unit/container
doesn't register a failure when this exits

Follow-up for 9de91f0f4c715b278637af8b73cabac892d7e000

3 weeks agocleanup: VLAN Id -> VLAN ID
Sebastian Bernardt [Sat, 18 Apr 2026 11:31:04 +0000 (21:31 +1000)] 
cleanup: VLAN Id -> VLAN ID

"VLAN ID" is used throughout the documentation and codebase, but appears
(when present) in `networkctl status` tables as `VLan Id`.

3 weeks agonetwork: restart DHCPv6, NDisc, and RADV when tracked IPv6LL is dropped
Aritra Basu [Tue, 21 Apr 2026 23:09:20 +0000 (19:09 -0400)] 
network: restart DHCPv6, NDisc, and RADV when tracked IPv6LL is dropped

When the tracked IPv6 link-local address is removed, networkd clears
link->ipv6ll_address, but keeps DHCPv6, NDisc, and RADV running. These
engines keep using a stale source identity which affects the following:
- DHCPv6 client continues to send Solicit/Renew/Rebind from a nonexistent
  source address.
- NDisc continues to send Router Solicitations from a nonexistent source
  address. Router Advertisements cannot be received properly.
- RADV continues to advertise with a stale source address. This can lead
  to downstream hosts configuring invalid routes.
- DHCP-PD prefixes remain configured without a valid upstream DHCPv6 path.

Added link_ipv6ll_lost() to stop IPv6 dynamic engines and related states:
- sd_dhcp6_client_stop()
- ndisc_stop() + ndisc_flush()
- sd_radv_stop()

This is called from address_drop() when the dropped address matches the
tracked IPv6LL. After clearing the tracked address, it scans for another
ready link-local address on the interface. If found, this is set as
link->ipv6ll_address and link_ipv6ll_gained() is called to restart the
engines with the new source identity.

This resolves the FIXME in address_drop().

Signed-off-by: Aritra Basu <aritrbas+gh@cisco.com>
3 weeks agoNEWS: mention new DHCP relay agent 42130/head
Yu Watanabe [Tue, 12 May 2026 06:15:08 +0000 (15:15 +0900)] 
NEWS: mention new DHCP relay agent

3 weeks agosd-dhcp-server: drop legacy DHCP relay mode
Yu Watanabe [Sun, 3 May 2026 23:43:41 +0000 (08:43 +0900)] 
sd-dhcp-server: drop legacy DHCP relay mode

3 weeks agonetwork: drop use of legacy DHCP relay agent in sd-dhcp-server
Yu Watanabe [Sun, 3 May 2026 23:29:51 +0000 (08:29 +0900)] 
network: drop use of legacy DHCP relay agent in sd-dhcp-server

Then, this deprecates
- BindToInterface=
- RelayTarget=
- RelayAgentCircuitId=
- RelayAgentRemoteId=
settings in [DHCPServer] section.
These are gracefully translated as new settings.

3 weeks agoman: document DHCP relay configuration
Yu Watanabe [Sun, 10 May 2026 23:56:40 +0000 (08:56 +0900)] 
man: document DHCP relay configuration