summary refs log tree commit diff
path: root/nixos/modules/system/boot/loader/grub/install-grub.pl
diff options
context:
space:
mode:
Diffstat (limited to 'nixos/modules/system/boot/loader/grub/install-grub.pl')
-rw-r--r--nixos/modules/system/boot/loader/grub/install-grub.pl780
1 files changed, 0 insertions, 780 deletions
diff --git a/nixos/modules/system/boot/loader/grub/install-grub.pl b/nixos/modules/system/boot/loader/grub/install-grub.pl
deleted file mode 100644
index 0c93b288fc6..00000000000
--- a/nixos/modules/system/boot/loader/grub/install-grub.pl
+++ /dev/null
@@ -1,780 +0,0 @@
-use strict;
-use warnings;
-use Class::Struct;
-use XML::LibXML;
-use File::Basename;
-use File::Path;
-use File::stat;
-use File::Copy;
-use File::Copy::Recursive qw(rcopy pathrm);
-use File::Slurp;
-use File::Temp;
-use JSON;
-use File::Find;
-require List::Compare;
-use POSIX;
-use Cwd;
-
-# system.build.toplevel path
-my $defaultConfig = $ARGV[1] or die;
-
-# Grub config XML generated by grubConfig function in grub.nix
-my $dom = XML::LibXML->load_xml(location => $ARGV[0]);
-
-sub get { my ($name) = @_; return $dom->findvalue("/expr/attrs/attr[\@name = '$name']/*/\@value"); }
-
-sub getList {
-    my ($name) = @_;
-    my @list = ();
-    foreach my $entry ($dom->findnodes("/expr/attrs/attr[\@name = '$name']/list/string/\@value")) {
-        $entry = $entry->findvalue(".") or die;
-        push(@list, $entry);
-    }
-    return @list;
-}
-
-sub readFile {
-    my ($fn) = @_; local $/ = undef;
-    open FILE, "<$fn" or return undef; my $s = <FILE>; close FILE;
-    local $/ = "\n"; chomp $s; return $s;
-}
-
-sub writeFile {
-    my ($fn, $s) = @_;
-    open FILE, ">$fn" or die "cannot create $fn: $!\n";
-    print FILE $s 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 $grubVersion = int(get("version"));
-my $grubTarget = get("grubTarget");
-my $extraConfig = get("extraConfig");
-my $extraPrepareConfig = get("extraPrepareConfig");
-my $extraPerEntryConfig = get("extraPerEntryConfig");
-my $extraEntries = get("extraEntries");
-my $extraEntriesBeforeNixOS = get("extraEntriesBeforeNixOS") eq "true";
-my $splashImage = get("splashImage");
-my $splashMode = get("splashMode");
-my $backgroundColor = get("backgroundColor");
-my $configurationLimit = int(get("configurationLimit"));
-my $copyKernels = get("copyKernels") eq "true";
-my $timeout = int(get("timeout"));
-my $defaultEntry = get("default");
-my $fsIdentifier = get("fsIdentifier");
-my $grubEfi = get("grubEfi");
-my $grubTargetEfi = get("grubTargetEfi");
-my $bootPath = get("bootPath");
-my $storePath = get("storePath");
-my $canTouchEfiVariables = get("canTouchEfiVariables");
-my $efiInstallAsRemovable = get("efiInstallAsRemovable");
-my $efiSysMountPoint = get("efiSysMountPoint");
-my $gfxmodeEfi = get("gfxmodeEfi");
-my $gfxmodeBios = get("gfxmodeBios");
-my $gfxpayloadEfi = get("gfxpayloadEfi");
-my $gfxpayloadBios = get("gfxpayloadBios");
-my $bootloaderId = get("bootloaderId");
-my $forceInstall = get("forceInstall");
-my $font = get("font");
-my $theme = get("theme");
-my $saveDefault = $defaultEntry eq "saved";
-$ENV{'PATH'} = get("path");
-
-die "unsupported GRUB version\n" if $grubVersion != 1 && $grubVersion != 2;
-
-print STDERR "updating GRUB $grubVersion menu...\n";
-
-mkpath("$bootPath/grub", 0, 0700);
-
-# Discover whether the bootPath is on the same filesystem as / and
-# /nix/store.  If not, then all kernels and initrds must be copied to
-# the bootPath.
-if (stat($bootPath)->dev != stat("/nix/store")->dev) {
-    $copyKernels = 1;
-}
-
-# Discover information about the location of the bootPath
-struct(Fs => {
-    device => '$',
-    type => '$',
-    mount => '$',
-});
-sub PathInMount {
-    my ($path, $mount) = @_;
-    my @splitMount = split /\//, $mount;
-    my @splitPath = split /\//, $path;
-    if ($#splitPath < $#splitMount) {
-        return 0;
-    }
-    for (my $i = 0; $i <= $#splitMount; $i++) {
-        if ($splitMount[$i] ne $splitPath[$i]) {
-            return 0;
-        }
-    }
-    return 1;
-}
-
-# Figure out what filesystem is used for the directory with init/initrd/kernel files
-sub GetFs {
-    my ($dir) = @_;
-    my $bestFs = Fs->new(device => "", type => "", mount => "");
-    foreach my $fs (read_file("/proc/self/mountinfo")) {
-        chomp $fs;
-        my @fields = split / /, $fs;
-        my $mountPoint = $fields[4];
-        next unless -d $mountPoint;
-        my @mountOptions = split /,/, $fields[5];
-
-        # Skip the optional fields.
-        my $n = 6; $n++ while $fields[$n] ne "-"; $n++;
-        my $fsType = $fields[$n];
-        my $device = $fields[$n + 1];
-        my @superOptions = split /,/, $fields[$n + 2];
-
-        # Skip the bind-mount on /nix/store.
-        next if $mountPoint eq "/nix/store" && (grep { $_ eq "rw" } @superOptions);
-        # 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);
-
-        # Is it better than our current match?
-        if (length($mountPoint) > length($bestFs->mount)) {
-            $bestFs = Fs->new(device => $device, type => $fsType, mount => $mountPoint);
-        }
-    }
-    return $bestFs;
-}
-struct (Grub => {
-    path => '$',
-    search => '$',
-});
-my $driveid = 1;
-sub GrubFs {
-    my ($dir) = @_;
-    my $fs = GetFs($dir);
-    my $path = substr($dir, length($fs->mount));
-    if (substr($path, 0, 1) ne "/") {
-        $path = "/$path";
-    }
-    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("@utillinux@/bin/blkid -o export @{[$fs->device]}");
-                if ($status != 0) {
-                    die "Failed to get blkid info (returned $status) for @{[$fs->mount]} on @{[$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("@btrfsprogs@/bin/btrfs subvol show @{[$fs->mount]}");
-                if ($status != 0) {
-                    die "Failed to retrieve subvolume info for @{[$fs->mount]}\n";
-                }
-                my @ids = join("\n", @id_info) =~ m/^(?!\/\n).*Subvolume ID:[ \t\n]*([0-9]+)/s;
-                if ($#ids > 0) {
-                    die "Btrfs subvol name for @{[$fs->device]} listed multiple times in mount\n"
-                } elsif ($#ids == 0) {
-                    my ($status, @path_info) = runCommand("@btrfsprogs@/bin/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($bootPath);
-my $grubStore;
-if ($copyKernels == 0) {
-    $grubStore = GrubFs($storePath);
-}
-
-# Generate the header.
-my $conf .= "# Automatically generated.  DO NOT EDIT THIS FILE!\n";
-
-if ($grubVersion == 1) {
-    # $defaultEntry might be "saved", indicating that we want to use the last selected configuration as default.
-    # Incidentally this is already the correct value for the grub 1 config to achieve this behaviour.
-    $conf .= "
-        default $defaultEntry
-        timeout $timeout
-    ";
-    if ($splashImage) {
-        copy $splashImage, "$bootPath/background.xpm.gz" or die "cannot copy $splashImage to $bootPath: $!\n";
-        $conf .= "splashimage " . ($grubBoot->path eq "/" ? "" : $grubBoot->path) . "/background.xpm.gz\n";
-    }
-}
-
-else {
-    my @users = ();
-    foreach my $user ($dom->findnodes('/expr/attrs/attr[@name = "users"]/attrs/attr')) {
-        my $name = $user->findvalue('@name') or die;
-        my $hashedPassword = $user->findvalue('./attrs/attr[@name = "hashedPassword"]/string/@value');
-        my $hashedPasswordFile = $user->findvalue('./attrs/attr[@name = "hashedPasswordFile"]/string/@value');
-        my $password = $user->findvalue('./attrs/attr[@name = "password"]/string/@value');
-        my $passwordFile = $user->findvalue('./attrs/attr[@name = "passwordFile"]/string/@value');
-
-        if ($hashedPasswordFile) {
-            open(my $f, '<', $hashedPasswordFile) or die "Can't read file '$hashedPasswordFile'!";
-            $hashedPassword = <$f>;
-            chomp $hashedPassword;
-        }
-        if ($passwordFile) {
-            open(my $f, '<', $passwordFile) or die "Can't read file '$passwordFile'!";
-            $password = <$f>;
-            chomp $password;
-        }
-
-        if ($hashedPassword) {
-            if (index($hashedPassword, "grub.pbkdf2.") == 0) {
-                $conf .= "\npassword_pbkdf2 $name $hashedPassword";
-            }
-            else {
-                die "Password hash for GRUB user '$name' is not valid!";
-            }
-        }
-        elsif ($password) {
-            $conf .= "\npassword $name $password";
-        }
-        else {
-            die "GRUB user '$name' has no password!";
-        }
-        push(@users, $name);
-    }
-    if (@users) {
-        $conf .= "\nset superusers=\"" . join(' ',@users) . "\"\n";
-    }
-
-    if ($copyKernels == 0) {
-        $conf .= "
-            " . $grubStore->search;
-    }
-    # FIXME: should use grub-mkconfig.
-    my $defaultEntryText = $defaultEntry;
-    if ($saveDefault) {
-        $defaultEntryText = "\"\${saved_entry}\"";
-    }
-    $conf .= "
-        " . $grubBoot->search . "
-        if [ -s \$prefix/grubenv ]; then
-          load_env
-        fi
-
-        # ‘grub-reboot’ sets a one-time saved entry, which we process here and
-        # then delete.
-        if [ \"\${next_entry}\" ]; then
-          set default=\"\${next_entry}\"
-          set next_entry=
-          save_env next_entry
-          set timeout=1
-          set boot_once=true
-        else
-          set default=$defaultEntryText
-          set timeout=$timeout
-        fi
-
-        function savedefault {
-            if [ -z \"\${boot_once}\"]; then
-            saved_entry=\"\${chosen}\"
-            save_env saved_entry
-            fi
-        }
-
-        # Setup the graphics stack for bios and efi systems
-        if [ \"\${grub_platform}\" = \"efi\" ]; then
-          insmod efi_gop
-          insmod efi_uga
-        else
-          insmod vbe
-        fi
-    ";
-
-    if ($font) {
-        copy $font, "$bootPath/converted-font.pf2" or die "cannot copy $font to $bootPath: $!\n";
-        $conf .= "
-            insmod font
-            if loadfont " . ($grubBoot->path eq "/" ? "" : $grubBoot->path) . "/converted-font.pf2; then
-              insmod gfxterm
-              if [ \"\${grub_platform}\" = \"efi\" ]; then
-                set gfxmode=$gfxmodeEfi
-                set gfxpayload=$gfxpayloadEfi
-              else
-                set gfxmode=$gfxmodeBios
-                set gfxpayload=$gfxpayloadBios
-              fi
-              terminal_output gfxterm
-            fi
-        ";
-    }
-    if ($splashImage) {
-        # Keeps the image's extension.
-        my ($filename, $dirs, $suffix) = fileparse($splashImage, qr"\..[^.]*$");
-        # The module for jpg is jpeg.
-        if ($suffix eq ".jpg") {
-            $suffix = ".jpeg";
-        }
-        if ($backgroundColor) {
-            $conf .= "
-            background_color '$backgroundColor'
-            ";
-        }
-        copy $splashImage, "$bootPath/background$suffix" or die "cannot copy $splashImage to $bootPath: $!\n";
-        $conf .= "
-            insmod " . substr($suffix, 1) . "
-            if background_image --mode '$splashMode' " . ($grubBoot->path eq "/" ? "" : $grubBoot->path) . "/background$suffix; then
-              set color_normal=white/black
-              set color_highlight=black/white
-            else
-              set menu_color_normal=cyan/blue
-              set menu_color_highlight=white/blue
-            fi
-        ";
-    }
-
-    rmtree("$bootPath/theme") or die "cannot clean up theme folder in $bootPath\n" if -e "$bootPath/theme";
-
-    if ($theme) {
-        # Copy theme
-        rcopy($theme, "$bootPath/theme") or die "cannot copy $theme to $bootPath\n";
-        $conf .= "
-            # Sets theme.
-            set theme=" . ($grubBoot->path eq "/" ? "" : $grubBoot->path) . "/theme/theme.txt
-            export theme
-            # Load theme fonts, if any
-        ";
-
-        find( { wanted => sub {
-            if ($_ =~ /\.pf2$/i) {
-                $font = File::Spec->abs2rel($File::Find::name, $theme);
-                $conf .= "
-                    loadfont " . ($grubBoot->path eq "/" ? "" : $grubBoot->path) . "/theme/$font
-                ";
-            }
-        }, no_chdir => 1 }, $theme );
-    }
-}
-
-$conf .= "$extraConfig\n";
-
-
-# Generate the menu entries.
-$conf .= "\n";
-
-my %copied;
-mkpath("$bootPath/kernels", 0, 0755) if $copyKernels;
-
-sub copyToKernelsDir {
-    my ($path) = @_;
-    return $grubStore->path . substr($path, length("/nix/store")) unless $copyKernels;
-    $path =~ /\/nix\/store\/(.*)/ or die;
-    my $name = $1; $name =~ s/\//-/g;
-    my $dst = "$bootPath/kernels/$name";
-    # Don't copy the file if $dst already exists.  This means that we
-    # have to create $dst atomically to prevent partially copied
-    # kernels or initrd if this script is ever interrupted.
-    if (! -e $dst) {
-        my $tmp = "$dst.tmp";
-        copy $path, $tmp or die "cannot copy $path to $tmp: $!\n";
-        rename $tmp, $dst or die "cannot rename $tmp to $dst: $!\n";
-    }
-    $copied{$dst} = 1;
-    return ($grubBoot->path eq "/" ? "" : $grubBoot->path) . "/kernels/$name";
-}
-
-sub addEntry {
-    my ($name, $path, $options) = @_;
-    return unless -e "$path/kernel" && -e "$path/initrd";
-
-    my $kernel = copyToKernelsDir(Cwd::abs_path("$path/kernel"));
-    my $initrd = copyToKernelsDir(Cwd::abs_path("$path/initrd"));
-
-    # Include second initrd with secrets
-    if (-e -x "$path/append-initrd-secrets") {
-        my $initrdName = basename($initrd);
-        my $initrdSecretsPath = "$bootPath/kernels/$initrdName-secrets";
-
-        mkpath(dirname($initrdSecretsPath), 0, 0755);
-        my $oldUmask = umask;
-        # Make sure initrd is not world readable (won't work if /boot is FAT)
-        umask 0137;
-        my $initrdSecretsPathTemp = File::Temp::mktemp("$initrdSecretsPath.XXXXXXXX");
-        system("$path/append-initrd-secrets", $initrdSecretsPathTemp) == 0 or die "failed to create initrd secrets: $!\n";
-        # Check whether any secrets were actually added
-        if (-e $initrdSecretsPathTemp && ! -z _) {
-            rename $initrdSecretsPathTemp, $initrdSecretsPath or die "failed to move initrd secrets into place: $!\n";
-            $copied{$initrdSecretsPath} = 1;
-            $initrd .= " " . ($grubBoot->path eq "/" ? "" : $grubBoot->path) . "/kernels/$initrdName-secrets";
-        } else {
-            unlink $initrdSecretsPathTemp;
-            rmdir dirname($initrdSecretsPathTemp);
-        }
-        umask $oldUmask;
-    }
-
-    my $xen = -e "$path/xen.gz" ? copyToKernelsDir(Cwd::abs_path("$path/xen.gz")) : undef;
-
-    # FIXME: $confName
-
-    my $kernelParams =
-        "init=" . Cwd::abs_path("$path/init") . " " .
-        readFile("$path/kernel-params");
-    my $xenParams = $xen && -e "$path/xen-params" ? readFile("$path/xen-params") : "";
-
-    if ($grubVersion == 1) {
-        $conf .= "title $name\n";
-        $conf .= "  $extraPerEntryConfig\n" if $extraPerEntryConfig;
-        $conf .= "  kernel $xen $xenParams\n" if $xen;
-        $conf .= "  " . ($xen ? "module" : "kernel") . " $kernel $kernelParams\n";
-        $conf .= "  " . ($xen ? "module" : "initrd") . " $initrd\n";
-        if ($saveDefault) {
-            $conf .= "  savedefault\n";
-        }
-        $conf .= "\n";
-    } else {
-        $conf .= "menuentry \"$name\" " . ($options||"") . " {\n";
-        if ($saveDefault) {
-            $conf .= "  savedefault\n";
-        }
-        $conf .= $grubBoot->search . "\n";
-        if ($copyKernels == 0) {
-            $conf .= $grubStore->search . "\n";
-        }
-        $conf .= "  $extraPerEntryConfig\n" if $extraPerEntryConfig;
-        $conf .= "  multiboot $xen $xenParams\n" if $xen;
-        $conf .= "  " . ($xen ? "module" : "linux") . " $kernel $kernelParams\n";
-        $conf .= "  " . ($xen ? "module" : "initrd") . " $initrd\n";
-        $conf .= "}\n\n";
-    }
-}
-
-
-# Add default entries.
-$conf .= "$extraEntries\n" if $extraEntriesBeforeNixOS;
-
-addEntry("NixOS - Default", $defaultConfig, "--unrestricted");
-
-$conf .= "$extraEntries\n" unless $extraEntriesBeforeNixOS;
-
-# Find all the children of the current default configuration
-# Do not search for grand children
-my @links = sort (glob "$defaultConfig/specialisation/*");
-foreach my $link (@links) {
-
-    my $entryName = "";
-
-    my $cfgName = readFile("$link/configuration-name");
-
-    my $date = strftime("%F", localtime(lstat($link)->mtime));
-    my $version =
-        -e "$link/nixos-version"
-        ? readFile("$link/nixos-version")
-        : basename((glob(dirname(Cwd::abs_path("$link/kernel")) . "/lib/modules/*"))[0]);
-
-    if ($cfgName) {
-        $entryName = $cfgName;
-    } else {
-        my $linkname = basename($link);
-        $entryName = "($linkname - $date - $version)";
-    }
-    addEntry("NixOS - $entryName", $link);
-}
-
-my $grubBootPath = $grubBoot->path;
-# extraEntries could refer to @bootRoot@, which we have to substitute
-$conf =~ s/\@bootRoot\@/$grubBootPath/g;
-
-# Emit submenus for all system profiles.
-sub addProfile {
-    my ($profile, $description) = @_;
-
-    # Add entries for all generations of this profile.
-    $conf .= "submenu \"$description\" {\n" if $grubVersion == 2;
-
-    sub nrFromGen { my ($x) = @_; $x =~ /\/\w+-(\d+)-link/; return $1; }
-
-    my @links = sort
-        { nrFromGen($b) <=> nrFromGen($a) }
-        (glob "$profile-*-link");
-
-    my $curEntry = 0;
-    foreach my $link (@links) {
-        last if $curEntry++ >= $configurationLimit;
-        if (! -e "$link/nixos-version") {
-            warn "skipping corrupt system profile entry ‘$link’\n";
-            next;
-        }
-        my $date = strftime("%F", localtime(lstat($link)->mtime));
-        my $version =
-            -e "$link/nixos-version"
-            ? readFile("$link/nixos-version")
-            : basename((glob(dirname(Cwd::abs_path("$link/kernel")) . "/lib/modules/*"))[0]);
-        addEntry("NixOS - Configuration " . nrFromGen($link) . " ($date - $version)", $link);
-    }
-
-    $conf .= "}\n" if $grubVersion == 2;
-}
-
-addProfile "/nix/var/nix/profiles/system", "NixOS - All configurations";
-
-if ($grubVersion == 2) {
-    for my $profile (glob "/nix/var/nix/profiles/system-profiles/*") {
-        my $name = basename($profile);
-        next unless $name =~ /^\w+$/;
-        addProfile $profile, "NixOS - Profile '$name'";
-    }
-}
-
-# extraPrepareConfig could refer to @bootPath@, which we have to substitute
-$extraPrepareConfig =~ s/\@bootPath\@/$bootPath/g;
-
-# Run extraPrepareConfig in sh
-if ($extraPrepareConfig ne "") {
-    system((get("shell"), "-c", $extraPrepareConfig));
-}
-
-# write the GRUB config.
-my $confFile = $grubVersion == 1 ? "$bootPath/grub/menu.lst" : "$bootPath/grub/grub.cfg";
-my $tmpFile = $confFile . ".tmp";
-writeFile($tmpFile, $conf);
-
-
-# check whether to install GRUB EFI or not
-sub getEfiTarget {
-    if ($grubVersion == 1) {
-        return "no"
-    } elsif (($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 {
-        # prevent an installation if neither grub nor grubEfi is given
-        return "neither"
-    }
-}
-
-my $efiTarget = getEfiTarget();
-
-# Append entries detected by os-prober
-if (get("useOSProber") eq "true") {
-    if ($saveDefault) {
-        # os-prober will read this to determine if "savedefault" should be added to generated entries
-        $ENV{'GRUB_SAVEDEFAULT'} = "true";
-    }
-
-    my $targetpackage = ($efiTarget eq "no") ? $grub : $grubEfi;
-    system(get("shell"), "-c", "pkgdatadir=$targetpackage/share/grub $targetpackage/etc/grub.d/30_os-prober >> $tmpFile");
-}
-
-# Atomically switch to the new config
-rename $tmpFile, $confFile or die "cannot rename $tmpFile to $confFile: $!\n";
-
-
-# Remove obsolete files from $bootPath/kernels.
-foreach my $fn (glob "$bootPath/kernels/*") {
-    next if defined $copied{$fn};
-    print STDERR "removing obsolete file $fn\n";
-    unlink $fn;
-}
-
-
-#
-# Install GRUB if the parameters changed from the last time we installed it.
-#
-
-struct(GrubState => {
-    name => '$',
-    version => '$',
-    efi => '$',
-    devices => '$',
-    efiMountPoint => '$',
-    extraGrubInstallArgs => '@',
-});
-# If you add something to the state file, only add it to the end
-# because it is read line-by-line.
-sub readGrubState {
-    my $defaultGrubState = GrubState->new(name => "", version => "", efi => "", devices => "", efiMountPoint => "", extraGrubInstallArgs => () );
-    open FILE, "<$bootPath/grub/state" or return $defaultGrubState;
-    local $/ = "\n";
-    my $name = <FILE>;
-    chomp($name);
-    my $version = <FILE>;
-    chomp($version);
-    my $efi = <FILE>;
-    chomp($efi);
-    my $devices = <FILE>;
-    chomp($devices);
-    my $efiMountPoint = <FILE>;
-    chomp($efiMountPoint);
-    # Historically, arguments in the state file were one per each line, but that
-    # gets really messy when newlines are involved, structured arguments
-    # like lists are needed (they have to have a separator encoding), or even worse,
-    # when we need to remove a setting in the future. Thus, the 6th line is a JSON
-    # object that can store structured data, with named keys, and all new state
-    # should go in there.
-    my $jsonStateLine = <FILE>;
-    # For historical reasons we do not check the values above for un-definedness
-    # (that is, when the state file has too few lines and EOF is reached),
-    # because the above come from the first version of this logic and are thus
-    # guaranteed to be present.
-    $jsonStateLine = defined $jsonStateLine ? $jsonStateLine : '{}'; # empty JSON object
-    chomp($jsonStateLine);
-    if ($jsonStateLine eq "") {
-        $jsonStateLine = '{}'; # empty JSON object
-    }
-    my %jsonState = %{decode_json($jsonStateLine)};
-    my @extraGrubInstallArgs = exists($jsonState{'extraGrubInstallArgs'}) ? @{$jsonState{'extraGrubInstallArgs'}} : ();
-    close FILE;
-    my $grubState = GrubState->new(name => $name, version => $version, efi => $efi, devices => $devices, efiMountPoint => $efiMountPoint, extraGrubInstallArgs => \@extraGrubInstallArgs );
-    return $grubState
-}
-
-my @deviceTargets = getList('devices');
-my $prevGrubState = readGrubState();
-my @prevDeviceTargets = split/,/, $prevGrubState->devices;
-my @extraGrubInstallArgs = getList('extraGrubInstallArgs');
-my @prevExtraGrubInstallArgs = @{$prevGrubState->extraGrubInstallArgs};
-
-my $devicesDiffer = scalar (List::Compare->new( '-u', '-a', \@deviceTargets, \@prevDeviceTargets)->get_symmetric_difference());
-my $extraGrubInstallArgsDiffer = scalar (List::Compare->new( '-u', '-a', \@extraGrubInstallArgs, \@prevExtraGrubInstallArgs)->get_symmetric_difference());
-my $nameDiffer = get("fullName") ne $prevGrubState->name;
-my $versionDiffer = get("fullVersion") ne $prevGrubState->version;
-my $efiDiffer = $efiTarget ne $prevGrubState->efi;
-my $efiMountPointDiffer = $efiSysMountPoint ne $prevGrubState->efiMountPoint;
-if (($ENV{'NIXOS_INSTALL_GRUB'} // "") eq "1") {
-    warn "NIXOS_INSTALL_GRUB env var deprecated, use NIXOS_INSTALL_BOOTLOADER";
-    $ENV{'NIXOS_INSTALL_BOOTLOADER'} = "1";
-}
-my $requireNewInstall = $devicesDiffer || $extraGrubInstallArgsDiffer || $nameDiffer || $versionDiffer || $efiDiffer || $efiMountPointDiffer || (($ENV{'NIXOS_INSTALL_BOOTLOADER'} // "") eq "1");
-
-# install a symlink so that grub can detect the boot drive
-my $tmpDir = File::Temp::tempdir(CLEANUP => 1) or die "Failed to create temporary space: $!";
-symlink "$bootPath", "$tmpDir/boot" or die "Failed to symlink $tmpDir/boot: $!";
-
-# 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";
-        my @command = ("$grub/sbin/grub-install", "--recheck", "--root-directory=$tmpDir", Cwd::abs_path($dev), @extraGrubInstallArgs);
-        if ($forceInstall eq "true") {
-            push @command, "--force";
-        }
-        if ($grubTarget ne "") {
-            push @command, "--target=$grubTarget";
-        }
-        (system @command) == 0 or die "$0: installation of GRUB on $dev failed: $!\n";
-    }
-}
-
-
-# install EFI GRUB
-if (($requireNewInstall != 0) && ($efiTarget eq "only" || $efiTarget eq "both")) {
-    print STDERR "installing the GRUB $grubVersion EFI boot loader into $efiSysMountPoint...\n";
-    my @command = ("$grubEfi/sbin/grub-install", "--recheck", "--target=$grubTargetEfi", "--boot-directory=$bootPath", "--efi-directory=$efiSysMountPoint", @extraGrubInstallArgs);
-    if ($forceInstall eq "true") {
-        push @command, "--force";
-    }
-    if ($canTouchEfiVariables eq "true") {
-        push @command, "--bootloader-id=$bootloaderId";
-    } else {
-        push @command, "--no-nvram";
-        push @command, "--removable" if $efiInstallAsRemovable eq "true";
-    }
-
-    (system @command) == 0 or die "$0: installation of GRUB EFI into $efiSysMountPoint failed: $!\n";
-}
-
-
-# update GRUB state file
-if ($requireNewInstall != 0) {
-    # Temp file for atomic rename.
-    my $stateFile = "$bootPath/grub/state";
-    my $stateFileTmp = $stateFile . ".tmp";
-
-    open FILE, ">$stateFileTmp" or die "cannot create $stateFileTmp: $!\n";
-    print FILE get("fullName"), "\n" or die;
-    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;
-    my %jsonState = (
-        extraGrubInstallArgs => \@extraGrubInstallArgs
-    );
-    my $jsonStateLine = encode_json(\%jsonState);
-    print FILE $jsonStateLine, "\n" or die;
-    close FILE or die;
-
-    # Atomically switch to the new state file
-    rename $stateFileTmp, $stateFile or die "cannot rename $stateFileTmp to $stateFile: $!\n";
-}