Change the review fan-out from one subagent per commit to one subagent per
lens, each reviewing every commit through a single perspective. Four base
lenses (correctness/memory safety, lifetimes/concurrency, security, API/style)
always run; the orchestrator skims the diff and adds 1-3 PR-specific lenses
(e.g. a DNS protocol lens for resolved changes). A single generalist reviewer
tended to converge on one finding on large diffs; focused lenses dig deeper.
Commits are reviewed in chronological order via a commit-order.txt manifest,
since the SHA-named worktree dirs don't sort chronologically.
Co-developed-by: Claude Opus 4.8 <noreply@anthropic.com>
This is already a primary architecture in Ubuntu, and more distributions
are adding support for it. It's too slow for emulation, but we can at
least verify that compilation works.
Use the arm worker, for two reasons:
- it is already set up with ports.ubuntu.com so we don't have to muck
with apt sources manually
- it is used a lot less than the x86 worker
2026-05-29T18:00:43.7496388Z ../src/core/dynamic-user.c: In function ‘dynamic_user_realize’:
2026-05-29T18:00:43.7497098Z ../src/core/dynamic-user.c:436:29: error: ‘new_uid’ may be used uninitialized [-Werror=maybe-uninitialized]
2026-05-29T18:00:43.7497758Z 436 | num = new_uid;
2026-05-29T18:00:43.7498026Z | ~~~~^~~~~~~~~
2026-05-29T18:00:43.7498465Z ../src/core/dynamic-user.c:361:23: note: ‘new_uid’ was declared here
2026-05-29T18:00:43.7498802Z 361 | uid_t new_uid;
2026-05-29T18:00:43.7499039Z | ^~~~~~~
2026-05-29T18:00:43.7499315Z In file included from ../src/core/dynamic-user.c:23:
2026-05-29T18:00:43.7499651Z In function ‘dynamic_user_push’,
2026-05-29T18:00:43.7500063Z inlined from ‘dynamic_user_realize’ at ../src/core/dynamic-user.c:453:13:
2026-05-29T18:00:43.7501021Z ../src/basic/socket-util.h:131:63: error: ‘new_uid_lock_fd’ may be used uninitialized [-Werror=maybe-uninitialized]
2026-05-29T18:00:43.7501897Z 131 | #define send_one_fd_iov(transport_fd, fd, iov, iovlen, flags) send_one_fd_iov_sa(transport_fd, fd, iov, iovlen, NULL, 0, flags)
2026-05-29T18:00:43.7502530Z | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2026-05-29T18:00:43.7503145Z ../src/core/dynamic-user.c:320:16: note: in expansion of macro ‘send_one_fd_iov’
2026-05-29T18:00:43.7503647Z 320 | return send_one_fd_iov(d->storage_socket[1], lock_fd, &iov, 1, MSG_DONTWAIT);
2026-05-29T18:00:43.7504027Z | ^~~~~~~~~~~~~~~
2026-05-29T18:00:43.7504397Z ../src/core/dynamic-user.c: In function ‘dynamic_user_realize’:
2026-05-29T18:00:43.7504888Z ../src/core/dynamic-user.c:360:21: note: ‘new_uid_lock_fd’ was declared here
2026-05-29T18:00:43.7505256Z 360 | int new_uid_lock_fd;
2026-05-29T18:00:43.7505511Z | ^~~~~~~~~~~~~~~
2026-05-29T18:00:43.7505882Z ../src/core/dynamic-user.c: In function ‘dynamic_user_current’:
2026-05-29T18:00:43.7506461Z ../src/core/dynamic-user.c:468:15: error: ‘uid’ may be used uninitialized [-Werror=maybe-uninitialized]
2026-05-29T18:00:43.7506895Z 468 | uid_t uid;
2026-05-29T18:00:43.7507096Z | ^~~
2026-05-29T18:26:14.2420944Z In function ‘dynamic_user_push’,
2026-05-29T18:26:14.2421730Z inlined from ‘dynamic_user_realize’ at ../src/core/dynamic-user.c:453:13:
2026-05-29T18:26:14.2435240Z ../src/basic/socket-util.h:131:63: error: ‘new_uid_lock_fd’ may be used uninitialized [-Werror=maybe-uninitialized]
2026-05-29T18:26:14.2440497Z 131 | #define send_one_fd_iov(transport_fd, fd, iov, iovlen, flags) send_one_fd_iov_sa(transport_fd, fd, iov, iovlen, NULL, 0, flags)
2026-05-29T18:26:14.2442511Z | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2026-05-29T18:26:14.2445002Z ../src/core/dynamic-user.c:320:16: note: in expansion of macro ‘send_one_fd_iov’
2026-05-29T18:26:14.2445727Z 320 | return send_one_fd_iov(d->storage_socket[1], lock_fd, &iov, 1, MSG_DONTWAIT);
2026-05-29T18:26:14.2448345Z | ^~~~~~~~~~~~~~~
2026-05-29T18:26:14.2448952Z ../src/core/dynamic-user.c: In function ‘dynamic_user_realize’:
2026-05-29T18:26:14.2451781Z ../src/core/dynamic-user.c:360:21: note: ‘new_uid_lock_fd’ was declared here
2026-05-29T18:26:14.2452287Z 360 | int new_uid_lock_fd;
2026-05-29T18:26:14.2454430Z | ^~~~~~~~~~~~~~~
2026-05-29T18:26:14.2454960Z ../src/core/dynamic-user.c: In function ‘dynamic_user_current’:
2026-05-29T18:26:14.2457632Z ../src/core/dynamic-user.c:468:15: error: ‘uid’ may be used uninitialized [-Werror=maybe-uninitialized]
2026-05-29T18:26:14.2458207Z 468 | uid_t uid;
2026-05-29T18:26:14.2460327Z | ^~~
Bump the Bedrock model ID to us.anthropic.claude-opus-4-8 (the -v1 suffix
was dropped after 4.6), pin ANTHROPIC_DEFAULT_OPUS_MODEL so the review
subagents resolve to 4.8 as well, and switch the effort level from max to
xhigh.
Co-developed-by: Claude Opus 4.8 <noreply@anthropic.com>
arm64 hosts support running armv7 (armhf) binaries, so we can
cross compile and run the unit tests without performance issues.
armv7 (armhf) is a primary architecture on Ubuntu, so build
regressions block new version updates, and adding coverage
helps to avoid introducing regressions.
resolved watches networkd state changes and RTNL updates separately. RTNL is
currently processed at SD_EVENT_PRIORITY_IMPORTANT, while networkd state
changes are processed later at SD_EVENT_PRIORITY_IMPORTANT+5.
If both are pending, an RTM_NEWADDR update can make a link relevant for
LLMNR/mDNS scope allocation before resolved has consumed the corresponding
networkd state update. This can let scope recalculation use stale per-link
settings until the networkd event is processed.
Run the networkd monitor source before RTNL by using
SD_EVENT_PRIORITY_IMPORTANT-5. This lets resolved consume current link settings
before reacting to RTNL address updates in the same event loop iteration.
Fixes#42079
Co-developed-by: OpenAI Codex <noreply@openai.com>
When using --console=gui the QEMU window closes immediately when the VM
has stopped, so any console output at shutdown is lost, which makes
debugging difficult. Ensure the VM stays booted for a minimum of 15s.
Switch the executable-owned call sites from the plain dlopen_<lib>()
helpers to the new DLOPEN_<LIB>() macros, so that each binary that loads
an optional library at runtime now carries its own .note.dlopen note
instead of relying solely on libsystemd-shared. Each call site passes a
priority reflecting whether it hard-depends on the library (required) or
degrades gracefully without it (recommended).
Co-developed-by: Claude Opus 4.8 <noreply@anthropic.com>
Since this was introduced I constantly find myself waiting for VMs to
shut down at the end of a test. This not only happens with mkosi integration
tests, but with other VM-based tests like for example autopkgtest. In this
example, this dracut test suite runtime is tripled due to the artificial delay:
[ 5.813234] systemd-shutdown[1]: Syncing filesystems and block devices.
[ 5.814635] systemd-shutdown[1]: Delaying shutdown for 9s, in order to reach minimum uptime of 15s.
[ 8.816855] systemd-shutdown[1]: Delaying shutdown for 6s, in order to reach minimum uptime of 15s.
[ 11.819747] systemd-shutdown[1]: Delaying shutdown for 3s, in order to reach minimum uptime of 15s.
[ 14.822660] systemd-shutdown[1]: Delaying shutdown for 601ms, in order to reach minimum uptime of 15s.
[ 15.427777] systemd-shutdown[1]: Powering off.
[ 15.429681] sd 0:0:0:0: [sda] Synchronizing SCSI cache
[ 15.433620] ACPI: PM: Preparing to enter system sleep state S5
[ 15.435148] reboot: Power down
TEST: root filesystem on a ext4 filesystem with systemd and extensions [OK]
autopkgtest [19:39:12]: test 46-systemd-sysext: -----------------------]
autopkgtest [19:39:13]: test 46-systemd-sysext: - - - - - - - - - - results - - - - - - - - - -
46-systemd-sysext PASS
Contrary to what the comment claimed, the scrollback of a VM is _not_
cleared, EDK2 just prints many pages, and one can just scroll up (a lot).
Do not delay by default on VMs. Move the check so that in both containers
and VMs users can override and force a delay with the env var.
Follow-up for 0874eea302
This macro emits an SD_ELF_NOTE_DLOPEN note so that calling sites,
and not just libsystemd-shared, get the ELF stamped with the notes
documenting the dependency. Currently most of the dlopen notes end
up in libsystemd-shared, and executables have no way to document
the optional dependencies they need. With this new macro, this
issue can be fixed.
Co-developed-by: Claude Opus 4.8 <noreply@anthropic.com>
If the SD_ELF_NOTE_DLOPEN macro gets used twice in the same binary,
with identical content, it will add two identical notes, which is
wasteful and confusing.
Emit each note into a COMDAT group keyed on its JSON payload, with an
assembler .ifndef guard, so byte-identical notes fold to a single copy
within a translation unit (assembler) and across translation units
(linker). The section is marked SHF_GNU_RETAIN so --gc-sections keeps it,
and uses the portable "%note" section type so it also assembles on
architectures where "@" is the comment character (e.g. 32-bit ARM).
This ensures SD_ELF_NOTE_DLOPEN can be used as many times as needed,
and the result will be automatically deduplicated.
The SHF_GNU_RETAIN (R) flag requires binutils >= 2.36, which cuts
off CentOS 9. To avoid breaking builds, override the flags passed
to the linker to skip that flag. This unfortunately means in many
cases the ELF notes section will be dropped by the linker due to
--gc-sections. For CentOS 9 builds, the choice is thus between
not using --gc-sections and losing dlopen ELF notes, and the latter
is made here given it's less impactful.
Co-developed-by: Claude Opus 4.8 <noreply@anthropic.com>
Unexpected cleanup of live X11 socket files was reported in #35182,
suggesting an underlying issue with the `!` boot safety switch for
tmpfiles.
Regardless of that bug, time-based cleanup of X11 sockets is likely to
be unwanted behaviour as systems often stay up for extended periods of
time, and cleanup of these directories based on age alone is liable to
cause issues at runtime for user sessions.
This adds the following device to AV production hwdb:
- ID 17cc:2420 Native Instruments Traktor MX2
Support for this new HID-based DJ controller was also recently
merged to Mixxx.
In https://bugzilla.redhat.com/show_bug.cgi?id=2479961 a user
reported that they are confused that 'init 6' and such commands
do not work anymore. We removed support for the whole interface,
but it's likely that such commands persist in various scripts
and finger memories. Let's give a helpful hint that this inteface
is gone and what to use instead.
We shouldn't say that that they boot into "a … legacy target", because
they boot into the standard targets. Those names are just aliases now.
(And also the user is not required to know what SysV even is, so it
shouldn't be used in the main explanation.)
The claude bot keeps getting this wrong again and again:
Claude: nit: systemd coding style requires braces on both branches of
an if/else when one branch uses them. Here the if branch
is a single statement without braces but the else branch
uses braces
Specifically mention this is not the case in the coding style doc
to hopefully make it stop hallucinating this rule
TEST-60-MOUNT-RATELIMIT sometimes fails as it cannot see the 'left rate limit'
message in the journal. Tests relying on specific log messages are often flaky,
as the journal is lossy.
Change the test case to check for the desired outcome instead, as that also
catches regressions, without being over reliant on the journal.
Fixes https://github.com/systemd/systemd/issues/32712
testcase_varlink_subscribe_devices in TEST-58-REPART spawns a varlinkctl
subscriber as a transient Type=notify service so systemd-run only returns
once varlinkctl has received the first reply (the "ready" sentinel or the
first "add"), guaranteeing the server-side sd-device monitor is up before
the test triggers any uevents. Loopback devices are created and detached
via systemd-dissect --attach / --detach against small ext4 images.
Covers:
1. "ready" sentinel arrives even on an empty initial set
2. losetup-style attach => "add" event with the expected node
3. detach => "remove" event with the expected node
4. 5 add/remove cycles in a row stay in sync
5. two coexisting loop devices each produce their own add/remove
6. a device that exists before the subscription starts shows up in
the initial enumeration, and "ready" arrives only after it
7. without subscribe:true the reply omits the "action" field
(back-compat for older clients)
The case is skipped inside containers since nspawn --private-network
filters the kernel uevent socket away from the subscribed server.
Extend the Varlink call so it can optionally stay open after the initial
enumeration and stream additions and removals over the same connection.
Useful for UIs that want a live list of candidate disks without polling.
New input "subscribe" (default false) and new output "action" (an enum
"add" / "remove" / "ready"). When subscribing:
- The server starts an sd-device monitor on the "block" subsystem
*before* the initial enumeration so events occurring during that
window aren't dropped. Duplicate "add" events for the same device
are legitimate and documented; clients upsert by identifier.
- The initial candidate set is streamed as "add" notifications.
- Exactly one "ready" notification follows, marking the boundary
between the initial picture and live deltas.
- Live SD_DEVICE_REMOVE events become "remove" notifications carrying
only "node".
- All other live actions re-run blockdev_list_one(); MATCH_YES maps
to "add" (which doubles as "device metadata changed"), MATCH_FILTERED
maps to "remove" so transitions driven by the dynamic
ignoreEmpty / ignoreReadOnly filters (size becoming 0, read-only flag
flipping on) are propagated as the device leaving the candidate set.
Clients may therefore receive a "remove" for a device they never saw
an "add" for; that is documented as legal.
Existing non-subscribing callers see no schema change: the new "action"
field is omitted from their replies via SD_JSON_BUILD_PAIR_CONDITION,
and the original NoCandidateDevices sentinel still fires when the
enumeration is empty.
The per-link subscription state is freed via an on-disconnect callback
bound lazily on first subscribe.
Subscribers to block-device uevents need to apply the same filter set
blockdev_list() uses over the bulk enumeration, one device at a time.
Pull the per-device body out as blockdev_list_one(), expose
blockdev_list_get_root_devnos() so callers can compute the IGNORE_ROOT
devnos once up-front, and introduce a 4-valued return code so callers
can distinguish:
MATCH_NO - fails a static filter (subsystem, ZRAM, IGNORE_ROOT,
REQUIRE_PARTITION_SCANNING, REQUIRE_LUKS)
MATCH_YES - fully matches
MATCH_FILTERED - passes static filters but fails a dynamic one
(IGNORE_EMPTY, IGNORE_READ_ONLY) - useful to surface
as "device just became invisible" transitions when
the kernel flips size/ro at runtime
MATCH_SKIPPED - soft error during filter evaluation; callers should
treat this like MATCH_FILTERED, but the distinct code
makes the soft failure visible rather than silently
swallowed inside blockdev_list_one()
*ret is initialized on every non-negative return (BLOCK_DEVICE_NULL for
MATCH_NO / MATCH_SKIPPED, fully populated for MATCH_YES / MATCH_FILTERED),
and untouched on negative return. blockdev_list() itself collapses
everything except MATCH_YES back into "skip", so existing callers see
no behavior change.
repart.c is already 11 kLOC. The candidate-device enumeration path is
about to grow a subscription mode that brings its own helpers and
per-link state, which doesn't belong in the partitioning core.
Move vl_method_list_candidate_devices() (and only that function -- the
header exports just that symbol) into a new src/repart/repart-list-candidate-devices.{c,h}.
No behavior change.
Inspired by #42307, but does not fix it. We just recognize more types of
errors that can be triggered by RO media, and downgrade to debug log
level.
Inspired-by: #42307
Add two testcases to TEST-71-HOSTNAME:
- testcase_tags exercises the new "hostnamectl tags" +/- prefix syntax
(add/remove, idempotency, the no-mixing rule, invalid input), the
AddAndRemoveTags() D-Bus method and the SetTags() Varlink method
(set/add/remove, explicit empty set, current-list basis).
- testcase_varlink_setters exercises the new SetHostname(),
SetStaticHostname(), SetPrettyHostname(), SetIconName(), SetChassis(),
SetDeployment() and SetLocation() Varlink methods, including resetting
values via null and rejection of invalid input.
When a device carries a SYSTEMD_MACHINE_TAG udev property, tag it for
systemd and pull in systemd-machine-tag@<tag>.service, which adds the
given tag to the host's machine tags. In other words, attaching the
property to a device makes the host auto-tag itself with the specified
machine tag.
Add a service template that adds the machine tag given as its instance
name to the host's machine tags. Whenever an instance is pulled in, the
tag is added; the operation is idempotent.
It talks to hostnamed over Varlink (which is socket-activated), so it
works very early at boot, before the system bus is up. It is ordered
after local-fs.target so that /etc/machine-info can be written, requires
hostnamed's socket and the local filesystems to be available, and does
not run in the initrd.
Teach the "tags" verb to accept arguments prefixed with '+' or '-': a
'+'-prefixed argument adds all of its (colon-separated) tags to the
configured list, a '-'-prefixed one removes them, mapping onto the new
AddAndRemoveTags() D-Bus method. The prefix applies to the whole
argument, so e.g.
hostnamectl tags +foo:bar -quux:ooo
adds foo and bar and removes quux and ooo. Plain (replace) and prefixed
(add/remove) arguments may not be mixed in one invocation.
Let's refactor things so that there's a separate xyz_is_valid() call for
each field, and make it mostly wrap string_is_safe().
This tightens the rules on some fields, mostly to refuse newlines and
some other things.
Wire up the usual SIGRTMIN+18 control signal handler and a memory
pressure event source in hostnamed's event loop, like our other
long-running daemons, so it reacts to memory pressure (e.g. by trimming
its heap) and supports the common debug/control commands. Watchdog
support via sd_event_set_watchdog() was already in place.
Add a SD_VARLINK_FIELD_COMMENT for every field of the Describe() method
that still lacked one, plus an interface comment and a symbol comment for
the Describe() method itself, so that introspecting io.systemd.Hostname
produces fully documented output.
Add SetHostname(), SetStaticHostname(), SetPrettyHostname(), SetIconName(),
SetChassis(), SetDeployment() and SetLocation() to the io.systemd.Hostname
Varlink interface, mirroring the existing D-Bus methods of the same names.
Each takes a single nullable string "newValue" (null clears/resets the
value; the method name itself makes clear what the value is) plus the usual
allowInteractiveAuthentication polkit input, and applies the same
validation, polkit actions and /etc/hostname resp. /etc/machine-info
persistence as its D-Bus counterpart. The five machine-info setters share
a common helper. The hostname validator is reused from the D-Bus path,
translating its INVALID_ARGS error into a Varlink invalid-parameter error.
Being reachable over the socket-activated Varlink socket, these work in
early boot before the system bus is up.
Add a SetTags() method to the io.systemd.Hostname Varlink interface that
combines what the D-Bus SetTags() and AddAndRemoveTags() methods do into
a single call: it takes three tag lists, 'set', 'add' and 'remove'. If
'set' is supplied the tag list is first reset to it (an explicit empty
array clears it), otherwise the current tags are used as basis; then the
'add' tags are added and the 'remove' tags are dropped.
The set arithmetic is shared with the D-Bus AddAndRemoveTags() handler
via machine_tags_add_remove().
Being reachable over Varlink (and hence socket-activatable without the
system bus) this is usable very early at boot, before dbus-daemon is up.
Add a new D-Bus method on org.freedesktop.hostname1 that incrementally
updates the machine tags instead of replacing the whole list: it takes
two string arrays, one of tags to add and one of tags to remove, and
stores (current ∪ add) \ remove.
This avoids the read-modify-write race that clients would otherwise hit
when several of them each manage a subset of the host's tags.
Factor the tag persistence and the write-error-to-D-Bus-error mapping out
of method_set_tags() into helpers, and add a machine_tags_add_remove()
helper for the set arithmetic, all to be shared with further callers.