Now that the socket forward code is extracted we can
extend it to not just support bidirectional sockets
but also input/output fd-pairs. This will be needed
for e.g. the varlinkctl protocol upgrade support where
one side of the connection is a fd-pair (stdin/stdout).
This is done by creating two half-duplex forwarders
that operate independantly. This also allows to simplify
some state tracking, e.g. because each fd serves only one
direction we don't need to dynamically create the event mask
with EPOLLIN etc, its enough to set it once. It also handles
non-pollable FDs transparently.
Thanks to Lennart for his excellent suggestions here.
The varlink spec supports protocol upgrades and they are very
useful to e.g. transfer binary data directly via varlink. So
far sd-varlink was not supporting this.
This commit adds a new public sd_varlink_call_and_upgrade()
that sends a method call, waits for the reply, then steals
the connection fds for raw I/O. It returns separate input_fd
and output_fd to support both bidirectional sockets and pipe
pairs.
A helper is extracted and shared between sd_varlink_call_full()
and sd_varlink_call_and_upgrade(). A new `protocol_upgrade`
bool in `struct sd_varlink` ensures that on a protocol upgrade
request we only exactly read the varlink protocol bytes and
leave anything beyond that to the caller that speaks the upgraded
protocol.
Note that this is the client side of the library implementation
only for now. The server side needs work but this is already
useful as it allows to talk to varlink servers that speak protocol
upgrades (like the rust implemenations of varlink).
Since v257, terminal_fix_size() is called during early boot via
console_setup() → reset_dev_console_fd() to query terminal dimensions
via ANSI escape sequences. This has caused intermittent boot hangs
where the system gets stuck with a blinking cursor and requires a
keypress to continue (see systemd/systemd#35499).
The function tries CSI 18 first, then falls back to DSR if that fails.
Previously, each method independently opened a non-blocking fd, disabled
echo/icanon, ran its query, restored termios, and closed its fd. This
created two problems:
1. Echo window between CSI 18 and DSR fallback: After CSI 18 times out
and restores termios (re-enabling ECHO and ICANON), there is a brief
window before DSR disables them again. If the terminal's CSI 18
response arrives during this window, it is echoed back to the
terminal — where the terminal interprets \e[8;rows;cols t as a
"resize text area" command — and the response bytes land in the
canonical line buffer as stale input that can confuse the DSR
response parser.
2. Cursor left at bottom-right on DSR timeout: The DSR method worked by
sending two DSR queries — one to save the cursor position, then
moving the cursor to (32766,32766) and sending another to read the
clamped position. If neither response was received (timeout), the
cursor restore was skipped (conditional on saved_row > 0), leaving
the cursor at the bottom-right corner of the terminal. The
subsequent terminal_reset_ansi_seq() then moved it to the beginning
of the last line via \e[1G, making boot output appear at the bottom
of the screen — giving the appearance of a hang even when the system
was still booting.
This commit fixes both issues:
- terminal_fix_size() now opens the non-blocking fd and configures
termios once for both query methods, so echo stays disabled for the
entire CSI 18 → DSR fallback sequence with no gap. tcflush(TCIFLUSH)
is called before each query to drain any stale input from the tty
input queue.
- The DSR method now uses DECSC (\e7) / DECRC (\e8) to save and restore
the cursor position via hardware, instead of querying it with a
separate DSR round-trip. All four sequences (DECSC, CUP to
bottom-right, DSR query, DECRC) are sent in a single write, so the
terminal processes DECRC and restores the cursor regardless of whether
userspace ever reads the DSR response. This eliminates the
cursor-at-bottom-right artifact on timeout and simplifies the read
loop to only need a single DSR response instead of two.
- The repeated setup boilerplate (dumb check, verify_same, fd_reopen,
termios save/disable) is extracted into terminal_prepare_query(),
shared by terminal_get_size_by_csi18(), terminal_get_size_by_dsr(),
and terminal_fix_size().
Fixes: systemd/systemd#35499
Co-developed-by: Claude Opus 4.6 <noreply@anthropic.com>
Add TERMIOS_NULL sentinel, TermiosResetContext, and CLEANUP_TERMIOS_RESET()
macro (modeled after CLEANUP_ARRAY()) to automatically restore terminal
settings when leaving scope, replacing manual goto+tcsetattr patterns.
Migrate ask_string_full(), terminal_get_cursor_position(),
get_default_background_color(), terminal_get_terminfo_by_dcs(),
terminal_get_size_by_dsr() and terminal_get_size_by_csi18() to use the new
cleanup macro, removing the goto-based cleanup labels and replacing them
with direct returns.
Co-developed-by: Claude Opus 4.6 <noreply@anthropic.com>
Replace assert_se() calls with the more descriptive ASSERT_OK(),
ASSERT_OK_ZERO(), ASSERT_OK_ERRNO(), ASSERT_OK_POSITIVE(),
ASSERT_OK_EQ_ERRNO(), ASSERT_FAIL(), ASSERT_TRUE(), ASSERT_FALSE(),
ASSERT_EQ(), ASSERT_LE(), and ASSERT_NOT_NULL() macros throughout the
test file.
Co-developed-by: Claude Opus 4.6 <noreply@anthropic.com>
After having some more experience with how this works, I think some
changes are in order. So there are a handful of preparatory patches and
then conversion of a few progs that make use of the new functionality.
When `Format=empty` is set we need to check for `NoAuto` support for
the partition type, else we print a warning later in the build.
Followup for 381304a
This doesn't really matter as it runs in user contexts, but
follow good practice and mark all variables containing secrets
for erasure on cleanup
Reported on yeswehack.com as YWH-PGM9780-170
`updatectl enable --now` systematically fails because the update phase find
resources that are not pending. So instead we should ignore them.
Fixes#41254
Sysupdate temporary file names do not match their extension-release names. So
they will always fail. That makes enabling any other sysexts/confexts fail
which has catastrophic consequences. Unfortunately since 260, sysupdate
leaves temporary files for long time instead just while downloading. So
this kind of failure now happens much more often.
Coverity flags allocated - 1 as a potential underflow when
allocated is 0. After GREEDY_REALLOC succeeds the buffer is
guaranteed non-empty, but Coverity cannot trace through the
conditional. Add an assert to document this.
CID#1548053
Follow-up for ec20fe5ffb
Trivial ordering/modernizing change that got highlighted by
claude and refined by keszybz to move to the modern systemd
style.
Thanks to keszybz for suggesting this.
Coverity flags UINT32_MAX - data.container_id as an underflow
when container_id could be UID_INVALID (UINT32_MAX). After
successful sd_json_dispatch_uid_gid(), the values are guaranteed
valid, but Coverity cannot trace through the callback. Add
asserts to document this invariant.
CID#1548072
Follow-up for 91c4d1affd
The setup_size field from the kernel image header is used as part
of the memcpy size. Clamp it to sizeof(SetupHeader) to ensure the
copy does not read beyond the struct bounds even if the kernel
image header contains an unexpected value.
CID#1549197
Follow-up for d62c177756
Coverity flags the multi-term output.iov_len accumulation as a
potential overflow. Add an assert after the calculation to verify
the result is at least as large as the input, catching wraparound.
CID#1548068
Follow-up for 21bc0b6fa1
Use overflow-safe ADD_SAFE() instead of raw addition when
computing the next matching calendar component with repeat.
On overflow, skip the component instead of using a bogus value.
CID#1548052
Follow-up for a2eb5ea79c
Use pre-decrement starting from 3 instead of post-decrement
starting from 2, so that the unsigned counter does not wrap
past zero on the final iteration.
CID#1548035
Follow-up for 02f19706a9
Use CONST_ALIGN_TO to express the compile-time overflow check for
the ALIGN(sizeof(sd_bus_message)) + sizeof(BusMessageHeader)
allocation, since ALIGN() is not constexpr.
CID#1548031
Follow-up for de1c301ed1
Coverity flags idx += 2*sizeof(char*) and idx += sizeof(char*)
as potential overflows. The idx is bounded by the ms buffer size
calculation, add asserts to document this.
CID#1548028
Follow-up for e8a7a31539
Coverity flags compile-time constant multiplications of
USEC_PER_SEC, USEC_PER_MSEC, and USEC_PER_HOUR as potential
overflows. Add assert_cc() to prove they fit at build time.
CID#1548025
CID#1548048
CID#1548055
CID#1548059
Follow-up for 500727c220
Follow-up for 27d340c772
Follow-up for e537352b9b
Follow-up for 1007ec60e6
Coverity flags a->after->offset + a->after->current_size as a
potential overflow. Both values are validated as not UINT64_MAX
by existing asserts, add an explicit overflow check to document
the invariant for static analyzers.
CID#1548063
Follow-up for e594a3b154
Coverity flags ALIGN(sizeof(NDiscDNSSL)) + strlen(*j) + 1 as a
potential overflow. Domain names are protocol-bounded but add an
assert to make this explicit for static analyzers.
CID#1548066
Follow-up for 1e7a0e21c9
Coverity flags ALIGN(sizeof(DnsPacket)) + size calculations in
dns_packet_new() and dns_packet_dup() as potential overflows. The
sizes are bounded by DNS_PACKET_SIZE_MAX but add asserts to make
this explicit for static analyzers.
CID#1548058
CID#1548076
Follow-up for c73ce96b56
Coverity flags (uint64_t) sc * (uint64_t) ps as a potential
overflow. Add an assert to make the bounds explicit for static
analyzers.
CID#1548042
Follow-up for eefc66aa8f
Coverity flags ALIGN(sizeof(struct passwd/group)) + bufsize as
potential overflows in the getpw/getgr helpers. Add asserts to
make the bounds explicit for static analyzers.
CID#1548047
CID#1548049
CID#1548069
CID#1548070
Follow-up for 75673cd8ae
Coverity flags arithmetic in BUS_MESSAGE_SIZE(),
BUS_MESSAGE_BODY_BEGIN() and message_from_header() as potential
overflows. The values are validated at message creation time, but
add asserts to make the invariants explicit for static analyzers.
CID#1548023
CID#1548030
CID#1548046
Follow-up for 6629161f82
Coverity flags the subtraction from msg_controllen as a potential
underflow. The CMSG_SPACE was added when send_ucred was set, and
the subtraction only runs when send_ucred was true, so it is safe.
Add an assert to document this invariant.
CID#1548074
Follow-up for 64144440a5
Same pattern as the fix for sd_json_variant_unset_field in
9b3715d529: cache the element
count in a local variable and assert it is at least 2 before
subtracting.
CID#1548029
Follow-up for f2ff34ff2a
Coverity flags max_size*2 as a potential overflow. The value is
bounded by MAX_SIZE_UPPER (128 MiB) or JOURNAL_COMPACT_SIZE_MAX
(4 GiB), so doubling is safe within uint64_t. Add an assert to
document this.
CID#1548019
Follow-up for 8580d1f73d
The restriction requiring --empty= to be require, force, or create
when using --el-torito= is unnecessary.
context_verify_eltorito_overlap() already validates that the ISO 9660
blocks don't collide with GPT partition entries or the first usable
LBA, which is sufficient to guarantee safety regardless of the empty
mode.
This is needed for two-stage image builds where the first stage creates
the usr and verity partitions, and the second stage adds --el-torito=
to produce a bootable ISO with a UKI containing usrhash= derived from
the verity hash of the first stage. In the second stage, repart runs
with --empty=allow since the image already exists.
Co-developed-by: Claude Opus 4.6 <noreply@anthropic.com>
This only points the firmware to the ESP. The ISO9660 is empty.
The initramfs should create a loop device to change block size
and enable GPT partitions.
This was tested using OVMF on qemu, with:
`-drive if=pflash,file=OVMF_CODE.fd,readonly=on,format=raw -drive if=pflash,file=OVMF_VARS.fd,format=raw -drive if=none,id=live-disk,file=dick.iso,media=cdrom,format=raw,readonly=on -device virtio-scsi-pci,id=scsi -device scsi-cd,drive=live-disk`
And a simple definition:
```
[Partition]
Type=esp
Format=vfat
CopyFiles=/usr/lib/systemd/boot/efi/systemd-bootx64.efi:/EFI/BOOT/BOOTX64.EFI
```
I tried to implement a varlink service using sd-varlink, and
not being able to use the approach with sentinel is exteremely
painful. This is useful internally and likewise externally.
Some shells will try to parse this, or expand it, causing an error. Lets
quote it so it's simpler for people.
Signed-off-by: Morten Linderud <morten@linderud.pw>
AllowDiscards= will set allow-discards in the persistent flags which will make
activating the device automatically activate with that option. This is
useful for devices discovered through gpt-auto-generator without
needing to use some kernel command line to set the option.