Skip to content

sysupdate: refuse reboot/pending logic when --component= is used#42578

Merged
poettering merged 2 commits into
systemd:mainfrom
Ar-maan05:sysupdate-component-reboot-42330
Jun 19, 2026
Merged

sysupdate: refuse reboot/pending logic when --component= is used#42578
poettering merged 2 commits into
systemd:mainfrom
Ar-maan05:sysupdate-component-reboot-42330

Conversation

@Ar-maan05

Copy link
Copy Markdown
Contributor

Fixes #42330

The pending and reboot verbs, and the --reboot switch, decide whether to reboot by comparing the newest installed version against the booted OS version (IMAGE_VERSION= from os-release). When a component is selected via
--component=, this ends up comparing the component's version against the unrelated host OS version; by design these live in separate version spaces, so the comparison is meaningless and reboot decisions become arbitrary: depending on the relative version strings, sysupdate either always reboots or never does.

Example from the issue:

% /usr/lib/systemd/systemd-sysupdate --component=containerd reboot
Newest installed version '2.3.0' is older than booted version '20260527200656'.

This refuses the combination with a clear error instead of silently performing a bogus comparison:

  • verb_pending_or_reboot() rejects --component= for the pending/reboot verbs (mirroring the existing --root=/--image= rejection).
  • verb_update_impl() rejects --reboot combined with --component=, before any update work is done.

Correctly tracking a per-component "booted" version (which could be "none", making a reboot always apply) is a larger feature and left for the future, as the reporter suggested.

The daemon (sysupdated) and updatectl don't perform this host-version comparison, so the change is confined to the systemd-sysupdate CLI.

Documentation and a negative regression test (TEST-72) are included.

AI-use Disclosure:

I took assistance from Claude Opus 4.8 to scope out the issue, help with writing proper comments/documentation, and help with writing the PR description.

@github-actions github-actions Bot added documentation tests sysupdate please-review PR is ready for (re-)review by a maintainer labels Jun 13, 2026
@github-actions

github-actions Bot commented Jun 13, 2026

Copy link
Copy Markdown

Claude review of PR #42578 (19e40a6)

The change is correct and complete: every path that compares the newest installed version against the host IMAGE_VERSION= or triggers reboot logic (verb_pending_or_reboot() for the pending/reboot verbs, verb_update_impl() for update/acquire via arg_reboot) is now guarded against --component=. Guards are placed before any bogus comparison or side effect, the man-page additions match the enforced behavior, and the regression test exercises all three combinations. No correctness, memory-safety, lifetime, or security issues found. All earlier feedback has been addressed.

Suggestions

  • Guard placement consistencysrc/sysupdate/sysupdate.c:1558 — the arg_reboot && arg_component check is verb-local, while the analogous combination checks live together in parse_argv(); functionally fine, consistency-only.
  • Negative test asserts weaklytest/units/TEST-72-SYSUPDATE.sh:587 — the (! ... ) checks only confirm non-zero exit, not that the new guard is what failed.
  • Grep pattern too loosetest/units/TEST-72-SYSUPDATE.sh:587grep -F 'may not be combined' matches several distinct guard messages, so it doesn't confirm the component guard specifically fired; grepping a more distinctive substring would keep the assertion pinned to the intended guard.

Nits

  • Redundant ! in negated capturetest/units/TEST-72-SYSUPDATE.sh:587out="$(! ... 2>&1)" works, but under set -e the ! is redundant once the grep is the assertion; the file's established idiom is (! cmd) |& tee file; grep ... file.

Workflow run

Comment thread src/sysupdate/sysupdate.c Outdated
Comment thread test/units/TEST-72-SYSUPDATE.sh Outdated
@Ar-maan05

Copy link
Copy Markdown
Contributor Author

@bluca I have addressed both points from the claude-review pass in the latest push: moved the --reboot/--component= check into parse_argv() with the other combination checks, and the TEST-72 negative cases now grep for the specific error instead of just asserting non-zero exit.

Comment thread test/units/TEST-72-SYSUPDATE.sh Outdated
@Ar-maan05
Ar-maan05 force-pushed the sysupdate-component-reboot-42330 branch from 1211efc to 548d546 Compare June 13, 2026 09:41
@poettering poettering added good-to-merge/after-next-release and removed please-review PR is ready for (re-)review by a maintainer labels Jun 15, 2026
@poettering

Copy link
Copy Markdown
Member

lgtm

The `pending` and `reboot` verbs, as well as the `--reboot` switch, compare
the newest installed version against the booted OS version (IMAGE_VERSION= from
os-release). When a component is selected via --component=, this compares the
component's version against the unrelated host OS version, which by design live
in separate version spaces. The result is arbitrary reboot decisions: depending
on the relative version strings sysupdate would either always or never reboot.

Refuse the combination with a clear error instead of silently performing a
bogus comparison. Correctly tracking a per-component booted version is left as a
future feature.

Fixes: systemd#42330
Move the --reboot/--component= rejection into parse_argv() alongside the
other cross-option checks, and tighten TEST-72 to assert the specific
guard message rather than merely a non-zero exit.
@bluca
bluca force-pushed the sysupdate-component-reboot-42330 branch from 548d546 to 19e40a6 Compare June 19, 2026 18:52
@poettering
poettering merged commit 9eb163d into systemd:main Jun 19, 2026
48 of 62 checks passed
Comment on lines +587 to +589
(! "$SYSUPDATE" --component=some-component pending) |& grep -F 'may not be combined' >/dev/null
(! "$SYSUPDATE" --component=some-component reboot) |& grep -F 'may not be combined' >/dev/null
(! "$SYSUPDATE" --component=some-component update --reboot) |& grep -F 'may not be combined' >/dev/null

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Claude: suggestion: grep -F 'may not be combined' is loose enough that it doesn't confirm the component guard is what fired. That substring appears in several guard messages in sysupdate.c — the --root=/--image= guards in verb_pending_or_reboot() and parse_argv(), the --definitions= guard, and the two new --component= guards. The three invocations here pass only --component=, so today only the intended guards can match and the assertion is correct. But it is fragile: a future change that made one of these commands hit a different 'may not be combined' check first (e.g. a default --root=, or reordered cross-option checks) would keep the test green while no longer exercising the component behaviour it claims to. Grepping for a distinctive part of the message (e.g. --component= together with the booted-OS-version phrasing) would pin each assertion to the actual guard.

@Ar-maan05
Ar-maan05 deleted the sysupdate-component-reboot-42330 branch June 22, 2026 10:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Development

Successfully merging this pull request may close these issues.

"systemd-sysupdate --component reboot" compares wrong versions

3 participants