Use the new copy timestamp clamping mechanism from the previous commit
to fix unreproducible wall-clock files in the generated images.
That covers both modes: online mode writes through the kernel, and
offline mode stages the tree in a temporary directory before handing it
to mkfs or mcopy. `mcopy -m` then carries the clamped mtimes into the
FAT.
This complements commit 34c3d57474 (directory times) and commit
f191ca982c (FAT insertion order).
Cover all combinations (online/offline, with and without epoch) in the
new `testcase_vfat_reproducibility()`. Update `testcase_make_symlinks()`
to cover the symlink creation/re-fix their parent directory code paths.
Sadly, images are still not reproducible byte for byte. Document
systemd-repart's $SOURCE_DATE_EPOCH handling and remaining
reproducibility issues in the manpage.
Add a `ts_clamp` argument to `copy_tree_at_full()` and
`copy_times_full()` that clamps copied inodes to a given time stamp.
This is the recommended `$SOURCE_DATE_EPOCH` semantics [1] for
reproducible builds. Their non-`_full` APIs keep existing behaviour by
clamping to `USEC_INFINITY`.
atime and mtime are clamped separately: a file that was merely read
after the epoch has to keep its mtime and still lose its atime. E.g. FAT
(EFI partition) stores an access date.
[1] https://reproducible-builds.org/specs/source-date-epoch/
`r` at that point holds the return value of `pidref_safe_fork_full()`,
which is 0 in the child, so a failing `setenv()` was reported as
"Success".
Also, fix a stray "°".
Previously we just wrote /etc/hostname and returned. The kernel hostname
was left at whatever PID 1 sethostname()'d very early in boot (before
/etc/hostname existed), which meant hostnamectl reported the transient
hostname instead of the static one until the next reboot.
Call io.systemd.Hostname.SetStaticHostname on the running system so
hostnamed writes /etc/hostname and updates the kernel hostname in one
step. If hostnamed is unreachable (masked or absent on minimal images)
fall back to writing /etc/hostname directly. --root=/--image= also keeps
writing the file directly, since hostnamed only manages the running
system.
As mentioned in a05fe6684a, glibc provides two
wrappers for epoll_pwait2() on 32-bit architectures, and sys/epoll.h,
together with features-time64.h, selects the appropriate one.
To avoid depending on symbols introduced in newer glibc releases, that
commit relied on the glibc internal macro __USE_TIME_BITS64 to determine
which wrapper to use. However, that is incorrect on some architectures.
See:
https://sourceware.org/git/?p=glibc.git;a=commit;h=a4ed0471d71739928a0d0fa3258b3ff3b158e9b9
The above glibc commit introduces a new internal macro,
__USE_TIME64_REDIRECTS, which correctly describes whether the time64
wrapper should be used. However, we cannot rely on it because it was
introduced in glibc 2.40, while our baseline remains glibc 2.34.
Moreover, even after raising the baseline, relying on glibc internal
implementation details is undesirable.
Instead, call the epoll_pwait2 syscall directly. This avoids any
dependency on glibc wrapper selection logic while preserving the original
goal of avoiding newer glibc symbols.
As a side effect, this also enables epoll_pwait2() on musl, which does not
currently provide a libc wrapper for it.
Currently, epoll_pwait2() is only used by sd-event, so this is also the
simplest solution.
Otherwise, test-dlopen-note.py fails when libarchive support is disabled
but libacl support is enabled.
Also, log the dlopen_libarchive() failure at LOG_ERR level, matching how
the other failures are already logged.
Fixes#43530.
The final enablement pieces needed for coco tests in systemd CI. Runners
will be incus containers, these two commits enable running coco tests
with mkosi boot (where image is a directory), then start a confidential
guest with vmspawn as part of the test.
The calculator key (Fn + numpad =) emits a press event but never a
release, leaving KEY_CALC permanently held down. Desktop environments
then repeatedly spawn the calculator.
Before:
MSC_SCAN a1 / KEY_CALC value 1
(no release for the remaining 24s of the capture)
After:
MSC_SCAN a1 / KEY_CALC value 1
MSC_SCAN a1 / KEY_CALC value 0 (14us later)
Scancode 0xd7 (Fn+F4) is an atkbd echo of the mic mute key that
ideapad-laptop already reports as KEY_MICMUTE with a proper
press/release pair. Mapping it to unknown silences the repeated
"Unknown key pressed" kernel messages without affecting the working
key.
Tested on Fedora 44, kernel 7.1.10, BIOS P5CN31WW.
The NitroSense button on the Acer Nitro V 15 (ANV15-52) emits atkbd
scancode 0xf5, the same as its sibling ANV15-51 (#38415). Map it to
prog1 so it is usable out of the box.
Verified on hardware:
dmi:bvnINSYDECorp.:bvrV1.31:bd06/27/2025:br1.31:efr1.7:svnAcer:pnNitroANV15-52:pvrV1.31:rvnRPL:rnSportage_RTH
evdev capture on "AT Translated Set 2 keyboard":
EV_MSC MSC_SCAN f5
EV_KEY KEY_PRESENTATION 425 (via the generic Acer f5 rule)
Add a TEST_MKOSI_ARGS environment variable whose contents are appended
to the mkosi invocation launching the test image, without affecting the
image build. This lets the environment adapt how tests are run, e.g.
pass --format=directory --output-dir=... to boot the test container
from a directory format output in environments that cannot dissect disk
images, such as unprivileged containers, where loop devices and udev
are not available.
Signed-off-by: Paul Meyer <katexochen0@gmail.com>
In a mount namespace owned by a non-initial user namespace, the kernel
only allows mounting a fresh proc or sysfs if the namespace already
contains a fully visible mount of the same filesystem type
(mount_too_revealing()). systemd-nspawn's pivoted root contains no such
mount, so booting the test container inside an unprivileged container
(e.g. a containerized CI runner) fails with EPERM when mounting /proc.
When running in a non-initial user namespace, satisfy the check by
binding a read-only instance of each into the container under /work.
Skipping the binds on regular privileged runs keeps the container
isolated from the host's proc and sysfs. Binding non-recursively keeps
foreign submounts (e.g. lxcfs overmounts) out, which would spoil full
visibility where they end up locked, and which read-only would not
cover.
Signed-off-by: Paul Meyer <katexochen0@gmail.com>
Since kernel v6.17, we can set a path to unix socket to core_pattern
(with request mode). See also:
https://lore.kernel.org/all/20250603-work-coredump-socket-protocol-v2-0-05a5f0c18ecc@kernel.org/
This introduces a tiny service that prepares and listens on a UNIX
socket to be passed to the kernel core pattern. When a process is
crashed, the kernel connects to the socket, and sends information
about the crashed process and passes coredump through the socket.
The service accepts the connection, and forks a worker process that
receives coredump from the kernel.
This also renames coredump_context_read_pidfd_info() to
coredump_context_read_code(), as it only reads COREDUMP_CODE.
This does not change anything effectively, as the function is called
only once. Preparation for later change.
UpdateHomeEx needs to set up the home temporarily so that it can
write the refreshed identity records. Inspect and password changes use
the same setup path for metadata-oriented work.
For LUKS homes with luksDiscard=no, home_setup_luks() fully
allocates the backing image while setting it up. If diskSize=max was
previously written to a sparse image, this can fail with ENOSPC before
the user can disable auto-resize mode again.
Add a setup flag that lets metadata operations skip the full-image
fallocate step. Real create, activate, and resize paths keep the
existing allocation behavior.
Before, reproduced on Ubuntu 26.04 with /home on tmpfs:
homectl create reprohomed \
--storage=luks \
--fs-type=btrfs \
--disk-size=300M \
--auto-resize-mode=shrink-and-grow \
--luks-discard=no
homectl update reprohomed --disk-size=max
dd if=/dev/zero of=/var/tmp/homed-repro/filler bs=1M count=500
systemctl restart systemd-homed.service
homectl update reprohomed --auto-resize-mode=off
Operation on home reprohomed failed:
Not enough disk space for home reprohomed
Fixes#34527
Follow-up for: ab3b6fcb40
Previously, even when the compressed data was truncated, or had
trailing garbage, the decompressor might not detect it.
To fix the issue, update the check if stream is finished.
With this change, now decompressor_push() must be called with
size == 0 to finalize the stream.
* b12500baf3 Drop sd-sysupdate for upstream builds, experimental again
* 674dd1e684 d/t/localed-locale: skip in Debian, not supported
* 9bd985d014 d/t/localed-locale: clean up on any error with a trap
* 56153a917f d/t/control: add dependencies missing for incus image
When a partition is deleted from a table containing multiple partitions
of the same type, filling the resulting partition-number gap can place
a new partition before an existing partition matched to an earlier
definition. This changes definition matching on the next invocation and
breaks idempotency.
Keep new partitions after existing partitions of the same type. If no
partition table slot is available after them, fall back to the first
unused slot.
Which existing partition is matched to which definition is still
determined by partition type and partition number order, as documented,
and is unchanged by this.
Fixes#43449
dns_cache_lookup() computes each answer item's expiry ('until', also the
basis of the SD_RESOLVED_CLAMP_TTL TTL patch) as "30s from now" whenever
the caller did not pass SD_RESOLVED_NO_STALE — keyed on the lookup mode,
not on whether the entry being returned is actually stale. That misfires
in both directions:
* A fresh entry hit by a serve-stale retry (second transaction attempt
with StaleRetentionSec= set) has its TTL reported as 30s instead of
its real remaining TTL.
* A lookup that passes neither SD_RESOLVED_NO_STALE nor
SD_RESOLVED_CLAMP_TTL — as the mDNS browse path does for clients
that set no flags — leaves 'current' at 0, so every answer item's
expiry becomes the constant absolute time 30s after boot,
permanently in the past. The RFC 6762 section 5.2 cache maintenance
schedule that resolved-dns-browse-services.c derives from
item->until then degenerates to its already-expired fallback.
Key the rewrite on the entry's actual staleness instead: an entry whose
TTL has lapsed keeps reporting "30s from now", so clients don't hold on
to stale data for long, and a fresh entry reports its real expiry. For
lookups with SD_RESOLVED_NO_STALE set nothing changes: a stale entry
already makes the whole chain miss, so every item returned in that mode
is fresh.
This splits coredumpctl.c into small pieces, and fixes several minor
issues such that memleak, unremoved temporary files, and missing
uncompressed core file handling. This also makes `coredumpctl
dump/debug` command accept --json= option that was previously silently
ignored.