fix(session): mount the boot FAT at /boot/firmware on Bookworm
Raspberry Pi OS Bookworm keeps the FAT boot partition at /boot/firmware, where the raspi-firmware post-update hook syncs the initramfs. Binding it at /boot in the chroot sent update-initramfs's output to the ext4 root, so the firmware booted a stock initramfs without cryptsetup -> (initramfs) emergency shell, no LUKS prompt. boot_bind_target() detects the layout and binds (and unmounts) the FAT at the right place; legacy single-FAT layouts still use /boot. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -88,10 +88,24 @@ class ImageSession:
|
||||
ui.info("The following mounts refering this setup exist:")
|
||||
runner.run(["findmnt", "-R", str(self.working_folder)], check=False)
|
||||
|
||||
def boot_bind_target(self) -> str:
|
||||
"""Where the FAT partition belongs inside the chroot.
|
||||
|
||||
Raspberry Pi OS Bookworm keeps it at /boot/firmware (the raspi-firmware
|
||||
post-update hook syncs the initramfs there); older layouts use /boot.
|
||||
Binding it wrong sends update-initramfs's output to the ext4 root, so the
|
||||
firmware boots a stock initramfs without cryptsetup -> initramfs shell.
|
||||
"""
|
||||
if (self.root_mount_path / "boot/firmware").is_dir():
|
||||
return f"{self.root_mount_path}/boot/firmware"
|
||||
return f"{self.root_mount_path}/boot"
|
||||
|
||||
def mount_chroot_binds(self) -> None:
|
||||
ui.info("Mount chroot environments...")
|
||||
root = self.root_mount_path
|
||||
runner.run(["mount", "--bind", str(self.boot_mount_path), f"{root}/boot"], sudo=True)
|
||||
runner.run(
|
||||
["mount", "--bind", str(self.boot_mount_path), self.boot_bind_target()], sudo=True
|
||||
)
|
||||
runner.run(["mount", "--bind", "/dev", f"{root}/dev"], sudo=True)
|
||||
runner.run(["mount", "--bind", "/sys", f"{root}/sys"], sudo=True)
|
||||
runner.run(["mount", "--bind", "/proc", f"{root}/proc"], sudo=True)
|
||||
@@ -142,7 +156,7 @@ class ImageSession:
|
||||
self._umount(f"{root}/dev", lazy=True)
|
||||
self._umount(f"{root}/proc")
|
||||
self._umount(f"{root}/sys")
|
||||
self._umount(f"{root}/boot")
|
||||
self._umount(self.boot_bind_target())
|
||||
self._umount(str(root))
|
||||
if self.boot_mount_path is not None:
|
||||
self._umount(str(self.boot_mount_path))
|
||||
|
||||
@@ -60,3 +60,17 @@ def test_destructor_closes_luks_mapper(tmp_path, fake_runner):
|
||||
session.decrypt_root()
|
||||
session.destructor()
|
||||
assert len(fake_runner.find("luksClose", "linux-image-manager-uuid-1")) == 1
|
||||
|
||||
|
||||
def test_boot_bind_target_bookworm_uses_boot_firmware(tmp_path):
|
||||
session = ImageSession(Device("sda"))
|
||||
session.root_mount_path = tmp_path
|
||||
(tmp_path / "boot/firmware").mkdir(parents=True)
|
||||
assert session.boot_bind_target() == f"{tmp_path}/boot/firmware"
|
||||
|
||||
|
||||
def test_boot_bind_target_legacy_uses_boot(tmp_path):
|
||||
session = ImageSession(Device("sda"))
|
||||
session.root_mount_path = tmp_path
|
||||
(tmp_path / "boot").mkdir()
|
||||
assert session.boot_bind_target() == f"{tmp_path}/boot"
|
||||
|
||||
Reference in New Issue
Block a user