orchestrator: implement protected-mode boot (Limine in EFI/Omarchy, fstab/crypttab/mkinitcpio, efibootmgr with BootOrder preservation)

This commit is contained in:
Ryan committed 2026-05-21 18:18:50 -04:00
1 parent 26e6a78d3a
commit 05a1c6f271
1 file changed
+350 -7
@@ -33,6 +33,7 @@ from __future__ import annotations
import json
import os
import re
import shutil
import subprocess
from pathlib import Path
@@ -340,12 +341,312 @@ def arch_install_base(ctx: InstallContext) -> None:
# ─────────────────────────────────────────────────────────────────────────────
# configure_protected_boot: Omarchy-owned fstab/crypttab/mkinitcpio/bootloader.
# Implemented in Step 8.
#
# Order:
# 1. fstab — written from our known mount intent (no genfstab)
# 2. crypttab + mkinitcpio.conf — encrypt/btrfs hooks + initramfs btrfs deps
# 3. mkinitcpio -P — generate /boot/initramfs-{kernel}{,-fallback}.img
# 4. Limine into EFI/Omarchy — never touches EFI/Microsoft or EFI/BOOT
# 5. efibootmgr entry, BootOrder preserves whatever was there + Omarchy first
# 6. Sanity: Windows entry must survive
# ─────────────────────────────────────────────────────────────────────────────
def configure_protected_boot(ctx: InstallContext) -> None:
raise NotImplementedError(
"Implemented in Step 8 — see REFACTOR-PLAN-C3-EXECUTION.md"
protected = ctx.state["protected"]
info("› ensuring limine + efibootmgr installed in target")
subprocess.run(
["arch-chroot", str(ctx.target), "pacman", "-S",
"--needed", "--noconfirm", "limine", "efibootmgr"],
check=True,
)
info("› writing /etc/fstab")
_write_fstab(ctx, protected)
if protected.get("luks_uuid"):
info("› writing /etc/crypttab.initramfs")
_write_crypttab(ctx, protected)
info("› editing /etc/mkinitcpio.conf")
_edit_mkinitcpio_conf(ctx, protected)
info("› running mkinitcpio -P")
_run_mkinitcpio(ctx)
info("› capturing efibootmgr state pre-install")
pre_state = _read_efibootmgr()
windows_before = _find_label_entries(pre_state["entries"], "Windows")
info("› installing Limine into EFI/Omarchy")
_install_limine(ctx, protected)
info("› registering efibootmgr entry")
_register_efibootmgr_entry(ctx, protected, pre_state)
info("› verifying Windows boot entry survived")
post_state = _read_efibootmgr()
windows_after = _find_label_entries(post_state["entries"], "Windows")
if windows_before and not windows_after:
raise RuntimeError(
"Windows boot entry disappeared during Limine install — aborting"
)
# ── fstab ────────────────────────────────────────────────────────────────────
def _btrfs_root_device(protected: dict) -> str:
"""Device that holds the btrfs filesystem (mapper for encrypted, raw
partition for plain)."""
if protected.get("luks_uuid"):
return "/dev/mapper/omarchy_root"
return protected["root_device"]
def _blkid_uuid(device: str) -> str:
res = subprocess.run(
["blkid", "-s", "UUID", "-o", "value", device],
capture_output=True, text=True, check=True,
)
uuid = res.stdout.strip()
if not uuid:
raise RuntimeError(f"blkid returned no UUID for {device}")
return uuid
def _esp_device(ctx: InstallContext, protected: dict) -> str:
esp_mp = ctx.target / protected["esp_mount"].lstrip("/")
res = subprocess.run(
["findmnt", "-n", "-o", "SOURCE", str(esp_mp)],
capture_output=True, text=True, check=True,
)
dev = res.stdout.strip()
if not dev:
raise RuntimeError(f"could not resolve ESP device at {esp_mp}")
return dev
def _write_fstab(ctx: InstallContext, protected: dict) -> None:
btrfs_dev = _btrfs_root_device(protected)
btrfs_uuid = _blkid_uuid(btrfs_dev)
esp_dev = _esp_device(ctx, protected)
esp_uuid = _blkid_uuid(esp_dev)
esp_mount = protected["esp_mount"]
btrfs_opts = "noatime,compress=zstd,subvol="
lines = [
"# /etc/fstab — generated by omarchy installer (protected mode)",
"# <device> <mount> <fs> <options> <dump> <pass>",
f"UUID={btrfs_uuid} / btrfs {btrfs_opts}@ 0 0",
f"UUID={btrfs_uuid} /home btrfs {btrfs_opts}@home 0 0",
f"UUID={btrfs_uuid} /var/log btrfs {btrfs_opts}@log 0 0",
f"UUID={btrfs_uuid} /var/cache/pacman/pkg btrfs {btrfs_opts}@pkg 0 0",
f"UUID={esp_uuid} {esp_mount} vfat umask=0077 0 2",
"",
]
fstab = ctx.target / "etc" / "fstab"
fstab.write_text("\n".join(lines))
# ── crypttab ─────────────────────────────────────────────────────────────────
def _write_crypttab(ctx: InstallContext, protected: dict) -> None:
luks_uuid = protected["luks_uuid"]
crypttab = ctx.target / "etc" / "crypttab.initramfs"
crypttab.write_text(f"omarchy_root UUID={luks_uuid} none luks,discard\n")
# ── mkinitcpio.conf ──────────────────────────────────────────────────────────
def _edit_mkinitcpio_conf(ctx: InstallContext, protected: dict) -> None:
conf = ctx.target / "etc" / "mkinitcpio.conf"
text = conf.read_text()
if protected.get("luks_uuid"):
hooks = (
"HOOKS=(base udev autodetect microcode modconf kms keyboard "
"keymap consolefont block encrypt filesystems fsck)"
)
else:
hooks = (
"HOOKS=(base udev autodetect microcode modconf kms keyboard "
"keymap consolefont block filesystems fsck)"
)
text = _replace_assignment(text, "HOOKS", hooks)
text = _replace_assignment(text, "MODULES", "MODULES=(btrfs)")
text = _replace_assignment(text, "BINARIES", "BINARIES=(/usr/bin/btrfs)")
conf.write_text(text)
def _replace_assignment(text: str, key: str, new_line: str) -> str:
"""Replace a `KEY=(...)` line in mkinitcpio.conf-style text. If the key
isn't present, append the line."""
pattern = re.compile(rf"^{re.escape(key)}=\(.*\)\s*$", re.MULTILINE)
if pattern.search(text):
return pattern.sub(new_line, text, count=1)
if not text.endswith("\n"):
text += "\n"
return text + new_line + "\n"
# ── mkinitcpio ───────────────────────────────────────────────────────────────
def _run_mkinitcpio(ctx: InstallContext) -> None:
subprocess.run(
["arch-chroot", str(ctx.target), "mkinitcpio", "-P"],
check=True,
)
# ── Limine ───────────────────────────────────────────────────────────────────
LIMINE_CONF_TEMPLATE = """\
timeout: 3
default_entry: 1
interface_branding: Omarchy Bootloader
/Omarchy Linux
protocol: linux
path: uuid({btrfs_uuid}):/@/boot/vmlinuz-{kernel}
cmdline: {cmdline}
module_path: uuid({btrfs_uuid}):/@/boot/initramfs-{kernel}.img
/Omarchy Linux (fallback)
protocol: linux
path: uuid({btrfs_uuid}):/@/boot/vmlinuz-{kernel}
cmdline: {cmdline}
module_path: uuid({btrfs_uuid}):/@/boot/initramfs-{kernel}-fallback.img
"""
def _omarchy_esp_path(ctx: InstallContext, protected: dict) -> Path:
esp_mount = ctx.target / protected["esp_mount"].lstrip("/")
return esp_mount / protected["esp_path"].lstrip("/")
def _build_cmdline(protected: dict, btrfs_uuid: str) -> str:
if protected.get("luks_uuid"):
return (
f"cryptdevice=UUID={protected['luks_uuid']}:omarchy_root "
"root=/dev/mapper/omarchy_root rw "
"rootflags=subvol=@ rootfstype=btrfs quiet splash"
)
return (
f"root=UUID={btrfs_uuid} rw "
"rootflags=subvol=@ rootfstype=btrfs quiet splash"
)
def _install_limine(ctx: InstallContext, protected: dict) -> None:
src = ctx.target / "usr" / "share" / "limine" / "BOOTX64.EFI"
if not src.exists():
raise RuntimeError(
f"Limine EFI binary not found at {src} — limine package missing in target"
)
omarchy_esp = _omarchy_esp_path(ctx, protected)
omarchy_esp.mkdir(parents=True, exist_ok=True)
dst = omarchy_esp / "BOOTX64.EFI"
shutil.copy2(src, dst)
btrfs_uuid = _blkid_uuid(_btrfs_root_device(protected))
cmdline = _build_cmdline(protected, btrfs_uuid)
conf = LIMINE_CONF_TEMPLATE.format(
btrfs_uuid=btrfs_uuid,
kernel=protected["kernel"],
cmdline=cmdline,
)
(omarchy_esp / "limine.conf").write_text(conf)
# ── efibootmgr ───────────────────────────────────────────────────────────────
_BOOT_ENTRY_RE = re.compile(r"^Boot([0-9A-Fa-f]{4})\*?\s+(.*)$")
_BOOT_ORDER_RE = re.compile(r"^BootOrder:\s*(.*)$")
def _read_efibootmgr() -> dict:
res = subprocess.run(
["efibootmgr"],
capture_output=True, text=True, check=True,
)
entries: dict[str, str] = {}
order: list[str] = []
for line in res.stdout.splitlines():
m = _BOOT_ENTRY_RE.match(line)
if m:
entries[m.group(1).upper()] = m.group(2).strip()
continue
m = _BOOT_ORDER_RE.match(line)
if m:
order = [n.strip().upper() for n in m.group(1).split(",") if n.strip()]
return {"entries": entries, "order": order, "raw": res.stdout}
def _find_label_entries(entries: dict[str, str], needle: str) -> list[str]:
return [num for num, label in entries.items() if needle.lower() in label.lower()]
def _split_partition_device(part_dev: str) -> tuple[str, int]:
parent = subprocess.run(
["lsblk", "-ndo", "PKNAME", part_dev],
capture_output=True, text=True, check=True,
).stdout.strip()
if not parent:
raise RuntimeError(f"could not find parent disk for {part_dev}")
part_num = subprocess.run(
["lsblk", "-ndo", "PARTN", part_dev],
capture_output=True, text=True, check=True,
).stdout.strip()
if not part_num:
raise RuntimeError(f"could not find partition number for {part_dev}")
return f"/dev/{parent}", int(part_num)
def _register_efibootmgr_entry(
ctx: InstallContext, protected: dict, pre_state: dict
) -> None:
esp_dev = _esp_device(ctx, protected)
disk, part_num = _split_partition_device(esp_dev)
# Clean up any stale "Omarchy Linux" entries so we don't accumulate dupes
# across re-installs.
for num in _find_label_entries(pre_state["entries"], "Omarchy Linux"):
subprocess.run(
["efibootmgr", "--bootnum", num, "--delete-bootnum"],
check=False, capture_output=True,
)
subprocess.run(
[
"efibootmgr",
"--create",
"--disk", disk,
"--part", str(part_num),
"--label", "Omarchy Linux",
"--loader", "\\EFI\\Omarchy\\BOOTX64.EFI",
"--unicode",
],
check=True, capture_output=True, text=True,
)
post = _read_efibootmgr()
new_omarchy = _find_label_entries(post["entries"], "Omarchy Linux")
if not new_omarchy:
raise RuntimeError(
"efibootmgr --create reported success but no Omarchy Linux entry found"
)
omarchy_num = new_omarchy[0]
# Preserve the original BootOrder, but put Omarchy first.
keep = [n for n in pre_state["order"] if n not in new_omarchy]
new_order = ",".join([omarchy_num, *keep])
subprocess.run(
["efibootmgr", "--bootorder", new_order],
check=True, capture_output=True,
)
@@ -498,13 +799,55 @@ def validate_boot_full(ctx: InstallContext) -> None:
# ─────────────────────────────────────────────────────────────────────────────
# validate_boot_protected: hard checks for the dualboot/protected path.
# Implemented in Step 8.
# Mirrors validate_boot_full but checks the Omarchy ESP subdir, fstab/crypttab,
# kernel/initramfs presence, and efibootmgr entry registration.
# ─────────────────────────────────────────────────────────────────────────────
def validate_boot_protected(ctx: InstallContext) -> None:
raise NotImplementedError(
"Implemented in Step 8 — see REFACTOR-PLAN-C3-EXECUTION.md"
)
protected = ctx.state["protected"]
kernel = protected["kernel"]
omarchy_esp = _omarchy_esp_path(ctx, protected)
bootx64 = omarchy_esp / "BOOTX64.EFI"
if not bootx64.exists() or bootx64.stat().st_size == 0:
raise RuntimeError(f"{bootx64} missing or empty")
limine_conf = omarchy_esp / "limine.conf"
if not limine_conf.exists():
raise RuntimeError(f"{limine_conf} missing")
if "/Omarchy Linux" not in limine_conf.read_text():
raise RuntimeError(f"{limine_conf} has no /Omarchy Linux entry")
fstab = ctx.target / "etc" / "fstab"
if not fstab.exists():
raise RuntimeError(f"{fstab} missing")
fstab_text = fstab.read_text()
btrfs_uuid = _blkid_uuid(_btrfs_root_device(protected))
esp_uuid = _blkid_uuid(_esp_device(ctx, protected))
if btrfs_uuid not in fstab_text:
raise RuntimeError(f"{fstab} missing btrfs UUID {btrfs_uuid}")
if esp_uuid not in fstab_text:
raise RuntimeError(f"{fstab} missing ESP UUID {esp_uuid}")
if protected.get("luks_uuid"):
crypttab = ctx.target / "etc" / "crypttab.initramfs"
if not crypttab.exists():
raise RuntimeError(f"{crypttab} missing")
if protected["luks_uuid"] not in crypttab.read_text():
raise RuntimeError(f"{crypttab} missing LUKS UUID {protected['luks_uuid']}")
vmlinuz = ctx.target / "boot" / f"vmlinuz-{kernel}"
if not vmlinuz.exists():
raise RuntimeError(f"{vmlinuz} missing")
initramfs = ctx.target / "boot" / f"initramfs-{kernel}.img"
if not initramfs.exists():
raise RuntimeError(f"{initramfs} missing")
post = _read_efibootmgr()
if not _find_label_entries(post["entries"], "Omarchy Linux"):
raise RuntimeError("no 'Omarchy Linux' entry registered in efibootmgr")
# ─────────────────────────────────────────────────────────────────────────────