mirror of
https://github.com/NixOS/nixpkgs.git
synced 2024-11-17 15:22:59 +01:00
nixos/systemd-boot: Support extra EFI entries
This commit is contained in:
parent
96690c5b66
commit
f6b61981b1
2 changed files with 118 additions and 28 deletions
|
@ -45,16 +45,6 @@ initrd {initrd}
|
||||||
options {kernel_params}
|
options {kernel_params}
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# The boot loader entry for memtest86.
|
|
||||||
#
|
|
||||||
# TODO: This is hard-coded to use the 64-bit EFI app, but it could probably
|
|
||||||
# be updated to use the 32-bit EFI app on 32-bit systems. The 32-bit EFI
|
|
||||||
# app filename is BOOTIA32.efi.
|
|
||||||
MEMTEST_BOOT_ENTRY = """title MemTest86
|
|
||||||
efi /efi/memtest86/BOOTX64.efi
|
|
||||||
"""
|
|
||||||
|
|
||||||
|
|
||||||
def generation_conf_filename(profile: Optional[str], generation: int, specialisation: Optional[str]) -> str:
|
def generation_conf_filename(profile: Optional[str], generation: int, specialisation: Optional[str]) -> str:
|
||||||
pieces = [
|
pieces = [
|
||||||
"nixos",
|
"nixos",
|
||||||
|
@ -283,23 +273,24 @@ def main() -> None:
|
||||||
except OSError as e:
|
except OSError as e:
|
||||||
print("ignoring profile '{}' in the list of boot entries because of the following error:\n{}".format(profile, e), file=sys.stderr)
|
print("ignoring profile '{}' in the list of boot entries because of the following error:\n{}".format(profile, e), file=sys.stderr)
|
||||||
|
|
||||||
memtest_entry_file = "@efiSysMountPoint@/loader/entries/memtest86.conf"
|
for root, _, files in os.walk('@efiSysMountPoint@/efi/nixos/.extra-files', topdown=False):
|
||||||
if os.path.exists(memtest_entry_file):
|
relative_root = root.removeprefix("@efiSysMountPoint@/efi/nixos/.extra-files").removeprefix("/")
|
||||||
os.unlink(memtest_entry_file)
|
actual_root = os.path.join("@efiSysMountPoint@", relative_root)
|
||||||
shutil.rmtree("@efiSysMountPoint@/efi/memtest86", ignore_errors=True)
|
|
||||||
if "@memtest86@" != "":
|
|
||||||
mkdir_p("@efiSysMountPoint@/efi/memtest86")
|
|
||||||
for path in glob.iglob("@memtest86@/*"):
|
|
||||||
if os.path.isdir(path):
|
|
||||||
shutil.copytree(path, os.path.join("@efiSysMountPoint@/efi/memtest86", os.path.basename(path)))
|
|
||||||
else:
|
|
||||||
shutil.copy(path, "@efiSysMountPoint@/efi/memtest86/")
|
|
||||||
|
|
||||||
memtest_entry_file = "@efiSysMountPoint@/loader/entries/memtest86.conf"
|
for file in files:
|
||||||
memtest_entry_file_tmp_path = "%s.tmp" % memtest_entry_file
|
actual_file = os.path.join(actual_root, file)
|
||||||
with open(memtest_entry_file_tmp_path, 'w') as f:
|
|
||||||
f.write(MEMTEST_BOOT_ENTRY)
|
if os.path.exists(actual_file):
|
||||||
os.rename(memtest_entry_file_tmp_path, memtest_entry_file)
|
os.unlink(actual_file)
|
||||||
|
os.unlink(os.path.join(root, file))
|
||||||
|
|
||||||
|
if not len(os.listdir(actual_root)):
|
||||||
|
os.rmdir(actual_root)
|
||||||
|
os.rmdir(root)
|
||||||
|
|
||||||
|
mkdir_p("@efiSysMountPoint@/efi/nixos/.extra-files")
|
||||||
|
|
||||||
|
subprocess.check_call("@copyExtraFiles@")
|
||||||
|
|
||||||
# Since fat32 provides little recovery facilities after a crash,
|
# Since fat32 provides little recovery facilities after a crash,
|
||||||
# it can leave the system in an unbootable state, when a crash/outage
|
# it can leave the system in an unbootable state, when a crash/outage
|
||||||
|
|
|
@ -29,6 +29,20 @@ let
|
||||||
inherit (efi) efiSysMountPoint canTouchEfiVariables;
|
inherit (efi) efiSysMountPoint canTouchEfiVariables;
|
||||||
|
|
||||||
memtest86 = if cfg.memtest86.enable then pkgs.memtest86-efi else "";
|
memtest86 = if cfg.memtest86.enable then pkgs.memtest86-efi else "";
|
||||||
|
|
||||||
|
copyExtraFiles = pkgs.writeShellScript "copy-extra-files" ''
|
||||||
|
empty_file=$(mktemp)
|
||||||
|
|
||||||
|
${concatStrings (mapAttrsToList (n: v: ''
|
||||||
|
${pkgs.coreutils}/bin/install -Dp "${v}" "${efi.efiSysMountPoint}/"${escapeShellArg n}
|
||||||
|
${pkgs.coreutils}/bin/install -D $empty_file "${efi.efiSysMountPoint}/efi/nixos/.extra-files/"${escapeShellArg n}
|
||||||
|
'') cfg.extraFiles)}
|
||||||
|
|
||||||
|
${concatStrings (mapAttrsToList (n: v: ''
|
||||||
|
${pkgs.coreutils}/bin/install -Dp "${pkgs.writeText n v}" "${efi.efiSysMountPoint}/loader/entries/"${escapeShellArg n}
|
||||||
|
${pkgs.coreutils}/bin/install -D $empty_file "${efi.efiSysMountPoint}/efi/nixos/.extra-files/loader/entries/"${escapeShellArg n}
|
||||||
|
'') cfg.extraEntries)}
|
||||||
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
checkedSystemdBootBuilder = pkgs.runCommand "systemd-boot" {
|
checkedSystemdBootBuilder = pkgs.runCommand "systemd-boot" {
|
||||||
|
@ -125,6 +139,51 @@ in {
|
||||||
<literal>true</literal>.
|
<literal>true</literal>.
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
|
entryFilename = mkOption {
|
||||||
|
default = "memtest86.conf";
|
||||||
|
type = types.str;
|
||||||
|
description = ''
|
||||||
|
<literal>systemd-boot</literal> orders the menu entries by the config file names,
|
||||||
|
so if you want something to appear after all the NixOS entries,
|
||||||
|
it should start with <filename>o</filename> or onwards.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
extraEntries = mkOption {
|
||||||
|
type = types.attrsOf types.lines;
|
||||||
|
default = {};
|
||||||
|
example = literalExpression ''
|
||||||
|
{ "memtest86.conf" = '''
|
||||||
|
title MemTest86
|
||||||
|
efi /efi/memtest86/memtest86.efi
|
||||||
|
'''; }
|
||||||
|
'';
|
||||||
|
description = ''
|
||||||
|
Any additional entries you want added to the <literal>systemd-boot</literal> menu.
|
||||||
|
These entries will be copied to <filename>/boot/loader/entries</filename>.
|
||||||
|
Each attribute name denotes the destination file name,
|
||||||
|
and the corresponding attribute value is the contents of the entry.
|
||||||
|
|
||||||
|
<literal>systemd-boot</literal> orders the menu entries by the config file names,
|
||||||
|
so if you want something to appear after all the NixOS entries,
|
||||||
|
it should start with <filename>o</filename> or onwards.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
extraFiles = mkOption {
|
||||||
|
type = types.attrsOf types.path;
|
||||||
|
default = {};
|
||||||
|
example = literalExpression ''
|
||||||
|
{ "efi/memtest86/memtest86.efi" = "''${pkgs.memtest86-efi}/BOOTX64.efi"; }
|
||||||
|
'';
|
||||||
|
description = ''
|
||||||
|
A set of files to be copied to <filename>/boot</filename>.
|
||||||
|
Each attribute name denotes the destination file name in
|
||||||
|
<filename>/boot</filename>, while the corresponding
|
||||||
|
attribute value specifies the source file.
|
||||||
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
graceful = mkOption {
|
graceful = mkOption {
|
||||||
|
@ -148,15 +207,55 @@ in {
|
||||||
assertions = [
|
assertions = [
|
||||||
{
|
{
|
||||||
assertion = (config.boot.kernelPackages.kernel.features or { efiBootStub = true; }) ? efiBootStub;
|
assertion = (config.boot.kernelPackages.kernel.features or { efiBootStub = true; }) ? efiBootStub;
|
||||||
|
|
||||||
message = "This kernel does not support the EFI boot stub";
|
message = "This kernel does not support the EFI boot stub";
|
||||||
}
|
}
|
||||||
];
|
] ++ concatMap (filename: [
|
||||||
|
{
|
||||||
|
assertion = !(hasInfix "/" filename);
|
||||||
|
message = "boot.loader.systemd-boot.extraEntries.${lib.strings.escapeNixIdentifier filename} is invalid: entries within folders are not supported";
|
||||||
|
}
|
||||||
|
{
|
||||||
|
assertion = hasSuffix ".conf" filename;
|
||||||
|
message = "boot.loader.systemd-boot.extraEntries.${lib.strings.escapeNixIdentifier filename} is invalid: entries must have a .conf file extension";
|
||||||
|
}
|
||||||
|
]) (builtins.attrNames cfg.extraEntries)
|
||||||
|
++ concatMap (filename: [
|
||||||
|
{
|
||||||
|
assertion = !(hasPrefix "/" filename);
|
||||||
|
message = "boot.loader.systemd-boot.extraFiles.${lib.strings.escapeNixIdentifier filename} is invalid: paths must not begin with a slash";
|
||||||
|
}
|
||||||
|
{
|
||||||
|
assertion = !(hasInfix ".." filename);
|
||||||
|
message = "boot.loader.systemd-boot.extraFiles.${lib.strings.escapeNixIdentifier filename} is invalid: paths must not reference the parent directory";
|
||||||
|
}
|
||||||
|
{
|
||||||
|
assertion = !(hasInfix "nixos/.extra-files" (toLower filename));
|
||||||
|
message = "boot.loader.systemd-boot.extraFiles.${lib.strings.escapeNixIdentifier filename} is invalid: files cannot be placed in the nixos/.extra-files directory";
|
||||||
|
}
|
||||||
|
]) (builtins.attrNames cfg.extraFiles);
|
||||||
|
|
||||||
boot.loader.grub.enable = mkDefault false;
|
boot.loader.grub.enable = mkDefault false;
|
||||||
|
|
||||||
boot.loader.supportsInitrdSecrets = true;
|
boot.loader.supportsInitrdSecrets = true;
|
||||||
|
|
||||||
|
boot.loader.systemd-boot.extraFiles = mkMerge [
|
||||||
|
# TODO: This is hard-coded to use the 64-bit EFI app, but it could probably
|
||||||
|
# be updated to use the 32-bit EFI app on 32-bit systems. The 32-bit EFI
|
||||||
|
# app filename is BOOTIA32.efi.
|
||||||
|
(mkIf cfg.memtest86.enable {
|
||||||
|
"efi/memtest86/BOOTX64.efi" = "${pkgs.memtest86-efi}/BOOTX64.efi";
|
||||||
|
})
|
||||||
|
];
|
||||||
|
|
||||||
|
boot.loader.systemd-boot.extraEntries = mkMerge [
|
||||||
|
(mkIf cfg.memtest86.enable {
|
||||||
|
"${cfg.memtest86.entryFilename}" = ''
|
||||||
|
title MemTest86
|
||||||
|
efi /efi/memtest86/BOOTX64.efi
|
||||||
|
'';
|
||||||
|
})
|
||||||
|
];
|
||||||
|
|
||||||
system = {
|
system = {
|
||||||
build.installBootLoader = checkedSystemdBootBuilder;
|
build.installBootLoader = checkedSystemdBootBuilder;
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue