orchestrator: converge free-space boot on finalizer

This commit is contained in:
Ryan Hughes committed 2026-05-22 16:33:11 -04:00
1 parent 948a53cc0a
commit de0f013b5e
2 files changed
+67 -139

No files matched your search

+1 -1
View File
@@ -634,7 +634,7 @@ _EOF_
{
"esp_device": "$efi_dev",
"esp_mount": "$esp_mount_in_target",
"esp_path": "/EFI/Omarchy",
"esp_path": "/EFI/limine",
"luks_uuid": $luks_uuid_json,
"root_device": "$root_partition_device",
"kernel": "$kernel_choice"
@@ -536,15 +536,13 @@ def arch_install_base(ctx: InstallContext) -> None:
# ─────────────────────────────────────────────────────────────────────────────
# configure_protected_boot: Omarchy-owned fstab/crypttab/mkinitcpio/bootloader.
# configure_protected_boot: protected-mode fstab + Limine handoff.
#
# 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
# Free-space installs should converge with full-disk installs as soon as the
# target is mounted. This phase only writes the mount/boot intent that the
# common finalizer needs, and registers a Limine EFI entry on the chosen ESP.
# The final UKI/initramfs build is deliberately left to login/limine-snapper.sh
# (`limine-update`), same as full-disk installs.
# ─────────────────────────────────────────────────────────────────────────────
def configure_protected_boot(ctx: InstallContext) -> None:
@@ -557,18 +555,15 @@ def configure_protected_boot(ctx: InstallContext) -> None:
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("› writing Limine defaults")
_write_protected_limine_defaults(ctx, protected)
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("› installing Limine into protected ESP")
_install_protected_limine_efi(ctx, protected)
info("› registering efibootmgr entry")
_register_efibootmgr_entry(ctx, protected, pre_state)
@@ -645,123 +640,66 @@ def _write_crypttab(ctx: InstallContext, protected: dict) -> None:
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: {kernel_path}
cmdline: {cmdline}
module_path: {initrd_path}
/Omarchy Linux (fallback)
protocol: linux
path: {kernel_path}
cmdline: {cmdline}
module_path: {initrd_fb_path}
"""
def _protected_esp_mount(ctx: InstallContext, protected: dict) -> Path:
return ctx.target / protected["esp_mount"].lstrip("/")
def _omarchy_esp_path(ctx: InstallContext, protected: dict) -> Path:
esp_mount = ctx.target / protected["esp_mount"].lstrip("/")
return esp_mount / protected["esp_path"].lstrip("/")
return _protected_esp_mount(ctx, protected) / 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"
"root=/dev/mapper/omarchy_root zswap.enabled=0 "
"rootflags=subvol=@ rw rootfstype=btrfs"
)
return (
f"root=UUID={btrfs_uuid} rw "
"rootflags=subvol=@ rootfstype=btrfs quiet splash"
f"root=UUID={btrfs_uuid} zswap.enabled=0 "
"rootflags=subvol=@ rw rootfstype=btrfs"
)
def _install_limine(ctx: InstallContext, protected: dict) -> None:
def _write_protected_limine_defaults(ctx: InstallContext, protected: dict) -> None:
btrfs_uuid = _blkid_uuid(_btrfs_root_device(protected))
cmdline = _build_cmdline(protected, btrfs_uuid)
default_text = _limine_template(ctx, "default.conf").read_text()
default_text = default_text.replace("@@CMDLINE@@", cmdline)
default_text = re.sub(r'^ESP_PATH=.*$', f'ESP_PATH="{protected["esp_mount"]}"', default_text, flags=re.MULTILINE)
# Free-space installs may share a Windows ESP. Never claim EFI/BOOT as a
# fallback loader in that mode; use the explicit NVRAM entry instead.
default_text = re.sub(r'^ENABLE_LIMINE_FALLBACK=.*$', 'ENABLE_LIMINE_FALLBACK=no', default_text, flags=re.MULTILINE)
default_limine = ctx.target / "etc" / "default" / "limine"
default_limine.parent.mkdir(parents=True, exist_ok=True)
default_limine.write_text(default_text)
kernel_cmdline = ctx.target / "etc" / "kernel" / "cmdline"
kernel_cmdline.parent.mkdir(parents=True, exist_ok=True)
kernel_cmdline.write_text(cmdline + "\n")
def _install_protected_limine_efi(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)
limine_dir = _omarchy_esp_path(ctx, protected)
limine_dir.mkdir(parents=True, exist_ok=True)
shutil.copy2(src, limine_dir / "limine_x64.efi")
dst = omarchy_esp / "BOOTX64.EFI"
shutil.copy2(src, dst)
btrfs_uuid = _blkid_uuid(_btrfs_root_device(protected))
kernel = protected["kernel"]
if protected["esp_mount"] == "/boot":
kernel_path = f"boot():/vmlinuz-{kernel}"
initrd_path = f"boot():/initramfs-{kernel}.img"
initrd_fb_path = f"boot():/initramfs-{kernel}-fallback.img"
elif protected["esp_mount"] == "/efi":
kernel_path = f"uuid({btrfs_uuid}):/@/boot/vmlinuz-{kernel}"
initrd_path = f"uuid({btrfs_uuid}):/@/boot/initramfs-{kernel}.img"
initrd_fb_path = f"uuid({btrfs_uuid}):/@/boot/initramfs-{kernel}-fallback.img"
else:
raise RuntimeError(f"unsupported ESP mountpoint: {protected['esp_mount']}")
cmdline = _build_cmdline(protected, btrfs_uuid)
conf = LIMINE_CONF_TEMPLATE.format(
kernel_path=kernel_path,
initrd_path=initrd_path,
initrd_fb_path=initrd_fb_path,
cmdline=cmdline,
esp_mount_target = Path(protected["esp_mount"])
hook_command = (
f"/usr/bin/cp /usr/share/limine/BOOTX64.EFI "
f"{esp_mount_target / protected['esp_path'].lstrip('/')}/limine_x64.efi"
)
(omarchy_esp / "limine.conf").write_text(conf)
_write_limine_pacman_hook(ctx.target, hook_command)
# ── efibootmgr ───────────────────────────────────────────────────────────────
@@ -814,9 +752,9 @@ def _register_efibootmgr_entry(
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"):
# Clean up any stale Limine entries pointing at our protected install path
# so we don't accumulate dupes across re-installs.
for num in _find_label_entries(pre_state["entries"], "Limine"):
subprocess.run(
["efibootmgr", "--bootnum", num, "--delete-bootnum"],
check=False, capture_output=True,
@@ -828,18 +766,18 @@ def _register_efibootmgr_entry(
"--create",
"--disk", disk,
"--part", str(part_num),
"--label", "Omarchy Linux",
"--loader", "\\EFI\\Omarchy\\BOOTX64.EFI",
"--label", "Limine",
"--loader", "\\EFI\\limine\\limine_x64.efi",
"--unicode",
],
check=True, capture_output=True, text=True,
)
post = _read_efibootmgr()
new_omarchy = _find_label_entries(post["entries"], "Omarchy Linux")
new_omarchy = _find_label_entries(post["entries"], "Limine")
if not new_omarchy:
raise RuntimeError(
"efibootmgr --create reported success but no Omarchy Linux entry found"
"efibootmgr --create reported success but no Limine entry found"
)
omarchy_num = new_omarchy[0]
@@ -1028,25 +966,26 @@ def validate_boot_full(ctx: InstallContext) -> None:
# ─────────────────────────────────────────────────────────────────────────────
# validate_boot_protected: hard checks for the dualboot/protected path.
# Mirrors validate_boot_full but checks the Omarchy ESP subdir, fstab/crypttab,
# kernel/initramfs presence, and efibootmgr entry registration.
# Mirrors validate_boot_full but checks the protected ESP, fstab/crypttab,
# final Limine UKI, and efibootmgr entry registration.
# ─────────────────────────────────────────────────────────────────────────────
def validate_boot_protected(ctx: InstallContext) -> None:
protected = ctx.state["protected"]
kernel = protected["kernel"]
omarchy_esp = _omarchy_esp_path(ctx, protected)
limine_dir = _omarchy_esp_path(ctx, protected)
esp_mount = _protected_esp_mount(ctx, protected)
bootx64 = omarchy_esp / "BOOTX64.EFI"
bootx64 = limine_dir / "limine_x64.efi"
if not bootx64.exists() or bootx64.stat().st_size == 0:
raise RuntimeError(f"{bootx64} missing or empty")
limine_conf = omarchy_esp / "limine.conf"
limine_conf = esp_mount / "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")
if "Omarchy" not in limine_conf.read_text():
raise RuntimeError(f"{limine_conf} has no Omarchy entry")
fstab = ctx.target / "etc" / "fstab"
if not fstab.exists():
@@ -1066,24 +1005,13 @@ def validate_boot_protected(ctx: InstallContext) -> None:
if protected["luks_uuid"] not in crypttab.read_text():
raise RuntimeError(f"{crypttab} missing LUKS UUID {protected['luks_uuid']}")
if protected["esp_mount"] == "/boot":
kernel_dir = ctx.target / protected["esp_mount"].lstrip("/")
elif protected["esp_mount"] == "/efi":
kernel_dir = ctx.target / "boot"
else:
raise RuntimeError(f"unsupported ESP mountpoint: {protected['esp_mount']}")
vmlinuz = kernel_dir / f"vmlinuz-{kernel}"
if not vmlinuz.exists():
raise RuntimeError(f"{vmlinuz} missing")
initramfs = kernel_dir / f"initramfs-{kernel}.img"
if not initramfs.exists():
raise RuntimeError(f"{initramfs} missing")
uki = esp_mount / "EFI" / "Linux" / f"omarchy_{kernel}.efi"
if not uki.exists() or uki.stat().st_size == 0:
raise RuntimeError(f"{uki} missing or empty")
post = _read_efibootmgr()
if not _find_label_entries(post["entries"], "Omarchy Linux"):
raise RuntimeError("no 'Omarchy Linux' entry registered in efibootmgr")
if not _find_label_entries(post["entries"], "Limine"):
raise RuntimeError("no 'Limine' entry registered in efibootmgr")
# ─────────────────────────────────────────────────────────────────────────────