diff --git a/nixos/modules/system/boot/loader/grub/install-grub.pl b/nixos/modules/system/boot/loader/grub/install-grub.pl index a83733db63b0c..b9f61337cefd1 100644 --- a/nixos/modules/system/boot/loader/grub/install-grub.pl +++ b/nixos/modules/system/boot/loader/grub/install-grub.pl @@ -1,5 +1,6 @@ use strict; use warnings; +use Class::Struct; use XML::LibXML; use File::Basename; use File::Path; @@ -47,20 +48,64 @@ sub writeFile { 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")->dev) { $copyKernels = 1; } +# Discover information about the location of /boot +struct(Fs => { + device => '$', + type => '$', + mount => '$', +}); +sub GetFs { + my ($dir) = @_; + my @boot = split(/[ \n\t]+/, `df -T "$dir" | tail -n 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) { + 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 $lbl = "/dev/disk/by-label/"; + if (index($fs->device, $lbl) == 0) { + $search = "--label " . substr($fs->device, length($lbl)); + } + my $uuid = "/dev/disk/by-uuid/"; + if (index($fs->device, $uuid) == 0) { + $search = "--fs-uuid " . substr($fs->device, length($uuid)); + } + } + 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"); # Generate the header. my $conf .= "# Automatically generated. DO NOT EDIT THIS FILE!\n"; @@ -72,12 +117,14 @@ sub writeFile { "; 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 @@ -98,7 +145,7 @@ sub writeFile { 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 @@ -112,7 +159,7 @@ sub writeFile { 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 @@ -134,7 +181,7 @@ sub writeFile { 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"; @@ -147,7 +194,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 { @@ -174,6 +221,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"; @@ -191,7 +240,7 @@ sub addEntry { $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 { diff --git a/pkgs/tools/misc/grub/2.0x.nix b/pkgs/tools/misc/grub/2.0x.nix index ae3fe14876420..4931e08485540 100644 --- a/pkgs/tools/misc/grub/2.0x.nix +++ b/pkgs/tools/misc/grub/2.0x.nix @@ -1,11 +1,12 @@ -{ fetchurl, stdenv, flex, bison, gettext, ncurses, libusb, freetype, qemu -, devicemapper, EFIsupport ? false }: +{ fetchurl, fetchgit, stdenv, autogen, flex, bison, python, autoconf, automake, gettext, ncurses, libusb, freetype, qemu +, devicemapper, linuxPackages, EFIsupport ? false }: let prefix = "grub${if EFIsupport then "-efi" else ""}"; version = "2.00"; + revision = "bc8a613"; unifont_bdf = fetchurl { url = "http://unifoundry.com/unifont-5.1.20080820.bdf.gz"; @@ -15,15 +16,16 @@ let in stdenv.mkDerivation rec { - name = "${prefix}-${version}"; + name = "${prefix}-${version}.${toString revision}"; - src = fetchurl { - url = "mirror://gnu/grub/grub-${version}.tar.xz"; - sha256 = "0n64hpmsccvicagvr0c6v0kgp2yw0kgnd3jvsyd26cnwgs7c6kkq"; + src = fetchgit { + url = "http://git.savannah.gnu.org/r/grub.git/"; + rev = "bc8a6137b23292771d8b1a9bd0b32288c3d94e7d"; + sha256 = "10z3nyngplzmp7267w4cqwwrh986jfd5rq9mm2yyp68nabk1s806"; }; - nativeBuildInputs = [ flex bison ]; - buildInputs = [ ncurses libusb freetype gettext devicemapper ] + nativeBuildInputs = [ autogen flex bison python autoconf automake ]; + buildInputs = [ ncurses libusb freetype gettext devicemapper linuxPackages.zfs ] ++ stdenv.lib.optional doCheck qemu; preConfigure = @@ -43,14 +45,11 @@ stdenv.mkDerivation rec { # See . 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" ''; @@ -62,7 +61,8 @@ stdenv.mkDerivation rec { else if stdenv.system == "x86_64-linux" then "x86_64" else throw "unsupported EFI firmware architecture"; in - stdenv.lib.optionals EFIsupport + [ "--enable-libzfs" ] ++ + stdenv.lib.optionals EFIsupport [ "--with-platform=efi" "--target=${arch}" "--program-prefix=" ]; doCheck = false; diff --git a/pkgs/top-level/all-packages.nix b/pkgs/top-level/all-packages.nix index 929fd87e963cd..ee5573cd47d76 100644 --- a/pkgs/top-level/all-packages.nix +++ b/pkgs/top-level/all-packages.nix @@ -1073,7 +1073,7 @@ let buggyBiosCDSupport = config.grub.buggyBiosCDSupport or true; }; - grub2 = callPackage ../tools/misc/grub/2.0x.nix { libusb = libusb1; }; + grub2 = callPackage ../tools/misc/grub/2.0x.nix { }; grub2_efi = grub2.override { EFIsupport = true; };