Skip to content

Commit c955ca5

Browse files
committed
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.
1 parent ef56e77 commit c955ca5

File tree

1 file changed

+5
-45
lines changed

1 file changed

+5
-45
lines changed

nixos/modules/system/boot/loader/grub/install-grub.pl

Lines changed: 5 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -113,56 +113,16 @@ sub runCommand {
113113
type => '$',
114114
mount => '$',
115115
});
116-
sub PathInMount {
117-
my ($path, $mount) = @_;
118-
my @splitMount = split /\//, $mount;
119-
my @splitPath = split /\//, $path;
120-
if ($#splitPath < $#splitMount) {
121-
return 0;
122-
}
123-
for (my $i = 0; $i <= $#splitMount; $i++) {
124-
if ($splitMount[$i] ne $splitPath[$i]) {
125-
return 0;
126-
}
127-
}
128-
return 1;
129-
}
130116

131117
# Figure out what filesystem is used for the directory with init/initrd/kernel files
132118
sub GetFs {
133119
my ($dir) = @_;
134-
my $bestFs = Fs->new(device => "", type => "", mount => "");
135-
foreach my $fs (read_file("/proc/self/mountinfo")) {
136-
chomp $fs;
137-
my @fields = split / /, $fs;
138-
my $mountPoint = $fields[4];
139-
my @mountOptions = split /,/, $fields[5];
140-
141-
# Skip the optional fields.
142-
my $n = 6; $n++ while $fields[$n] ne "-"; $n++;
143-
my $fsType = $fields[$n];
144-
my $device = $fields[$n + 1];
145-
my @superOptions = split /,/, $fields[$n + 2];
146-
147-
# Skip the bind-mount on /nix/store.
148-
next if $mountPoint eq "/nix/store" && (grep { $_ eq "rw" } @superOptions);
149-
# Skip mount point generated by systemd-efi-boot-generator?
150-
next if $fsType eq "autofs";
151-
152-
# Ensure this matches the intended directory
153-
next unless PathInMount($dir, $mountPoint);
154-
155-
# Is it better than our current match?
156-
if (length($mountPoint) > length($bestFs->mount)) {
157-
158-
# -d performs a stat, which can hang forever on network file systems,
159-
# so we only make this call last, when it's likely that this is the mount point we need.
160-
next unless -d $mountPoint;
161-
162-
$bestFs = Fs->new(device => $device, type => $fsType, mount => $mountPoint);
163-
}
120+
my ($status, @devInfo) = runCommand("@utillinux@/bin/findmnt", "-n", "-v", "-o", "SOURCE,FSTYPE,TARGET", "-T", @{[$dir]});
121+
if ($status != 0) {
122+
die "Failed to get file system (returned $status) for @{[$dir]}";
164123
}
165-
return $bestFs;
124+
my @fields = split /\s+/, $devInfo[0];
125+
return Fs->new(device => $fields[0], type => $fields[1], mount => $fields[2]);
166126
}
167127
struct (Grub => {
168128
path => '$',

0 commit comments

Comments
 (0)