From 7e3519a7cf273e80c0b055158e9bd2d5ea1c11ad Mon Sep 17 00:00:00 2001 From: Daniel Fullmer Date: Sun, 14 Jun 2020 13:16:30 -0400 Subject: [PATCH 1/3] nixos/systemd-boot: update bootloader if needed --- .../loader/systemd-boot/systemd-boot-builder.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) 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 f48a085ce57a4..788b2014cedfa 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 @@ -197,6 +197,22 @@ def main(): subprocess.check_call(["@systemd@/bin/bootctl", "--path=@efiSysMountPoint@", "install"]) else: subprocess.check_call(["@systemd@/bin/bootctl", "--path=@efiSysMountPoint@", "--no-variables", "install"]) + else: + # Update bootloader to latest if needed + systemd_version = subprocess.check_output(["@systemd@/bin/bootctl", "--version"], universal_newlines=True).split()[1] + sdboot_status = subprocess.check_output(["@systemd@/bin/bootctl", "--path=@efiSysMountPoint@", "status"], universal_newlines=True) + + # See status_binaries() in systemd bootctl.c for code which generates this + m = re.search("^\W+File:.*/EFI/(BOOT|systemd)/.*\.efi \(systemd-boot (\d+)\)$", + sdboot_status, re.IGNORECASE | re.MULTILINE) + if m is None: + print("could not find any previously installed systemd-boot") + else: + sdboot_version = m.group(2) + if systemd_version > sdboot_version: + print("updating systemd-boot from %s to %s" % (sdboot_version, systemd_version)) + subprocess.check_call(["@systemd@/bin/bootctl", "--path=@efiSysMountPoint@", "update"]) + mkdir_p("@efiSysMountPoint@/efi/nixos") mkdir_p("@efiSysMountPoint@/loader/entries") From 5cd28326dbe955c4793bb79ba8a927f7454974c4 Mon Sep 17 00:00:00 2001 From: Daniel Fullmer Date: Sun, 14 Jun 2020 14:14:43 -0400 Subject: [PATCH 2/3] nixos/systemd-boot: add test for updating --- nixos/tests/systemd-boot.nix | 57 ++++++++++++++++++++++++++---------- 1 file changed, 42 insertions(+), 15 deletions(-) diff --git a/nixos/tests/systemd-boot.nix b/nixos/tests/systemd-boot.nix index e911c3933616b..eba4729d6de84 100644 --- a/nixos/tests/systemd-boot.nix +++ b/nixos/tests/systemd-boot.nix @@ -6,26 +6,53 @@ with import ../lib/testing-python.nix { inherit system pkgs; }; with pkgs.lib; -makeTest { - name = "systemd-boot"; - meta.maintainers = with pkgs.stdenv.lib.maintainers; [ danielfullmer ]; - - machine = { pkgs, lib, ... }: { +let + common = { virtualisation.useBootLoader = true; virtualisation.useEFIBoot = true; boot.loader.systemd-boot.enable = true; }; +in +{ + basic = makeTest { + name = "systemd-boot"; + meta.maintainers = with pkgs.stdenv.lib.maintainers; [ danielfullmer ]; + + machine = common; + + testScript = '' + machine.start() + machine.wait_for_unit("multi-user.target") - testScript = '' - machine.start() - machine.wait_for_unit("multi-user.target") + machine.succeed("test -e /boot/loader/entries/nixos-generation-1.conf") + + # Ensure we actually booted using systemd-boot + # Magic number is the vendor UUID used by systemd-boot. + machine.succeed( + "test -e /sys/firmware/efi/efivars/LoaderEntrySelected-4a67b082-0a4c-41cf-b6c7-440b29bb8c4f" + ) + ''; + }; - machine.succeed("test -e /boot/loader/entries/nixos-generation-1.conf") + update = makeTest { + name = "systemd-boot-update"; + meta.maintainers = with pkgs.stdenv.lib.maintainers; [ danielfullmer ]; - # Ensure we actually booted using systemd-boot. - # Magic number is the vendor UUID used by systemd-boot. - machine.succeed( - "test -e /sys/firmware/efi/efivars/LoaderEntrySelected-4a67b082-0a4c-41cf-b6c7-440b29bb8c4f" - ) - ''; + machine = common; + + testScript = '' + machine.succeed("mount -o remount,rw /boot") + + # Replace version inside sd-boot with something older. See magic[] string in systemd src/boot/efi/boot.c + machine.succeed( + """ + find /boot -iname '*.efi' -print0 | \ + xargs -0 -I '{}' sed -i 's/#### LoaderInfo: systemd-boot .* ####/#### LoaderInfo: systemd-boot 001 ####/' '{}' + """ + ) + + output = machine.succeed("/run/current-system/bin/switch-to-configuration boot") + assert "updating systemd-boot from 001 to " in output + ''; + }; } From 42b92250b95a9092b7fc08dd623ec23bbffe96ce Mon Sep 17 00:00:00 2001 From: Florian Klink Date: Thu, 30 Apr 2020 23:57:39 +0200 Subject: [PATCH 3/3] nixos/systemd-boot: fix default boot entry selection https://github.com/systemd/systemd/commit/6cd12ebcfe459466257ea63022a32515d756e719 changed behaviour - now the "default" entry needs to identity an entry with its full name, including the ".conf". Reported-In: https://github.com/NixOS/nixpkgs/issues/86422 --- .../system/boot/loader/systemd-boot/systemd-boot-builder.py | 4 ++-- 1 file changed, 2 insertions(+), 2 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 788b2014cedfa..d8baed65c6df3 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 @@ -47,9 +47,9 @@ def write_loader_conf(profile, generation): if "@timeout@" != "": f.write("timeout @timeout@\n") if profile: - f.write("default nixos-%s-generation-%d\n" % (profile, generation)) + f.write("default nixos-%s-generation-%d.conf\n".format(profile, generation)) else: - f.write("default nixos-generation-%d\n" % (generation)) + f.write("default nixos-generation-%d.conf\n".format(generation)) if not @editor@: f.write("editor 0\n"); f.write("console-mode @consoleMode@\n");