From 548802cb74876067cd0cee09e953069aaaeb723d Mon Sep 17 00:00:00 2001 From: Kira Bruneau Date: Thu, 16 Jan 2025 12:19:04 -0500 Subject: [PATCH] install-grub.pl: use findmnt to get the boot filesystem The current implementation of GetFS uses heuristics to find the best filesystem for the given boot path. Using findmnt is more robust. Specifically, this fixes mounting tmpfs on / for [NixOS impermanence](https://github.com/nix-community/impermanence). Before this change, GetFs would incorrectly match /boot to the tmpfs filesystem, resulting in a broken grub config. --- .../system/boot/loader/grub/install-grub.pl | 50 ++----------------- 1 file changed, 5 insertions(+), 45 deletions(-) diff --git a/nixos/modules/system/boot/loader/grub/install-grub.pl b/nixos/modules/system/boot/loader/grub/install-grub.pl index 6f0f62546a018a..bae85ac39491b0 100644 --- a/nixos/modules/system/boot/loader/grub/install-grub.pl +++ b/nixos/modules/system/boot/loader/grub/install-grub.pl @@ -113,56 +113,16 @@ sub runCommand { 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, @devInfo) = runCommand("@utillinux@/bin/findmnt", "-n", "-v", "-o", "SOURCE,FSTYPE,TARGET", "-T", @{[$dir]}); + if ($status != 0 || $#devInfo != 1) { + die "Failed to get file system (returned $status) for @{[$dir]}"; } - return $bestFs; + my @fields = split /\s+/, $devInfo[0]; + return Fs->new(device => $fields[0], type => $fields[1], mount => $fields[2]); } struct (Grub => { path => '$',