Merge pull request #5994 from ts468/grub
Add 'target' parameter for GRUB installation chain
This commit is contained in:
commit
2a0754ccbc
@ -6,6 +6,8 @@ let
|
|||||||
|
|
||||||
cfg = config.boot.loader.grub;
|
cfg = config.boot.loader.grub;
|
||||||
|
|
||||||
|
efi = config.boot.loader.efi;
|
||||||
|
|
||||||
realGrub = if cfg.version == 1 then pkgs.grub
|
realGrub = if cfg.version == 1 then pkgs.grub
|
||||||
else pkgs.grub2.override { zfsSupport = cfg.zfsSupport; };
|
else pkgs.grub2.override { zfsSupport = cfg.zfsSupport; };
|
||||||
|
|
||||||
@ -16,21 +18,31 @@ let
|
|||||||
then null
|
then null
|
||||||
else realGrub;
|
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;
|
f = x: if x == null then "" else "" + x;
|
||||||
|
|
||||||
grubConfig = pkgs.writeText "grub-config.xml" (builtins.toXML
|
grubConfig = pkgs.writeText "grub-config.xml" (builtins.toXML
|
||||||
{ splashImage = f config.boot.loader.grub.splashImage;
|
{ splashImage = f config.boot.loader.grub.splashImage;
|
||||||
grub = f grub;
|
grub = f grub;
|
||||||
|
grubTarget = f grub.grubTarget;
|
||||||
shell = "${pkgs.stdenv.shell}";
|
shell = "${pkgs.stdenv.shell}";
|
||||||
fullVersion = (builtins.parseDrvName realGrub.name).version;
|
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)
|
inherit (cfg)
|
||||||
version extraConfig extraPerEntryConfig extraEntries
|
version extraConfig extraPerEntryConfig extraEntries
|
||||||
extraEntriesBeforeNixOS extraPrepareConfig configurationLimit copyKernels timeout
|
extraEntriesBeforeNixOS extraPrepareConfig configurationLimit copyKernels timeout
|
||||||
default devices fsIdentifier;
|
default devices fsIdentifier efiSupport;
|
||||||
path = (makeSearchPath "bin" [
|
path = (makeSearchPath "bin" ([
|
||||||
pkgs.coreutils pkgs.gnused pkgs.gnugrep pkgs.findutils pkgs.diffutils pkgs.btrfsProgs
|
pkgs.coreutils pkgs.gnused pkgs.gnugrep pkgs.findutils pkgs.diffutils pkgs.btrfsProgs
|
||||||
pkgs.utillinux
|
pkgs.utillinux ] ++ (if cfg.efiSupport && (cfg.version == 2) then [pkgs.efibootmgr ] else [])
|
||||||
]) + ":" + (makeSearchPath "sbin" [
|
)) + ":" + (makeSearchPath "sbin" [
|
||||||
pkgs.mdadm pkgs.utillinux
|
pkgs.mdadm pkgs.utillinux
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
@ -231,6 +243,18 @@ in
|
|||||||
type = types.bool;
|
type = types.bool;
|
||||||
description = ''
|
description = ''
|
||||||
Whether grub should be build against libzfs.
|
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
|
if cfg.devices == [] then
|
||||||
throw "You must set the option ‘boot.loader.grub.device’ to make the system bootable."
|
throw "You must set the option ‘boot.loader.grub.device’ to make the system bootable."
|
||||||
else
|
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 "") +
|
(if cfg.enableCryptodisk then "GRUB_ENABLE_CRYPTODISK=y " else "") +
|
||||||
"${pkgs.perl}/bin/perl ${./install-grub.pl} ${grubConfig}";
|
"${pkgs.perl}/bin/perl ${./install-grub.pl} ${grubConfig}";
|
||||||
|
|
||||||
|
@ -7,6 +7,7 @@ use File::Path;
|
|||||||
use File::stat;
|
use File::stat;
|
||||||
use File::Copy;
|
use File::Copy;
|
||||||
use File::Slurp;
|
use File::Slurp;
|
||||||
|
require List::Compare;
|
||||||
use POSIX;
|
use POSIX;
|
||||||
use Cwd;
|
use Cwd;
|
||||||
|
|
||||||
@ -39,6 +40,7 @@ sub runCommand {
|
|||||||
|
|
||||||
my $grub = get("grub");
|
my $grub = get("grub");
|
||||||
my $grubVersion = int(get("version"));
|
my $grubVersion = int(get("version"));
|
||||||
|
my $grubTarget = get("grubTarget");
|
||||||
my $extraConfig = get("extraConfig");
|
my $extraConfig = get("extraConfig");
|
||||||
my $extraPrepareConfig = get("extraPrepareConfig");
|
my $extraPrepareConfig = get("extraPrepareConfig");
|
||||||
my $extraPerEntryConfig = get("extraPerEntryConfig");
|
my $extraPerEntryConfig = get("extraPerEntryConfig");
|
||||||
@ -50,6 +52,10 @@ my $copyKernels = get("copyKernels") eq "true";
|
|||||||
my $timeout = int(get("timeout"));
|
my $timeout = int(get("timeout"));
|
||||||
my $defaultEntry = int(get("default"));
|
my $defaultEntry = int(get("default"));
|
||||||
my $fsIdentifier = get("fsIdentifier");
|
my $fsIdentifier = get("fsIdentifier");
|
||||||
|
my $grubEfi = get("grubEfi");
|
||||||
|
my $grubTargetEfi = get("grubTargetEfi");
|
||||||
|
my $canTouchEfiVariables = get("canTouchEfiVariables");
|
||||||
|
my $efiSysMountPoint = get("efiSysMountPoint");
|
||||||
$ENV{'PATH'} = get("path");
|
$ENV{'PATH'} = get("path");
|
||||||
|
|
||||||
die "unsupported GRUB version\n" if $grubVersion != 1 && $grubVersion != 2;
|
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.
|
# Skip the read-only bind-mount on /nix/store.
|
||||||
next if $mountPoint eq "/nix/store" && (grep { $_ eq "rw" } @superOptions) && (grep { $_ eq "ro" } @mountOptions);
|
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
|
# Ensure this matches the intended directory
|
||||||
next unless PathInMount($dir, $mountPoint);
|
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?
|
# Install GRUB if the parameters changed from the last time we installed it.
|
||||||
my $prevVersion = readFile("/boot/grub/version") // "";
|
#
|
||||||
if (($ENV{'NIXOS_INSTALL_GRUB'} // "") eq "1" || get("fullVersion") ne $prevVersion) {
|
|
||||||
|
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')) {
|
foreach my $dev ($dom->findnodes('/expr/attrs/attr[@name = "devices"]/list/string/@value')) {
|
||||||
$dev = $dev->findvalue(".") or die;
|
$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";
|
next if $dev eq "nodev";
|
||||||
print STDERR "installing the GRUB $grubVersion boot loader on $dev...\n";
|
print STDERR "installing the GRUB $grubVersion boot loader on $dev...\n";
|
||||||
|
if ($grubTarget eq "") {
|
||||||
system("$grub/sbin/grub-install", "--recheck", Cwd::abs_path($dev)) == 0
|
system("$grub/sbin/grub-install", "--recheck", Cwd::abs_path($dev)) == 0
|
||||||
or die "$0: installation of GRUB on $dev failed\n";
|
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;
|
||||||
}
|
}
|
||||||
|
@ -7,12 +7,18 @@
|
|||||||
|
|
||||||
with stdenv.lib;
|
with stdenv.lib;
|
||||||
let
|
let
|
||||||
|
pcSystems = {
|
||||||
|
"i686-linux".target = "i386";
|
||||||
|
"x86_64-linux".target = "i386";
|
||||||
|
};
|
||||||
|
|
||||||
efiSystems = {
|
efiSystems = {
|
||||||
"i686-linux".target = "i386";
|
"i686-linux".target = "i386";
|
||||||
"x86_64-linux".target = "x86_64";
|
"x86_64-linux".target = "x86_64";
|
||||||
};
|
};
|
||||||
|
|
||||||
canEfi = any (system: stdenv.system == system) (mapAttrsToList (name: _: name) efiSystems);
|
canEfi = any (system: stdenv.system == system) (mapAttrsToList (name: _: name) efiSystems);
|
||||||
|
inPCSystems = any (system: stdenv.system == system) (mapAttrsToList (name: _: name) pcSystems);
|
||||||
|
|
||||||
version = "2.02-git-1de3a4";
|
version = "2.02-git-1de3a4";
|
||||||
|
|
||||||
@ -80,6 +86,13 @@ stdenv.mkDerivation rec {
|
|||||||
configureFlags = optional zfsSupport "--enable-libzfs"
|
configureFlags = optional zfsSupport "--enable-libzfs"
|
||||||
++ optionals efiSupport [ "--with-platform=efi" "--target=${efiSystems.${stdenv.system}.target}" "--program-prefix=" ];
|
++ optionals efiSupport [ "--with-platform=efi" "--target=${efiSystems.${stdenv.system}.target}" "--program-prefix=" ];
|
||||||
|
|
||||||
|
# save target that grub is compiled for
|
||||||
|
grubTarget = if efiSupport
|
||||||
|
then "${efiSystems.${stdenv.system}.target}-efi"
|
||||||
|
else if inPCSystems
|
||||||
|
then "${pcSystems.${stdenv.system}.target}-pc"
|
||||||
|
else "";
|
||||||
|
|
||||||
doCheck = false;
|
doCheck = false;
|
||||||
enableParallelBuilding = true;
|
enableParallelBuilding = true;
|
||||||
|
|
||||||
|
@ -227,6 +227,14 @@ let self = _self // overrides; _self = with self; {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
ListCompare = buildPerlPackage {
|
||||||
|
name = "List-Compare-1.18";
|
||||||
|
src = fetchurl {
|
||||||
|
url = mirror://cpan/authors/id/J/JK/JKEENAN/List-Compare-0.39.tar.gz;
|
||||||
|
sha256 = "1v4gn176faanzf1kr9axdp1220da7nkvz0d66mnk34nd0skjjxcl";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
ArchiveCpio = buildPerlPackage {
|
ArchiveCpio = buildPerlPackage {
|
||||||
name = "Archive-Cpio-0.09";
|
name = "Archive-Cpio-0.09";
|
||||||
src = fetchurl {
|
src = fetchurl {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user