init/plymouth: replace plymouth CLI with direct socket IPC#358
Merged
Conversation
Talk to plymouthd directly over its abstract Unix socket instead of fork-exec'ing the plymouth CLI client for ping, show-splash, display-message, quit, and update-root-fs. The wire protocol is documented in Plymouth's ply-boot-protocol.h. plysocket.go encapsulates dial / send / recv with three helpers: - plymouthSendRecv(frame): raw frame, 1-byte response - plymouthCmd(typ, arg): NUL-terminated argument frame, expects ACK - plymouthPingOnce(): single ping, returns true on ACK Drop /usr/bin/plymouth from the initramfs (~80KB binary plus glib + libply-boot-client transitive deps). plymouthd alone is sufficient now that init speaks the protocol directly. No call-site signature changes; plymouthAskPassword stays on the exec path for now and converts in a later commit when ctx threading lands.
Inherited file descriptors are closed (FD_CLOEXEC) when booster exec's to systemd, so a plymouthd that inherits booster's stderr will receive EPIPE on its next stderr write and die — before systemd's plymouth-start.service can attach to the existing session. Open /dev/kmsg explicitly and assign it to cmd.Stderr so plymouthd's diagnostic output ends up in the kernel ring buffer (visible in journalctl -k post-boot) and survives the handoff to systemd.
Wrap the display-message socket call in a goroutine. plymouthd is single-threaded and can stall during render setup or while a password prompt is on screen; a synchronous in-process call would block the calling goroutine on splash state, slowing concurrent unlock work.
Change waitForPlymouthInit() to take a ctx and return an error so unlock paths can bail when a sibling token has already cleared the volume — instead of blocking on plymouthd startup for a volume that's already being unlocked. requestKeyboardPassword previously waited unconditionally on plymouth-init then re-checked ctx; merging the two into a single ctx-aware select removes the redundant check and lets cancellation propagate cleanly through the wait.
plymouthAskPassword now takes a ctx. On cancellation the underlying socket is closed; the in-flight read returns and the goroutine exits cleanly, holding no resources from the dropped prompt. In plymouthd builds whose connection-hangup handler tears down pending prompts, the daemon also dismisses the on-screen prompt UI on the same socket close, completing the UX. Older plymouthd builds leave the prompt UI visible on the splash until something else clears it; boot still proceeds correctly — matching upstream's prior behaviour minus the orphaned plymouth subprocess and leaked goroutine the exec path produced. Serialize calls under plymouthPasswordMu so concurrent unlock goroutines don't stack two prompts on the splash. The mutex pairs with a re-check of ctx.Err() after acquire to skip our prompt entirely if the volume was unlocked while we were waiting on the lock — avoids flashing a UI for an already-unlocking volume. askPasswordWithFallback honors ctx cancellation by returning ctx.Err() without falling back to the console reader. Falling back would print a prompt to /dev/console that the LUKS unlock loop has already abandoned, which is at best confusing and at worst lets the user type a passphrase that gets discarded.
anatol
reviewed
May 7, 2026
Address review feedback on PR anatol#358: add a file-level reference covering the upstream protocol header, frame format, the full verb table (with the six booster uses called out), and server response bytes.
Owner
|
Thank you very much for this change! |
pilotstew
added a commit
to pilotstew/booster
that referenced
this pull request
May 14, 2026
Adds a new NOTES subsection covering the concurrent-unlock model that landed across PRs anatol#350, anatol#353, anatol#355, anatol#356, anatol#357, anatol#358, and anatol#362: PIN-token serialization in ascending LUKS2 token-ID order, cancel-on-win semantics for keyboard/FIDO2-PIN/TPM2-PIN prompts on both the console and the Plymouth splash (with the MR !393 caveat for older Plymouth builds), and the per-token 3-attempt PIN cap with empty-PIN skip. Trims two paragraphs from the existing 'Password entry' subsection (auto-dismiss and PIN attempts) now that the new section covers them in fuller context. 'Password entry' keeps the Ctrl+W / Ctrl+U / Tab edit-key reference.
anatol
pushed a commit
that referenced
this pull request
May 14, 2026
Adds a new NOTES subsection covering the concurrent-unlock model that landed across PRs #350, #353, #355, #356, #357, #358, and #362: PIN-token serialization in ascending LUKS2 token-ID order, cancel-on-win semantics for keyboard/FIDO2-PIN/TPM2-PIN prompts on both the console and the Plymouth splash (with the MR !393 caveat for older Plymouth builds), and the per-token 3-attempt PIN cap with empty-PIN skip. Trims two paragraphs from the existing 'Password entry' subsection (auto-dismiss and PIN attempts) now that the new section covers them in fuller context. 'Password entry' keeps the Ctrl+W / Ctrl+U / Tab edit-key reference.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Talk to plymouthd directly over its abstract Unix socket
(
\x00/org/freedesktop/plymouthd) instead of fork-exec'ing theplymouthCLI client. The wire protocol is documented in Plymouth'sply-boot-protocol.h.Carved into 5 commits for review:
init/plymouth: replace plymouth CLI with direct socket IPC—add
init/plysocket.go(transport), swap the 5 exec call sites forping / show-splash / display-message / quit / update-root-fs. Drop
/usr/bin/plymouthfrom the initramfs (~80KB binary plusglib+libply-boot-clienttransitive deps). No call-sitesignature changes;
plymouthAskPasswordstays on the exec pathfor now and converts in commit 5 when ctx threading lands.
init/plymouth: redirect plymouthd stderr to /dev/kmsg—inherited fds are closed (FD_CLOEXEC) when booster exec's to
systemd, so a plymouthd that inherits booster's stderr receives
EPIPE on its next stderr write and dies before
plymouth-start.servicecan attach. Routing to/dev/kmsgsurvives the handoff and lands the diagnostic output in the
kernel ring buffer.
init/plymouth: make plymouthMessage fire-and-forget—plymouthd is single-threaded; a synchronous in-process
display-messagecall would block on splash state, slowingconcurrent unlock work. Wrap in a goroutine.
init/plymouth: thread ctx through waitForPlymouthInit—small signature change so unlock paths can bail when a sibling
token has already cleared the volume, instead of blocking on
plymouthd init for a volume that's already being unlocked.
init/plymouth: ctx-aware password prompt with cancel-on-hangup(the headline) —
plymouthAskPassword(ctx, prompt)plus aserialization mutex. On ctx cancel the underlying socket is closed;
the goroutine returns cleanly. plymouthd builds whose
connection-hangup handler tears down pending prompts also dismiss
the on-screen UI on close — older builds leave the UI visible
until the splash is otherwise cleared, but boot proceeds correctly
either way (matching upstream's prior behaviour minus the orphaned
plymouth subprocess and leaked goroutine the exec path produced).
askPasswordWithFallbackskips the console fallback when ctx isalready cancelled, so an already-unlocking volume doesn't flash a
stray console prompt.
Why
/usr/bin/plymouthand its transitive deps from theinitramfs.
the socket and the prompt goroutine returns immediately. The prior
exec path left both the subprocess and the goroutine blocked
indefinitely.
init/luks: convert done channel to context.Context #354 / init/luks: extend ctx cancellation to FIDO2-PIN and TPM2-PIN prompts #356 — keyboard, FIDO2-PIN, and TPM2-PIN prompts already
cancel on autounlock; this extends the same to the splash prompt.
No new dependencies. Tests for splash messaging (#357) still pass
unchanged.
Upstream Plymouth dependency
The cancel-on-hangup behavior in commit 5 — dismissing the on-screen
prompt when the booster client disconnects — depends on plymouthd
having a connection-hangup handler that tears down pending prompts.
That fix is Plymouth MR !393,
currently awaiting upstream review (closes Plymouth issues #125 and
#126).
This PR does not require !393 to land first. Without it, booster
still cleans up its end of the socket on cancel — boot proceeds
correctly, the goroutine returns, no orphaned subprocess. The only
visible difference is a stale prompt that lingers on the splash until
plymouth quits later in boot. Pure visual polish, not a regression vs.
the exec path.
Once !393 is in users' plymouthd, the splash prompt also dismisses
cleanly, completing the UX that #354 / #355 / #356 brought to the
console side.
Test plan
go build ./init ./generatorcleanTestPromptVolumeUnlockedandTestTokenFriendlyNamepass/usr/bin/plymouthin the cpio)unlock paths
handler — confirm no behavioural regression vs. exec path