]> git.ipfire.org Git - thirdparty/systemd.git/log
thirdparty/systemd.git
2 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.

2 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()

2 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()

2 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.

2 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.

2 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

2 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.

2 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.

2 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.

2 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.

2 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.

2 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.

2 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

2 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>
2 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

2 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

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

2 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

2 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

2 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

2 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

2 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

2 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
2 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()

2 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.

2 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

2 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.

2 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

2 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.

2 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.

2 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)

2 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

2 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

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

2 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>
2 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

2 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

2 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.

2 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>
2 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)

2 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.

2 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

2 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

2 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

2 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
2 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.)

2 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.

2 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.

2 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.

2 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).

2 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.

2 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>
2 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
2 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.

2 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.

2 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.

2 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.

2 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.

2 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.

2 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.

2 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.

2 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

2 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.

2 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

2 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`.

2 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>
2 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

2 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

2 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.

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

2 weeks agotest-network: add test case for DHCP relay
Yu Watanabe [Sun, 10 May 2026 22:48:27 +0000 (07:48 +0900)] 
test-network: add test case for DHCP relay

2 weeks agonetwork: re-implement DHCP relay support with new sd-dhcp-relay
Yu Watanabe [Sun, 3 May 2026 00:56:45 +0000 (09:56 +0900)] 
network: re-implement DHCP relay support with new sd-dhcp-relay

2 weeks agofuzz: introduce fuzzer for DHCP relay agent
Yu Watanabe [Sat, 2 May 2026 14:32:33 +0000 (23:32 +0900)] 
fuzz: introduce fuzzer for DHCP relay agent

2 weeks agotest: add unit test for DHCP relay agent
Yu Watanabe [Sat, 2 May 2026 14:18:32 +0000 (23:18 +0900)] 
test: add unit test for DHCP relay agent

2 weeks agosd-dhcp-relay: introduce new DHCP relay agent
Yu Watanabe [Tue, 28 Apr 2026 04:27:43 +0000 (13:27 +0900)] 
sd-dhcp-relay: introduce new DHCP relay agent

Previously, sd-dhcp-server can be run as a DHCP relay agent.
But, DHCP server and DHCP relay agent behave completely differently,
hence there is almost no code that can be shared between the two modes.
Let's split out the DHCP relay agent feature from sd-dhcp-server.

The new DHCP relay agent supports:
- multiple upstream and downstream interfaces,
- gateway address (giaddr field in DHCP message header) is configurable,
- supports more DHCP relay agent information sub-options,
- each interface has their own socket fd, and each socket is bound to
  the interface, so that we can enable/disable each interface
  safely without affecting other interfaces, and we can filter out any
  unexpected packets from unmanaged interfaces,

networkd integration and test cases will be added later.

2 weeks agologind: keep lingering users at startup-time GC
Rocker Zhang [Sat, 16 May 2026 05:07:56 +0000 (13:07 +0800)] 
logind: keep lingering users at startup-time GC

manager_startup() runs manager_gc(m, /* drop_not_started= */ false)
before the user_start() loop. user_may_gc()'s linger guard requires
user_unit_active() to be true to keep a user, but at this point the
per-user units have not been started yet, so for any lingering user
that ended up in the user_gc_queue the guard falls through and
manager_gc frees the User struct before user_start() ever runs.

This only manifests after `systemctl soft-reboot`, because /run is
tmpfs and survives soft-reboot: /run/systemd/users/UID files persist,
and manager_enumerate_users() in src/login/logind.c explicitly calls
user_add_to_gc_queue() for every UID it loads from there. Cold boot is
unaffected because /run is empty, so the linger users that come in via
manager_enumerate_linger_users() never enter the GC queue at all and
reach user_start() directly.

Special-case the startup-time GC: if a linger file exists, keep the
user regardless of unit state — user_start() is about to run and will
queue the appropriate jobs. Steady-state GC (drop_not_started=true, in
the event loop) still requires user_unit_active() so we don't hold on
to records for lingering users whose units genuinely died.

Fixes: https://github.com/systemd/systemd/issues/41789
Co-developed-by: Claude Opus 4.7 <noreply@anthropic.com>
2 weeks agovmspawn: add shell completion for --coco
Paul Meyer [Thu, 21 May 2026 06:07:51 +0000 (08:07 +0200)] 
vmspawn: add shell completion for --coco

Fixes 4f8215add24ac9018fb68399f0b957cf0eb3b0c6.

Signed-off-by: Paul Meyer <katexochen0@gmail.com>
2 weeks agotree-wide: standardize header names across src/fundamental, src/basic and src/shared
Daan De Meyer [Mon, 18 May 2026 20:29:04 +0000 (20:29 +0000)] 
tree-wide: standardize header names across src/fundamental, src/basic and src/shared

Drop the -fundamental suffix from src/fundamental/ headers in favor of names
that match their src/basic/ or src/shared/ counterparts (e.g.
macro-fundamental.h -> macro.h, assert-fundamental.h -> assert-util.h,
cleanup-fundamental.h -> cleanup-util.h). Rename src/basic/{btrfs,label}.{c,h}
to use the -util suffix to match the existing shared/btrfs-util and
shared/label-util siblings. Rename src/shared/mkdir-label.{c,h} to mkdir.{c,h}
and src/shared/tmpfile-util-label.{c,h} to tmpfile-util.{c,h} to match the
corresponding src/basic names.

This saves us from having to come up with separate names for files that do
the same thing across tiers, and it makes it easier to move stuff between
src/fundamental, src/basic and src/shared: consumers just #include "foo.h"
and pick up whichever tier their -I path resolves to first, so call sites
don't need to be updated when an API moves between layers.

Where a higher-tier wrapper exists (e.g. src/basic/macro.h wrapping
src/fundamental/macro.h), the wrapper uses an explicit "../fundamental/foo.h"
or "../basic/foo.h" relative include for the lower-tier header. We can't use
GCC's #include_next directive for this — when the wrapper is reachable both
via same-dir-as-source lookup and via -I (e.g. -Isrc/shared) for the
directory it lives in, #include_next advances by exactly one slot in libcpp's
internal directory chain and lands on the same physical directory it was
already in, never reaching the lower-tier sibling (see make_cpp_dir() in
gcc/libcpp/files.cc:1986).

To make sure the right headers are always picked up, the include directories
are reordered so that e.g. src/shared always takes priority over src/basic and
similar for the other directories.

Co-developed-by: Claude Opus 4.7 <noreply@anthropic.com>
2 weeks agotest-network: follow-up for modem manager test and add test case for networkctl dhcp...
Yu Watanabe [Thu, 21 May 2026 00:10:30 +0000 (09:10 +0900)] 
test-network: follow-up for modem manager test and add test case for networkctl dhcp-lease (#42203)

2 weeks agofirstboot: make clear where the full screen console wizards end
Lennart Poettering [Wed, 20 May 2026 21:17:11 +0000 (23:17 +0200)] 
firstboot: make clear where the full screen console wizards end

The three first boot screens are visually separated from the console
output before them via the "chome" and welcome strings and sufficient
whitespace. But so far they weren't from the output after them. This is
sometimes a big confusing. Let's add a bit of a separator between the
end and what comes next, too.

Just cosmetics, nothing else.

2 weeks agovmspawn: rearrange --help and man page a bit (#42200)
Yu Watanabe [Thu, 21 May 2026 00:07:34 +0000 (09:07 +0900)] 
vmspawn: rearrange --help and man page a bit (#42200)

This does not change man page or --help contents at all, but it does
introduce new sections, and moves some knobs between sections. It also
reorders things in the man page so that man page and --help show items
in the same order again.

2 weeks agoreport: use new --help formatting calls
Lennart Poettering [Wed, 20 May 2026 13:45:30 +0000 (15:45 +0200)] 
report: use new --help formatting calls

2 weeks agotest-network: fix path to test-ndisc-send 42218/head
Yu Watanabe [Wed, 20 May 2026 14:44:49 +0000 (23:44 +0900)] 
test-network: fix path to test-ndisc-send

Follow-up for 9dcdf16b25545d942b872cc0abdbb7c9a6b5f9f1.

Previously, test cases that use test-ndisc-send executable did not
tested in our mkosi CIs...

2 weeks agoRevert "network: fix max MTU check for IPv6 MTU adjustments"
Yu Watanabe [Wed, 20 May 2026 22:47:37 +0000 (07:47 +0900)] 
Revert "network: fix max MTU check for IPv6 MTU adjustments"

This reverts commit 32417c172383847ec78b672c537594e3efe8f0e0.

IPv6 MTU cannot be larger than the current interface MTU.
The previous behavior is correct.

2 weeks agotest-network: fix test case for Neighbor Announcement message handling
Yu Watanabe [Wed, 20 May 2026 22:34:43 +0000 (07:34 +0900)] 
test-network: fix test case for Neighbor Announcement message handling

After 9142bd5a8e9ed94ecbb1e335305e24760b90ad2a, when NA without router
flag is received, the corresponding redirect route and the default route
is removed, but the other routes are kept.

The corresponding test case was not updated by the commit, and the test
case has been unfortunately skipped...

This fixes the test case, and added more checks.

2 weeks agotest-network: add test cases for 'networkctl dhcp-lease' command 42203/head
Yu Watanabe [Wed, 20 May 2026 15:28:38 +0000 (00:28 +0900)] 
test-network: add test cases for 'networkctl dhcp-lease' command

Addresses the request:
https://github.com/systemd/systemd/pull/42137#pullrequestreview-4305664376

2 weeks agotest-network: try to stop test-modem-manager-mock.service only when necessary
Yu Watanabe [Wed, 20 May 2026 14:40:51 +0000 (23:40 +0900)] 
test-network: try to stop test-modem-manager-mock.service only when necessary

Otherwise, all test cases that does not create/start the service emits
the following error:
```
Failed to stop test-modem-manager-mock.service: Unit test-modem-manager-mock.service not loaded.
```

Moreover, without this change, extra 'systemctl daemon-reload' is triggered after
all test cases. That's super heavy, especially when the test is running on
sanitizers.

Follow-up for abe3d570f8006fca5138b2d5cfb4e8b530be02e5.

2 weeks agoinclude: update kernel headers from v7.1-rc4
Yu Watanabe [Wed, 20 May 2026 19:57:21 +0000 (04:57 +0900)] 
include: update kernel headers from v7.1-rc4

It seems there is no notable changes to us.

2 weeks agotest-network: use networkctl_status() helper function at one more place
Yu Watanabe [Wed, 20 May 2026 19:33:01 +0000 (04:33 +0900)] 
test-network: use networkctl_status() helper function at one more place

2 weeks agoBump minimum required version of musl to 1.2.6 (#42208)
Yu Watanabe [Wed, 20 May 2026 22:04:12 +0000 (07:04 +0900)] 
Bump minimum required version of musl to 1.2.6 (#42208)

musl v1.2.6 has been released on 2026-03-20, and alpine-edge already has it:
https://pkgs.alpinelinux.org/package/edge/main/x86_64/musl

2 weeks agomkosi: update debian commit reference to 3e1930512d1efee7e11b619a5f493b3229594a51
Luca Boccassi [Wed, 20 May 2026 20:18:35 +0000 (21:18 +0100)] 
mkosi: update debian commit reference to 3e1930512d1efee7e11b619a5f493b3229594a51

3e1930512d Downgrade dependency on dbus to recommends in sd-container
61d6ecf0a0 Conflict with sysuser-helper
fbc4646437 autopkgtest: add dependency on procps

2 weeks agoman: order --secure-boot= to the same location in man page as in --help for vmspawn 42200/head
Lennart Poettering [Wed, 20 May 2026 14:23:36 +0000 (16:23 +0200)] 
man: order --secure-boot= to the same location in man page as in --help for vmspawn

2 weeks agovmspawn: move --kernel=/--initrd= under the "Execution" section
Lennart Poettering [Wed, 20 May 2026 13:52:57 +0000 (15:52 +0200)] 
vmspawn: move --kernel=/--initrd= under the "Execution" section

This has little to do with host configuration (where it was so far), and
a lot with what being executed, let's move it over.

Note that --help and man page so far differed here quite a bit: the
former had the "Execution" section, the latter didn't. This creates it
in the man page, to bring the two back in sync.

2 weeks agovmspawn: split out networking related options into its own "Networking" section in...
Lennart Poettering [Wed, 20 May 2026 13:50:32 +0000 (15:50 +0200)] 
vmspawn: split out networking related options into its own "Networking" section in --help

2 weeks agovmspawn: split 'Integration' section into 'Logging' and 'SSH'
Lennart Poettering [Wed, 20 May 2026 13:48:44 +0000 (15:48 +0200)] 
vmspawn: split 'Integration' section into 'Logging' and 'SSH'

Each of the two has multiple options, hence let's split them out.

2 weeks agovmspawn: move image related knobs close to --image=
Lennart Poettering [Wed, 20 May 2026 13:45:57 +0000 (15:45 +0200)] 
vmspawn: move image related knobs close to --image=

(Also, arrange the order if the image options group in the man page to
the same as in the --help text)

2 weeks agoNEWS: mention bump of musl requirement 42208/head
Yu Watanabe [Wed, 20 May 2026 19:07:36 +0000 (04:07 +0900)] 
NEWS: mention bump of musl requirement

2 weeks agomusl: drop several statx definitions
Yu Watanabe [Wed, 20 May 2026 16:14:59 +0000 (01:14 +0900)] 
musl: drop several statx definitions

Those dropped definitions have been provided since musl v1.2.6.

2 weeks agomusl: drop renameat2() wrapper
Yu Watanabe [Wed, 20 May 2026 16:08:24 +0000 (01:08 +0900)] 
musl: drop renameat2() wrapper

musl provides renameat2() since v1.2.6:
https://git.musl-libc.org/cgit/musl/commit/?id=05ce67fea99ca09cd4b6625cff7aec9cc222dd5a

2 weeks agoREADME: bump required minimum version of musl to 1.2.6
Yu Watanabe [Wed, 20 May 2026 16:30:43 +0000 (01:30 +0900)] 
README: bump required minimum version of musl to 1.2.6

musl v1.2.6 has been released on 2026-03-20:
https://git.musl-libc.org/cgit/musl/commit/?id=9fa28ece75d8a2191de7c5bb53bed224c5947417

alpine/postmarketos already have musl v1.2.6 in the edge repository:
https://pkgs.alpinelinux.org/package/edge/main/x86_64/musl

Also, Yocto Project 6.0 (wrynose) already has v1.2.6.

Let's bump the requirement now.