In https://gcc.gnu.org/PR121911 `gcc` started enforcing the type of
`__stack_chk_guard` to `uintptr_t` and broke `systemd` build as:
```
../src/boot/efi-log.c:136:17: error: conflicting types for '__stack_chk_guard'; have 'intptr_t' {aka 'long int'}
136 | _used_ intptr_t __stack_chk_guard = (intptr_t) 0x70f6967de78acae3;
| ^~~~~~~~~~~~~~~~~
cc1: note: previous declaration of '__stack_chk_guard' with type 'long unsigned int'
../src/boot/efi-log.c:136:17: error: declaration of '__stack_chk_guard' shadows a global declaration [-Werror=shadow]
136 | _used_ intptr_t __stack_chk_guard = (intptr_t) 0x70f6967de78acae3;
| ^~~~~~~~~~~~~~~~~
```
Let's match the declaration to unsigned type as suggested by upstream in
https://gcc.gnu.org/PR121911#c6.
This test is sometimes flaky under sanitizers, and it does repeated
calls with the same parameters to run through different greps, and
the second one sometimes fails.
Store the result and grep it twice instead to try and reduce
flakiness.
```
[ 2089.891152] TEST-04-JOURNAL.sh[22392]: + systemd-run --unit=test-journalctl-varlink-2-18237.service --wait bash -c 'echo hello-from-varlink-test-2'
[ 2090.066050] TEST-04-JOURNAL.sh[22460]: + varlinkctl call --more /run/systemd/io.systemd.JournalAccess io.systemd.JournalAccess.GetEntries '{"units": ["test-journalctl-varlink-1-22690.service"]}'
[ 2090.067075] TEST-04-JOURNAL.sh[22461]: + grep -q hello-from-varlink-test-1
[ 2090.384551] TEST-04-JOURNAL.sh[22466]: + varlinkctl call --more /run/systemd/io.systemd.JournalAccess io.systemd.JournalAccess.GetEntries '{"units": ["test-journalctl-varlink-1-22690.service"]}'
[ 2090.385373] TEST-04-JOURNAL.sh[22467]: + grep hello-from-varlink-test-2
[ 2090.723461] TEST-04-JOURNAL.sh[22474]: + grep -q hello-from-varlink-test-1
[ 2090.724294] TEST-04-JOURNAL.sh[22473]: + varlinkctl call --more /run/systemd/io.systemd.JournalAccess io.systemd.JournalAccess.GetEntries '{"units": ["test-journalctl-varlink-1-22690.service", "test-journalctl-varlink-2-18237.service"]}'
[ 2091.135655] TEST-04-JOURNAL.sh[22480]: + varlinkctl call --more /run/systemd/io.systemd.JournalAccess io.systemd.JournalAccess.GetEntries '{"units": ["test-journalctl-varlink-1-22690.service", "test-journalctl-varlink-2-18237.service"]}'
[ 2091.136605] TEST-04-JOURNAL.sh[22481]: + grep -q hello-from-varlink-test-2
[ 2091.479930] TEST-04-JOURNAL.sh[22480]: Method call failed: io.systemd.JournalAccess.NoEntries
```
An error snuck into the pattern parsing of the `MatchPattern` key in the
sysupdate transfer files. If there's two files "part1-v2.raw", and
"part1-v2.raw.tar" in the source folder, and MatchPattern="part1-@v.raw",
sysupdate will incorrectly choose "part1-v2.raw.tar" instead of
"part1-v2.raw".
While the pattern matching works perfectly fine, after the full pattern
is successfully matched to the string, we don't ensure that the string
actually ends when the pattern just did.
This means we can end up choosing a wrong file for the update, if the
filename/path happens to start with the same MatchPattern.
Fix it by ensuring the string ends after our match pattern ended.
We removed the concept of facts, so we need to update the existing
io.systemd.Basic facts provider to metrics. This commit does just
that. Its mostly mechanical.
This also means that facts.{c,h} and varlink-io.systemd.Facts.{c,h}
are gone now.
When a report upload fails the backend often provides useful
details via the varlink error. Show them as part of the upload
error message. For now we just dump the json because we have
no structure that the backends should follow. We may want to
consider adding one (like check for an "error_message" key in
the json). But for now this is a nice step forward.
Two new verbs are added: "generate" and "upload". The first one just
creates a "report", i.e. puts the metrics into a structured JSON object
that in the future is intended to carry additional data like a
signature:
$ build/systemd-report generate io.systemd.Manager.UnitsTotal
{
"mediaType" : "application/vnd.io.systemd.report",
"timestamp" : "Tue 2026-04-28 22:30:09 UTC",
"metrics" : [
{
"name" : "io.systemd.Manager.UnitsTotal",
"value" : 520
}
]
}
The second verb can be used to upload or otherwise process the report.
It builds on the code added in 0a8560eed8.
In /run/systemd/metrics-upload/ we expect a set of sockets. We'll call
out to each one of them. This allows the data to be processed in custom
ways, incl. writing to storage or sending over the network.
Each socket must provide a single interface:
io.systemd.Metrics.Upload {"report":$data}
This test is sometimes flaky under sanitizers, and it does repeated
calls with the same parameters to run through different greps, and
the second one sometimes fails.
Store the result and grep it twice instead to try and reduce
flakiness.
[ 2089.891152] TEST-04-JOURNAL.sh[22392]: + systemd-run --unit=test-journalctl-varlink-2-18237.service --wait bash -c 'echo hello-from-varlink-test-2'
[ 2090.066050] TEST-04-JOURNAL.sh[22460]: + varlinkctl call --more /run/systemd/io.systemd.JournalAccess io.systemd.JournalAccess.GetEntries '{"units": ["test-journalctl-varlink-1-22690.service"]}'
[ 2090.067075] TEST-04-JOURNAL.sh[22461]: + grep -q hello-from-varlink-test-1
[ 2090.384551] TEST-04-JOURNAL.sh[22466]: + varlinkctl call --more /run/systemd/io.systemd.JournalAccess io.systemd.JournalAccess.GetEntries '{"units": ["test-journalctl-varlink-1-22690.service"]}'
[ 2090.385373] TEST-04-JOURNAL.sh[22467]: + grep hello-from-varlink-test-2
[ 2090.723461] TEST-04-JOURNAL.sh[22474]: + grep -q hello-from-varlink-test-1
[ 2090.724294] TEST-04-JOURNAL.sh[22473]: + varlinkctl call --more /run/systemd/io.systemd.JournalAccess io.systemd.JournalAccess.GetEntries '{"units": ["test-journalctl-varlink-1-22690.service", "test-journalctl-varlink-2-18237.service"]}'
[ 2091.135655] TEST-04-JOURNAL.sh[22480]: + varlinkctl call --more /run/systemd/io.systemd.JournalAccess io.systemd.JournalAccess.GetEntries '{"units": ["test-journalctl-varlink-1-22690.service", "test-journalctl-varlink-2-18237.service"]}'
[ 2091.136605] TEST-04-JOURNAL.sh[22481]: + grep -q hello-from-varlink-test-2
[ 2091.479930] TEST-04-JOURNAL.sh[22480]: Method call failed: io.systemd.JournalAccess.NoEntries
If all entries of a menu prompt start with the same prefix, let's
preselect the prefix to enhance user experience.
This is particularly relevant when prompting for a disk to install
things on, as typically they all start with the same prefix /dev/, and
if there's only a single target medium discoverable, then we can even
fill it out fully.
The test asserts that pgscan is 0, but under sanitizers this sometimes
fails and shows up as 1. We cannot control what the kernel scans, and
with sanitizers the runtime can be slow enough it's possible that the
kernel does a pass on the cgroup of the unit test.
Instead of asserting that it's 0, assert that it's between 0 and 9,
which seems a reasonable range.
Fixes https://github.com/systemd/systemd/issues/37710
With SD_VARLINK_SERVER_ROOT_ONLY, we refuse all unprivileged operations.
This is silly, the user can and should be able to do anything that doesn't
require privileges.
E.g.:
$ SYSTEMD_LOG_LEVEL=debug varlinkctl introspect /usr/lib/systemd/systemd-pcrextend
Forking off Varlink child process '/usr/lib/systemd/systemd-pcrextend'.
Successfully forked off '(sd-vlexec)' as PID 568993.
varlink: Setting state idle-client
json-stream: Sending message: {"method":"org.varlink.service.GetInterfaceDescription","parameters":{"interface":"io.systemd.PCRExtend"}}
Skipping PR_SET_MM, as we don't have privileges.
varlink: Changing state idle-client → calling
varlink: Unprivileged client attempted connection, refusing.
Failed to run Varlink event loop: Operation not permitted
json-stream: Got POLLHUP from socket.
varlink: Changing state calling → pending-disconnect
varlink: Connection was closed.
Failed to issue org.varlink.service.GetInterfaceDescription() varlink call: Connection reset by peer
This and similar commands now work, e.g.
$ SYSTEMD_LOG_LEVEL=debug varlinkctl call --more ./build/bootctl io.systemd.BootControl.ListBootEntries {}
...
Failed to open directory "/efi": No such file or directory
File system "/boot" is not a FAT EFI System Partition (ESP) file system.
...
Method call failed: Permission denied
{
"origin" : "linux",
"errno" : 13,
"errnoName" : "EACCES"
}
Which is fine — we lack privileges to actually return a useful answer, but the
call itself should go through.
I didn't touch udevd, which refuses to run if it is not root, and does a lot of
privileged setup, so would refuse to start even if the check was removed.
This is a reiteration of #38764, but this time on top of "bootctl link"
for installing a kernel, i.e. #41543, instead of "kernel-install".
It's the same as #41543, only adds three new commits on top.
The LUKS subtest in testcase_btrfs_basic leaves stale LUKS headers on
the underlying SCSI devices, so if the VM is rebooted the test fails
because the LUKS signature is still there and blkid finds it.
[ 7.683] + udevadm lock ... mkfs.btrfs -f -L btrfs_root -U deadbeef-dead-dead-beef-000000000000 /dev/disk/by-id/scsi-0systemd_foobar_deadbeefbtrfs0
[ 7.729] Label: btrfs_root
[ 7.729] UUID: deadbeef-dead-dead-beef-000000000000
[ 7.743] + udevadm wait --settle --timeout=30 /dev/disk/by-id/scsi-0systemd_foobar_deadbeefbtrfs0 /dev/disk/by-uuid/deadbeef-dead-dead-beef-000000000000 /dev/disk/by-label/btrfs_root
[ 7.788] sda: ... SYMLINK+="disk/by-label/$env{ID_FS_LABEL_ENC}": Added device node symlink "disk/by-label/encdisk0".
[ 37.998] Timed out for waiting devices being initialized.
[ 38.002] TEST-64-UDEV-STORAGE-btrfs_basic.service: Main process exited, code=exited, status=1/FAILURE
Likewise for the BTRFS UUID:
ERROR: non-unique UUID: deadbeef-dead-dead-beef-000000000001
So wipe that too.
drive_info_add_fail() calls bridge_unregister_drive() followed by
drive_info_unref(), then continues to access the DriveInfo object.
While all current callers hold their own reference, it is a bit
fragile and it trips static analyzers. Take a local reference.
CID#1655804
Follow-up for 1d0a8e5dbd
option_get_synopsis() returns a heap-allocated string. Capture it in
a _cleanup_free_ variable so it is freed after being used in the log
message.
CID#1657828
Follow-up for 05fea7df1b
I thought that this would require some bigger changes, but it turns out
that the existing functionality is good enough with some minor
adjustments if used appropriately.
The behaviour of help_section() is changed to simplify all callers.
The user-facing components are the "systemd-importd.service" unit and
the "importctl" binary, so using these names makes more sense.
There _is_ a "systemd-import" binary, but it's in "/usr/lib/systemd/",
so this is a confusing name for a user-facing form.
partition_is_luks2_integrity() was returning -EINVAL when it
encountered a non-LUKS2 header (e.g. LUKS v1), which caused the
caller to abort the entire disk dissection. A LUKS v1 partition
simply isn't LUKS2-with-integrity, so return 0 instead and let
dissection continue normally.
systemd-dissect --mtree calls io.systemd.PCRExtend over Varlink to extend
the verity NvPCR after activation, and the test then diffs the measure
log to find the new entry. But systemd-pcrextend.socket has
ConditionSecurity=measured-os, which fails when the firmware did not
initialize PCRs, so the test fails.
[ 10.056930] systemd[1]: systemd-pcrextend.socket - TPM PCR Measurements skipped, unmet condition check ConditionSecurity=measured-os
Follow-up for 521a523ce0
Add ReloadCount to the io.systemd.Metrics family table so it can be
queried alongside other manager-level metrics via systemd-report.
Also extend the existing integration test to cross-check the value
returned by systemd-report against the D-Bus and Varlink transports
on every assertion.
Co-developed-by: Claude Opus 4.7 <noreply@anthropic.com>
Signed-off-by: Simon Lucido <simonlucido@meta.com>
The logic that was tested in the previous commit is used to implement
the behaviour for unit-shell and other verbs without changes.
The compare-versions synopsis is shortened to "V1 [OP] V2" to make the
verb synopsis fit. Unusual capitalizaition of "Command" is changed to
"COMMAND" (it's a replace arg, not a fixed string), and some help
strings are adjusted. The order of options in --help is based on the
existing order in parse_argv(). The old order in --help was mostly
random. I think it might be good to figure out something more rational
here, but I'm leaving that as a separate step.
The urlification of dot(1) in the --help string is lost. It's hard to
do this with the help string being stored in a read-only section.
I think this is not worth the trouble to reimplement in the current
scheme.
The search domain limit is already enforced by dns_search_domain_new(),
but in this case it's way too late. Let's enforce it during the first
loop to avoid unnecessary parsing.
---
Also, set a similar limit for NTAs - introduce a new constant, since
there's no pre-existing limit. I pulled the value from a thin air since
there's (AFAIK) no mandated maximum/minimum for NTAs, but given they're
supposed to be a manual and _temporary_ workarounds, hopefully 2K of
NTAs will be more than enough (if not, please yell).
Also note: the newly added error messages don't have the trailing "."
and similarly the newly introduced constant doesn't have the "u" suffix
to match the style of the surrounding code (and I didn't want to fix the
surrounding code to make the diff minimal). If this is not desirable,
please also yell.
A segfault is observed when both key_file and tpm2-device are
simultaneously passed to systemd-cryptsetup, e.g.:
systemd-cryptsetup attach test_data /vol /my-pass tpm2-device=auto
The crash appears after commit 5c6aad9 but the flaw in the logic was
pre-existing.
Fixes#41867
TEST-06-SELINUX occasionally fails because repeated nspawn invocations use
the same machine name and scope:
TEST-06-SELINUX.sh[598]: Failed to allocate scope: Unit H.scope was already loaded or has a fragment file.
Use a different machine name/scope for each invocation in the test
case to avoid hitting this issue
The search domain limit is already enforced by dns_search_domain_new(),
but in this case it's way too late. Let's enforce it during the first
loop to avoid unnecessary parsing.
The dditest block calls systemd-repart with Encrypt=tpm2 but without
--tpm2-public-key-pcrs=. Since systemd-stub drops
/run/systemd/tpm2-pcr-public-key.pem when booting from a signed UKI
systemd-repart auto-loads it and enrolls a signed PCR policy, and
then systemd-cryptsetup tpm2-device=auto has no matching signature file,
so unlock fails.
--tpm2-public-key= is not enough as the default kicks in then.
Follow-up for cd18656d47
mdadm --zero-superblock only wipes the MD metadata on the underlying
disks, not the LVM PV header that lives in the array data area. When
the VM is restarted and the test re-creates the array with the same
UUID, /dev/md127 exposes the old data including the LVM PV header, so
udev's 69-lvm.rules auto-triggers lvm-activate-mdlvm_vg.service which
races with the test's own pvcreate for exclusive access on /dev/md127.
Wipe the LVM signature off the MD device (and the underlying disks as
a belt-and-braces measure) to avoid the race on re-run, fixing failures
when the VM is rebooted instead of shut down.
Co-developed-by: Claude Opus 4.7 <noreply@anthropic.com>
The image configuration was changed and the main sources are
now in a drop-in apt sources files too, so deleting the whole
drop-in directory breaks installing packages. Just delete the
disabled ones and chrome.
On initrds where nfnetlink module is missing, trying to open
a NETLINK_NETFILTER netlink socket takes a lot of time then fails.
This makes boot noticibly slower. Even though probably no
unit in an initrd need netfilter.
So here we delay opening the socket until we know we need it.
write_to_journal() was called via $(...) command substitution, so
SERVICE_COUNTER++ ran in a subshell and never incremented in the
parent:
[ 1492.668302] TEST-04-JOURNAL.sh[15064]: + local service=test-0-18493.service
[ 1492.725882] TEST-04-JOURNAL.sh[15064]: + local service=test-0-18009.service
[ 1492.739643] TEST-04-JOURNAL.sh[15064]: + local service=test-0-18493.service
[ 1492.774586] TEST-04-JOURNAL.sh[15064]: + local service=test-0-25540.service
[ 1492.815664] TEST-04-JOURNAL.sh[15064]: + local service=test-0-15916.service
[ 1492.867067] TEST-04-JOURNAL.sh[15064]: + local service=test-0-20327.service
[ 1492.899077] TEST-04-JOURNAL.sh[15064]: + local service=test-0-86.service
[ 1497.289715] TEST-04-JOURNAL.sh[15064]: + local service=test-0-10849.service
[ 1497.335791] TEST-04-JOURNAL.sh[15064]: + local service=test-0-18009.service
With 99999 possible unit names collisions are rare but not impossible,
so every now and then a CI run fails.
Have write_to_journal() set a global SERVICE_NAME variable instead and
call it directly so SERVICE_COUNTER actually goes up through the test.
When key_file is passed along with tpm2-device= to systemd-cryptsetup, the
logic is to try the blob as a TPM blob first, and then fall back to trying the
file as a regular key file. Check that this fallback works.