diff options
Diffstat (limited to 'nixos/modules/system/boot/loader/systemd-boot/systemd-boot-builder.py')
-rw-r--r-- | nixos/modules/system/boot/loader/systemd-boot/systemd-boot-builder.py | 89 |
1 files changed, 51 insertions, 38 deletions
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 6cd46f30373b5..055afe95df60b 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 @@ -15,6 +15,19 @@ import json from typing import NamedTuple, Dict, List from dataclasses import dataclass +# These values will be replaced with actual values during the package build +EFI_SYS_MOUNT_POINT = "@efiSysMountPoint@" +TIMEOUT = "@timeout@" +EDITOR = bool("@editor@") +CONSOLE_MODE = "@consoleMode@" +BOOTSPEC_TOOLS = "@bootspecTools@" +DISTRO_NAME = "@distroName@" +NIX = "@nix@" +SYSTEMD = "@systemd@" +CONFIGURATION_LIMIT = int("@configurationLimit@") +CAN_TOUCH_EFI_VARIABLES = "@canTouchEfiVariables@" +GRACEFUL = "@graceful@" +COPY_EXTRA_FILES = "@copyExtraFiles@" @dataclass class BootSpec: @@ -29,7 +42,6 @@ class BootSpec: initrdSecrets: str | None = None - libc = ctypes.CDLL("libc.so.6") class SystemIdentifier(NamedTuple): @@ -75,16 +87,16 @@ def generation_conf_filename(profile: str | None, generation: int, specialisatio def write_loader_conf(profile: str | None, generation: int, specialisation: str | None) -> None: - with open("@efiSysMountPoint@/loader/loader.conf.tmp", 'w') as f: - if "@timeout@" != "": - f.write("timeout @timeout@\n") + with open(f"{EFI_SYS_MOUNT_POINT}/loader/loader.conf.tmp", 'w') as f: + if TIMEOUT != "": + f.write(f"timeout {TIMEOUT}\n") f.write("default %s\n" % generation_conf_filename(profile, generation, specialisation)) - if not @editor@: + if not EDITOR: f.write("editor 0\n") - f.write("console-mode @consoleMode@\n") + f.write(f"console-mode {CONSOLE_MODE}\n") f.flush() os.fsync(f.fileno()) - os.rename("@efiSysMountPoint@/loader/loader.conf.tmp", "@efiSysMountPoint@/loader/loader.conf") + os.rename(f"{EFI_SYS_MOUNT_POINT}/loader/loader.conf.tmp", f"{EFI_SYS_MOUNT_POINT}/loader/loader.conf") def get_bootspec(profile: str | None, generation: int) -> BootSpec: @@ -95,7 +107,7 @@ def get_bootspec(profile: str | None, generation: int) -> BootSpec: bootspec_json = json.load(boot_json_f) else: boot_json_str = subprocess.check_output([ - "@bootspecTools@/bin/synthesize", + f"{BOOTSPEC_TOOLS}/bin/synthesize", "--version", "1", system_directory, @@ -116,7 +128,7 @@ def copy_from_file(file: str, dry_run: bool = False) -> str: store_dir = os.path.basename(os.path.dirname(store_file_path)) efi_file_path = "/efi/nixos/%s-%s.efi" % (store_dir, suffix) if not dry_run: - copy_if_not_exists(store_file_path, "@efiSysMountPoint@%s" % (efi_file_path)) + copy_if_not_exists(store_file_path, f"{EFI_SYS_MOUNT_POINT}%s" % (efi_file_path)) return efi_file_path def write_entry(profile: str | None, generation: int, specialisation: str | None, @@ -126,13 +138,14 @@ def write_entry(profile: str | None, generation: int, specialisation: str | None kernel = copy_from_file(bootspec.kernel) initrd = copy_from_file(bootspec.initrd) - title = "@distroName@{profile}{specialisation}".format( + title = "{name}{profile}{specialisation}".format( + name=DISTRO_NAME, profile=" [" + profile + "]" if profile else "", specialisation=" (%s)" % specialisation if specialisation else "") try: if bootspec.initrdSecrets is not None: - subprocess.check_call([bootspec.initrdSecrets, "@efiSysMountPoint@%s" % (initrd)]) + subprocess.check_call([bootspec.initrdSecrets, f"{EFI_SYS_MOUNT_POINT}%s" % (initrd)]) except subprocess.CalledProcessError: if current: print("failed to create initrd secrets!", file=sys.stderr) @@ -142,7 +155,7 @@ def write_entry(profile: str | None, generation: int, specialisation: str | None f'for "{title} - Configuration {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) - entry_file = "@efiSysMountPoint@/loader/entries/%s" % ( + entry_file = f"{EFI_SYS_MOUNT_POINT}/loader/entries/%s" % ( generation_conf_filename(profile, generation, specialisation)) tmp_path = "%s.tmp" % (entry_file) kernel_params = "init=%s " % bootspec.init @@ -167,7 +180,7 @@ def write_entry(profile: str | None, generation: int, specialisation: str | None def get_generations(profile: str | None = None) -> list[SystemIdentifier]: gen_list = subprocess.check_output([ - "@nix@/bin/nix-env", + f"{NIX}/bin/nix-env", "--list-generations", "-p", "/nix/var/nix/profiles/%s" % ("system-profiles/" + profile if profile else "system"), @@ -176,7 +189,7 @@ def get_generations(profile: str | None = None) -> list[SystemIdentifier]: gen_lines = gen_list.split('\n') gen_lines.pop() - configurationLimit = @configurationLimit@ + configurationLimit = CONFIGURATION_LIMIT configurations = [ SystemIdentifier( profile=profile, @@ -189,14 +202,14 @@ def get_generations(profile: str | None = None) -> list[SystemIdentifier]: def remove_old_entries(gens: list[SystemIdentifier]) -> None: - rex_profile = re.compile(r"^@efiSysMountPoint@/loader/entries/nixos-(.*)-generation-.*\.conf$") - rex_generation = re.compile(r"^@efiSysMountPoint@/loader/entries/nixos.*-generation-([0-9]+)(-specialisation-.*)?\.conf$") + rex_profile = re.compile(r"^" + re.escape(EFI_SYS_MOUNT_POINT) + "/loader/entries/nixos-(.*)-generation-.*\.conf$") + rex_generation = re.compile(r"^" + re.escape(EFI_SYS_MOUNT_POINT) + "/loader/entries/nixos.*-generation-([0-9]+)(-specialisation-.*)?\.conf$") known_paths = [] for gen in gens: bootspec = get_bootspec(gen.profile, gen.generation) known_paths.append(copy_from_file(bootspec.kernel, True)) known_paths.append(copy_from_file(bootspec.initrd, True)) - for path in glob.iglob("@efiSysMountPoint@/loader/entries/nixos*-generation-[1-9]*.conf"): + for path in glob.iglob(f"{EFI_SYS_MOUNT_POINT}/loader/entries/nixos*-generation-[1-9]*.conf"): if rex_profile.match(path): prof = rex_profile.sub(r"\1", path) else: @@ -207,7 +220,7 @@ def remove_old_entries(gens: list[SystemIdentifier]) -> None: continue if not (prof, gen_number, None) in gens: os.unlink(path) - for path in glob.iglob("@efiSysMountPoint@/efi/nixos/*"): + for path in glob.iglob(f"{EFI_SYS_MOUNT_POINT}/efi/nixos/*"): if not path in known_paths and not os.path.isdir(path): os.unlink(path) @@ -230,7 +243,7 @@ def install_bootloader(args: argparse.Namespace) -> None: # Since systemd version 232 a machine ID is required and it might not # be there on newly installed systems, so let's generate one so that # bootctl can find it and we can also pass it to write_entry() later. - cmd = ["@systemd@/bin/systemd-machine-id-setup", "--print"] + cmd = [f"{SYSTEMD}/bin/systemd-machine-id-setup", "--print"] machine_id = subprocess.run( cmd, text=True, check=True, stdout=subprocess.PIPE ).stdout.rstrip() @@ -242,22 +255,22 @@ def install_bootloader(args: argparse.Namespace) -> None: # flags to pass to bootctl install/update bootctl_flags = [] - if "@canTouchEfiVariables@" != "1": + if CAN_TOUCH_EFI_VARIABLES != "1": bootctl_flags.append("--no-variables") - if "@graceful@" == "1": + if GRACEFUL == "1": bootctl_flags.append("--graceful") if os.getenv("NIXOS_INSTALL_BOOTLOADER") == "1": # bootctl uses fopen() with modes "wxe" and fails if the file exists. - if os.path.exists("@efiSysMountPoint@/loader/loader.conf"): - os.unlink("@efiSysMountPoint@/loader/loader.conf") + if os.path.exists(f"{EFI_SYS_MOUNT_POINT}/loader/loader.conf"): + os.unlink(f"{EFI_SYS_MOUNT_POINT}/loader/loader.conf") - subprocess.check_call(["@systemd@/bin/bootctl", "--esp-path=@efiSysMountPoint@"] + bootctl_flags + ["install"]) + subprocess.check_call([f"{SYSTEMD}/bin/bootctl", f"--esp-path={EFI_SYS_MOUNT_POINT}"] + bootctl_flags + ["install"]) else: # Update bootloader to latest if needed - available_out = subprocess.check_output(["@systemd@/bin/bootctl", "--version"], universal_newlines=True).split()[2] - installed_out = subprocess.check_output(["@systemd@/bin/bootctl", "--esp-path=@efiSysMountPoint@", "status"], universal_newlines=True) + available_out = subprocess.check_output([f"{SYSTEMD}/bin/bootctl", "--version"], universal_newlines=True).split()[2] + installed_out = subprocess.check_output([f"{SYSTEMD}/bin/bootctl", f"--esp-path={EFI_SYS_MOUNT_POINT}", "status"], universal_newlines=True) # See status_binaries() in systemd bootctl.c for code which generates this installed_match = re.search(r"^\W+File:.*/EFI/(?:BOOT|systemd)/.*\.efi \(systemd-boot ([\d.]+[^)]*)\)$", @@ -276,10 +289,10 @@ def install_bootloader(args: argparse.Namespace) -> None: if installed_version < available_version: print("updating systemd-boot from %s to %s" % (installed_version, available_version)) - subprocess.check_call(["@systemd@/bin/bootctl", "--esp-path=@efiSysMountPoint@"] + bootctl_flags + ["update"]) + subprocess.check_call([f"{SYSTEMD}/bin/bootctl", f"--esp-path={EFI_SYS_MOUNT_POINT}"] + bootctl_flags + ["update"]) - os.makedirs("@efiSysMountPoint@/efi/nixos", exist_ok=True) - os.makedirs("@efiSysMountPoint@/loader/entries", exist_ok=True) + os.makedirs(f"{EFI_SYS_MOUNT_POINT}/efi/nixos", exist_ok=True) + os.makedirs(f"{EFI_SYS_MOUNT_POINT}/loader/entries", exist_ok=True) gens = get_generations() for profile in get_profiles(): @@ -302,9 +315,9 @@ def install_bootloader(args: argparse.Namespace) -> None: else: raise e - for root, _, files in os.walk('@efiSysMountPoint@/efi/nixos/.extra-files', topdown=False): - relative_root = root.removeprefix("@efiSysMountPoint@/efi/nixos/.extra-files").removeprefix("/") - actual_root = os.path.join("@efiSysMountPoint@", relative_root) + for root, _, files in os.walk(f"{EFI_SYS_MOUNT_POINT}/efi/nixos/.extra-files", topdown=False): + relative_root = root.removeprefix(f"{EFI_SYS_MOUNT_POINT}/efi/nixos/.extra-files").removeprefix("/") + actual_root = os.path.join(f"{EFI_SYS_MOUNT_POINT}", relative_root) for file in files: actual_file = os.path.join(actual_root, file) @@ -317,14 +330,14 @@ def install_bootloader(args: argparse.Namespace) -> None: os.rmdir(actual_root) os.rmdir(root) - os.makedirs("@efiSysMountPoint@/efi/nixos/.extra-files", exist_ok=True) + os.makedirs(f"{EFI_SYS_MOUNT_POINT}/efi/nixos/.extra-files", exist_ok=True) - subprocess.check_call("@copyExtraFiles@") + subprocess.check_call(COPY_EXTRA_FILES) def main() -> None: - parser = argparse.ArgumentParser(description='Update @distroName@-related systemd-boot files') - parser.add_argument('default_config', metavar='DEFAULT-CONFIG', help='The default @distroName@ config to boot') + parser = argparse.ArgumentParser(description=f"Update {DISTRO_NAME}-related systemd-boot files") + parser.add_argument('default_config', metavar='DEFAULT-CONFIG', help=f"The default {DISTRO_NAME} config to boot") args = parser.parse_args() try: @@ -334,9 +347,9 @@ def main() -> None: # it can leave the system in an unbootable state, when a crash/outage # happens shortly after an update. To decrease the likelihood of this # event sync the efi filesystem after each update. - rc = libc.syncfs(os.open("@efiSysMountPoint@", os.O_RDONLY)) + rc = libc.syncfs(os.open(f"{EFI_SYS_MOUNT_POINT}", os.O_RDONLY)) if rc != 0: - print("could not sync @efiSysMountPoint@: {}".format(os.strerror(rc)), file=sys.stderr) + print(f"could not sync {EFI_SYS_MOUNT_POINT}: {os.strerror(rc)}", file=sys.stderr) if __name__ == '__main__': |