diff --git a/nixos/modules/system/boot/loader/systemd-boot/systemd-boot-builder.py b/nixos/modules/system/boot/loader/systemd-boot/systemd-boot-builder.py index d3dd29147651..6f46d38286c3 100644 --- a/nixos/modules/system/boot/loader/systemd-boot/systemd-boot-builder.py +++ b/nixos/modules/system/boot/loader/systemd-boot/systemd-boot-builder.py @@ -140,23 +140,30 @@ class SystemIdentifier(NamedTuple): @dataclass class BootFile: system_identifier: SystemIdentifier + current: bool path: Path writer: WriteBootFile @staticmethod - def from_source(system_identifier: SystemIdentifier, source: Path) -> "BootFile": + def from_source( + system_identifier: SystemIdentifier, current: bool, source: Path + ) -> "BootFile": return BootFile( system_identifier=system_identifier, + current=current, path=boot_path(source), writer=CopyWriter(source=source), ) @staticmethod def from_initrd( - system_identifier: SystemIdentifier, source: Path, initrd_secrets: Path | None + system_identifier: SystemIdentifier, + current: bool, + source: Path, + initrd_secrets: Path | None, ) -> "BootFile": if initrd_secrets is None: - return BootFile.from_source(system_identifier, source) + return BootFile.from_source(system_identifier, current, source) else: # We're trying to calculate a canonical path unique to # this initrd and secret-appender. The boot_path is the @@ -173,6 +180,7 @@ class BootFile: combined_hash = hashlib.sha256(combined.encode("utf-8")).hexdigest() return BootFile( system_identifier=system_identifier, + current=current, path=NIXOS_DIR / f"{combined_hash}-initrd.efi", writer=InitrdWithSecretsWriter( source=source, initrd_secrets=initrd_secrets @@ -181,7 +189,7 @@ class BootFile: @staticmethod def from_entry( - system_identifier: SystemIdentifier, contents: bytes + system_identifier: SystemIdentifier, current: bool, contents: bytes ) -> tuple["BootFile", str]: contents_hash = hashlib.sha256(contents).hexdigest() path_prefix = f"nixos-{contents_hash}" @@ -199,6 +207,7 @@ class BootFile: return ( BootFile( system_identifier=system_identifier, + current=current, path=path, writer=ContentsWriter(contents=contents), ), @@ -336,19 +345,23 @@ def boot_file( specialisation: str | None, machine_id: str | None, bootspec: BootSpec, + current: bool, ) -> tuple[BootFileList, str]: system_identifier = SystemIdentifier(profile, generation, specialisation) if specialisation: bootspec = bootspec.specialisations[specialisation] - kernel = BootFile.from_source(system_identifier, bootspec.kernel) + kernel = BootFile.from_source(system_identifier, current, bootspec.kernel) initrd = BootFile.from_initrd( system_identifier, + current, bootspec.initrd, Path(bootspec.initrdSecrets) if bootspec.initrdSecrets is not None else None, ) devicetree = None if bootspec.devicetree is not None: - devicetree = BootFile.from_source(system_identifier, bootspec.devicetree) + devicetree = BootFile.from_source( + system_identifier, current, bootspec.devicetree + ) kernel_params = " ".join([f"init={bootspec.init}"] + bootspec.kernelParams) build_time = int(system_dir(profile, generation, specialisation).stat().st_ctime) @@ -371,7 +384,9 @@ def boot_file( f"sort-key {bootspec.sortKey}", ] contents = "\n".join(filter(None, boot_entry)) - entry, bootctl_id = BootFile.from_entry(system_identifier, contents.encode("utf-8")) + entry, bootctl_id = BootFile.from_entry( + system_identifier, current, contents.encode("utf-8") + ) return (list(filter(None, [kernel, initrd, devicetree, entry])), bootctl_id) @@ -520,7 +535,9 @@ def install_bootloader(args: argparse.Namespace) -> None: for gen in gens: bootspec = get_bootspec(gen.profile, gen.generation) is_default = Path(bootspec.init).parent == default_config - new_boot_files, new_bootctl_id = boot_file(*gen, machine_id, bootspec) + new_boot_files, new_bootctl_id = boot_file( + *gen, machine_id, bootspec, current=is_default + ) boot_files.extend(new_boot_files) if is_default: default_entry_id = new_bootctl_id @@ -532,6 +549,7 @@ def install_bootloader(args: argparse.Namespace) -> None: specialisation_name, machine_id, bootspec, + current=is_default, ) boot_files.extend(new_boot_files) if is_default: @@ -599,7 +617,22 @@ def garbage_collect(gc_roots: BootFileList) -> None: def write_boot_files(boot_files: BootFileList) -> None: for boot_file in boot_files: boot_path = BOOT_MOUNT_POINT / boot_file.path - boot_file.writer.write_boot_file(boot_path) + try: + boot_file.writer.write_boot_file(boot_path) + except subprocess.CalledProcessError: + if boot_file.current: + print("failed to create initrd secrets!", file=sys.stderr) + sys.exit(1) + print( + "warning: failed to create initrd secrets for generation " + f"{boot_file.system_identifier.generation}, an older generation", + file=sys.stderr, + ) + print( + "note: this is normal after having removed " + "or renamed a file in `boot.initrd.secrets`", + file=sys.stderr, + ) def main() -> None: