Merge pull request #3903 from wkennington/master.grub

Bring back grub update with fixes
This commit is contained in:
Aristid Breitkreuz 2014-09-02 20:59:27 +02:00
commit 3a33731e54
11 changed files with 281 additions and 71 deletions

View File

@ -20,6 +20,13 @@ sub uniq {
return @res; return @res;
} }
sub runCommand {
my ($cmd) = @_;
open FILE, "$cmd 2>&1 |" or die "Failed to execute: $cmd\n";
my @ret = <FILE>;
close FILE;
return ($?, @ret);
}
# Process the command line. # Process the command line.
my $outDir = "/etc/nixos"; my $outDir = "/etc/nixos";
@ -304,6 +311,9 @@ foreach my $fs (read_file("/proc/self/mountinfo")) {
# Maybe this is a bind-mount of a filesystem we saw earlier? # Maybe this is a bind-mount of a filesystem we saw earlier?
if (defined $fsByDev{$fields[2]}) { if (defined $fsByDev{$fields[2]}) {
# Make sure this isn't a btrfs subvolume
my ($status, @msg) = runCommand("btrfs subvol show $rootDir$mountPoint");
if (join("", @msg) =~ /ERROR:/) {
my $path = $fields[3]; $path = "" if $path eq "/"; my $path = $fields[3]; $path = "" if $path eq "/";
my $base = $fsByDev{$fields[2]}; my $base = $fsByDev{$fields[2]};
$base = "" if $base eq "/"; $base = "" if $base eq "/";
@ -317,6 +327,7 @@ foreach my $fs (read_file("/proc/self/mountinfo")) {
EOF EOF
next; next;
} }
}
$fsByDev{$fields[2]} = $mountPoint; $fsByDev{$fields[2]} = $mountPoint;
# We don't know how to handle FUSE filesystems. # We don't know how to handle FUSE filesystems.
@ -337,6 +348,30 @@ EOF
} }
} }
# Is this a btrfs filesystem?
if ($fsType eq "btrfs") {
my ($status, @id_info) = runCommand("btrfs subvol show $rootDir$mountPoint");
if ($status != 0 || join("", @msg) =~ /ERROR:/) {
die "Failed to retreive subvolume info for $mountPoint\n";
}
my @ids = join("", @id_info) =~ m/Object ID:[ \t\n]*([^ \t\n]*)/;
if ($#ids > 0) {
die "Btrfs subvol name for $mountPoint listed multiple times in mount\n"
} elsif ($#ids == 0) {
my ($status, @path_info) = runCommand("btrfs subvol list $rootDir$mountPoint");
if ($status != 0) {
die "Failed to find $mountPoint subvolume id from btrfs\n";
}
my @paths = join("", @path_info) =~ m/ID $ids[0] [^\n]* path ([^\n]*)/;
if ($#paths > 0) {
die "Btrfs returned multiple paths for a single subvolume id, mountpoint $mountPoint\n";
} elsif ($#paths != 0) {
die "Btrfs did not return a path for the subvolume at $mountPoint\n";
}
push @extraOptions, "subvol=$paths[0]";
}
}
# Emit the filesystem. # Emit the filesystem.
$fileSystems .= <<EOF; $fileSystems .= <<EOF;
fileSystems.\"$mountPoint\" = fileSystems.\"$mountPoint\" =

View File

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

View File

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

View File

@ -6,7 +6,8 @@ let
cfg = config.boot.loader.grub; 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 = grub =
# Don't include GRUB if we're only generating a GRUB menu (e.g., # Don't include GRUB if we're only generating a GRUB menu (e.g.,
@ -25,11 +26,12 @@ let
inherit (cfg) inherit (cfg)
version extraConfig extraPerEntryConfig extraEntries version extraConfig extraPerEntryConfig extraEntries
extraEntriesBeforeNixOS extraPrepareConfig configurationLimit copyKernels timeout extraEntriesBeforeNixOS extraPrepareConfig configurationLimit copyKernels timeout
default devices explicitBootRoot; default devices fsIdentifier;
path = (makeSearchPath "bin" [ 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" [ ]) + ":" + (makeSearchPath "sbin" [
pkgs.mdadm pkgs.mdadm pkgs.utillinux
]); ]);
}); });
@ -209,12 +211,26 @@ in
''; '';
}; };
explicitBootRoot = mkOption { fsIdentifier = mkOption {
default = ""; default = "uuid";
type = types.str; type = types.addCheck types.str
(type: type == "uuid" || type == "label" || type == "provided");
description = '' description = ''
The relative path of /boot within the parent volume. Leave empty Determines how grub will identify devices when generating the
if /boot is not a btrfs subvolume. 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}" ${pkgs.coreutils}/bin/cp -pf "${v}" "/boot/${n}"
'') config.boot.loader.grub.extraFiles); '') config.boot.loader.grub.extraFiles);
assertions = [{ assertion = !cfg.zfsSupport || cfg.version == 2;
message = "Only grub version 2 provides zfs support";}];
}) })
]; ];

View File

@ -1,5 +1,6 @@
use strict; use strict;
use warnings; use warnings;
use Class::Struct;
use XML::LibXML; use XML::LibXML;
use File::Basename; use File::Basename;
use File::Path; use File::Path;
@ -27,6 +28,14 @@ sub writeFile {
close FILE or die; 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 $grub = get("grub");
my $grubVersion = int(get("version")); my $grubVersion = int(get("version"));
my $extraConfig = get("extraConfig"); my $extraConfig = get("extraConfig");
@ -39,7 +48,7 @@ my $configurationLimit = int(get("configurationLimit"));
my $copyKernels = get("copyKernels") eq "true"; 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 $explicitBootRoot = get("explicitBootRoot"); my $fsIdentifier = get("fsIdentifier");
$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;
@ -48,23 +57,115 @@ print STDERR "updating GRUB $grubVersion menu...\n";
mkpath("/boot/grub", 0, 0700); mkpath("/boot/grub", 0, 0700);
# Discover whether /boot is on the same filesystem as / and # Discover whether /boot is on the same filesystem as / and
# /nix/store. If not, then all kernels and initrds must be copied to # /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 # /boot.
# root of the /boot filesystem. `$bootRoot' is the path to be if (stat("/boot")->dev != stat("/nix/store")->dev) {
# 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) {
$copyKernels = 1; $copyKernels = 1;
} }
if ($explicitBootRoot ne "") { # Discover information about the location of /boot
$bootRoot = $explicitBootRoot; 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, @id_info) = runCommand("btrfs subvol show @{[$fs->mount]}");
if ($status != 0) {
die "Failed to retreive subvolume info for @{[$fs->mount]}\n";
}
my @ids = join("", @id_info) =~ m/Object ID:[ \t\n]*([^ \t\n]*)/;
if ($#ids > 0) {
die "Btrfs subvol name for @{[$fs->device]} listed multiple times in mount\n"
} elsif ($#ids == 0) {
my ($status, @path_info) = runCommand("btrfs subvol list @{[$fs->mount]}");
if ($status != 0) {
die "Failed to find @{[$fs->mount]} subvolume id from btrfs\n";
}
my @paths = join("", @path_info) =~ m/ID $ids[0] [^\n]* path ([^\n]*)/;
if ($#paths > 0) {
die "Btrfs returned multiple paths for a single subvolume id, mountpoint @{[$fs->mount]}\n";
} elsif ($#paths != 0) {
die "Btrfs did not return a path for the subvolume at @{[$fs->mount]}\n";
}
$path = "/$paths[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");
# FIXME: Should be /nix/store, but this fails in the installer
my $grubStore = GrubFs("/nix");
# Generate the header. # Generate the header.
my $conf .= "# Automatically generated. DO NOT EDIT THIS FILE!\n"; my $conf .= "# Automatically generated. DO NOT EDIT THIS FILE!\n";
@ -76,12 +177,17 @@ if ($grubVersion == 1) {
"; ";
if ($splashImage) { if ($splashImage) {
copy $splashImage, "/boot/background.xpm.gz" or die "cannot copy $splashImage to /boot\n"; 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 { else {
if ($copyKernels == 0) {
$conf .= " $conf .= "
" . $grubStore->search;
}
$conf .= "
" . $grubBoot->search . "
if [ -s \$prefix/grubenv ]; then if [ -s \$prefix/grubenv ]; then
load_env load_env
fi fi
@ -102,7 +208,7 @@ else {
set timeout=$timeout set timeout=$timeout
fi fi
if loadfont $bootRoot/grub/fonts/unicode.pf2; then if loadfont " . $grubBoot->path . "/grub/fonts/unicode.pf2; then
set gfxmode=640x480 set gfxmode=640x480
insmod gfxterm insmod gfxterm
insmod vbe insmod vbe
@ -116,7 +222,7 @@ else {
copy $splashImage, "/boot/background.png" or die "cannot copy $splashImage to /boot\n"; copy $splashImage, "/boot/background.png" or die "cannot copy $splashImage to /boot\n";
$conf .= " $conf .= "
insmod png insmod png
if background_image $bootRoot/background.png; then if background_image " . $grubBoot->path . "/background.png; then
set color_normal=white/black set color_normal=white/black
set color_highlight=black/white set color_highlight=black/white
else else
@ -138,7 +244,7 @@ mkpath("/boot/kernels", 0, 0755) if $copyKernels;
sub copyToKernelsDir { sub copyToKernelsDir {
my ($path) = @_; my ($path) = @_;
return $path unless $copyKernels; return $grubStore->path . substr($path, length("/nix")) unless $copyKernels;
$path =~ /\/nix\/store\/(.*)/ or die; $path =~ /\/nix\/store\/(.*)/ or die;
my $name = $1; $name =~ s/\//-/g; my $name = $1; $name =~ s/\//-/g;
my $dst = "/boot/kernels/$name"; my $dst = "/boot/kernels/$name";
@ -151,7 +257,7 @@ sub copyToKernelsDir {
rename $tmp, $dst or die "cannot rename $tmp to $dst\n"; rename $tmp, $dst or die "cannot rename $tmp to $dst\n";
} }
$copied{$dst} = 1; $copied{$dst} = 1;
return "$bootRoot/kernels/$name"; return $grubBoot->path . "/kernels/$name";
} }
sub addEntry { sub addEntry {
@ -178,6 +284,10 @@ sub addEntry {
$conf .= " " . ($xen ? "module" : "initrd") . " $initrd\n\n"; $conf .= " " . ($xen ? "module" : "initrd") . " $initrd\n\n";
} else { } else {
$conf .= "menuentry \"$name\" {\n"; $conf .= "menuentry \"$name\" {\n";
$conf .= $grubBoot->search . "\n";
if ($copyKernels == 0) {
$conf .= $grubStore->search . "\n";
}
$conf .= " $extraPerEntryConfig\n" if $extraPerEntryConfig; $conf .= " $extraPerEntryConfig\n" if $extraPerEntryConfig;
$conf .= " multiboot $xen $xenParams\n" if $xen; $conf .= " multiboot $xen $xenParams\n" if $xen;
$conf .= " " . ($xen ? "module" : "linux") . " $kernel $kernelParams\n"; $conf .= " " . ($xen ? "module" : "linux") . " $kernel $kernelParams\n";
@ -195,7 +305,7 @@ addEntry("NixOS - Default", $defaultConfig);
$conf .= "$extraEntries\n" unless $extraEntriesBeforeNixOS; $conf .= "$extraEntries\n" unless $extraEntriesBeforeNixOS;
# extraEntries could refer to @bootRoot@, which we have to substitute # 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. # Emit submenus for all system profiles.
sub addProfile { sub addProfile {

View File

@ -148,6 +148,10 @@ in
''; '';
}; };
boot.loader.grub = mkIf inInitrd {
zfsSupport = true;
};
systemd.services."zpool-import" = { systemd.services."zpool-import" = {
description = "Import zpools"; description = "Import zpools";
after = [ "systemd-udev-settle.service" ]; after = [ "systemd-udev-settle.service" ];

View File

@ -52,6 +52,11 @@ in rec {
(all nixos.tests.installer.lvm) (all nixos.tests.installer.lvm)
(all nixos.tests.installer.separateBoot) (all nixos.tests.installer.separateBoot)
(all nixos.tests.installer.simple) (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.installer.btrfsSubvolDefault)
(all nixos.tests.ipv6) (all nixos.tests.ipv6)
(all nixos.tests.kde4) (all nixos.tests.kde4)
(all nixos.tests.login) (all nixos.tests.login)

View File

@ -231,7 +231,8 @@ in rec {
tests.installer.simpleLabels = forAllSystems (system: (import tests/installer.nix { inherit system; }).simpleLabels.test); 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.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.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.installer.btrfsSubvolDefault = forAllSystems (system: (import tests/installer.nix { inherit system; }).btrfsSubvolDefault.test);
tests.influxdb = callTest tests/influxdb.nix {}; tests.influxdb = callTest tests/influxdb.nix {};
tests.ipv6 = callTest tests/ipv6.nix {}; tests.ipv6 = callTest tests/ipv6.nix {};
tests.jenkins = callTest tests/jenkins.nix {}; tests.jenkins = callTest tests/jenkins.nix {};

View File

@ -35,8 +35,8 @@ let
# The configuration to install. # 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, ... }: { config, pkgs, modulesPath, ... }:
{ imports = { imports =
@ -54,6 +54,7 @@ let
''} ''}
boot.loader.grub.device = "${grubDevice}"; boot.loader.grub.device = "${grubDevice}";
boot.loader.grub.extraConfig = "serial; terminal_output.serial"; boot.loader.grub.extraConfig = "serial; terminal_output.serial";
boot.loader.grub.fsIdentifier = "${grubIdentifier}";
''} ''}
environment.systemPackages = [ ${optionalString testChannel "pkgs.rlwrap"} ]; environment.systemPackages = [ ${optionalString testChannel "pkgs.rlwrap"} ];
@ -93,7 +94,7 @@ let
# disk, and then reboot from the hard disk. It's parameterized with # disk, and then reboot from the hard disk. It's parameterized with
# a test script fragment `createPartitions', which must create # a test script fragment `createPartitions', which must create
# partitions and filesystems. # partitions and filesystems.
testScriptFun = { createPartitions, testChannel, useEFI, grubVersion, grubDevice }: testScriptFun = { createPartitions, testChannel, useEFI, grubVersion, grubDevice, grubIdentifier }:
let let
# FIXME: OVMF doesn't boot from virtio http://www.mail-archive.com/edk2-devel@lists.sourceforge.net/msg01501.html # 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"; 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->succeed("cat /mnt/etc/nixos/hardware-configuration.nix >&2");
$machine->copyFileFromHost( $machine->copyFileFromHost(
"${ makeConfig { inherit testChannel useEFI grubVersion grubDevice; } }", "${ makeConfig { inherit testChannel useEFI grubVersion grubDevice grubIdentifier; } }",
"/mnt/etc/nixos/configuration.nix"); "/mnt/etc/nixos/configuration.nix");
# Perform the installation. # Perform the installation.
@ -216,13 +217,13 @@ let
makeInstallerTest = name: 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 { makeTest {
inherit iso; inherit iso;
name = "installer-" + name; name = "installer-" + name;
nodes = if testChannel then { inherit webserver; } else { }; nodes = if testChannel then { inherit webserver; } else { };
testScript = testScriptFun { testScript = testScriptFun {
inherit createPartitions testChannel useEFI grubVersion grubDevice; inherit createPartitions testChannel useEFI grubVersion grubDevice grubIdentifier;
}; };
}; };
@ -461,11 +462,36 @@ in {
"mount LABEL=root /mnt", "mount LABEL=root /mnt",
"btrfs subvol create /mnt/boot", "btrfs subvol create /mnt/boot",
"btrfs subvol create /mnt/nixos", "btrfs subvol create /mnt/nixos",
"btrfs subvol create /mnt/nixos/default",
"umount /mnt", "umount /mnt",
"mount -o defaults,subvol=nixos LABEL=root /mnt", "mount -o defaults,subvol=nixos/default LABEL=root /mnt",
"mkdir /mnt/boot", "mkdir /mnt/boot",
"mount -o defaults,subvol=boot LABEL=root /mnt/boot", "mount -o defaults,subvol=boot LABEL=root /mnt/boot",
); );
''; '';
}; };
# Test to see if we can detect default and aux subvolumes correctly
btrfsSubvolDefault = makeInstallerTest "btrfsSubvolDefault" {
createPartitions = ''
$machine->succeed(
"sgdisk -Z /dev/vda",
"sgdisk -n 1:0:+1M -n 2:0:+1G -N 3 -t 1:ef02 -t 2:8200 -t 3:8300 -c 3:root /dev/vda",
"mkswap /dev/vda2 -L swap",
"swapon -L swap",
"mkfs.btrfs -L root /dev/vda3",
"btrfs device scan",
"mount LABEL=root /mnt",
"btrfs subvol create /mnt/badpath",
"btrfs subvol create /mnt/badpath/boot",
"btrfs subvol create /mnt/nixos",
"btrfs subvol set-default \$(btrfs subvol list /mnt | grep 'nixos' | awk '{print \$2}') /mnt",
"umount /mnt",
"mount -o defaults LABEL=root /mnt",
"mkdir -p /mnt/badpath/boot", # Help ensure the detection mechanism is actually looking up subvolumes
"mkdir /mnt/boot",
"mount -o defaults,subvol=badpath/boot LABEL=root /mnt/boot",
);
'';
};
} }

View File

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

View File

@ -1235,9 +1235,11 @@ let
buggyBiosCDSupport = config.grub.buggyBiosCDSupport or true; 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 { gssdp = callPackage ../development/libraries/gssdp {
inherit (gnome) libsoup; inherit (gnome) libsoup;