diff --git a/nixos/modules/system/boot/loader/grub/grub.nix b/nixos/modules/system/boot/loader/grub/grub.nix index 81f94e8639d9d..f1a352867016b 100644 --- a/nixos/modules/system/boot/loader/grub/grub.nix +++ b/nixos/modules/system/boot/loader/grub/grub.nix @@ -90,7 +90,7 @@ let timeoutStyle ; path = with pkgs; makeBinPath ( - [ coreutils gnused gnugrep findutils diffutils btrfs-progs util-linux mdadm ] + [ coreutils gnused gnugrep findutils diffutils util-linux mdadm ] ++ optional cfg.efiSupport efibootmgr ++ optionals cfg.useOSProber [ busybox os-prober ]); font = lib.optionalString (cfg.font != null) ( @@ -730,7 +730,6 @@ in install-grub-pl = pkgs.substituteAll { src = ./install-grub.pl; utillinux = pkgs.util-linux; - btrfsprogs = pkgs.btrfs-progs; inherit (config.system.nixos) distroName; }; perl = pkgs.perl.withPackages (p: with p; [ diff --git a/nixos/modules/system/boot/loader/grub/install-grub.pl b/nixos/modules/system/boot/loader/grub/install-grub.pl index 6f0f62546a018..71a9c5e1cff02 100644 --- a/nixos/modules/system/boot/loader/grub/install-grub.pl +++ b/nixos/modules/system/boot/loader/grub/install-grub.pl @@ -110,59 +110,20 @@ sub runCommand { # Discover information about the location of the bootPath struct(Fs => { device => '$', + root => '$', 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]; - 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)) { - - # -d performs a stat, which can hang forever on network file systems, - # so we only make this call last, when it's likely that this is the mount point we need. - next unless -d $mountPoint; - - $bestFs = Fs->new(device => $device, type => $fsType, mount => $mountPoint); - } + my ($status, @pathInfo) = runCommand("@utillinux@/bin/findmnt", "-n", "-u", "-v", "-o", "SOURCE,FSROOT,FSTYPE,TARGET", "-T", @{[$dir]}); + if ($status != 0 || @pathInfo != 1) { + die "Failed to get file system (returned $status) for @{[$dir]}"; } - return $bestFs; + my @fields = split /\s+/, $pathInfo[0]; + return Fs->new(device => $fields[0], root => $fields[1], type => $fields[2], mount => $fields[3]); } struct (Grub => { path => '$', @@ -172,10 +133,7 @@ sub GetFs { sub GrubFs { my ($dir) = @_; my $fs = GetFs($dir); - my $path = substr($dir, length($fs->mount)); - if (substr($path, 0, 1) ne "/") { - $path = "/$path"; - } + my $path = File::Spec->catdir($fs->root, substr($dir, length($fs->mount))); my $search = ""; # ZFS is completely separate logic as zpools are always identified by a label @@ -217,30 +175,6 @@ sub GrubFs { } $search .= $matches[0]; } - - # BTRFS is a special case in that we need to fix the referenced 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;