diff options
Diffstat (limited to 'nixos/modules/system')
-rw-r--r-- | nixos/modules/system/boot/kernel.nix | 1 | ||||
-rw-r--r-- | nixos/modules/system/boot/loader/grub/grub.nix | 37 | ||||
-rw-r--r-- | nixos/modules/system/boot/loader/grub/install-grub.pl | 146 | ||||
-rw-r--r-- | nixos/modules/system/boot/loader/gummiboot/gummiboot.nix | 2 | ||||
-rw-r--r-- | nixos/modules/system/boot/luksroot.nix | 67 | ||||
-rw-r--r-- | nixos/modules/system/boot/modprobe.nix | 5 | ||||
-rw-r--r-- | nixos/modules/system/boot/stage-1.nix | 12 | ||||
-rw-r--r-- | nixos/modules/system/boot/stage-2-init.sh | 4 | ||||
-rw-r--r-- | nixos/modules/system/boot/systemd.nix | 2 |
9 files changed, 211 insertions, 65 deletions
diff --git a/nixos/modules/system/boot/kernel.nix b/nixos/modules/system/boot/kernel.nix index 9beb7fabce1..79b173a6ead 100644 --- a/nixos/modules/system/boot/kernel.nix +++ b/nixos/modules/system/boot/kernel.nix @@ -195,6 +195,7 @@ in "xhci_hcd" "usbhid" "hid_generic" + "hid_apple" "hid_logitech_dj" "hid_lenovo_tpkbd" "hid_roccat" # Unix domain sockets (needed by udev). "unix" diff --git a/nixos/modules/system/boot/loader/grub/grub.nix b/nixos/modules/system/boot/loader/grub/grub.nix index 0cc060db8f9..bc9a155ac95 100644 --- a/nixos/modules/system/boot/loader/grub/grub.nix +++ b/nixos/modules/system/boot/loader/grub/grub.nix @@ -6,7 +6,8 @@ let cfg = config.boot.loader.grub; - realGrub = if cfg.version == 1 then pkgs.grub else pkgs.grub2; + realGrub = if cfg.version == 1 then pkgs.grub + else pkgs.grub2.override { zfsSupport = cfg.zfsSupport; }; grub = # Don't include GRUB if we're only generating a GRUB menu (e.g., @@ -25,11 +26,12 @@ let inherit (cfg) version extraConfig extraPerEntryConfig extraEntries extraEntriesBeforeNixOS extraPrepareConfig configurationLimit copyKernels timeout - default devices explicitBootRoot; + default devices fsIdentifier; path = (makeSearchPath "bin" [ - pkgs.coreutils pkgs.gnused pkgs.gnugrep pkgs.findutils pkgs.diffutils + pkgs.coreutils pkgs.gnused pkgs.gnugrep pkgs.findutils pkgs.diffutils pkgs.btrfsProgs + pkgs.utillinux ]) + ":" + (makeSearchPath "sbin" [ - pkgs.mdadm + pkgs.mdadm pkgs.utillinux ]); }); @@ -209,12 +211,26 @@ in ''; }; - explicitBootRoot = mkOption { - default = ""; - type = types.str; + fsIdentifier = mkOption { + default = "uuid"; + type = types.addCheck types.str + (type: type == "uuid" || type == "label" || type == "provided"); description = '' - The relative path of /boot within the parent volume. Leave empty - if /boot is not a btrfs subvolume. + Determines how grub will identify devices when generating the + configuration file. A value of uuid / label signifies that grub + will always resolve the uuid or label of the device before using + it in the configuration. A value of provided means that grub will + use the device name as show in <command>df</command> or + <command>mount</command>. Note, zfs zpools / datasets are ignored + and will always be mounted using their labels. + ''; + }; + + zfsSupport = mkOption { + default = false; + type = types.bool; + description = '' + Whether grub should be build against libzfs. ''; }; @@ -260,6 +276,9 @@ in ${pkgs.coreutils}/bin/cp -pf "${v}" "/boot/${n}" '') config.boot.loader.grub.extraFiles); + assertions = [{ assertion = !cfg.zfsSupport || cfg.version == 2; + message = "Only grub version 2 provides zfs support";}]; + }) ]; diff --git a/nixos/modules/system/boot/loader/grub/install-grub.pl b/nixos/modules/system/boot/loader/grub/install-grub.pl index c3aa8518b8b..2dad8b36db3 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; @@ -27,6 +28,14 @@ sub writeFile { 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 $extraConfig = get("extraConfig"); @@ -39,7 +48,7 @@ my $configurationLimit = int(get("configurationLimit")); my $copyKernels = get("copyKernels") eq "true"; my $timeout = int(get("timeout")); my $defaultEntry = int(get("default")); -my $explicitBootRoot = get("explicitBootRoot"); +my $fsIdentifier = get("fsIdentifier"); $ENV{'PATH'} = get("path"); die "unsupported GRUB version\n" if $grubVersion != 1 && $grubVersion != 2; @@ -48,24 +57,114 @@ print STDERR "updating GRUB $grubVersion menu...\n"; 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/store")->dev) { $copyKernels = 1; } -if ($explicitBootRoot ne "") { - $bootRoot = $explicitBootRoot; +# Discover information about the location of /boot +struct(Fs => { + device => '$', + type => '$', + mount => '$', +}); +sub GetFs { + my ($dir) = @_; + my ($status, @dfOut) = runCommand("df -T $dir"); + if ($status != 0 || $#dfOut != 1) { + die "Failed to retrieve output about $dir from `df`"; + } + my @boot = split(/[ \n\t]+/, $dfOut[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) { + # 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("blkid -o export @{[$fs->device]}"); + if ($status != 0) { + die "Failed to get blkid info 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("btrfs subvol show @{[$fs->mount]}"); + if ($status != 0) { + die "Failed to retrieve subvolume info for @{[$fs->mount]}\n"; + } + my @ids = join("", @id_info) =~ m/Object ID:[ \t\n]*([^ \t\n]*)/; + if ($#ids > 0) { + die "Btrfs subvol name for @{[$fs->device]} listed multiple times in mount\n" + } elsif ($#ids == 0) { + my ($status, @path_info) = runCommand("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("/boot"); +my $grubStore = GrubFs("/nix/store"); # Generate the header. my $conf .= "# Automatically generated. DO NOT EDIT THIS FILE!\n"; @@ -77,12 +176,17 @@ if ($grubVersion == 1) { "; 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 { + if ($copyKernels == 0) { + $conf .= " + " . $grubStore->search; + } $conf .= " + " . $grubBoot->search . " if [ -s \$prefix/grubenv ]; then load_env fi @@ -103,7 +207,7 @@ else { 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 @@ -117,7 +221,7 @@ else { 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 @@ -139,7 +243,7 @@ mkpath("/boot/kernels", 0, 0755) if $copyKernels; sub copyToKernelsDir { my ($path) = @_; - return $path unless $copyKernels; + return $grubStore->path . substr($path, length("/nix/store")) unless $copyKernels; $path =~ /\/nix\/store\/(.*)/ or die; my $name = $1; $name =~ s/\//-/g; my $dst = "/boot/kernels/$name"; @@ -152,7 +256,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 { @@ -179,6 +283,10 @@ sub addEntry { $conf .= " " . ($xen ? "module" : "initrd") . " $initrd\n\n"; } else { $conf .= "menuentry \"$name\" {\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"; @@ -196,7 +304,7 @@ addEntry("NixOS - Default", $defaultConfig); $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/nixos/modules/system/boot/loader/gummiboot/gummiboot.nix b/nixos/modules/system/boot/loader/gummiboot/gummiboot.nix index e7a481e90a7..003f72b37f9 100644 --- a/nixos/modules/system/boot/loader/gummiboot/gummiboot.nix +++ b/nixos/modules/system/boot/loader/gummiboot/gummiboot.nix @@ -16,7 +16,7 @@ let nix = config.nix.package; - inherit (cfg) timeout; + timeout = if cfg.timeout != null then cfg.timeout else ""; inherit (efi) efiSysMountPoint canTouchEfiVariables; }; diff --git a/nixos/modules/system/boot/luksroot.nix b/nixos/modules/system/boot/luksroot.nix index c923cc49c44..70ff1d588a3 100644 --- a/nixos/modules/system/boot/luksroot.nix +++ b/nixos/modules/system/boot/luksroot.nix @@ -342,40 +342,39 @@ in description = "Path where the ramfs used to update the LUKS key will be mounted in stage-1"; }; - storage = mkOption { - type = types.optionSet; - description = "Options related to the storing the salt"; - - options = { - device = mkOption { - default = /dev/sda1; - type = types.path; - description = '' - An unencrypted device that will temporarily be mounted in stage-1. - Must contain the current salt to create the challenge for this LUKS device. - ''; - }; - - fsType = mkOption { - default = "vfat"; - type = types.string; - description = "The filesystem of the unencrypted device"; - }; - - mountPoint = mkOption { - default = "/crypt-storage"; - type = types.string; - description = "Path where the unencrypted device will be mounted in stage-1"; - }; - - path = mkOption { - default = "/crypt-storage/default"; - type = types.string; - description = '' - Absolute path of the salt on the unencrypted device with - that device's root directory as "/". - ''; - }; + /* TODO: Add to the documentation of the current module: + + Options related to the storing the salt. + */ + storage = { + device = mkOption { + default = "/dev/sda1"; + type = types.path; + description = '' + An unencrypted device that will temporarily be mounted in stage-1. + Must contain the current salt to create the challenge for this LUKS device. + ''; + }; + + fsType = mkOption { + default = "vfat"; + type = types.string; + description = "The filesystem of the unencrypted device"; + }; + + mountPoint = mkOption { + default = "/crypt-storage"; + type = types.string; + description = "Path where the unencrypted device will be mounted in stage-1"; + }; + + path = mkOption { + default = "/crypt-storage/default"; + type = types.string; + description = '' + Absolute path of the salt on the unencrypted device with + that device's root directory as "/". + ''; }; }; }; diff --git a/nixos/modules/system/boot/modprobe.nix b/nixos/modules/system/boot/modprobe.nix index 652eb046f50..eaf8cf1ecd6 100644 --- a/nixos/modules/system/boot/modprobe.nix +++ b/nixos/modules/system/boot/modprobe.nix @@ -77,6 +77,11 @@ with lib; '')} ${config.boot.extraModprobeConfig} ''; + environment.etc."modprobe.d/usb-load-ehci-first.conf".text = + '' + softdep uhci_hcd pre: ehci_hcd + softdep ohci_hcd pre: ehci_hcd + ''; environment.systemPackages = [ config.system.sbin.modprobe pkgs.kmod ]; diff --git a/nixos/modules/system/boot/stage-1.nix b/nixos/modules/system/boot/stage-1.nix index 6a069c5d054..426da778f43 100644 --- a/nixos/modules/system/boot/stage-1.nix +++ b/nixos/modules/system/boot/stage-1.nix @@ -199,6 +199,18 @@ let { object = pkgs.writeText "mdadm.conf" config.boot.initrd.mdadmConf; symlink = "/etc/mdadm.conf"; } + { object = pkgs.stdenv.mkDerivation { + name = "initrd-kmod-blacklist-ubuntu"; + builder = pkgs.writeText "builder.sh" '' + source $stdenv/setup + target=$out + + ${pkgs.perl}/bin/perl -0pe 's/## file: iwlwifi.conf(.+?)##/##/s;' $src > $out + ''; + src = "${pkgs.kmod-blacklist-ubuntu}/modprobe.conf"; + }; + symlink = "/etc/modprobe.d/ubuntu.conf"; + } ]; }; diff --git a/nixos/modules/system/boot/stage-2-init.sh b/nixos/modules/system/boot/stage-2-init.sh index fcefdfa88a3..6fff776f858 100644 --- a/nixos/modules/system/boot/stage-2-init.sh +++ b/nixos/modules/system/boot/stage-2-init.sh @@ -29,7 +29,9 @@ setPath "@path@" # Normally, stage 1 mounts the root filesystem read/writable. # However, in some environments, stage 2 is executed directly, and the # root is read-only. So make it writable here. -mount -n -o remount,rw none / +if [ "$container" != systemd-nspawn ]; then + mount -n -o remount,rw none / +fi # Likewise, stage 1 mounts /proc, /dev and /sys, so if we don't have a diff --git a/nixos/modules/system/boot/systemd.nix b/nixos/modules/system/boot/systemd.nix index 455c40693b0..e353e9246b0 100644 --- a/nixos/modules/system/boot/systemd.nix +++ b/nixos/modules/system/boot/systemd.nix @@ -744,7 +744,7 @@ in # Make all journals readable to users in the wheel and adm # groups, in addition to those in the systemd-journal group. # Users can always read their own journals. - ${pkgs.acl}/bin/setfacl -nm g:wheel:rx,d:g:wheel:rx,g:adm:rx,d:g:adm:rx /var/log/journal + ${pkgs.acl}/bin/setfacl -nm g:wheel:rx,d:g:wheel:rx,g:adm:rx,d:g:adm:rx /var/log/journal || true ''; # Target for ‘charon send-keys’ to hook into. |