deploy: one-shot boot without the bootloader's help (terra runs Limine)

`install <config> localhost` assumed systemd-boot. terra's CachyOS boots
Limine, so it stopped at "/boot/loader/entries doesn't exist" — the check
added in e538788 doing its job, but with nowhere to go.

Limine cannot help here at all: `bootctl status` lists it as
`✗ One-shot entry control`, and CachyOS's pacman hooks regenerate
limine.conf regardless. So drop below the bootloader entirely and use the
firmware's own BootNext, pointing at a temporary UEFI entry that
EFI-stub-boots the installer kernel straight off the ESP. That keeps the
property which makes this safe to attempt: BootNext is spent by that one
boot, so a failed try still comes back on the normal bootloader.

  - picked at runtime: systemd-boot loader entry when $BOOT/loader/entries
    exists, else arm_efi_bootnext(). jupiter/neptun and terra-after-install
    keep the systemd-boot path.
  - `efibootmgr --create-only`, NOT `--create`: the latter pushes the entry
    to the front of BootOrder, which would make a wiped installer the
    permanent default if the install died halfway.
  - the EFI stub loads initrd= from the volume it was loaded from, so this
    mode stages on --print-esp-path rather than --print-boot-path.
  - stale entries from an earlier attempt are removed before adding one, and
    homelab-auto-install.service deletes the entry as soon as it boots, so
    nothing lingers in NVRAM pointing at a reformatted partition.
  - label matching is EXACT ("Homelab Installer"); a prefix match would have
    deleted this box's Windows or Limine entry.

Verified against terra's real NVRAM (read-only): the label parser picks out
Limine/UEFI OS/Windows by exact name and rejects prefixes, and both branches
run end-to-end under stubs — BootNext mode emits the right --disk/--part,
loader path and initrd= cmdline, systemd-boot mode still writes its entry and
never calls efibootmgr.

README/CLAUDE.md corrected: terra runs Limine, not systemd-boot.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-24 02:35:33 +02:00
co-authored by Claude Opus 4.8
parent e538788907
commit c87fd3b1f2
4 changed files with 148 additions and 17 deletions
+14
View File
@@ -131,6 +131,20 @@ kept its ssh host key. Run it after ANY change to the kexec paths.
`HOMELAB_INSTALLER_STAGE_DIR` skips the prompt for scripted use. Both this and
`kexec-local` self-elevate via `sudo` (`require_root()`) rather than requiring you to
prefix the command yourself.
- **terra runs Limine, not systemd-boot** — `bootctl set-oneshot` is useless there
(`bootctl status` lists `✗ One-shot entry control`, and CachyOS's pacman hooks
regenerate `limine.conf` anyway). `local_install_prepare_and_reboot()` therefore
picks its one-shot mechanism at runtime: a systemd-boot loader entry when
`$BOOT/loader/entries` exists, otherwise `arm_efi_bootnext()` — a temporary UEFI
entry that EFI-stub-boots the kernel off the ESP, armed via the firmware's
`BootNext`. Created with `efibootmgr --create-only` (NOT `--create`, which pushes
it to the front of `BootOrder` and would make a wiped installer the permanent
default if anything went wrong). BootNext is spent by that one boot, so a failed
attempt still comes back on the normal bootloader. The EFI-stub path needs the
kernel on the **ESP** itself, not on a separate XBOOTLDR — hence `--print-esp-path`
rather than `--print-boot-path` in that mode. `homelab-auto-install.service` deletes
the leftover NVRAM entry as soon as it boots; both it and the script match the label
`Homelab Installer` EXACTLY (a prefix match would delete the Windows or Limine entry).
- **The staging-dir guard must fail CLOSED, and `findmnt` needs `--nofsroot`**: on btrfs
`findmnt -no SOURCE` prints `/dev/sdb2[/@]`, which `lsblk` cannot open, so a naive
parent-device lookup comes back empty. Treating empty as "different disk" silently