diff options
author | William A. Kennington III <william@wkennington.com> | 2015-02-08 14:18:13 -0800 |
---|---|---|
committer | William A. Kennington III <william@wkennington.com> | 2015-02-08 14:18:13 -0800 |
commit | 2a0754ccbc0e2c4f01803ab1824930c6276a331a (patch) | |
tree | ea07080349d97672b625b3f0d660324b203baad2 /nixos/modules/system/boot/loader | |
parent | ac99fefae1e9300a24bbe76ba2cf6f5d390b6a20 (diff) | |
parent | 37673708661542797d4ad6de2c74e3ce6863b2cb (diff) | |
download | nixlib-2a0754ccbc0e2c4f01803ab1824930c6276a331a.tar nixlib-2a0754ccbc0e2c4f01803ab1824930c6276a331a.tar.gz nixlib-2a0754ccbc0e2c4f01803ab1824930c6276a331a.tar.bz2 nixlib-2a0754ccbc0e2c4f01803ab1824930c6276a331a.tar.lz nixlib-2a0754ccbc0e2c4f01803ab1824930c6276a331a.tar.xz nixlib-2a0754ccbc0e2c4f01803ab1824930c6276a331a.tar.zst nixlib-2a0754ccbc0e2c4f01803ab1824930c6276a331a.zip |
Merge pull request #5994 from ts468/grub
Add 'target' parameter for GRUB installation chain
Diffstat (limited to 'nixos/modules/system/boot/loader')
-rw-r--r-- | nixos/modules/system/boot/loader/grub/grub.nix | 34 | ||||
-rw-r--r-- | nixos/modules/system/boot/loader/grub/install-grub.pl | 120 |
2 files changed, 142 insertions, 12 deletions
diff --git a/nixos/modules/system/boot/loader/grub/grub.nix b/nixos/modules/system/boot/loader/grub/grub.nix index b16a725aba8e..ed2249a4ba7a 100644 --- a/nixos/modules/system/boot/loader/grub/grub.nix +++ b/nixos/modules/system/boot/loader/grub/grub.nix @@ -6,6 +6,8 @@ let cfg = config.boot.loader.grub; + efi = config.boot.loader.efi; + realGrub = if cfg.version == 1 then pkgs.grub else pkgs.grub2.override { zfsSupport = cfg.zfsSupport; }; @@ -16,21 +18,31 @@ let then null else realGrub; + grubEfi = + # EFI version of Grub v2 + if (cfg.devices != ["nodev"]) && cfg.efiSupport && (cfg.version == 2) + then pkgs.grub2.override { zfsSupport = cfg.zfsSupport; efiSupport = cfg.efiSupport; } + else null; + f = x: if x == null then "" else "" + x; grubConfig = pkgs.writeText "grub-config.xml" (builtins.toXML { splashImage = f config.boot.loader.grub.splashImage; grub = f grub; + grubTarget = f grub.grubTarget; shell = "${pkgs.stdenv.shell}"; fullVersion = (builtins.parseDrvName realGrub.name).version; + grubEfi = f grubEfi; + grubTargetEfi = if cfg.efiSupport && (cfg.version == 2) then f grubEfi.grubTarget else ""; + inherit (efi) efiSysMountPoint canTouchEfiVariables; inherit (cfg) version extraConfig extraPerEntryConfig extraEntries extraEntriesBeforeNixOS extraPrepareConfig configurationLimit copyKernels timeout - default devices fsIdentifier; - path = (makeSearchPath "bin" [ + default devices fsIdentifier efiSupport; + path = (makeSearchPath "bin" ([ pkgs.coreutils pkgs.gnused pkgs.gnugrep pkgs.findutils pkgs.diffutils pkgs.btrfsProgs - pkgs.utillinux - ]) + ":" + (makeSearchPath "sbin" [ + pkgs.utillinux ] ++ (if cfg.efiSupport && (cfg.version == 2) then [pkgs.efibootmgr ] else []) + )) + ":" + (makeSearchPath "sbin" [ pkgs.mdadm pkgs.utillinux ]); }); @@ -231,6 +243,18 @@ in type = types.bool; description = '' Whether grub should be build against libzfs. + ZFS support is only available for GRUB v2. + This option is ignored for GRUB v1. + ''; + }; + + efiSupport = mkOption { + default = false; + type = types.bool; + description = '' + Whether grub should be build with EFI support. + EFI support is only available for GRUB v2. + This option is ignored for GRUB v1. ''; }; @@ -269,7 +293,7 @@ in if cfg.devices == [] then throw "You must set the option ‘boot.loader.grub.device’ to make the system bootable." else - "PERL5LIB=${makePerlPath (with pkgs.perlPackages; [ FileSlurp XMLLibXML XMLSAX ])} " + + "PERL5LIB=${makePerlPath (with pkgs.perlPackages; [ FileSlurp XMLLibXML XMLSAX ListCompare ])} " + (if cfg.enableCryptodisk then "GRUB_ENABLE_CRYPTODISK=y " else "") + "${pkgs.perl}/bin/perl ${./install-grub.pl} ${grubConfig}"; diff --git a/nixos/modules/system/boot/loader/grub/install-grub.pl b/nixos/modules/system/boot/loader/grub/install-grub.pl index ffee0271e93b..74a934c67931 100644 --- a/nixos/modules/system/boot/loader/grub/install-grub.pl +++ b/nixos/modules/system/boot/loader/grub/install-grub.pl @@ -7,6 +7,7 @@ use File::Path; use File::stat; use File::Copy; use File::Slurp; +require List::Compare; use POSIX; use Cwd; @@ -39,6 +40,7 @@ sub runCommand { my $grub = get("grub"); my $grubVersion = int(get("version")); +my $grubTarget = get("grubTarget"); my $extraConfig = get("extraConfig"); my $extraPrepareConfig = get("extraPrepareConfig"); my $extraPerEntryConfig = get("extraPerEntryConfig"); @@ -50,6 +52,10 @@ my $copyKernels = get("copyKernels") eq "true"; my $timeout = int(get("timeout")); my $defaultEntry = int(get("default")); my $fsIdentifier = get("fsIdentifier"); +my $grubEfi = get("grubEfi"); +my $grubTargetEfi = get("grubTargetEfi"); +my $canTouchEfiVariables = get("canTouchEfiVariables"); +my $efiSysMountPoint = get("efiSysMountPoint"); $ENV{'PATH'} = get("path"); die "unsupported GRUB version\n" if $grubVersion != 1 && $grubVersion != 2; @@ -103,6 +109,8 @@ sub GetFs { # Skip the read-only bind-mount on /nix/store. next if $mountPoint eq "/nix/store" && (grep { $_ eq "rw" } @superOptions) && (grep { $_ eq "ro" } @mountOptions); + # Skip mount point generated by systemd-efi-boot-generator? + next if $fsType eq "autofs"; # Ensure this matches the intended directory next unless PathInMount($dir, $mountPoint); @@ -402,16 +410,114 @@ foreach my $fn (glob "/boot/kernels/*") { } -# Install GRUB if the version changed from the last time we installed -# it. FIXME: shouldn't we reinstall if ‘devices’ changed? -my $prevVersion = readFile("/boot/grub/version") // ""; -if (($ENV{'NIXOS_INSTALL_GRUB'} // "") eq "1" || get("fullVersion") ne $prevVersion) { +# +# Install GRUB if the parameters changed from the last time we installed it. +# + +struct(GrubState => { + version => '$', + efi => '$', + devices => '$', + efiMountPoint => '$', +}); +sub readGrubState { + my $defaultGrubState = GrubState->new(version => "", efi => "", devices => "", efiMountPoint => "" ); + open FILE, "</boot/grub/state" or return $defaultGrubState; + local $/ = "\n"; + my $version = <FILE>; + chomp($version); + my $efi = <FILE>; + chomp($efi); + my $devices = <FILE>; + chomp($devices); + my $efiMountPoint = <FILE>; + chomp($efiMountPoint); + close FILE; + my $grubState = GrubState->new(version => $version, efi => $efi, devices => $devices, efiMountPoint => $efiMountPoint ); + return $grubState +} + +sub getDeviceTargets { + my @devices = (); foreach my $dev ($dom->findnodes('/expr/attrs/attr[@name = "devices"]/list/string/@value')) { $dev = $dev->findvalue(".") or die; + push(@devices, $dev); + } + return @devices; +} + +# check whether to install GRUB EFI or not +sub getEfiTarget { + if (($grub ne "") && ($grubEfi ne "")) { + # EFI can only be installed when target is set; + # A target is also required then for non-EFI grub + if (($grubTarget eq "") || ($grubTargetEfi eq "")) { die } + else { return "both" } + } elsif (($grub ne "") && ($grubEfi eq "")) { + # TODO: It would be safer to disallow non-EFI grub installation if no taget is given. + # If no target is given, then grub auto-detects the target which can lead to errors. + # E.g. it seems as if grub would auto-detect a EFI target based on the availability + # of a EFI partition. + # However, it seems as auto-detection is currently relied on for non-x86_64 and non-i386 + # architectures in NixOS. That would have to be fixed in the nixos modules first. + return "no" + } elsif (($grub eq "") && ($grubEfi ne "")) { + # EFI can only be installed when target is set; + if ($grubTargetEfi eq "") { die } + else {return "only" } + } else { + # at least one grub target has to be given + die + } +} + +my @deviceTargets = getDeviceTargets(); +my $efiTarget = getEfiTarget(); +my $prevGrubState = readGrubState(); +my @prevDeviceTargets = split/:/, $prevGrubState->devices; + +my $devicesDiffer = scalar (List::Compare->new( '-u', '-a', \@deviceTargets, \@prevDeviceTargets)->get_symmetric_difference() ); +my $versionDiffer = (get("fullVersion") eq \$prevGrubState->version); +my $efiDiffer = ($efiTarget eq \$prevGrubState->efi); +my $efiMountPointDiffer = ($efiSysMountPoint eq \$prevGrubState->efiMountPoint); +my $requireNewInstall = $devicesDiffer || $versionDiffer || $efiDiffer || $efiMountPointDiffer || (($ENV{'NIXOS_INSTALL_GRUB'} // "") eq "1"); + + +# install non-EFI GRUB +if (($requireNewInstall != 0) && ($efiTarget eq "no" || $efiTarget eq "both")) { + foreach my $dev (@deviceTargets) { next if $dev eq "nodev"; print STDERR "installing the GRUB $grubVersion boot loader on $dev...\n"; - system("$grub/sbin/grub-install", "--recheck", Cwd::abs_path($dev)) == 0 - or die "$0: installation of GRUB on $dev failed\n"; + if ($grubTarget eq "") { + system("$grub/sbin/grub-install", "--recheck", Cwd::abs_path($dev)) == 0 + or die "$0: installation of GRUB on $dev failed\n"; + } else { + system("$grub/sbin/grub-install", "--recheck", "--target=$grubTarget", Cwd::abs_path($dev)) == 0 + or die "$0: installation of GRUB on $dev failed\n"; + } } - writeFile("/boot/grub/version", get("fullVersion")); +} + + +# install EFI GRUB +if (($requireNewInstall != 0) && ($efiTarget eq "only" || $efiTarget eq "both")) { + print STDERR "installing the GRUB $grubVersion EFI boot loader into $efiSysMountPoint...\n"; + if ($canTouchEfiVariables eq "true") { + system("$grubEfi/sbin/grub-install", "--recheck", "--target=$grubTargetEfi", "--efi-directory=$efiSysMountPoint") == 0 + or die "$0: installation of GRUB EFI into $efiSysMountPoint failed\n"; + } else { + system("$grubEfi/sbin/grub-install", "--recheck", "--target=$grubTargetEfi", "--efi-directory=$efiSysMountPoint", "--no-nvram") == 0 + or die "$0: installation of GRUB EFI into $efiSysMountPoint failed\n"; + } +} + + +# update GRUB state file +if ($requireNewInstall != 0) { + open FILE, ">/boot/grub/state" or die "cannot create /boot/grub/state: $!\n"; + print FILE get("fullVersion"), "\n" or die; + print FILE $efiTarget, "\n" or die; + print FILE join( ":", @deviceTargets ), "\n" or die; + print FILE $efiSysMountPoint, "\n" or die; + close FILE or die; } |