tools: preview the plymouth splash unprivileged; #137 attempt 1 reverted
All checks were successful
Check / eval (push) Successful in 3m49s

Answering "how do I give you root": you don't. tools/plymouth-preview.sh
renders the splash — LUKS dialog included — into X11 windows in ~10s with
no reboot, no root and no DRM:

- unshare -rm = user + mount namespace; every mount dies with it.
- /run/plymouth is BOTH the socket dir and the compiled-in plugin path
  (`strings plymouthd` → /run/plymouth/plugins/), so we bind a writable dir
  over it AND recreate its symlinks — miss those and plymouth can't find
  x11.so, silently skips X11 and reaches for a tty.
- never pass --tty (main.c:2133 takes the X11 path only while default_tty
  is unset); /dev/dri is masked so a preview physically cannot mode-set a
  real output — which matters on a docked session (#127).
- PLY_CREATE_FAKE_MULTI_HEAD_SETUP fakes 800x600 + 640x480 heads.
- debug wants plymouth.debug=stream: — `file:` buffers and yields nothing.

What it proved immediately: with a STABLE two-head canvas the current theme
centres correctly on both heads. So the geometry is fine and #137 really is
the timing bug (positions frozen at parse time vs a canvas that resizes
when a head arrives) — recorded in the item.

And it caught my own fix: hoisting positions into layout() rendered the
background on both heads and nothing else — no logo, no bar — with NO parse
error logged. Reverted rather than shipped, because that script draws the
passphrase box on an encrypted machine. #137 carries the failure, the prime
suspect (plymouth script scope: assignment lands in `local` unless the name
already exists) and the fast edit/render loop for the next attempt.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-16 12:42:31 +01:00
parent 3e6cc6fe84
commit 0cd6212b9c
3 changed files with 118 additions and 13 deletions

View File

@@ -214,20 +214,48 @@ the existing `refresh_callback` (already running at 50 fps) whenever
included), entry, lock, any live bullets, progress box/bar. Keep it a
canvas-change check, not an every-frame recompute.
**Testing — the rig exists, and it needs root.** nixpkgs' plymouth ships
`x11.so`, and plymouth has a built-in fake dual-head mode:
`PLY_CREATE_FAKE_MULTI_HEAD_SETUP=1` (`renderers/x11/plugin.c:294`) creates
800×600 + 640×480 heads, so the splash can be rendered in a window with no
DRM and no reboot. Caveat: that fake path builds both heads up front, so it
proves *rendering and centring*, not the canvas-change bug itself — for that,
plug/unplug while the splash is up, or compare a boot with and without the
external. `plymouthd` wants root and its theme comes from
`/etc/plymouth/plymouthd.conf`, so this needs a sudo session.
**The rig works, needs no root, and is in `scratchpad/ply-rig.sh`** (recipe
below — rebuild it, it is ~20 lines). Rendered on the dev box 2026-07-16:
**Do not ship this blind:** the same script draws the **LUKS passphrase box**,
this machine is encrypted, and a script that fails to parse leaves a prompt you
cannot see. Pass = with the rig, a two-head render centred on both; then a real
docked boot + shutdown, undocked unchanged.
- `unshare -rm` gives a user + mount namespace: root *in there* only, every
mount invisible to the real system and gone when it exits.
- `/run/plymouth` is BOTH the daemon's socket dir **and** its compiled-in
plugin/theme path (`strings plymouthd``/run/plymouth/plugins/`). Bind a
writable dir over it **and recreate its three symlinks** (`plugins`,
`themes`, `plymouthd.defaults``/etc/plymouth/…`) or plymouth cannot find
`x11.so`, silently skips X11 and reaches for a tty.
- **Do not pass `--tty`**: `main.c:2133` only takes the X11 path while
`default_tty` is unset. Bind an empty dir over `/dev/dri` too — with X11
first in the renderer order (`ply-renderer.c:283`) DRM is never used, and the
mask makes that a guarantee rather than a hope.
- `PLY_CREATE_FAKE_MULTI_HEAD_SETUP=1` → 800×600 + 640×480 windows.
`plymouth show-splash`, then `plymouth ask-for-password` renders the LUKS
dialog. Debug: `--kernel-command-line="plymouth.debug=stream:/path splash"`
(**`stream:`**, not `file:``file:` buffers and you get nothing).
- Fast loop: copy the theme into the rig's `themes/` and sed its `.plymouth`
`ScriptFile=`/`ImageDir=` to the copy — then editing the script is a 10s
render instead of a 3min `nixos-rebuild`.
**What the rig already proved (2026-07-16):** with a *stable* two-head canvas
the **current** theme centres correctly on both heads — logo and progress bar
each in their own head's middle. So the geometry is not the bug, which is the
evidence for the timing diagnosis above. The fake path builds both heads up
front, so it cannot reproduce a canvas *change*: for that, plug/unplug while
the splash is up, or compare a boot with and without the external.
**Attempt 1 failed, and the rig caught it — that is the point.** Hoisting the
positions into a `layout()` called from `refresh_callback` rendered the
background on both heads and **nothing else**: no logo, no progress bar. The
script plugin logs `starting boot animation` and **no parse error**, so it
fails *silently* — reverted rather than shipped (that script draws the LUKS box
on an encrypted machine). Next session: bisect with the fast loop. Prime
suspect is scope — plymouth script assigns into `local` unless the name already
exists, so a `logo.image = …` inside a function may not be the `logo` the rest
of the script sees, even though the same pattern works in `update_progress_bar`.
Test that hypothesis *first*, in isolation, before rewriting anything.
Pass = with the rig, a two-head render centred on both **plus the password
dialog visible**; then a real docked boot + shutdown, undocked unchanged.
### 143. Rofi keeps the selected *row number* when the search changes, so the highlight lands on an unrelated entry