Change:
Describe the bug With systemd-boot v245, the set in by is no longer respected. In the current state, it will always choose the boot loader entry with the largest in the loader file. This corresponds to the largest generation number. To Reproduce Steps to reproduce the behavior: , run or to ensure the latest is used. to switch back to a previous generation. and notice that it still defaults to the latest generation, not the previous one. Additional context This is a result of the following change: The fix seems fairly straightforward, to just have include the suffix on the entry in the file. However, we would still have a problem if the user is using an older version of (if he or she hasn't updated with ). Similarly, a user who hasn't updated using since updating to would not encounter this issue, since the is still correct for their version of . Upstream issue: Notify maintainers
Does the following patch fix it for you? If yes, I can send a PR fixing this.
Yes, it does. But my concern is that it would break this for people who hadn't already run .
Yeah, this is definitely a problem - currently, all fresh installations with systemd 245 won't have a working default selection, and if we update with above patch, all existing ones will break. I don't think upstream will revert the change either - it has been in their codebase since November 2019. We could add some code to that compares ${systemd}/lib/systemd/boot/efi/systemd-boot[x64,aa64].efi with what's in and invokes if it differs to always update bootctl - what do you think?
Updating the bootloader seems like a good idea in general. I would not perform the check the file manually but rather parse the output of for now. This would result in less updates (only for systemd version upgrades) and is therefore less risky (at the cost of missing some fixes of without a bump). It also saves us from re-implementing things like finding out where $ESP is and what infix needs to got into path
would you be willing to file a PR doing as suggested?
Unfortunately, I won't be able to work on this in the near future. I'm up against some deadlines for graduation.
all good, thanks for the heads-up! Maybe someone else picks it up in the meantime :-)

Discussion:
if "@timeout@" != "": f.write("timeout @timeout@n") if profile: <del> f.write("default nixos-%s-generation-%dn" % (profile, generation)) </del> <ins> f.write("default nixos-%s-generation-%d.confn".format(profile, generation)) </ins> else: <del> f.write("default nixos-generation-%dn" % (generation)) </del> <ins> f.write("default nixos-generation-%d.confn".format(generation)) </ins> if not @editor@: f.write("editor 0n"); f.write("console-mode @consoleMode@n");

subprocess.check_call(["@systemd@/bin/bootctl", "--path=@efiSysMountPoint@", "install"]) else: subprocess.check_call(["@systemd@/bin/bootctl", "--path=@efiSysMountPoint@", "--no-variables", "install"]) <ins> 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"]) </ins> mkdir_p("@efiSysMountPoint@/efi/nixos") mkdir_p("@efiSysMountPoint@/loader/entries")

with import ../lib/testing-python.nix { inherit system pkgs; }; with pkgs.lib; <del> makeTest { name = "systemd-boot"; meta.maintainers = with pkgs.stdenv.lib.maintainers; [ danielfullmer ]; machine = { pkgs, lib, ... }: { </del> <ins> let common = { </ins> virtualisation.useBootLoader = true; virtualisation.useEFIBoot = true; boot.loader.systemd-boot.enable = true; }; <ins> 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") </ins> <del> testScript = '' machine.start() machine.wait_for_unit("multi-user.target") </del> <ins> 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" ) ''; }; </ins> <del> machine.succeed("test -e /boot/loader/entries/nixos-generation-1.conf") </del> <ins> update = makeTest { name = "systemd-boot-update"; meta.maintainers = with pkgs.stdenv.lib.maintainers; [ danielfullmer ]; </ins> <del> # 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" ) ''; </del> <ins> 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 ''; }; </ins> }