Skip to content

reboot: Propagate a refused reboot as an error - #13

Draft
cgwalters-bot wants to merge 1 commit into
mainfrom
bot/reboot-propagate-error
Draft

cgwalters-bot wants to merge 1 commit into
mainfrom
bot/reboot-propagate-error

Conversation

@cgwalters-bot

@cgwalters-bot cgwalters-bot commented Sep 24, 2026 •

Copy link
Copy Markdown
Collaborator

bootc reboots by running systemctl reboot through systemd-run, so that it runs outside bootc's mount namespace. Without --wait, bootc only learns that the transient unit started, not whether the reboot was accepted. It then parks and waits for the SIGTERM from shutdown. If logind refuses the reboot, that SIGTERM never comes, and bootc upgrade --apply (and so bootc-fetch-apply-updates.service) hangs instead of failing.

systemd 257 and later refuse reboots from root while a block mode shutdown inhibitor is held, so this can happen today. This PR adds --wait --pipe --collect, which brings the exit status and systemctl's error message back to bootc.

There is a small race. Once the reboot has been accepted, shutdown can stop the transient unit or kill systemd-run before it reports success. bootc would then print an error and exit while the system goes down, instead of being terminated by SIGTERM. The window is short, because systemctl reboot returns as soon as the job is queued, and the reboot happens either way.

--wait and --pipe also talk to systemd over the D-Bus system bus rather than /run/systemd/private. Where dbus isn't running (e.g. rescue.target), --apply now fails loudly and keeps the staged changes. A code comment notes this.

This is split out of the reboot inhibitor PR (bootc#1047), which builds on it.

Testing

  • Reproduction, in ephemeral bcvk VMs of the published images, run as root with systemd-inhibit --what=shutdown --mode=block held:
    • centos-bootc:stream10 (systemd 257): systemd-run --quiet -- systemctl reboot, which is bootc's current invocation, exited 0 and the VM stayed up. That's the case where bootc waits forever. systemd-run --quiet --wait --pipe --collect -- systemctl reboot exited 1 and printed Operation inhibited by "probe" ... reason is "testing".
    • centos-bootc:stream9 (systemd 252): the current invocation just rebooted, because logind there doesn't enforce the lock for root. That's the gap the follow-up PR closes.
  • just validate and just unit-tests (443 tests) passed on a 16-core RHEL 10 devspace, rebased on current main (41049cc). The branch was built in its own checkout, with its own cargo target and buildah cache directories, and the built image reports g2dde3623.

Generated-by: https://github.com/cgwalters/#llms


Review draft in cgwalters-forge, not upstream yet. This section is removed when the PR is opened upstream.

  • Upstream: bootc-dev/bootc, base main
  • Board item: PVTI_lADOE9oHIs4BlJLczg9kEQc
  • Fork CI: off; the devspace testing described above is this PR's CI, and upstream CI runs once it is opened there

To review:

  • Approve, or comment /promote on a line of its own, to open it upstream, ready for review. Either covers only the commits pushed so far.
  • If upstream requires DCO, approving also signs off: promote adds Signed-off-by: Colin Walters <walters@verbum.org> to the commits lacking it (the bot's and yours; anyone else's only if you ask), with you as committer.
  • Add a /draft line (in the same comment or before) to open it upstream as a draft (/ready undoes that).
  • Close to drop it.
  • Edit the title and description freely: they become the upstream PR's. Review comments are squashed into the commits they concern, with a reply here.

We run `systemctl reboot` via `systemd-run` so it's outside our mount
namespace, but without --wait we only learn whether the transient
unit was started, not whether the reboot was accepted. If logind
refuses it, bootc then parks forever waiting for a SIGTERM that never
comes, and e.g. `bootc upgrade --apply` from
bootc-fetch-apply-updates.service would just hang instead of failing.

One way to get there is a block mode shutdown inhibitor: since systemd
257, logind rejects reboot requests from root too while one is held,
unless the caller explicitly asks to skip inhibitors. On CentOS Stream
10 with such a lock held, `systemd-run -- systemctl reboot` exits 0
while the system stays up, so bootc would wait forever.

With --wait and --pipe, the exit status and systemctl's error message
come back to us. --collect avoids leaving a failed transient unit
behind in that case.

There is a small race with --wait: once the reboot is accepted,
shutdown can stop the transient unit or kill systemd-run before it
reports success, and bootc would then print an error and exit while
the system goes down instead of parking until SIGTERM. The window is
short since `systemctl reboot` returns as soon as the job is queued,
and the reboot happens either way; only the exit status of the bootc
process being shut down is affected.

Generated-by: AI
@cgwalters-bot
cgwalters-bot force-pushed the bot/reboot-propagate-error branch from 2dde362 to b994ba3 Compare September 29, 2026 19:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant