Revert "Revert "Merge pull request #2449 from wkennington/master.grub""

This reverts commit 94205f5f21.

Conflicts:
	nixos/modules/system/boot/loader/grub/install-grub.pl
wip/yesman
William A. Kennington III 10 years ago
parent af4c369d0a
commit 36614ff3e2
  1. 21
      nixos/modules/installer/tools/nixos-generate-config.pl
  2. 1
      nixos/modules/installer/tools/tools.nix
  3. 3
      nixos/modules/installer/virtualbox-demo.nix
  4. 37
      nixos/modules/system/boot/loader/grub/grub.nix
  5. 135
      nixos/modules/system/boot/loader/grub/install-grub.pl
  6. 6
      nixos/modules/tasks/filesystems/zfs.nix
  7. 4
      nixos/release-combined.nix
  8. 2
      nixos/release.nix
  9. 13
      nixos/tests/installer.nix
  10. 62
      pkgs/tools/misc/grub/2.0x.nix
  11. 6
      pkgs/top-level/all-packages.nix

@ -20,6 +20,13 @@ sub uniq {
return @res;
}
sub runCommand {
my ($cmd) = @_;
open FILE, "$cmd 2>/dev/null |" or die "Failed to execute: $cmd\n";
my @ret = <FILE>;
close FILE;
return ($?, @ret);
}
# Process the command line.
my $outDir = "/etc/nixos";
@ -337,6 +344,20 @@ EOF
}
}
# Is this a btrfs filesystem?
if ($fsType eq "btrfs") {
my ($status, @info) = runCommand("btrfs subvol show $rootDir$mountPoint");
if ($status != 0) {
die "Failed to retreive subvolume info for $mountPoint";
}
my @subvols = join("", @info) =~ m/Name:[ \t\n]*([^ \t\n]*)/;
if ($#subvols > 0) {
die "Btrfs subvol name for $mountPoint listed multiple times in mount\n"
} elsif ($#subvols == 0) {
push @extraOptions, "subvol=$subvols[0]";
}
}
# Emit the filesystem.
$fileSystems .= <<EOF;
fileSystems.\"$mountPoint\" =

@ -38,6 +38,7 @@ let
nixos-generate-config = makeProg {
name = "nixos-generate-config";
src = ./nixos-generate-config.pl;
path = [ pkgs.btrfsProgs ];
perl = "${pkgs.perl}/bin/perl -I${pkgs.perlPackages.FileSlurp}/lib/perl5/site_perl";
};

@ -10,6 +10,9 @@ with lib;
../profiles/clone-config.nix
];
# FIXME: UUID detection is currently broken
boot.loader.grub.fsIdentifier = "provided";
# Allow mounting of shared folders.
users.extraUsers.demo.extraGroups = [ "vboxsf" ];

@ -6,7 +6,8 @@ let
cfg = config.boot.loader.grub;
realGrub = if cfg.version == 1 then pkgs.grub else pkgs.grub2;
realGrub = if cfg.version == 1 then pkgs.grub
else pkgs.grub2.override { zfsSupport = cfg.zfsSupport; };
grub =
# Don't include GRUB if we're only generating a GRUB menu (e.g.,
@ -25,11 +26,12 @@ let
inherit (cfg)
version extraConfig extraPerEntryConfig extraEntries
extraEntriesBeforeNixOS extraPrepareConfig configurationLimit copyKernels timeout
default devices explicitBootRoot;
default devices fsIdentifier;
path = (makeSearchPath "bin" [
pkgs.coreutils pkgs.gnused pkgs.gnugrep pkgs.findutils pkgs.diffutils
pkgs.coreutils pkgs.gnused pkgs.gnugrep pkgs.findutils pkgs.diffutils pkgs.btrfsProgs
pkgs.utillinux
]) + ":" + (makeSearchPath "sbin" [
pkgs.mdadm
pkgs.mdadm pkgs.utillinux
]);
});
@ -209,12 +211,26 @@ in
'';
};
explicitBootRoot = mkOption {
default = "";
type = types.str;
fsIdentifier = mkOption {
default = "uuid";
type = types.addCheck types.str
(type: type == "uuid" || type == "label" || type == "provided");
description = ''
The relative path of /boot within the parent volume. Leave empty
if /boot is not a btrfs subvolume.
Determines how grub will identify devices when generating the
configuration file. A value of uuid / label signifies that grub
will always resolve the uuid or label of the device before using
it in the configuration. A value of provided means that grub will
use the device name as show in <command>df</command> or
<command>mount</command>. Note, zfs zpools / datasets are ignored
and will always be mounted using their labels.
'';
};
zfsSupport = mkOption {
default = false;
type = types.bool;
description = ''
Whether grub should be build against libzfs.
'';
};
@ -260,6 +276,9 @@ in
${pkgs.coreutils}/bin/cp -pf "${v}" "/boot/${n}"
'') config.boot.loader.grub.extraFiles);
assertions = [{ assertion = !cfg.zfsSupport || cfg.version == 2;
message = "Only grub version 2 provides zfs support";}];
})
];

@ -1,5 +1,6 @@
use strict;
use warnings;
use Class::Struct;
use XML::LibXML;
use File::Basename;
use File::Path;
@ -27,6 +28,14 @@ sub writeFile {
close FILE or die;
}
sub runCommand {
my ($cmd) = @_;
open FILE, "$cmd 2>/dev/null |" or die "Failed to execute: $cmd\n";
my @ret = <FILE>;
close FILE;
return ($?, @ret);
}
my $grub = get("grub");
my $grubVersion = int(get("version"));
my $extraConfig = get("extraConfig");
@ -39,7 +48,7 @@ my $configurationLimit = int(get("configurationLimit"));
my $copyKernels = get("copyKernels") eq "true";
my $timeout = int(get("timeout"));
my $defaultEntry = int(get("default"));
my $explicitBootRoot = get("explicitBootRoot");
my $fsIdentifier = get("fsIdentifier");
$ENV{'PATH'} = get("path");
die "unsupported GRUB version\n" if $grubVersion != 1 && $grubVersion != 2;
@ -48,22 +57,108 @@ print STDERR "updating GRUB $grubVersion menu...\n";
mkpath("/boot/grub", 0, 0700);
# Discover whether /boot is on the same filesystem as / and
# /nix/store. If not, then all kernels and initrds must be copied to
# /boot, and all paths in the GRUB config file must be relative to the
# root of the /boot filesystem. `$bootRoot' is the path to be
# prepended to paths under /boot.
my $bootRoot = "/boot";
if (stat("/")->dev != stat("/boot")->dev) {
$bootRoot = "";
$copyKernels = 1;
} elsif (stat("/boot")->dev != stat("/nix/store")->dev) {
# /boot.
if (stat("/boot")->dev != stat("/nix/store")->dev) {
$copyKernels = 1;
}
if ($explicitBootRoot ne "") {
$bootRoot = $explicitBootRoot;
# Discover information about the location of /boot
struct(Fs => {
device => '$',
type => '$',
mount => '$',
});
sub GetFs {
my ($dir) = @_;
my ($status, @dfOut) = runCommand("df -T $dir");
if ($status != 0 || $#dfOut != 1) {
die "Failed to retrieve output about $dir from `df`";
}
my @boot = split(/[ \n\t]+/, $dfOut[1]);
return Fs->new(device => $boot[0], type => $boot[1], mount => $boot[6]);
}
struct (Grub => {
path => '$',
search => '$',
});
my $driveid = 1;
sub GrubFs {
my ($dir) = @_;
my $fs = GetFs($dir);
my $path = "/" . substr($dir, length($fs->mount));
my $search = "";
if ($grubVersion > 1) {
# ZFS is completely separate logic as zpools are always identified by a label
# or custom UUID
if ($fs->type eq 'zfs') {
my $sid = index($fs->device, '/');
if ($sid < 0) {
$search = '--label ' . $fs->device;
$path = '/@' . $path;
} else {
$search = '--label ' . substr($fs->device, 0, $sid);
$path = '/' . substr($fs->device, $sid) . '/@' . $path;
}
} else {
my %types = ('uuid' => '--fs-uuid', 'label' => '--label');
if ($fsIdentifier eq 'provided') {
# If the provided dev is identifying the partition using a label or uuid,
# we should get the label / uuid and do a proper search
my @matches = $fs->device =~ m/\/dev\/disk\/by-(label|uuid)\/(.*)/;
if ($#matches > 1) {
die "Too many matched devices"
} elsif ($#matches == 1) {
$search = "$types{$matches[0]} $matches[1]"
}
} else {
# Determine the identifying type
$search = $types{$fsIdentifier} . ' ';
# Based on the type pull in the identifier from the system
my ($status, @devInfo) = runCommand("blkid -o export @{[$fs->device]}");
if ($status != 0) {
die "Failed to get blkid info for @{[$fs->device]}";
}
my @matches = join("", @devInfo) =~ m/@{[uc $fsIdentifier]}=([^\n]*)/;
if ($#matches != 0) {
die "Couldn't find a $types{$fsIdentifier} for @{[$fs->device]}\n"
}
$search .= $matches[0];
}
# BTRFS is a special case in that we need to fix the referrenced path based on subvolumes
if ($fs->type eq 'btrfs') {
my ($status, @info) = runCommand("btrfs subvol show @{[$fs->mount]}");
if ($status != 0) {
die "Failed to retreive subvolume info for @{[$fs->mount]}";
}
my @subvols = join("", @info) =~ m/Name:[ \t\n]*([^ \t\n]*)/;
if ($#subvols > 0) {
die "Btrfs subvol name for @{[$fs->device]} listed multiple times in mount\n"
} elsif ($#subvols == 0) {
$path = "/$subvols[0]$path";
}
}
}
if (not $search eq "") {
$search = "search --set=drive$driveid " . $search;
$path = "(\$drive$driveid)$path";
$driveid += 1;
}
}
return Grub->new(path => $path, search => $search);
}
my $grubBoot = GrubFs("/boot");
my $grubStore = GrubFs("/nix");
# We don't need to copy if we can read the kernels directly
if ($grubStore->search ne "") {
$copyKernels = 0;
}
# Generate the header.
@ -76,12 +171,14 @@ if ($grubVersion == 1) {
";
if ($splashImage) {
copy $splashImage, "/boot/background.xpm.gz" or die "cannot copy $splashImage to /boot\n";
$conf .= "splashimage $bootRoot/background.xpm.gz\n";
$conf .= "splashimage " . $grubBoot->path . "/background.xpm.gz\n";
}
}
else {
$conf .= "
" . $grubBoot->search . "
" . $grubStore->search . "
if [ -s \$prefix/grubenv ]; then
load_env
fi
@ -102,7 +199,7 @@ else {
set timeout=$timeout
fi
if loadfont $bootRoot/grub/fonts/unicode.pf2; then
if loadfont " . $grubBoot->path . "/grub/fonts/unicode.pf2; then
set gfxmode=640x480
insmod gfxterm
insmod vbe
@ -116,7 +213,7 @@ else {
copy $splashImage, "/boot/background.png" or die "cannot copy $splashImage to /boot\n";
$conf .= "
insmod png
if background_image $bootRoot/background.png; then
if background_image " . $grubBoot->path . "/background.png; then
set color_normal=white/black
set color_highlight=black/white
else
@ -138,7 +235,7 @@ mkpath("/boot/kernels", 0, 0755) if $copyKernels;
sub copyToKernelsDir {
my ($path) = @_;
return $path unless $copyKernels;
return $grubStore->path . substr($path, length("/nix")) unless $copyKernels;
$path =~ /\/nix\/store\/(.*)/ or die;
my $name = $1; $name =~ s/\//-/g;
my $dst = "/boot/kernels/$name";
@ -151,7 +248,7 @@ sub copyToKernelsDir {
rename $tmp, $dst or die "cannot rename $tmp to $dst\n";
}
$copied{$dst} = 1;
return "$bootRoot/kernels/$name";
return $grubBoot->path . "/kernels/$name";
}
sub addEntry {
@ -178,6 +275,8 @@ sub addEntry {
$conf .= " " . ($xen ? "module" : "initrd") . " $initrd\n\n";
} else {
$conf .= "menuentry \"$name\" {\n";
$conf .= $grubBoot->search . "\n";
$conf .= $grubStore->search . "\n";
$conf .= " $extraPerEntryConfig\n" if $extraPerEntryConfig;
$conf .= " multiboot $xen $xenParams\n" if $xen;
$conf .= " " . ($xen ? "module" : "linux") . " $kernel $kernelParams\n";
@ -195,7 +294,7 @@ addEntry("NixOS - Default", $defaultConfig);
$conf .= "$extraEntries\n" unless $extraEntriesBeforeNixOS;
# extraEntries could refer to @bootRoot@, which we have to substitute
$conf =~ s/\@bootRoot\@/$bootRoot/g;
$conf =~ s/\@bootRoot\@/$grubBoot->path/g;
# Emit submenus for all system profiles.
sub addProfile {

@ -133,7 +133,7 @@ in
};
boot.initrd = mkIf inInitrd {
kernelModules = [ "spl" "zfs" ] ;
kernelModules = [ "spl" "zfs" ];
extraUtilsCommands =
''
cp -v ${zfsPkg}/sbin/zfs $out/bin
@ -148,6 +148,10 @@ in
'';
};
boot.loader.grub = mkIf inInitrd {
zfsSupport = true;
};
systemd.services."zpool-import" = {
description = "Import zpools";
after = [ "systemd-udev-settle.service" ];

@ -52,6 +52,10 @@ in rec {
(all nixos.tests.installer.lvm)
(all nixos.tests.installer.separateBoot)
(all nixos.tests.installer.simple)
(all nixos.tests.installer.simpleLabels)
(all nixos.tests.installer.simpleProvided)
(all nixos.tests.installer.btrfsSimple)
(all nixos.tests.installer.btrfsSubvols)
(all nixos.tests.ipv6)
(all nixos.tests.kde4)
(all nixos.tests.login)

@ -231,7 +231,7 @@ in rec {
tests.installer.simpleLabels = forAllSystems (system: (import tests/installer.nix { inherit system; }).simpleLabels.test);
tests.installer.simpleProvided = forAllSystems (system: (import tests/installer.nix { inherit system; }).simpleProvided.test);
tests.installer.btrfsSimple = forAllSystems (system: (import tests/installer.nix { inherit system; }).btrfsSimple.test);
#tests.installer.btrfsSubvols = forAllSystems (system: (import tests/installer.nix { inherit system; }).btrfsSubvols.test);
tests.installer.btrfsSubvols = forAllSystems (system: (import tests/installer.nix { inherit system; }).btrfsSubvols.test);
tests.influxdb = callTest tests/influxdb.nix {};
tests.ipv6 = callTest tests/ipv6.nix {};
tests.jenkins = callTest tests/jenkins.nix {};

@ -35,8 +35,8 @@ let
# The configuration to install.
makeConfig = { testChannel, useEFI, grubVersion, grubDevice }: pkgs.writeText "configuration.nix"
''
makeConfig = { testChannel, useEFI, grubVersion, grubDevice, grubIdentifier }:
pkgs.writeText "configuration.nix" ''
{ config, pkgs, modulesPath, ... }:
{ imports =
@ -54,6 +54,7 @@ let
''}
boot.loader.grub.device = "${grubDevice}";
boot.loader.grub.extraConfig = "serial; terminal_output.serial";
boot.loader.grub.fsIdentifier = "${grubIdentifier}";
''}
environment.systemPackages = [ ${optionalString testChannel "pkgs.rlwrap"} ];
@ -93,7 +94,7 @@ let
# disk, and then reboot from the hard disk. It's parameterized with
# a test script fragment `createPartitions', which must create
# partitions and filesystems.
testScriptFun = { createPartitions, testChannel, useEFI, grubVersion, grubDevice }:
testScriptFun = { createPartitions, testChannel, useEFI, grubVersion, grubDevice, grubIdentifier }:
let
# FIXME: OVMF doesn't boot from virtio http://www.mail-archive.com/edk2-devel@lists.sourceforge.net/msg01501.html
iface = if useEFI || grubVersion == 1 then "scsi" else "virtio";
@ -161,7 +162,7 @@ let
$machine->succeed("cat /mnt/etc/nixos/hardware-configuration.nix >&2");
$machine->copyFileFromHost(
"${ makeConfig { inherit testChannel useEFI grubVersion grubDevice; } }",
"${ makeConfig { inherit testChannel useEFI grubVersion grubDevice grubIdentifier; } }",
"/mnt/etc/nixos/configuration.nix");
# Perform the installation.
@ -216,13 +217,13 @@ let
makeInstallerTest = name:
{ createPartitions, testChannel ? false, useEFI ? false, grubVersion ? 2, grubDevice ? "/dev/vda" }:
{ createPartitions, testChannel ? false, useEFI ? false, grubVersion ? 2, grubDevice ? "/dev/vda", grubIdentifier ? "uuid" }:
makeTest {
inherit iso;
name = "installer-" + name;
nodes = if testChannel then { inherit webserver; } else { };
testScript = testScriptFun {
inherit createPartitions testChannel useEFI grubVersion grubDevice;
inherit createPartitions testChannel useEFI grubVersion grubDevice grubIdentifier;
};
};

@ -1,30 +1,45 @@
{ fetchurl, stdenv, flex, bison, gettext, ncurses, libusb, freetype, qemu
, devicemapper, EFIsupport ? false }:
{ stdenv, fetchurl, autogen, flex, bison, python, autoconf, automake
, gettext, ncurses, libusb, freetype, qemu, devicemapper
, linuxPackages ? null
, efiSupport ? false
, zfsSupport ? false
}:
with stdenv.lib;
let
efiSystems = {
"i686-linux".target = "i386";
"x86_64-linux".target = "x86_64";
};
prefix = "grub${if EFIsupport then "-efi" else ""}";
canEfi = any (system: stdenv.system == system) (mapAttrsToList (name: _: name) efiSystems);
version = "2.00";
prefix = "grub${if efiSupport then "-efi" else ""}";
version = "2.02-beta2";
unifont_bdf = fetchurl {
url = "http://unifoundry.com/unifont-5.1.20080820.bdf.gz";
sha256 = "0s0qfff6n6282q28nwwblp5x295zd6n71kl43xj40vgvdqxv0fxx";
};
in (
in
assert efiSupport -> canEfi;
assert zfsSupport -> linuxPackages != null && linuxPackages.zfs != null;
stdenv.mkDerivation rec {
name = "${prefix}-${version}";
src = fetchurl {
url = "mirror://gnu/grub/grub-${version}.tar.xz";
sha256 = "0n64hpmsccvicagvr0c6v0kgp2yw0kgnd3jvsyd26cnwgs7c6kkq";
name = "grub-2.02-beta2.tar.xz";
url = "http://alpha.gnu.org/gnu/grub/grub-2.02~beta2.tar.xz";
sha256 = "13a13fhc0wf473dn73zhga15mjvkg6vqp4h25dxg4n7am2r05izn";
};
nativeBuildInputs = [ flex bison ];
nativeBuildInputs = [ autogen flex bison python autoconf automake ];
buildInputs = [ ncurses libusb freetype gettext devicemapper ]
++ stdenv.lib.optional doCheck qemu;
++ optional doCheck qemu
++ optional zfsSupport linuxPackages.zfs;
preConfigure =
'' for i in "tests/util/"*.in
@ -43,27 +58,19 @@ stdenv.mkDerivation rec {
# See <http://www.mail-archive.com/qemu-devel@nongnu.org/msg22775.html>.
sed -i "tests/util/grub-shell.in" \
-e's/qemu-system-i386/qemu-system-x86_64 -nodefaults/g'
# Fix for building on Glibc 2.16. Won't be needed once the
# gnulib in grub is updated.
sed -i '/gets is a security hole/d' grub-core/gnulib/stdio.in.h
'';
prePatch =
'' gunzip < "${unifont_bdf}" > "unifont.bdf"
'' sh autogen.sh
gunzip < "${unifont_bdf}" > "unifont.bdf"
sed -i "configure" \
-e "s|/usr/src/unifont.bdf|$PWD/unifont.bdf|g"
'';
patches = [ ./fix-bash-completion.patch ];
configureFlags =
let arch = if stdenv.system == "i686-linux" then "i386"
else if stdenv.system == "x86_64-linux" then "x86_64"
else throw "unsupported EFI firmware architecture";
in
stdenv.lib.optionals EFIsupport
[ "--with-platform=efi" "--target=${arch}" "--program-prefix=" ];
configureFlags = optional zfsSupport "--enable-libzfs"
++ optionals efiSupport [ "--with-platform=efi" "--target=${efiSystems.${stdenv.system}.target}" "--program-prefix=" ];
doCheck = false;
enableParallelBuilding = true;
@ -72,7 +79,7 @@ stdenv.mkDerivation rec {
paxmark pms $out/sbin/grub-{probe,bios-setup}
'';
meta = {
meta = with stdenv.lib; {
description = "GNU GRUB, the Grand Unified Boot Loader (2.x beta)";
longDescription =
@ -89,11 +96,8 @@ stdenv.mkDerivation rec {
homepage = http://www.gnu.org/software/grub/;
license = stdenv.lib.licenses.gpl3Plus;
license = licenses.gpl3Plus;
platforms = if EFIsupport then
[ "i686-linux" "x86_64-linux" ]
else
stdenv.lib.platforms.gnu;
platforms = platforms.gnu;
};
}
})

@ -1235,9 +1235,11 @@ let
buggyBiosCDSupport = config.grub.buggyBiosCDSupport or true;
};
grub2 = callPackage ../tools/misc/grub/2.0x.nix { libusb = libusb1; flex = flex_2_5_35; };
grub2 = callPackage ../tools/misc/grub/2.0x.nix { };
grub2_efi = grub2.override { EFIsupport = true; };
grub2_efi = grub2.override { efiSupport = true; };
grub2_zfs = grub2.override { zfsSupport = true; };
gssdp = callPackage ../development/libraries/gssdp {
inherit (gnome) libsoup;

Loading…
Cancel
Save