tools: preview the plymouth splash unprivileged; #137 attempt 1 reverted
All checks were successful
Check / eval (push) Successful in 3m49s
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:
@@ -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
|
included), entry, lock, any live bullets, progress box/bar. Keep it a
|
||||||
canvas-change check, not an every-frame recompute.
|
canvas-change check, not an every-frame recompute.
|
||||||
|
|
||||||
**Testing — the rig exists, and it needs root.** nixpkgs' plymouth ships
|
**The rig works, needs no root, and is in `scratchpad/ply-rig.sh`** (recipe
|
||||||
`x11.so`, and plymouth has a built-in fake dual-head mode:
|
below — rebuild it, it is ~20 lines). Rendered on the dev box 2026-07-16:
|
||||||
`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.
|
|
||||||
|
|
||||||
**Do not ship this blind:** the same script draws the **LUKS passphrase box**,
|
- `unshare -rm` gives a user + mount namespace: root *in there* only, every
|
||||||
this machine is encrypted, and a script that fails to parse leaves a prompt you
|
mount invisible to the real system and gone when it exits.
|
||||||
cannot see. Pass = with the rig, a two-head render centred on both; then a real
|
- `/run/plymouth` is BOTH the daemon's socket dir **and** its compiled-in
|
||||||
docked boot + shutdown, undocked unchanged.
|
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
|
### 143. Rofi keeps the selected *row number* when the search changes, so the highlight lands on an unrelated entry
|
||||||
|
|
||||||
|
|||||||
@@ -108,6 +108,19 @@ unattended env it uses is in the script, and the same flow works
|
|||||||
interactively from the live terminal. If the desktop comes up unthemed,
|
interactively from the live terminal. If the desktop comes up unthemed,
|
||||||
read `/var/log/nomarchy-hm-preactivate.log` on the installed system.
|
read `/var/log/nomarchy-hm-preactivate.log` on the installed system.
|
||||||
|
|
||||||
|
`tools/plymouth-preview.sh` renders the **boot splash** — including the LUKS
|
||||||
|
password dialog — into X11 windows in about ten seconds: no reboot, no root,
|
||||||
|
and no DRM. It runs plymouthd inside `unshare -rm` (a user + mount namespace),
|
||||||
|
binds a writable dir over `/run/plymouth` (which is both the daemon's socket
|
||||||
|
dir *and* its compiled-in plugin path), masks `/dev/dri` so a preview can never
|
||||||
|
mode-set a real output, and sets `PLY_CREATE_FAKE_MULTI_HEAD_SETUP` for plymouth's
|
||||||
|
built-in fake dual head. Pass it a theme store path to iterate on the script
|
||||||
|
without a rebuild. Use it before touching `modules/nixos/plymouth/`: that script
|
||||||
|
draws the passphrase box, a failure there is silent (the plugin logs
|
||||||
|
`starting boot animation` and no error), and "type your LUKS password blind" is
|
||||||
|
a bad way to find out. Its limit: the fake heads exist from the start, so it
|
||||||
|
cannot reproduce a head arriving *mid-splash* (#137).
|
||||||
|
|
||||||
Two full-desktop VM harnesses (softGL Hyprland, too heavy for `checks.*`)
|
Two full-desktop VM harnesses (softGL Hyprland, too heavy for `checks.*`)
|
||||||
live next to the scripts: `tools/theme-shot.nix` (themed-desktop
|
live next to the scripts: `tools/theme-shot.nix` (themed-desktop
|
||||||
screenshots) and `tools/monitor-fallback.nix` (KVM display transitions:
|
screenshots) and `tools/monitor-fallback.nix` (KVM display transitions:
|
||||||
|
|||||||
64
tools/plymouth-preview.sh
Executable file
64
tools/plymouth-preview.sh
Executable file
@@ -0,0 +1,64 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# Render the Plymouth splash in X11 windows — no root, no reboot, no DRM (#137).
|
||||||
|
#
|
||||||
|
# tools/plymouth-preview.sh [<theme-store-path>]
|
||||||
|
#
|
||||||
|
# Plymouth is otherwise untestable without rebooting, which is a poor loop for
|
||||||
|
# a script that draws the LUKS passphrase box on an encrypted machine. This
|
||||||
|
# gives you a real render in seconds:
|
||||||
|
#
|
||||||
|
# * `unshare -rm` = user + mount namespace. We are root only in here, and
|
||||||
|
# every mount below dies with the process.
|
||||||
|
# * /run/plymouth is both the daemon's socket dir AND its 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
|
||||||
|
# cannot find x11.so, silently skips X11, and goes looking for a tty.
|
||||||
|
# * X11 is first in plymouth's renderer order (ply-renderer.c:283) and is
|
||||||
|
# taken only while default_tty is unset — so never pass --tty. /dev/dri is
|
||||||
|
# masked as well: a preview must not be able to mode-set the real outputs.
|
||||||
|
# * PLY_CREATE_FAKE_MULTI_HEAD_SETUP (renderers/x11/plugin.c) fakes two heads
|
||||||
|
# (800x600 + 640x480) — the multi-monitor case, on a single-monitor desk.
|
||||||
|
#
|
||||||
|
# Caveat: the fake heads are created up front, so this proves rendering and
|
||||||
|
# centring, NOT #137's canvas-change bug (a head arriving mid-splash).
|
||||||
|
set -u
|
||||||
|
THEME="${1:-}"
|
||||||
|
PLY=$(nix build --no-link --print-out-paths nixpkgs#plymouth 2>/dev/null | head -1)
|
||||||
|
[ -n "$PLY" ] || { echo "could not build plymouth" >&2; exit 1; }
|
||||||
|
[ -n "${DISPLAY:-}" ] || { echo "no DISPLAY — the x11 renderer needs Xwayland" >&2; exit 1; }
|
||||||
|
|
||||||
|
export PLY THEME
|
||||||
|
unshare -rm -- bash -euc '
|
||||||
|
rm -rf /tmp/plyrig; mkdir -p /tmp/plyrig/run /tmp/plyrig/dri /tmp/plyrig/themes
|
||||||
|
if [ -n "$THEME" ]; then
|
||||||
|
cp -rL "$THEME/share/plymouth/themes/nomarchy" /tmp/plyrig/themes/
|
||||||
|
# The .plymouth bakes absolute store paths at build time; point them at the
|
||||||
|
# copy so the script here is the one that renders (edit + rerun = seconds).
|
||||||
|
sed -i "s|^ScriptFile=.*|ScriptFile=/tmp/plyrig/themes/nomarchy/nomarchy.script|;
|
||||||
|
s|^ImageDir=.*|ImageDir=/tmp/plyrig/themes/nomarchy|" \
|
||||||
|
/tmp/plyrig/themes/nomarchy/nomarchy.plymouth
|
||||||
|
ln -s /tmp/plyrig/themes /tmp/plyrig/run/themes
|
||||||
|
else
|
||||||
|
ln -s /etc/plymouth/themes /tmp/plyrig/run/themes
|
||||||
|
fi
|
||||||
|
ln -s /etc/plymouth/plugins /tmp/plyrig/run/plugins
|
||||||
|
ln -s /etc/plymouth/plymouthd.defaults /tmp/plyrig/run/plymouthd.defaults
|
||||||
|
mount --bind /tmp/plyrig/run /run/plymouth
|
||||||
|
mount --bind /tmp/plyrig/dri /dev/dri 2>/dev/null || true
|
||||||
|
|
||||||
|
export PLY_CREATE_FAKE_MULTI_HEAD_SETUP=1
|
||||||
|
"$PLY/sbin/plymouthd" --no-daemon --mode=boot --no-boot-log \
|
||||||
|
--kernel-command-line="plymouth.debug=stream:/tmp/plyrig/dbg.log splash" \
|
||||||
|
>/dev/null 2>&1 &
|
||||||
|
d=$!
|
||||||
|
sleep 2
|
||||||
|
"$PLY/bin/plymouth" show-splash >/dev/null 2>&1
|
||||||
|
echo "splash up — two windows (800x600, 640x480). Ctrl+C or wait 20s."
|
||||||
|
sleep 8
|
||||||
|
"$PLY/bin/plymouth" ask-for-password --prompt="Unlock" --number-of-tries=1 >/dev/null 2>&1 &
|
||||||
|
echo "password dialog requested (the LUKS path)"
|
||||||
|
sleep 10
|
||||||
|
"$PLY/bin/plymouth" quit >/dev/null 2>&1; sleep 1; kill $d 2>/dev/null
|
||||||
|
cp /tmp/plyrig/dbg.log /tmp/plymouth-preview.log 2>/dev/null
|
||||||
|
echo "log: /tmp/plymouth-preview.log"
|
||||||
|
'
|
||||||
Reference in New Issue
Block a user