diff options
author | Alyssa Ross <hi@alyssa.is> | 2021-08-04 10:43:07 +0000 |
---|---|---|
committer | Alyssa Ross <hi@alyssa.is> | 2021-08-04 10:43:07 +0000 |
commit | 62614cbef7da005c1eda8c9400160f6bcd6546b8 (patch) | |
tree | c2630f69080637987b68acb1ee8676d2681fe304 /nixos/modules/system | |
parent | d9c82ed3044c72cecf01c6ea042489d30914577c (diff) | |
parent | e24069138dfec3ef94f211f1da005bb5395adc11 (diff) | |
download | nixpkgs-62614cbef7da005c1eda8c9400160f6bcd6546b8.tar nixpkgs-62614cbef7da005c1eda8c9400160f6bcd6546b8.tar.gz nixpkgs-62614cbef7da005c1eda8c9400160f6bcd6546b8.tar.bz2 nixpkgs-62614cbef7da005c1eda8c9400160f6bcd6546b8.tar.lz nixpkgs-62614cbef7da005c1eda8c9400160f6bcd6546b8.tar.xz nixpkgs-62614cbef7da005c1eda8c9400160f6bcd6546b8.tar.zst nixpkgs-62614cbef7da005c1eda8c9400160f6bcd6546b8.zip |
Merge branch 'nixpkgs-update' into master
Diffstat (limited to 'nixos/modules/system')
36 files changed, 772 insertions, 389 deletions
diff --git a/nixos/modules/system/activation/activation-script.nix b/nixos/modules/system/activation/activation-script.nix index ddfd1af4a31..3a6930314b1 100644 --- a/nixos/modules/system/activation/activation-script.nix +++ b/nixos/modules/system/activation/activation-script.nix @@ -25,9 +25,23 @@ let stdenv.cc.libc # nscd in update-users-groups.pl shadow nettools # needed for hostname - utillinux # needed for mount and mountpoint + util-linux # needed for mount and mountpoint ]; + scriptType = with types; + let scriptOptions = + { deps = mkOption + { type = types.listOf types.str; + default = [ ]; + description = "List of dependencies. The script will run after these."; + }; + text = mkOption + { type = types.lines; + description = "The content of the script."; + }; + }; + in either str (submodule { options = scriptOptions; }); + in { @@ -40,16 +54,14 @@ in default = {}; example = literalExample '' - { stdio = { - text = ''' - # Needed by some programs. - ln -sfn /proc/self/fd /dev/fd - ln -sfn /proc/self/fd/0 /dev/stdin - ln -sfn /proc/self/fd/1 /dev/stdout - ln -sfn /proc/self/fd/2 /dev/stderr - '''; - deps = []; - }; + { stdio.text = + ''' + # Needed by some programs. + ln -sfn /proc/self/fd /dev/fd + ln -sfn /proc/self/fd/0 /dev/stdin + ln -sfn /proc/self/fd/1 /dev/stdout + ln -sfn /proc/self/fd/2 /dev/stderr + '''; } ''; @@ -62,7 +74,7 @@ in idempotent and fast. ''; - type = types.attrsOf types.unspecified; # FIXME + type = types.attrsOf scriptType; apply = set: { script = @@ -125,7 +137,7 @@ in idempotent and fast. ''; - type = types.attrsOf types.unspecified; + type = with types; attrsOf scriptType; apply = set: { script = '' diff --git a/nixos/modules/system/activation/switch-to-configuration.pl b/nixos/modules/system/activation/switch-to-configuration.pl index b82d69b3bb8..8bd85465472 100644 --- a/nixos/modules/system/activation/switch-to-configuration.pl +++ b/nixos/modules/system/activation/switch-to-configuration.pl @@ -1,4 +1,4 @@ -#! @perl@ +#! @perl@/bin/perl use strict; use warnings; diff --git a/nixos/modules/system/activation/top-level.nix b/nixos/modules/system/activation/top-level.nix index fb8644dd13a..d3e4923a993 100644 --- a/nixos/modules/system/activation/top-level.nix +++ b/nixos/modules/system/activation/top-level.nix @@ -1,4 +1,4 @@ -{ config, lib, pkgs, modules, baseModules, ... }: +{ config, lib, pkgs, modules, baseModules, specialArgs, ... }: with lib; @@ -13,7 +13,7 @@ let # !!! fix this children = mapAttrs (childName: childConfig: (import ../../../lib/eval-config.nix { - inherit baseModules; + inherit lib baseModules specialArgs; system = config.nixpkgs.initialSystem; modules = (optionals childConfig.inheritParentConfig modules) @@ -97,10 +97,11 @@ let allowSubstitutes = false; buildCommand = systemBuilder; - inherit (pkgs) utillinux coreutils; + inherit (pkgs) coreutils; systemd = config.systemd.package; shell = "${pkgs.bash}/bin/sh"; su = "${pkgs.shadow.su}/bin/su"; + utillinux = pkgs.util-linux; kernelParams = config.boot.kernelParams; installBootLoader = @@ -112,8 +113,7 @@ let configurationName = config.boot.loader.grub.configurationName; # Needed by switch-to-configuration. - - perl = "${pkgs.perl}/bin/perl " + (concatMapStringsSep " " (lib: "-I${lib}/${pkgs.perl.libPrefix}") (with pkgs.perlPackages; [ FileSlurp NetDBus XMLParser XMLTwig ])); + perl = pkgs.perl.withPackages (p: with p; [ FileSlurp NetDBus XMLParser XMLTwig ]); }; # Handle assertions and warnings @@ -125,7 +125,7 @@ let else showWarnings config.warnings baseSystem; # Replace runtime dependencies - system = fold ({ oldDependency, newDependency }: drv: + system = foldr ({ oldDependency, newDependency }: drv: pkgs.replaceDependency { inherit oldDependency newDependency drv; } ) baseSystemAssertWarn config.system.replaceRuntimeDependencies; @@ -159,9 +159,9 @@ in To switch to a specialised configuration (e.g. <literal>fewJobsManyCores</literal>) at runtime, run: - <programlisting> - # sudo /run/current-system/specialisation/fewJobsManyCores/bin/switch-to-configuration test - </programlisting> + <screen> + <prompt># </prompt>sudo /run/current-system/specialisation/fewJobsManyCores/bin/switch-to-configuration test + </screen> ''; type = types.attrsOf (types.submodule ( { ... }: { @@ -189,7 +189,7 @@ in system.boot.loader.kernelFile = mkOption { internal = true; - default = pkgs.stdenv.hostPlatform.platform.kernelTarget; + default = pkgs.stdenv.hostPlatform.linux-kernel.target; type = types.str; description = '' Name of the kernel file to be passed to the bootloader. diff --git a/nixos/modules/system/boot/binfmt.nix b/nixos/modules/system/boot/binfmt.nix index 9eeae0c3ef4..cbdf581d73a 100644 --- a/nixos/modules/system/boot/binfmt.nix +++ b/nixos/modules/system/boot/binfmt.nix @@ -20,8 +20,14 @@ let optionalString fixBinary "F"; in ":${name}:${type}:${offset'}:${magicOrExtension}:${mask'}:${interpreter}:${flags}"; - activationSnippet = name: { interpreter, ... }: - "ln -sf ${interpreter} /run/binfmt/${name}"; + activationSnippet = name: { interpreter, ... }: '' + rm -f /run/binfmt/${name} + cat > /run/binfmt/${name} << 'EOF' + #!${pkgs.bash}/bin/sh + exec -- ${interpreter} "$@" + EOF + chmod +x /run/binfmt/${name} + ''; getEmulator = system: (lib.systems.elaborate { inherit system; }).emulator pkgs; @@ -260,7 +266,7 @@ in { extra-platforms = ${toString (cfg.emulatedSystems ++ lib.optional pkgs.stdenv.hostPlatform.isx86_64 "i686-linux")} ''; nix.sandboxPaths = lib.mkIf (cfg.emulatedSystems != []) - ([ "/run/binfmt" ] ++ (map (system: dirOf (dirOf (getEmulator system))) cfg.emulatedSystems)); + ([ "/run/binfmt" "${pkgs.bash}" ] ++ (map (system: dirOf (dirOf (getEmulator system))) cfg.emulatedSystems)); environment.etc."binfmt.d/nixos.conf".source = builtins.toFile "binfmt_nixos.conf" (lib.concatStringsSep "\n" (lib.mapAttrsToList makeBinfmtLine config.boot.binfmt.registrations)); diff --git a/nixos/modules/system/boot/grow-partition.nix b/nixos/modules/system/boot/grow-partition.nix index 71a86c74772..87c981b24ce 100644 --- a/nixos/modules/system/boot/grow-partition.nix +++ b/nixos/modules/system/boot/grow-partition.nix @@ -20,10 +20,10 @@ with lib; boot.initrd.extraUtilsCommands = '' copy_bin_and_libs ${pkgs.gawk}/bin/gawk copy_bin_and_libs ${pkgs.gnused}/bin/sed - copy_bin_and_libs ${pkgs.utillinux}/sbin/sfdisk - copy_bin_and_libs ${pkgs.utillinux}/sbin/lsblk + copy_bin_and_libs ${pkgs.util-linux}/sbin/sfdisk + copy_bin_and_libs ${pkgs.util-linux}/sbin/lsblk - substitute "${pkgs.cloud-utils}/bin/.growpart-wrapped" "$out/bin/growpart" \ + substitute "${pkgs.cloud-utils.guest}/bin/.growpart-wrapped" "$out/bin/growpart" \ --replace "${pkgs.bash}/bin/sh" "/bin/sh" \ --replace "awk" "gawk" \ --replace "sed" "gnused" diff --git a/nixos/modules/system/boot/initrd-network.nix b/nixos/modules/system/boot/initrd-network.nix index ec794d6eb01..2a7417ed371 100644 --- a/nixos/modules/system/boot/initrd-network.nix +++ b/nixos/modules/system/boot/initrd-network.nix @@ -32,8 +32,8 @@ let fi if [ -n "$dns" ]; then rm -f /etc/resolv.conf - for i in $dns; do - echo "nameserver $dns" >> /etc/resolv.conf + for server in $dns; do + echo "nameserver $server" >> /etc/resolv.conf done fi fi diff --git a/nixos/modules/system/boot/initrd-openvpn.nix b/nixos/modules/system/boot/initrd-openvpn.nix index e59bc7b6678..b35fb0b57c0 100644 --- a/nixos/modules/system/boot/initrd-openvpn.nix +++ b/nixos/modules/system/boot/initrd-openvpn.nix @@ -55,7 +55,7 @@ in # The shared libraries are required for DNS resolution boot.initrd.extraUtilsCommands = '' copy_bin_and_libs ${pkgs.openvpn}/bin/openvpn - copy_bin_and_libs ${pkgs.iproute}/bin/ip + copy_bin_and_libs ${pkgs.iproute2}/bin/ip cp -pv ${pkgs.glibc}/lib/libresolv.so.2 $out/lib cp -pv ${pkgs.glibc}/lib/libnss_dns.so.2 $out/lib diff --git a/nixos/modules/system/boot/initrd-ssh.nix b/nixos/modules/system/boot/initrd-ssh.nix index f7ef2610370..00ac83a1897 100644 --- a/nixos/modules/system/boot/initrd-ssh.nix +++ b/nixos/modules/system/boot/initrd-ssh.nix @@ -159,9 +159,14 @@ in boot.initrd.extraUtilsCommandsTest = '' # sshd requires a host key to check config, so we pass in the test's + tmpkey="$(mktemp initrd-ssh-testkey.XXXXXXXXXX)" + cp "${../../../tests/initrd-network-ssh/ssh_host_ed25519_key}" "$tmpkey" + # keys from Nix store are world-readable, which sshd doesn't like + chmod 600 "$tmpkey" echo -n ${escapeShellArg sshdConfig} | $out/bin/sshd -t -f /dev/stdin \ - -h ${../../../tests/initrd-network-ssh/ssh_host_ed25519_key} + -h "$tmpkey" + rm "$tmpkey" ''; boot.initrd.network.postCommands = '' diff --git a/nixos/modules/system/boot/kernel.nix b/nixos/modules/system/boot/kernel.nix index 43871f439f7..1a6a9d99d5b 100644 --- a/nixos/modules/system/boot/kernel.nix +++ b/nixos/modules/system/boot/kernel.nix @@ -38,11 +38,11 @@ in default = pkgs.linuxPackages; type = types.unspecified // { merge = mergeEqualOption; }; apply = kernelPackages: kernelPackages.extend (self: super: { - kernel = super.kernel.override { + kernel = super.kernel.override (originalArgs: { inherit randstructSeed; - kernelPatches = super.kernel.kernelPatches ++ kernelPatches; + kernelPatches = (originalArgs.kernelPatches or []) ++ kernelPatches; features = lib.recursiveUpdate super.kernel.features features; - }; + }); }); # We don't want to evaluate all of linuxPackages for the manual # - some of it might not even evaluate correctly. @@ -156,6 +156,16 @@ in description = "List of modules that are always loaded by the initrd."; }; + boot.initrd.includeDefaultModules = mkOption { + type = types.bool; + default = true; + description = '' + This option, if set, adds a collection of default kernel modules + to <option>boot.initrd.availableKernelModules</option> and + <option>boot.initrd.kernelModules</option>. + ''; + }; + system.modulesTree = mkOption { type = types.listOf types.path; internal = true; @@ -195,7 +205,8 @@ in config = mkMerge [ (mkIf config.boot.initrd.enable { boot.initrd.availableKernelModules = - [ # Note: most of these (especially the SATA/PATA modules) + optionals config.boot.initrd.includeDefaultModules ([ + # Note: most of these (especially the SATA/PATA modules) # shouldn't be included by default since nixos-generate-config # detects them, but I'm keeping them for now for backwards # compatibility. @@ -227,7 +238,7 @@ in "xhci_pci" "usbhid" "hid_generic" "hid_lenovo" "hid_apple" "hid_roccat" - "hid_logitech_hidpp" "hid_logitech_dj" + "hid_logitech_hidpp" "hid_logitech_dj" "hid_microsoft" ] ++ optionals (pkgs.stdenv.isi686 || pkgs.stdenv.isx86_64) [ # Misc. x86 keyboard stuff. @@ -235,10 +246,11 @@ in # x86 RTC needed by the stage 2 init script. "rtc_cmos" - ]; + ]); boot.initrd.kernelModules = - [ # For LVM. + optionals config.boot.initrd.includeDefaultModules [ + # For LVM. "dm_mod" ]; }) diff --git a/nixos/modules/system/boot/kernel_config.nix b/nixos/modules/system/boot/kernel_config.nix index 783685c9dfe..5d9534024b0 100644 --- a/nixos/modules/system/boot/kernel_config.nix +++ b/nixos/modules/system/boot/kernel_config.nix @@ -2,24 +2,6 @@ with lib; let - findWinner = candidates: winner: - any (x: x == winner) candidates; - - # winners is an ordered list where first item wins over 2nd etc - mergeAnswer = winners: locs: defs: - let - values = map (x: x.value) defs; - inter = intersectLists values winners; - winner = head winners; - in - if defs == [] then abort "This case should never happen." - else if winner == [] then abort "Give a valid list of winner" - else if inter == [] then mergeOneOption locs defs - else if findWinner values winner then - winner - else - mergeAnswer (tail winners) locs defs; - mergeFalseByDefault = locs: defs: if defs == [] then abort "This case should never happen." else if any (x: x == false) (getValues defs) then false @@ -28,9 +10,7 @@ let kernelItem = types.submodule { options = { tristate = mkOption { - type = types.enum [ "y" "m" "n" null ] // { - merge = mergeAnswer [ "y" "m" "n" ]; - }; + type = types.enum [ "y" "m" "n" null ]; default = null; internal = true; visible = true; diff --git a/nixos/modules/system/boot/kexec.nix b/nixos/modules/system/boot/kexec.nix index 27a8e0217c5..03312aa26ed 100644 --- a/nixos/modules/system/boot/kexec.nix +++ b/nixos/modules/system/boot/kexec.nix @@ -1,7 +1,7 @@ { pkgs, lib, ... }: { - config = lib.mkIf (lib.any (lib.meta.platformMatch pkgs.stdenv.hostPlatform) pkgs.kexectools.meta.platforms) { + config = lib.mkIf (lib.meta.availableOn pkgs.stdenv.hostPlatform pkgs.kexectools) { environment.systemPackages = [ pkgs.kexectools ]; systemd.services.prepare-kexec = diff --git a/nixos/modules/system/boot/loader/generations-dir/generations-dir.nix b/nixos/modules/system/boot/loader/generations-dir/generations-dir.nix index 2d27611946e..1437ab38770 100644 --- a/nixos/modules/system/boot/loader/generations-dir/generations-dir.nix +++ b/nixos/modules/system/boot/loader/generations-dir/generations-dir.nix @@ -12,9 +12,6 @@ let inherit (config.boot.loader.generationsDir) copyKernels; }; - # Temporary check, for nixos to cope both with nixpkgs stdenv-updates and trunk - inherit (pkgs.stdenv.hostPlatform) platform; - in { @@ -59,7 +56,7 @@ in system.build.installBootLoader = generationsDirBuilder; system.boot.loader.id = "generationsDir"; - system.boot.loader.kernelFile = platform.kernelTarget; + system.boot.loader.kernelFile = pkgs.stdenv.hostPlatform.linux-kernel.target; }; } diff --git a/nixos/modules/system/boot/loader/generic-extlinux-compatible/extlinux-conf-builder.sh b/nixos/modules/system/boot/loader/generic-extlinux-compatible/extlinux-conf-builder.sh index 854684b87fa..5ffffb95edb 100644 --- a/nixos/modules/system/boot/loader/generic-extlinux-compatible/extlinux-conf-builder.sh +++ b/nixos/modules/system/boot/loader/generic-extlinux-compatible/extlinux-conf-builder.sh @@ -109,7 +109,7 @@ addEntry() { exit 1 fi fi - echo " APPEND systemConfig=$path init=$path/init $extraParams" + echo " APPEND init=$path/init $extraParams" } tmpFile="$target/extlinux/extlinux.conf.tmp.$$" diff --git a/nixos/modules/system/boot/loader/grub/grub.nix b/nixos/modules/system/boot/loader/grub/grub.nix index 20e39628eab..e183bc3648c 100644 --- a/nixos/modules/system/boot/loader/grub/grub.nix +++ b/nixos/modules/system/boot/loader/grub/grub.nix @@ -66,7 +66,7 @@ let extraEntriesBeforeNixOS extraPrepareConfig configurationLimit copyKernels default fsIdentifier efiSupport efiInstallAsRemovable gfxmodeEfi gfxmodeBios gfxpayloadEfi gfxpayloadBios; path = with pkgs; makeBinPath ( - [ coreutils gnused gnugrep findutils diffutils btrfs-progs utillinux mdadm ] + [ coreutils gnused gnugrep findutils diffutils btrfs-progs util-linux mdadm ] ++ optional (cfg.efiSupport && (cfg.version == 2)) efibootmgr ++ optionals cfg.useOSProber [ busybox os-prober ]); font = if cfg.font == null then "" @@ -75,7 +75,7 @@ let else "${convertedFont}"); }); - bootDeviceCounters = fold (device: attr: attr // { ${device} = (attr.${device} or 0) + 1; }) {} + bootDeviceCounters = foldr (device: attr: attr // { ${device} = (attr.${device} or 0) + 1; }) {} (concatMap (args: args.devices) cfg.mirroredBoots); convertedFont = (pkgs.runCommand "grub-font-converted.pf2" {} @@ -327,6 +327,26 @@ in ''; }; + extraInstallCommands = mkOption { + default = ""; + example = literalExample '' + # the example below generates detached signatures that GRUB can verify + # https://www.gnu.org/software/grub/manual/grub/grub.html#Using-digital-signatures + ''${pkgs.findutils}/bin/find /boot -not -path "/boot/efi/*" -type f -name '*.sig' -delete + old_gpg_home=$GNUPGHOME + export GNUPGHOME="$(mktemp -d)" + ''${pkgs.gnupg}/bin/gpg --import ''${priv_key} > /dev/null 2>&1 + ''${pkgs.findutils}/bin/find /boot -not -path "/boot/efi/*" -type f -exec ''${pkgs.gnupg}/bin/gpg --detach-sign "{}" \; > /dev/null 2>&1 + rm -rf $GNUPGHOME + export GNUPGHOME=$old_gpg_home + ''; + type = types.lines; + description = '' + Additional shell commands inserted in the bootloader installer + script after generating menu entries. + ''; + }; + extraPerEntryConfig = mkOption { default = ""; example = "root (hd0)"; @@ -705,17 +725,21 @@ in let install-grub-pl = pkgs.substituteAll { src = ./install-grub.pl; - inherit (pkgs) utillinux; + utillinux = pkgs.util-linux; btrfsprogs = pkgs.btrfs-progs; }; + perl = pkgs.perl.withPackages (p: with p; [ + FileSlurp FileCopyRecursive + XMLLibXML XMLSAX XMLSAXBase + ListCompare JSON + ]); in pkgs.writeScript "install-grub.sh" ('' #!${pkgs.runtimeShell} set -e - export PERL5LIB=${with pkgs.perlPackages; makePerlPath [ FileSlurp FileCopyRecursive XMLLibXML XMLSAX XMLSAXBase ListCompare JSON ]} ${optionalString cfg.enableCryptodisk "export GRUB_ENABLE_CRYPTODISK=y"} '' + flip concatMapStrings cfg.mirroredBoots (args: '' - ${pkgs.perl}/bin/perl ${install-grub-pl} ${grubConfig args} $@ - '')); + ${perl}/bin/perl ${install-grub-pl} ${grubConfig args} $@ + '') + cfg.extraInstallCommands); system.build.grub = grub; @@ -741,7 +765,7 @@ in + "'boot.loader.grub.mirroredBoots' to make the system bootable."; } { - assertion = cfg.efiSupport || all (c: c < 2) (mapAttrsToList (_: c: c) bootDeviceCounters); + assertion = cfg.efiSupport || all (c: c < 2) (mapAttrsToList (n: c: if n == "nodev" then 0 else c) bootDeviceCounters); message = "You cannot have duplicated devices in mirroredBoots"; } { diff --git a/nixos/modules/system/boot/loader/grub/install-grub.pl b/nixos/modules/system/boot/loader/grub/install-grub.pl index 59f5638044f..e0167654748 100644 --- a/nixos/modules/system/boot/loader/grub/install-grub.pl +++ b/nixos/modules/system/boot/loader/grub/install-grub.pl @@ -102,10 +102,10 @@ if (stat($bootPath)->dev != stat("/nix/store")->dev) { # Discover information about the location of the bootPath struct(Fs => { - device => '$', - type => '$', - mount => '$', -}); + device => '$', + type => '$', + mount => '$', + }); sub PathInMount { my ($path, $mount) = @_; my @splitMount = split /\//, $mount; @@ -154,16 +154,16 @@ sub GetFs { return $bestFs; } struct (Grub => { - path => '$', - search => '$', -}); + 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"; + $path = "/$path"; } my $search = ""; @@ -251,8 +251,8 @@ my $conf .= "# Automatically generated. DO NOT EDIT THIS FILE!\n"; if ($grubVersion == 1) { $conf .= " - default $defaultEntry - timeout $timeout + default $defaultEntry + timeout $timeout "; if ($splashImage) { copy $splashImage, "$bootPath/background.xpm.gz" or die "cannot copy $splashImage to $bootPath: $!\n"; @@ -302,51 +302,51 @@ else { if ($copyKernels == 0) { $conf .= " - " . $grubStore->search; + " . $grubStore->search; } # FIXME: should use grub-mkconfig. $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 - else - set default=$defaultEntry - set timeout=$timeout - 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 + " . $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 + else + set default=$defaultEntry + set timeout=$timeout + 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 + 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) { @@ -356,21 +356,21 @@ else { if ($suffix eq ".jpg") { $suffix = ".jpeg"; } - if ($backgroundColor) { - $conf .= " - background_color '$backgroundColor' - "; - } + 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 + 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 "; } @@ -380,21 +380,21 @@ else { # 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 ); - } + # 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"; @@ -433,25 +433,25 @@ sub addEntry { # 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 $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; @@ -459,9 +459,8 @@ sub addEntry { # FIXME: $confName my $kernelParams = - "systemConfig=" . Cwd::abs_path($path) . " " . - "init=" . Cwd::abs_path("$path/init") . " " . - readFile("$path/kernel-params"); + "init=" . Cwd::abs_path("$path/init") . " " . + readFile("$path/kernel-params"); my $xenParams = $xen && -e "$path/xen-params" ? readFile("$path/xen-params") : ""; if ($grubVersion == 1) { @@ -503,9 +502,9 @@ foreach my $link (@links) { 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]); + -e "$link/nixos-version" + ? readFile("$link/nixos-version") + : basename((glob(dirname(Cwd::abs_path("$link/kernel")) . "/lib/modules/*"))[0]); if ($cfgName) { $entryName = $cfgName; @@ -530,8 +529,8 @@ sub addProfile { sub nrFromGen { my ($x) = @_; $x =~ /\/\w+-(\d+)-link/; return $1; } my @links = sort - { nrFromGen($b) <=> nrFromGen($a) } - (glob "$profile-*-link"); + { nrFromGen($b) <=> nrFromGen($a) } + (glob "$profile-*-link"); my $curEntry = 0; foreach my $link (@links) { @@ -542,9 +541,9 @@ sub addProfile { } 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]); + -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); } @@ -566,7 +565,7 @@ $extraPrepareConfig =~ s/\@bootPath\@/$bootPath/g; # Run extraPrepareConfig in sh if ($extraPrepareConfig ne "") { - system((get("shell"), "-c", $extraPrepareConfig)); + system((get("shell"), "-c", $extraPrepareConfig)); } # write the GRUB config. @@ -627,13 +626,13 @@ foreach my $fn (glob "$bootPath/kernels/*") { # struct(GrubState => { - name => '$', - version => '$', - efi => '$', - devices => '$', - efiMountPoint => '$', - extraGrubInstallArgs => '@', -}); + 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 { diff --git a/nixos/modules/system/boot/loader/init-script/init-script-builder.sh b/nixos/modules/system/boot/loader/init-script/init-script-builder.sh index 2a1ec479fea..bd3fc64999d 100644 --- a/nixos/modules/system/boot/loader/init-script/init-script-builder.sh +++ b/nixos/modules/system/boot/loader/init-script/init-script-builder.sh @@ -49,7 +49,6 @@ addEntry() { echo "#!/bin/sh" echo "# $name" echo "# created by init-script-builder.sh" - echo "export systemConfig=$(readlink -f $path)" echo "exec $stage2" )" diff --git a/nixos/modules/system/boot/loader/raspberrypi/raspberrypi-builder.nix b/nixos/modules/system/boot/loader/raspberrypi/raspberrypi-builder.nix index e75aa9d1387..64e106036ab 100644 --- a/nixos/modules/system/boot/loader/raspberrypi/raspberrypi-builder.nix +++ b/nixos/modules/system/boot/loader/raspberrypi/raspberrypi-builder.nix @@ -1,10 +1,9 @@ -{ pkgs, configTxt }: +{ pkgs, configTxt, firmware ? pkgs.raspberrypifw }: pkgs.substituteAll { src = ./raspberrypi-builder.sh; isExecutable = true; - inherit (pkgs.buildPackages) bash; - path = with pkgs.buildPackages; [coreutils gnused gnugrep]; - firmware = pkgs.raspberrypifw; - inherit configTxt; + inherit (pkgs) bash; + path = [pkgs.coreutils pkgs.gnused pkgs.gnugrep]; + inherit firmware configTxt; } diff --git a/nixos/modules/system/boot/loader/raspberrypi/raspberrypi.nix b/nixos/modules/system/boot/loader/raspberrypi/raspberrypi.nix index 337afe9ef62..1023361f0b1 100644 --- a/nixos/modules/system/boot/loader/raspberrypi/raspberrypi.nix +++ b/nixos/modules/system/boot/loader/raspberrypi/raspberrypi.nix @@ -5,8 +5,6 @@ with lib; let cfg = config.boot.loader.raspberryPi; - inherit (pkgs.stdenv.hostPlatform) platform; - builderUboot = import ./uboot-builder.nix { inherit pkgs configTxt; inherit (cfg) version; }; builderGeneric = import ./raspberrypi-builder.nix { inherit pkgs configTxt; }; @@ -20,7 +18,7 @@ let timeoutStr = if blCfg.timeout == null then "-1" else toString blCfg.timeout; isAarch64 = pkgs.stdenv.hostPlatform.isAarch64; - optional = pkgs.stdenv.lib.optionalString; + optional = pkgs.lib.optionalString; configTxt = pkgs.writeText "config.txt" ('' @@ -60,8 +58,7 @@ in version = mkOption { default = 2; type = types.enum [ 0 1 2 3 4 ]; - description = '' - ''; + description = ""; }; uboot = { @@ -103,6 +100,6 @@ in system.build.installBootLoader = builder; system.boot.loader.id = "raspberrypi"; - system.boot.loader.kernelFile = platform.kernelTarget; + system.boot.loader.kernelFile = pkgs.stdenv.hostPlatform.linux-kernel.target; }; } diff --git a/nixos/modules/system/boot/loader/systemd-boot/systemd-boot-builder.py b/nixos/modules/system/boot/loader/systemd-boot/systemd-boot-builder.py index 97e824fe629..7134b432163 100644 --- a/nixos/modules/system/boot/loader/systemd-boot/systemd-boot-builder.py +++ b/nixos/modules/system/boot/loader/systemd-boot/systemd-boot-builder.py @@ -15,12 +15,15 @@ import re import datetime import glob import os.path +from typing import Tuple, List, Optional -def copy_if_not_exists(source, dest): + +def copy_if_not_exists(source: str, dest: str) -> None: if not os.path.exists(dest): shutil.copyfile(source, dest) -def system_dir(profile, generation): + +def system_dir(profile: Optional[str], generation: int) -> str: if profile: return "/nix/var/nix/profiles/system-profiles/%s-%d-link" % (profile, generation) else: @@ -42,7 +45,8 @@ MEMTEST_BOOT_ENTRY = """title MemTest86 efi /efi/memtest86/BOOTX64.efi """ -def write_loader_conf(profile, generation): + +def write_loader_conf(profile: Optional[str], generation: int) -> None: with open("@efiSysMountPoint@/loader/loader.conf.tmp", 'w') as f: if "@timeout@" != "": f.write("timeout @timeout@\n") @@ -55,10 +59,12 @@ def write_loader_conf(profile, generation): f.write("console-mode @consoleMode@\n"); os.rename("@efiSysMountPoint@/loader/loader.conf.tmp", "@efiSysMountPoint@/loader/loader.conf") -def profile_path(profile, generation, name): - return os.readlink("%s/%s" % (system_dir(profile, generation), name)) -def copy_from_profile(profile, generation, name, dry_run=False): +def profile_path(profile: Optional[str], generation: int, name: str) -> str: + return os.path.realpath("%s/%s" % (system_dir(profile, generation), name)) + + +def copy_from_profile(profile: Optional[str], generation: int, name: str, dry_run: bool = False) -> str: store_file_path = profile_path(profile, generation, name) suffix = os.path.basename(store_file_path) store_dir = os.path.basename(os.path.dirname(store_file_path)) @@ -67,7 +73,8 @@ def copy_from_profile(profile, generation, name, dry_run=False): copy_if_not_exists(store_file_path, "@efiSysMountPoint@%s" % (efi_file_path)) return efi_file_path -def describe_generation(generation_dir): + +def describe_generation(generation_dir: str) -> str: try: with open("%s/nixos-version" % generation_dir) as f: nixos_version = f.read() @@ -87,7 +94,8 @@ def describe_generation(generation_dir): return description -def write_entry(profile, generation, machine_id): + +def write_entry(profile: Optional[str], generation: int, machine_id: str) -> None: kernel = copy_from_profile(profile, generation, "kernel") initrd = copy_from_profile(profile, generation, "initrd") try: @@ -101,7 +109,7 @@ def write_entry(profile, generation, machine_id): entry_file = "@efiSysMountPoint@/loader/entries/nixos-generation-%d.conf" % (generation) generation_dir = os.readlink(system_dir(profile, generation)) tmp_path = "%s.tmp" % (entry_file) - kernel_params = "systemConfig=%s init=%s/init " % (generation_dir, generation_dir) + kernel_params = "init=%s/init " % generation_dir with open("%s/kernel-params" % (generation_dir)) as params_file: kernel_params = kernel_params + params_file.read() @@ -116,14 +124,16 @@ def write_entry(profile, generation, machine_id): f.write("machine-id %s\n" % machine_id) os.rename(tmp_path, entry_file) -def mkdir_p(path): + +def mkdir_p(path: str) -> None: try: os.makedirs(path) except OSError as e: if e.errno != errno.EEXIST or not os.path.isdir(path): raise -def get_generations(profile=None): + +def get_generations(profile: Optional[str] = None) -> List[Tuple[Optional[str], int]]: gen_list = subprocess.check_output([ "@nix@/bin/nix-env", "--list-generations", @@ -137,7 +147,8 @@ def get_generations(profile=None): configurationLimit = @configurationLimit@ return [ (profile, int(line.split()[0])) for line in gen_lines ][-configurationLimit:] -def remove_old_entries(gens): + +def remove_old_entries(gens: List[Tuple[Optional[str], int]]) -> None: rex_profile = re.compile("^@efiSysMountPoint@/loader/entries/nixos-(.*)-generation-.*\.conf$") rex_generation = re.compile("^@efiSysMountPoint@/loader/entries/nixos.*-generation-(.*)\.conf$") known_paths = [] @@ -150,8 +161,8 @@ def remove_old_entries(gens): prof = rex_profile.sub(r"\1", path) else: prof = "system" - gen = int(rex_generation.sub(r"\1", path)) - if not (prof, gen) in gens: + gen_number = int(rex_generation.sub(r"\1", path)) + if not (prof, gen_number) in gens: os.unlink(path) except ValueError: pass @@ -159,7 +170,8 @@ def remove_old_entries(gens): if not path in known_paths and not os.path.isdir(path): os.unlink(path) -def get_profiles(): + +def get_profiles() -> List[str]: if os.path.isdir("/nix/var/nix/profiles/system-profiles/"): return [x for x in os.listdir("/nix/var/nix/profiles/system-profiles/") @@ -167,7 +179,8 @@ def get_profiles(): else: return [] -def main(): + +def main() -> None: parser = argparse.ArgumentParser(description='Update NixOS-related systemd-boot files') parser.add_argument('default_config', metavar='DEFAULT-CONFIG', help='The default NixOS config to boot') args = parser.parse_args() @@ -182,7 +195,9 @@ def main(): # be there on newly installed systems, so let's generate one so that # bootctl can find it and we can also pass it to write_entry() later. cmd = ["@systemd@/bin/systemd-machine-id-setup", "--print"] - machine_id = subprocess.check_output(cmd).rstrip() + machine_id = subprocess.run( + cmd, text=True, check=True, stdout=subprocess.PIPE + ).stdout.rstrip() if os.getenv("NIXOS_INSTALL_GRUB") == "1": warnings.warn("NIXOS_INSTALL_GRUB env var deprecated, use NIXOS_INSTALL_BOOTLOADER", DeprecationWarning) @@ -213,7 +228,6 @@ def main(): print("updating systemd-boot from %s to %s" % (sdboot_version, systemd_version)) subprocess.check_call(["@systemd@/bin/bootctl", "--path=@efiSysMountPoint@", "update"]) - mkdir_p("@efiSysMountPoint@/efi/nixos") mkdir_p("@efiSysMountPoint@/loader/entries") @@ -222,9 +236,12 @@ def main(): gens += get_generations(profile) remove_old_entries(gens) for gen in gens: - write_entry(*gen, machine_id) - if os.readlink(system_dir(*gen)) == args.default_config: - write_loader_conf(*gen) + try: + write_entry(*gen, machine_id) + if os.readlink(system_dir(*gen)) == args.default_config: + write_loader_conf(*gen) + except OSError as e: + print("ignoring profile '{}' in the list of boot entries because of the following error:\n{}".format(profile, e), file=sys.stderr) memtest_entry_file = "@efiSysMountPoint@/loader/entries/memtest86.conf" if os.path.exists(memtest_entry_file): @@ -252,5 +269,6 @@ def main(): if rc != 0: print("could not sync @efiSysMountPoint@: {}".format(os.strerror(rc)), file=sys.stderr) + if __name__ == '__main__': main() diff --git a/nixos/modules/system/boot/loader/systemd-boot/systemd-boot.nix b/nixos/modules/system/boot/loader/systemd-boot/systemd-boot.nix index f0bd76a3c1d..ff304f570d3 100644 --- a/nixos/modules/system/boot/loader/systemd-boot/systemd-boot.nix +++ b/nixos/modules/system/boot/loader/systemd-boot/systemd-boot.nix @@ -7,7 +7,7 @@ let efi = config.boot.loader.efi; - gummibootBuilder = pkgs.substituteAll { + systemdBootBuilder = pkgs.substituteAll { src = ./systemd-boot-builder.py; isExecutable = true; @@ -30,6 +30,17 @@ let memtest86 = if cfg.memtest86.enable then pkgs.memtest86-efi else ""; }; + + checkedSystemdBootBuilder = pkgs.runCommand "systemd-boot" { + nativeBuildInputs = [ pkgs.mypy ]; + } '' + install -m755 ${systemdBootBuilder} $out + mypy \ + --no-implicit-optional \ + --disallow-untyped-calls \ + --disallow-untyped-defs \ + $out + ''; in { imports = @@ -131,7 +142,7 @@ in { boot.loader.supportsInitrdSecrets = true; system = { - build.installBootLoader = gummibootBuilder; + build.installBootLoader = checkedSystemdBootBuilder; boot.loader.id = "systemd-boot"; diff --git a/nixos/modules/system/boot/luksroot.nix b/nixos/modules/system/boot/luksroot.nix index 166f89c7066..f87d3b07a36 100644 --- a/nixos/modules/system/boot/luksroot.nix +++ b/nixos/modules/system/boot/luksroot.nix @@ -56,7 +56,7 @@ let ykinfo -v 1>/dev/null 2>&1 if [ $? != 0 ]; then - echo -n "Waiting $secs seconds for Yubikey to appear..." + echo -n "Waiting $secs seconds for YubiKey to appear..." local success=false for try in $(seq $secs); do echo -n . @@ -118,7 +118,7 @@ let # Cryptsetup locking directory mkdir -p /run/cryptsetup - # For Yubikey salt storage + # For YubiKey salt storage mkdir -p /crypt-storage ${optionalString luks.gpgSupport '' @@ -140,24 +140,27 @@ let umount /crypt-ramfs 2>/dev/null ''; - openCommand = name': { name, device, header, keyFile, keyFileSize, keyFileOffset, allowDiscards, yubikey, gpgCard, fido2, fallbackToPassword, preOpenCommands, postOpenCommands,... }: assert name' == name; + openCommand = name: dev: assert name == dev.name; let - csopen = "cryptsetup luksOpen ${device} ${name} ${optionalString allowDiscards "--allow-discards"} ${optionalString (header != null) "--header=${header}"}"; - cschange = "cryptsetup luksChangeKey ${device} ${optionalString (header != null) "--header=${header}"}"; + csopen = "cryptsetup luksOpen ${dev.device} ${dev.name}" + + optionalString dev.allowDiscards " --allow-discards" + + optionalString dev.bypassWorkqueues " --perf-no_read_workqueue --perf-no_write_workqueue" + + optionalString (dev.header != null) " --header=${dev.header}"; + cschange = "cryptsetup luksChangeKey ${dev.device} ${optionalString (dev.header != null) "--header=${dev.header}"}"; in '' # Wait for luksRoot (and optionally keyFile and/or header) to appear, e.g. # if on a USB drive. - wait_target "device" ${device} || die "${device} is unavailable" + wait_target "device" ${dev.device} || die "${dev.device} is unavailable" - ${optionalString (header != null) '' - wait_target "header" ${header} || die "${header} is unavailable" + ${optionalString (dev.header != null) '' + wait_target "header" ${dev.header} || die "${dev.header} is unavailable" ''} do_open_passphrase() { local passphrase while true; do - echo -n "Passphrase for ${device}: " + echo -n "Passphrase for ${dev.device}: " passphrase= while true; do if [ -e /crypt-ramfs/passphrase ]; then @@ -166,7 +169,7 @@ let break else # ask cryptsetup-askpass - echo -n "${device}" > /crypt-ramfs/device + echo -n "${dev.device}" > /crypt-ramfs/device # and try reading it from /dev/console with a timeout IFS= read -t 1 -r passphrase @@ -182,7 +185,7 @@ let fi fi done - echo -n "Verifying passphrase for ${device}..." + echo -n "Verifying passphrase for ${dev.device}..." echo -n "$passphrase" | ${csopen} --key-file=- if [ $? == 0 ]; then echo " - success" @@ -202,13 +205,13 @@ let # LUKS open_normally() { - ${if (keyFile != null) then '' - if wait_target "key file" ${keyFile}; then - ${csopen} --key-file=${keyFile} \ - ${optionalString (keyFileSize != null) "--keyfile-size=${toString keyFileSize}"} \ - ${optionalString (keyFileOffset != null) "--keyfile-offset=${toString keyFileOffset}"} + ${if (dev.keyFile != null) then '' + if wait_target "key file" ${dev.keyFile}; then + ${csopen} --key-file=${dev.keyFile} \ + ${optionalString (dev.keyFileSize != null) "--keyfile-size=${toString dev.keyFileSize}"} \ + ${optionalString (dev.keyFileOffset != null) "--keyfile-offset=${toString dev.keyFileOffset}"} else - ${if fallbackToPassword then "echo" else "die"} "${keyFile} is unavailable" + ${if dev.fallbackToPassword then "echo" else "die"} "${dev.keyFile} is unavailable" echo " - failing back to interactive password prompt" do_open_passphrase fi @@ -217,8 +220,8 @@ let ''} } - ${optionalString (luks.yubikeySupport && (yubikey != null)) '' - # Yubikey + ${optionalString (luks.yubikeySupport && (dev.yubikey != null)) '' + # YubiKey rbtohex() { ( od -An -vtx1 | tr -d ' \n' ) } @@ -243,31 +246,55 @@ let local new_response local new_k_luks - mount -t ${yubikey.storage.fsType} ${yubikey.storage.device} /crypt-storage || \ - die "Failed to mount Yubikey salt storage device" + mount -t ${dev.yubikey.storage.fsType} ${dev.yubikey.storage.device} /crypt-storage || \ + die "Failed to mount YubiKey salt storage device" - salt="$(cat /crypt-storage${yubikey.storage.path} | sed -n 1p | tr -d '\n')" - iterations="$(cat /crypt-storage${yubikey.storage.path} | sed -n 2p | tr -d '\n')" + salt="$(cat /crypt-storage${dev.yubikey.storage.path} | sed -n 1p | tr -d '\n')" + iterations="$(cat /crypt-storage${dev.yubikey.storage.path} | sed -n 2p | tr -d '\n')" challenge="$(echo -n $salt | openssl-wrap dgst -binary -sha512 | rbtohex)" - response="$(ykchalresp -${toString yubikey.slot} -x $challenge 2>/dev/null)" + response="$(ykchalresp -${toString dev.yubikey.slot} -x $challenge 2>/dev/null)" for try in $(seq 3); do - ${optionalString yubikey.twoFactor '' + ${optionalString dev.yubikey.twoFactor '' echo -n "Enter two-factor passphrase: " - read -r k_user - echo + k_user= + while true; do + if [ -e /crypt-ramfs/passphrase ]; then + echo "reused" + k_user=$(cat /crypt-ramfs/passphrase) + break + else + # Try reading it from /dev/console with a timeout + IFS= read -t 1 -r k_user + if [ -n "$k_user" ]; then + ${if luks.reusePassphrases then '' + # Remember it for the next device + echo -n "$k_user" > /crypt-ramfs/passphrase + '' else '' + # Don't save it to ramfs. We are very paranoid + ''} + echo + break + fi + fi + done ''} if [ ! -z "$k_user" ]; then - k_luks="$(echo -n $k_user | pbkdf2-sha512 ${toString yubikey.keyLength} $iterations $response | rbtohex)" + k_luks="$(echo -n $k_user | pbkdf2-sha512 ${toString dev.yubikey.keyLength} $iterations $response | rbtohex)" else - k_luks="$(echo | pbkdf2-sha512 ${toString yubikey.keyLength} $iterations $response | rbtohex)" + k_luks="$(echo | pbkdf2-sha512 ${toString dev.yubikey.keyLength} $iterations $response | rbtohex)" fi echo -n "$k_luks" | hextorb | ${csopen} --key-file=- if [ $? == 0 ]; then opened=true + ${if luks.reusePassphrases then '' + # We don't rm here because we might reuse it for the next device + '' else '' + rm -f /crypt-ramfs/passphrase + ''} break else opened=false @@ -278,7 +305,7 @@ let [ "$opened" == false ] && die "Maximum authentication errors reached" echo -n "Gathering entropy for new salt (please enter random keys to generate entropy if this blocks for long)..." - for i in $(seq ${toString yubikey.saltLength}); do + for i in $(seq ${toString dev.yubikey.saltLength}); do byte="$(dd if=/dev/random bs=1 count=1 2>/dev/null | rbtohex)"; new_salt="$new_salt$byte"; echo -n . @@ -286,25 +313,25 @@ let echo "ok" new_iterations="$iterations" - ${optionalString (yubikey.iterationStep > 0) '' - new_iterations="$(($new_iterations + ${toString yubikey.iterationStep}))" + ${optionalString (dev.yubikey.iterationStep > 0) '' + new_iterations="$(($new_iterations + ${toString dev.yubikey.iterationStep}))" ''} new_challenge="$(echo -n $new_salt | openssl-wrap dgst -binary -sha512 | rbtohex)" - new_response="$(ykchalresp -${toString yubikey.slot} -x $new_challenge 2>/dev/null)" + new_response="$(ykchalresp -${toString dev.yubikey.slot} -x $new_challenge 2>/dev/null)" if [ ! -z "$k_user" ]; then - new_k_luks="$(echo -n $k_user | pbkdf2-sha512 ${toString yubikey.keyLength} $new_iterations $new_response | rbtohex)" + new_k_luks="$(echo -n $k_user | pbkdf2-sha512 ${toString dev.yubikey.keyLength} $new_iterations $new_response | rbtohex)" else - new_k_luks="$(echo | pbkdf2-sha512 ${toString yubikey.keyLength} $new_iterations $new_response | rbtohex)" + new_k_luks="$(echo | pbkdf2-sha512 ${toString dev.yubikey.keyLength} $new_iterations $new_response | rbtohex)" fi echo -n "$new_k_luks" | hextorb > /crypt-ramfs/new_key echo -n "$k_luks" | hextorb | ${cschange} --key-file=- /crypt-ramfs/new_key if [ $? == 0 ]; then - echo -ne "$new_salt\n$new_iterations" > /crypt-storage${yubikey.storage.path} + echo -ne "$new_salt\n$new_iterations" > /crypt-storage${dev.yubikey.storage.path} else echo "Warning: Could not update LUKS key, current challenge persists!" fi @@ -314,16 +341,16 @@ let } open_with_hardware() { - if wait_yubikey ${toString yubikey.gracePeriod}; then + if wait_yubikey ${toString dev.yubikey.gracePeriod}; then do_open_yubikey else - echo "No yubikey found, falling back to non-yubikey open procedure" + echo "No YubiKey found, falling back to non-YubiKey open procedure" open_normally fi } ''} - ${optionalString (luks.gpgSupport && (gpgCard != null)) '' + ${optionalString (luks.gpgSupport && (dev.gpgCard != null)) '' do_open_gpg_card() { # Make all of these local to this function @@ -331,12 +358,12 @@ let local pin local opened - gpg --import /gpg-keys/${device}/pubkey.asc > /dev/null 2> /dev/null + gpg --import /gpg-keys/${dev.device}/pubkey.asc > /dev/null 2> /dev/null gpg --card-status > /dev/null 2> /dev/null for try in $(seq 3); do - echo -n "PIN for GPG Card associated with device ${device}: " + echo -n "PIN for GPG Card associated with device ${dev.device}: " pin= while true; do if [ -e /crypt-ramfs/passphrase ]; then @@ -358,8 +385,8 @@ let fi fi done - echo -n "Verifying passphrase for ${device}..." - echo -n "$pin" | gpg -q --batch --passphrase-fd 0 --pinentry-mode loopback -d /gpg-keys/${device}/cryptkey.gpg 2> /dev/null | ${csopen} --key-file=- > /dev/null 2> /dev/null + echo -n "Verifying passphrase for ${dev.device}..." + echo -n "$pin" | gpg -q --batch --passphrase-fd 0 --pinentry-mode loopback -d /gpg-keys/${dev.device}/cryptkey.gpg 2> /dev/null | ${csopen} --key-file=- > /dev/null 2> /dev/null if [ $? == 0 ]; then echo " - success" ${if luks.reusePassphrases then '' @@ -379,7 +406,7 @@ let } open_with_hardware() { - if wait_gpgcard ${toString gpgCard.gracePeriod}; then + if wait_gpgcard ${toString dev.gpgCard.gracePeriod}; then do_open_gpg_card else echo "No GPG Card found, falling back to normal open procedure" @@ -388,15 +415,15 @@ let } ''} - ${optionalString (luks.fido2Support && (fido2.credential != null)) '' + ${optionalString (luks.fido2Support && (dev.fido2.credential != null)) '' open_with_hardware() { local passsphrase - ${if fido2.passwordLess then '' + ${if dev.fido2.passwordLess then '' export passphrase="" '' else '' - read -rsp "FIDO2 salt for ${device}: " passphrase + read -rsp "FIDO2 salt for ${dev.device}: " passphrase echo ''} ${optionalString (lib.versionOlder kernelPackages.kernel.version "5.4") '' @@ -404,7 +431,7 @@ let echo "Please move your mouse to create needed randomness." ''} echo "Waiting for your FIDO2 device..." - fido2luks -i open ${device} ${name} ${fido2.credential} --await-dev ${toString fido2.gracePeriod} --salt string:$passphrase + fido2luks open ${dev.device} ${dev.name} ${dev.fido2.credential} --await-dev ${toString dev.fido2.gracePeriod} --salt string:$passphrase if [ $? -ne 0 ]; then echo "No FIDO2 key found, falling back to normal open procedure" open_normally @@ -413,16 +440,16 @@ let ''} # commands to run right before we mount our device - ${preOpenCommands} + ${dev.preOpenCommands} - ${if (luks.yubikeySupport && (yubikey != null)) || (luks.gpgSupport && (gpgCard != null)) || (luks.fido2Support && (fido2.credential != null)) then '' + ${if (luks.yubikeySupport && (dev.yubikey != null)) || (luks.gpgSupport && (dev.gpgCard != null)) || (luks.fido2Support && (dev.fido2.credential != null)) then '' open_with_hardware '' else '' open_normally ''} # commands to run right after we mounted our device - ${postOpenCommands} + ${dev.postOpenCommands} ''; askPass = pkgs.writeScriptBin "cryptsetup-askpass" '' @@ -516,7 +543,7 @@ in <filename>/dev/mapper/<replaceable>name</replaceable></filename>. ''; - type = with types; loaOf (submodule ( + type = with types; attrsOf (submodule ( { name, ... }: { options = { name = mkOption { @@ -594,6 +621,19 @@ in Whether to allow TRIM requests to the underlying device. This option has security implications; please read the LUKS documentation before activating it. + This option is incompatible with authenticated encryption (dm-crypt + stacked over dm-integrity). + ''; + }; + + bypassWorkqueues = mkOption { + default = false; + type = types.bool; + description = '' + Whether to bypass dm-crypt's internal read and write workqueues. + Enabling this should improve performance on SSDs; see + <link xlink:href="https://wiki.archlinux.org/index.php/Dm-crypt/Specialties#Disable_workqueue_for_increased_solid_state_drive_(SSD)_performance">here</link> + for more information. Needs Linux 5.9 or later. ''; }; @@ -641,7 +681,7 @@ in credential = mkOption { default = null; example = "f1d00200d8dc783f7fb1e10ace8da27f8312d72692abfca2f7e4960a73f48e82e1f7571f6ebfcee9fb434f9886ccc8fcc52a6614d8d2"; - type = types.str; + type = types.nullOr types.str; description = "The FIDO2 credential ID."; }; @@ -665,8 +705,8 @@ in yubikey = mkOption { default = null; description = '' - The options to use for this LUKS device in Yubikey-PBA. - If null (the default), Yubikey-PBA will be disabled for this device. + The options to use for this LUKS device in YubiKey-PBA. + If null (the default), YubiKey-PBA will be disabled for this device. ''; type = with types; nullOr (submodule { @@ -674,13 +714,13 @@ in twoFactor = mkOption { default = true; type = types.bool; - description = "Whether to use a passphrase and a Yubikey (true), or only a Yubikey (false)."; + description = "Whether to use a passphrase and a YubiKey (true), or only a YubiKey (false)."; }; slot = mkOption { default = 2; type = types.int; - description = "Which slot on the Yubikey to challenge."; + description = "Which slot on the YubiKey to challenge."; }; saltLength = mkOption { @@ -704,7 +744,7 @@ in gracePeriod = mkOption { default = 10; type = types.int; - description = "Time in seconds to wait for the Yubikey."; + description = "Time in seconds to wait for the YubiKey."; }; /* TODO: Add to the documentation of the current module: @@ -779,9 +819,9 @@ in default = false; type = types.bool; description = '' - Enables support for authenticating with a Yubikey on LUKS devices. + Enables support for authenticating with a YubiKey on LUKS devices. See the NixOS wiki for information on how to properly setup a LUKS device - and a Yubikey to work with this feature. + and a YubiKey to work with this feature. ''; }; @@ -799,7 +839,7 @@ in assertions = [ { assertion = !(luks.gpgSupport && luks.yubikeySupport); - message = "Yubikey and GPG Card may not be used at the same time."; + message = "YubiKey and GPG Card may not be used at the same time."; } { assertion = !(luks.gpgSupport && luks.fido2Support); @@ -807,7 +847,12 @@ in } { assertion = !(luks.fido2Support && luks.yubikeySupport); - message = "FIDO2 and Yubikey may not be used at the same time."; + message = "FIDO2 and YubiKey may not be used at the same time."; + } + + { assertion = any (dev: dev.bypassWorkqueues) (attrValues luks.devices) + -> versionAtLeast kernelPackages.kernel.version "5.9"; + message = "boot.initrd.luks.devices.<name>.bypassWorkqueues is not supported for kernels older than 5.9"; } ]; diff --git a/nixos/modules/system/boot/networkd.nix b/nixos/modules/system/boot/networkd.nix index 47689b2a470..1de58b3d2c4 100644 --- a/nixos/modules/system/boot/networkd.nix +++ b/nixos/modules/system/boot/networkd.nix @@ -436,7 +436,8 @@ let "IPv4ProxyARP" "IPv6ProxyNDP" "IPv6ProxyNDPAddress" - "IPv6PrefixDelegation" + "IPv6SendRA" + "DHCPv6PrefixDelegation" "IPv6MTUBytes" "Bridge" "Bond" @@ -477,7 +478,8 @@ let (assertMinimum "IPv6HopLimit" 0) (assertValueOneOf "IPv4ProxyARP" boolValues) (assertValueOneOf "IPv6ProxyNDP" boolValues) - (assertValueOneOf "IPv6PrefixDelegation" ["static" "dhcpv6" "yes" "false"]) + (assertValueOneOf "IPv6SendRA" boolValues) + (assertValueOneOf "DHCPv6PrefixDelegation" boolValues) (assertByteFormat "IPv6MTUBytes") (assertValueOneOf "ActiveSlave" boolValues) (assertValueOneOf "PrimarySlave" boolValues) @@ -643,16 +645,63 @@ let sectionDHCPv6 = checkUnitConfig "DHCPv6" [ (assertOnlyFields [ + "UseAddress" "UseDNS" "UseNTP" + "RouteMetric" "RapidCommit" + "MUDURL" + "RequestOptions" + "SendVendorOption" "ForceDHCPv6PDOtherInformation" "PrefixDelegationHint" + "WithoutRA" + "SendOption" + "UserClass" + "VendorClass" ]) + (assertValueOneOf "UseAddress" boolValues) (assertValueOneOf "UseDNS" boolValues) (assertValueOneOf "UseNTP" boolValues) + (assertInt "RouteMetric") (assertValueOneOf "RapidCommit" boolValues) (assertValueOneOf "ForceDHCPv6PDOtherInformation" boolValues) + (assertValueOneOf "WithoutRA" ["solicit" "information-request"]) + (assertRange "SendOption" 1 65536) + ]; + + sectionDHCPv6PrefixDelegation = checkUnitConfig "DHCPv6PrefixDelegation" [ + (assertOnlyFields [ + "SubnetId" + "Announce" + "Assign" + "Token" + ]) + (assertValueOneOf "Announce" boolValues) + (assertValueOneOf "Assign" boolValues) + ]; + + sectionIPv6AcceptRA = checkUnitConfig "IPv6AcceptRA" [ + (assertOnlyFields [ + "UseDNS" + "UseDomains" + "RouteTable" + "UseAutonomousPrefix" + "UseOnLinkPrefix" + "RouterDenyList" + "RouterAllowList" + "PrefixDenyList" + "PrefixAllowList" + "RouteDenyList" + "RouteAllowList" + "DHCPv6Client" + ]) + (assertValueOneOf "UseDNS" boolValues) + (assertValueOneOf "UseDomains" (boolValues ++ ["route"])) + (assertRange "RouteTable" 0 4294967295) + (assertValueOneOf "UseAutonomousPrefix" boolValues) + (assertValueOneOf "UseOnLinkPrefix" boolValues) + (assertValueOneOf "DHCPv6Client" (boolValues ++ ["always"])) ]; sectionDHCPServer = checkUnitConfig "DHCPServer" [ @@ -667,10 +716,17 @@ let "NTP" "EmitSIP" "SIP" + "EmitPOP3" + "POP3" + "EmitSMTP" + "SMTP" + "EmitLPR" + "LPR" "EmitRouter" "EmitTimezone" "Timezone" "SendOption" + "SendVendorOption" ]) (assertInt "PoolOffset") (assertMinimum "PoolOffset" 0) @@ -679,11 +735,14 @@ let (assertValueOneOf "EmitDNS" boolValues) (assertValueOneOf "EmitNTP" boolValues) (assertValueOneOf "EmitSIP" boolValues) + (assertValueOneOf "EmitPOP3" boolValues) + (assertValueOneOf "EmitSMTP" boolValues) + (assertValueOneOf "EmitLPR" boolValues) (assertValueOneOf "EmitRouter" boolValues) (assertValueOneOf "EmitTimezone" boolValues) ]; - sectionIPv6PrefixDelegation = checkUnitConfig "IPv6PrefixDelegation" [ + sectionIPv6SendRA = checkUnitConfig "IPv6SendRA" [ (assertOnlyFields [ "Managed" "OtherInformation" @@ -1088,6 +1147,30 @@ let ''; }; + dhcpV6PrefixDelegationConfig = mkOption { + default = {}; + example = { SubnetId = "auto"; Announce = true; }; + type = types.addCheck (types.attrsOf unitOption) check.network.sectionDHCPv6PrefixDelegation; + description = '' + Each attribute in this set specifies an option in the + <literal>[DHCPv6PrefixDelegation]</literal> section of the unit. See + <citerefentry><refentrytitle>systemd.network</refentrytitle> + <manvolnum>5</manvolnum></citerefentry> for details. + ''; + }; + + ipv6AcceptRAConfig = mkOption { + default = {}; + example = { UseDNS = true; DHCPv6Client = "always"; }; + type = types.addCheck (types.attrsOf unitOption) check.network.sectionIPv6AcceptRA; + description = '' + Each attribute in this set specifies an option in the + <literal>[IPv6AcceptRA]</literal> section of the unit. See + <citerefentry><refentrytitle>systemd.network</refentrytitle> + <manvolnum>5</manvolnum></citerefentry> for details. + ''; + }; + dhcpServerConfig = mkOption { default = {}; example = { PoolOffset = 50; EmitDNS = false; }; @@ -1100,13 +1183,20 @@ let ''; }; + # systemd.network.networks.*.ipv6PrefixDelegationConfig has been deprecated + # in 247 in favor of systemd.network.networks.*.ipv6SendRAConfig. ipv6PrefixDelegationConfig = mkOption { + visible = false; + apply = _: throw "The option `systemd.network.networks.*.ipv6PrefixDelegationConfig` has been replaced by `systemd.network.networks.*.ipv6SendRAConfig`."; + }; + + ipv6SendRAConfig = mkOption { default = {}; example = { EmitDNS = true; Managed = true; OtherInformation = true; }; - type = types.addCheck (types.attrsOf unitOption) check.network.sectionIPv6PrefixDelegation; + type = types.addCheck (types.attrsOf unitOption) check.network.sectionIPv6SendRA; description = '' Each attribute in this set specifies an option in the - <literal>[IPv6PrefixDelegation]</literal> section of the unit. See + <literal>[IPv6SendRA]</literal> section of the unit. See <citerefentry><refentrytitle>systemd.network</refentrytitle> <manvolnum>5</manvolnum></citerefentry> for details. ''; @@ -1455,13 +1545,21 @@ let [DHCPv6] ${attrsToSection def.dhcpV6Config} '' + + optionalString (def.dhcpV6PrefixDelegationConfig != { }) '' + [DHCPv6PrefixDelegation] + ${attrsToSection def.dhcpV6PrefixDelegationConfig} + '' + + optionalString (def.ipv6AcceptRAConfig != { }) '' + [IPv6AcceptRA] + ${attrsToSection def.ipv6AcceptRAConfig} + '' + optionalString (def.dhcpServerConfig != { }) '' [DHCPServer] ${attrsToSection def.dhcpServerConfig} '' - + optionalString (def.ipv6PrefixDelegationConfig != { }) '' - [IPv6PrefixDelegation] - ${attrsToSection def.ipv6PrefixDelegationConfig} + + optionalString (def.ipv6SendRAConfig != { }) '' + [IPv6SendRA] + ${attrsToSection def.ipv6SendRAConfig} '' + flip concatMapStrings def.ipv6Prefixes (x: '' [IPv6Prefix] @@ -1477,7 +1575,6 @@ let in { - options = { systemd.network.enable = mkOption { @@ -1551,9 +1648,6 @@ in wantedBy = [ "multi-user.target" ]; aliases = [ "dbus-org.freedesktop.network1.service" ]; restartTriggers = map (x: x.source) (attrValues unitFiles); - # prevent race condition with interface renaming (#39069) - requires = [ "systemd-udev-settle.service" ]; - after = [ "systemd-udev-settle.service" ]; }; systemd.services.systemd-networkd-wait-online = { diff --git a/nixos/modules/system/boot/pbkdf2-sha512.c b/nixos/modules/system/boot/pbkdf2-sha512.c index b40c383ac02..67e989957ba 100644 --- a/nixos/modules/system/boot/pbkdf2-sha512.c +++ b/nixos/modules/system/boot/pbkdf2-sha512.c @@ -35,4 +35,4 @@ int main(int argc, char** argv) fwrite(key, 1, key_length, stdout); return 0; -} \ No newline at end of file +} diff --git a/nixos/modules/system/boot/plymouth.nix b/nixos/modules/system/boot/plymouth.nix index 55e5b07ed61..2a545e55251 100644 --- a/nixos/modules/system/boot/plymouth.nix +++ b/nixos/modules/system/boot/plymouth.nix @@ -4,26 +4,48 @@ with lib; let - inherit (pkgs) plymouth; - inherit (pkgs) nixos-icons; + inherit (pkgs) plymouth nixos-icons; cfg = config.boot.plymouth; - nixosBreezePlymouth = pkgs.breeze-plymouth.override { + nixosBreezePlymouth = pkgs.plasma5Packages.breeze-plymouth.override { logoFile = cfg.logo; logoName = "nixos"; osName = "NixOS"; osVersion = config.system.nixos.release; }; + plymouthLogos = pkgs.runCommand "plymouth-logos" { inherit (cfg) logo; } '' + mkdir -p $out + + # For themes that are compiled with PLYMOUTH_LOGO_FILE + mkdir -p $out/etc/plymouth + ln -s $logo $out/etc/plymouth/logo.png + + # Logo for bgrt theme + # Note this is technically an abuse of watermark for the bgrt theme + # See: https://gitlab.freedesktop.org/plymouth/plymouth/-/issues/95#note_813768 + mkdir -p $out/share/plymouth/themes/spinner + ln -s $logo $out/share/plymouth/themes/spinner/watermark.png + + # Logo for spinfinity theme + # See: https://gitlab.freedesktop.org/plymouth/plymouth/-/issues/106 + mkdir -p $out/share/plymouth/themes/spinfinity + ln -s $logo $out/share/plymouth/themes/spinfinity/header-image.png + ''; + themesEnv = pkgs.buildEnv { name = "plymouth-themes"; - paths = [ plymouth ] ++ cfg.themePackages; + paths = [ + plymouth + plymouthLogos + ] ++ cfg.themePackages; }; configFile = pkgs.writeText "plymouthd.conf" '' [Daemon] ShowDelay=0 + DeviceTimeout=8 Theme=${cfg.theme} ${cfg.extraConfig} ''; @@ -38,8 +60,16 @@ in enable = mkEnableOption "Plymouth boot splash screen"; + font = mkOption { + default = "${pkgs.dejavu_fonts.minimal}/share/fonts/truetype/DejaVuSans.ttf"; + type = types.path; + description = '' + Font file made available for displaying text on the splash screen. + ''; + }; + themePackages = mkOption { - default = [ nixosBreezePlymouth ]; + default = lib.optional (cfg.theme == "breeze") nixosBreezePlymouth; type = types.listOf types.package; description = '' Extra theme packages for plymouth. @@ -47,7 +77,7 @@ in }; theme = mkOption { - default = "breeze"; + default = "bgrt"; type = types.str; description = '' Splash screen theme. @@ -56,7 +86,8 @@ in logo = mkOption { type = types.path; - default = "${nixos-icons}/share/icons/hicolor/128x128/apps/nix-snowflake.png"; + # Dimensions are 48x48 to match GDM logo + default = "${nixos-icons}/share/icons/hicolor/48x48/apps/nix-snowflake-white.png"; defaultText = ''pkgs.fetchurl { url = "https://nixos.org/logo/nixos-hires.png"; sha256 = "1ivzgd7iz0i06y36p8m5w48fd8pjqwxhdaavc0pxs7w1g7mcy5si"; @@ -102,37 +133,62 @@ in systemd.services.plymouth-poweroff.wantedBy = [ "poweroff.target" ]; systemd.services.plymouth-reboot.wantedBy = [ "reboot.target" ]; systemd.services.plymouth-read-write.wantedBy = [ "sysinit.target" ]; - systemd.services.systemd-ask-password-plymouth.wantedBy = ["multi-user.target"]; - systemd.paths.systemd-ask-password-plymouth.wantedBy = ["multi-user.target"]; + systemd.services.systemd-ask-password-plymouth.wantedBy = [ "multi-user.target" ]; + systemd.paths.systemd-ask-password-plymouth.wantedBy = [ "multi-user.target" ]; boot.initrd.extraUtilsCommands = '' - copy_bin_and_libs ${pkgs.plymouth}/bin/plymouthd - copy_bin_and_libs ${pkgs.plymouth}/bin/plymouth + copy_bin_and_libs ${plymouth}/bin/plymouth + copy_bin_and_libs ${plymouth}/bin/plymouthd + + # Check if the actual requested theme is here + if [[ ! -d ${themesEnv}/share/plymouth/themes/${cfg.theme} ]]; then + echo "The requested theme: ${cfg.theme} is not provided by any of the packages in boot.plymouth.themePackages" + exit 1 + fi moduleName="$(sed -n 's,ModuleName *= *,,p' ${themesEnv}/share/plymouth/themes/${cfg.theme}/${cfg.theme}.plymouth)" mkdir -p $out/lib/plymouth/renderers # module might come from a theme - cp ${themesEnv}/lib/plymouth/{text,details,$moduleName}.so $out/lib/plymouth + cp ${themesEnv}/lib/plymouth/{text,details,label,$moduleName}.so $out/lib/plymouth cp ${plymouth}/lib/plymouth/renderers/{drm,frame-buffer}.so $out/lib/plymouth/renderers mkdir -p $out/share/plymouth/themes cp ${plymouth}/share/plymouth/plymouthd.defaults $out/share/plymouth - # copy themes into working directory for patching + # Copy themes into working directory for patching mkdir themes - # use -L to copy the directories proper, not the symlinks to them - cp -r -L ${themesEnv}/share/plymouth/themes/{text,details,${cfg.theme}} themes - # patch out any attempted references to the theme or plymouth's themes directory + # Use -L to copy the directories proper, not the symlinks to them. + # Copy all themes because they're not large assets, and bgrt depends on the ImageDir of + # the spinner theme. + cp -r -L ${themesEnv}/share/plymouth/themes/* themes + + # Patch out any attempted references to the theme or plymouth's themes directory chmod -R +w themes find themes -type f | while read file do sed -i "s,/nix/.*/share/plymouth/themes,$out/share/plymouth/themes,g" $file done + # Install themes cp -r themes/* $out/share/plymouth/themes - cp ${cfg.logo} $out/share/plymouth/logo.png + + # Install logo + mkdir -p $out/etc/plymouth + cp -r -L ${themesEnv}/etc/plymouth $out + + # Setup font + mkdir -p $out/share/fonts + cp ${cfg.font} $out/share/fonts + mkdir -p $out/etc/fonts + cat > $out/etc/fonts/fonts.conf <<EOF + <?xml version="1.0"?> + <!DOCTYPE fontconfig SYSTEM "urn:fontconfig:fonts.dtd"> + <fontconfig> + <dir>$out/share/fonts</dir> + </fontconfig> + EOF ''; boot.initrd.extraUtilsCommandsTest = '' @@ -154,6 +210,7 @@ in ln -s $extraUtils/share/plymouth/logo.png /etc/plymouth/logo.png ln -s $extraUtils/share/plymouth/themes /etc/plymouth/themes ln -s $extraUtils/lib/plymouth /etc/plymouth/plugins + ln -s $extraUtils/etc/fonts /etc/fonts plymouthd --mode=boot --pid-file=/run/plymouth/pid --attach-to-session plymouth show-splash diff --git a/nixos/modules/system/boot/resolved.nix b/nixos/modules/system/boot/resolved.nix index b024f9cf5ee..a6fc07da0ab 100644 --- a/nixos/modules/system/boot/resolved.nix +++ b/nixos/modules/system/boot/resolved.nix @@ -136,11 +136,12 @@ in } ]; - users.users.resolved.group = "systemd-resolve"; + users.users.systemd-resolve.group = "systemd-resolve"; # add resolve to nss hosts database if enabled and nscd enabled # system.nssModules is configured in nixos/modules/system/boot/systemd.nix - system.nssDatabases.hosts = optional config.services.nscd.enable "resolve [!UNAVAIL=return]"; + # added with order 501 to allow modules to go before with mkBefore + system.nssDatabases.hosts = (mkOrder 501 ["resolve [!UNAVAIL=return]"]); systemd.additionalUpstreamSystemUnits = [ "systemd-resolved.service" diff --git a/nixos/modules/system/boot/shutdown.nix b/nixos/modules/system/boot/shutdown.nix index 11041066e07..8cda7b3aabe 100644 --- a/nixos/modules/system/boot/shutdown.nix +++ b/nixos/modules/system/boot/shutdown.nix @@ -18,7 +18,7 @@ with lib; serviceConfig = { Type = "oneshot"; - ExecStart = "${pkgs.utillinux}/sbin/hwclock --systohc ${if config.time.hardwareClockInLocalTime then "--localtime" else "--utc"}"; + ExecStart = "${pkgs.util-linux}/sbin/hwclock --systohc ${if config.time.hardwareClockInLocalTime then "--localtime" else "--utc"}"; }; }; diff --git a/nixos/modules/system/boot/stage-1-init.sh b/nixos/modules/system/boot/stage-1-init.sh index 0c1be71cf53..ddaf985878e 100644 --- a/nixos/modules/system/boot/stage-1-init.sh +++ b/nixos/modules/system/boot/stage-1-init.sh @@ -2,6 +2,13 @@ targetRoot=/mnt-root console=tty1 +verbose="@verbose@" + +info() { + if [[ -n "$verbose" ]]; then + echo "$@" + fi +} extraUtils="@extraUtils@" export LD_LIBRARY_PATH=@extraUtils@/lib @@ -55,7 +62,7 @@ EOF echo "Rebooting..." reboot -f else - echo "Continuing..." + info "Continuing..." fi } @@ -63,9 +70,9 @@ trap 'fail' 0 # Print a greeting. -echo -echo "[1;32m<<< NixOS Stage 1 >>>[0m" -echo +info +info "[1;32m<<< NixOS Stage 1 >>>[0m" +info # Make several required directories. mkdir -p /etc/udev @@ -120,7 +127,7 @@ eval "exec $logOutFd>&1 $logErrFd>&2" if test -w /dev/kmsg; then tee -i < /tmp/stage-1-init.log.fifo /proc/self/fd/"$logOutFd" | while read -r line; do if test -n "$line"; then - echo "<7>stage-1-init: $line" > /dev/kmsg + echo "<7>stage-1-init: [$(date)] $line" > /dev/kmsg fi done & else @@ -210,14 +217,18 @@ ln -s @modulesClosure@/lib/modules /lib/modules ln -s @modulesClosure@/lib/firmware /lib/firmware echo @extraUtils@/bin/modprobe > /proc/sys/kernel/modprobe for i in @kernelModules@; do - echo "loading module $(basename $i)..." + info "loading module $(basename $i)..." modprobe $i done # Create device nodes in /dev. @preDeviceCommands@ -echo "running udev..." +info "running udev..." +ln -sfn /proc/self/fd /dev/fd +ln -sfn /proc/self/fd/0 /dev/stdin +ln -sfn /proc/self/fd/1 /dev/stdout +ln -sfn /proc/self/fd/2 /dev/stderr mkdir -p /etc/systemd ln -sfn @linkUnits@ /etc/systemd/network mkdir -p /etc/udev @@ -231,8 +242,7 @@ udevadm settle # XXX: Use case usb->lvm will still fail, usb->luks->lvm is covered @preLVMCommands@ - -echo "starting device mapper and LVM..." +info "starting device mapper and LVM..." lvm vgchange -ay if test -n "$debug1devices"; then fail; fi @@ -355,6 +365,7 @@ mountFS() { case $options in *x-nixos.autoresize*) if [ "$fsType" = ext2 -o "$fsType" = ext3 -o "$fsType" = ext4 ]; then + modprobe "$fsType" echo "resizing $device..." e2fsck -fp "$device" resize2fs "$device" @@ -374,7 +385,7 @@ mountFS() { done fi - echo "mounting $device on $mountPoint..." + info "mounting $device on $mountPoint..." mkdir -p "/mnt-root$mountPoint" @@ -603,11 +614,16 @@ echo /sbin/modprobe > /proc/sys/kernel/modprobe # Start stage 2. `switch_root' deletes all files in the ramfs on the -# current root. Note that $stage2Init might be an absolute symlink, -# in which case "-e" won't work because we're not in the chroot yet. -if [ ! -e "$targetRoot/$stage2Init" ] && [ ! -L "$targetRoot/$stage2Init" ] ; then - echo "stage 2 init script ($targetRoot/$stage2Init) not found" - fail +# current root. The path has to be valid in the chroot not outside. +if [ ! -e "$targetRoot/$stage2Init" ]; then + stage2Check=${stage2Init} + while [ "$stage2Check" != "${stage2Check%/*}" ] && [ ! -L "$targetRoot/$stage2Check" ]; do + stage2Check=${stage2Check%/*} + done + if [ ! -L "$targetRoot/$stage2Check" ]; then + echo "stage 2 init script ($targetRoot/$stage2Init) not found" + fail + fi fi mkdir -m 0755 -p $targetRoot/proc $targetRoot/sys $targetRoot/dev $targetRoot/run diff --git a/nixos/modules/system/boot/stage-1.nix b/nixos/modules/system/boot/stage-1.nix index eee510d2c95..d606d473d91 100644 --- a/nixos/modules/system/boot/stage-1.nix +++ b/nixos/modules/system/boot/stage-1.nix @@ -22,7 +22,7 @@ let rootModules = config.boot.initrd.availableKernelModules ++ config.boot.initrd.kernelModules; kernel = modulesTree; firmware = firmware; - allowMissing = true; + allowMissing = false; }; @@ -107,8 +107,8 @@ let copy_bin_and_libs $BIN done - # Copy some utillinux stuff. - copy_bin_and_libs ${pkgs.utillinux}/sbin/blkid + # Copy some util-linux stuff. + copy_bin_and_libs ${pkgs.util-linux}/sbin/blkid # Copy dmsetup and lvm. copy_bin_and_libs ${getBin pkgs.lvm2}/bin/dmsetup @@ -119,12 +119,13 @@ let copy_bin_and_libs ${pkgs.mdadm}/sbin/mdmon # Copy udev. - copy_bin_and_libs ${udev}/lib/systemd/systemd-udevd - copy_bin_and_libs ${udev}/lib/systemd/systemd-sysctl copy_bin_and_libs ${udev}/bin/udevadm + copy_bin_and_libs ${udev}/lib/systemd/systemd-sysctl for BIN in ${udev}/lib/udev/*_id; do copy_bin_and_libs $BIN done + # systemd-udevd is only a symlink to udevadm these days + ln -sf udevadm $out/bin/systemd-udevd # Copy modprobe. copy_bin_and_libs ${pkgs.kmod}/bin/kmod @@ -204,13 +205,22 @@ let ''; # */ + # Networkd link files are used early by udev to set up interfaces early. + # This must be done in stage 1 to avoid race conditions between udev and + # network daemons. linkUnits = pkgs.runCommand "link-units" { allowedReferences = [ extraUtils ]; preferLocalBuild = true; - } '' + } ('' mkdir -p $out cp -v ${udev}/lib/systemd/network/*.link $out/ - ''; + '' + ( + let + links = filterAttrs (n: v: hasSuffix ".link" n) config.systemd.network.units; + files = mapAttrsToList (n: v: "${v.unit}/${n}") links; + in + concatMapStringsSep "\n" (file: "cp -v ${file} $out/") files + )); udevRules = pkgs.runCommand "udev-rules" { allowedReferences = [ extraUtils ]; @@ -234,7 +244,7 @@ let --replace scsi_id ${extraUtils}/bin/scsi_id \ --replace cdrom_id ${extraUtils}/bin/cdrom_id \ --replace ${pkgs.coreutils}/bin/basename ${extraUtils}/bin/basename \ - --replace ${pkgs.utillinux}/bin/blkid ${extraUtils}/bin/blkid \ + --replace ${pkgs.util-linux}/bin/blkid ${extraUtils}/bin/blkid \ --replace ${getBin pkgs.lvm2}/bin ${extraUtils}/bin \ --replace ${pkgs.mdadm}/sbin ${extraUtils}/sbin \ --replace ${pkgs.bash}/bin/sh ${extraUtils}/bin/sh \ @@ -279,7 +289,7 @@ let inherit (config.system.build) earlyMountScript; - inherit (config.boot.initrd) checkJournalingFS + inherit (config.boot.initrd) checkJournalingFS verbose preLVMCommands preDeviceCommands postDeviceCommands postMountCommands preFailCommands kernelModules; resumeDevices = map (sd: if sd ? device then sd.device else "/dev/disk/by-label/${sd.label}") @@ -307,7 +317,7 @@ let # the initial RAM disk. initialRamdisk = pkgs.makeInitrd { name = "initrd-${kernel-name}"; - inherit (config.boot.initrd) compressor prepend; + inherit (config.boot.initrd) compressor compressorArgs prepend; contents = [ { object = bootStage1; @@ -333,7 +343,9 @@ let # Script to add secret files to the initrd at bootloader update time initialRamdiskSecretAppender = - pkgs.writeScriptBin "append-initrd-secrets" + let + compressorExe = initialRamdisk.compressorExecutableFunction pkgs; + in pkgs.writeScriptBin "append-initrd-secrets" '' #!${pkgs.bash}/bin/bash -e function usage { @@ -374,8 +386,8 @@ let ) config.boot.initrd.secrets) } - (cd "$tmp" && find . -print0 | sort -z | cpio -o -H newc -R +0:+0 --reproducible --null) | \ - ${config.boot.initrd.compressor} >> "$1" + (cd "$tmp" && find . -print0 | sort -z | cpio --quiet -o -H newc -R +0:+0 --reproducible --null) | \ + ${compressorExe} ${lib.escapeShellArgs initialRamdisk.compressorArgs} >> "$1" ''; in @@ -510,13 +522,33 @@ in }; boot.initrd.compressor = mkOption { - internal = true; - default = "gzip -9n"; - type = types.str; - description = "The compressor to use on the initrd image."; + default = ( + if lib.versionAtLeast config.boot.kernelPackages.kernel.version "5.9" + then "zstd" + else "gzip" + ); + defaultText = "zstd if the kernel supports it (5.9+), gzip if not."; + type = types.unspecified; # We don't have a function type... + description = '' + The compressor to use on the initrd image. May be any of: + + <itemizedlist> + <listitem><para>The name of one of the predefined compressors, see <filename>pkgs/build-support/kernel/initrd-compressor-meta.nix</filename> for the definitions.</para></listitem> + <listitem><para>A function which, given the nixpkgs package set, returns the path to a compressor tool, e.g. <literal>pkgs: "''${pkgs.pigz}/bin/pigz"</literal></para></listitem> + <listitem><para>(not recommended, because it does not work when cross-compiling) the full path to a compressor tool, e.g. <literal>"''${pkgs.pigz}/bin/pigz"</literal></para></listitem> + </itemizedlist> + + The given program should read data from stdin and write it to stdout compressed. + ''; example = "xz"; }; + boot.initrd.compressorArgs = mkOption { + default = null; + type = types.nullOr (types.listOf types.str); + description = "Arguments to pass to the compressor for the initrd image, or null to use the compressor's defaults."; + }; + boot.initrd.secrets = mkOption { default = {}; type = types.attrsOf (types.nullOr types.path); @@ -542,6 +574,23 @@ in description = "Names of supported filesystem types in the initial ramdisk."; }; + boot.initrd.verbose = mkOption { + default = true; + type = types.bool; + description = + '' + Verbosity of the initrd. Please note that disabling verbosity removes + only the mandatory messages generated by the NixOS scripts. For a + completely silent boot, you might also want to set the two following + configuration options: + + <itemizedlist> + <listitem><para><literal>boot.consoleLogLevel = 0;</literal></para></listitem> + <listitem><para><literal>boot.kernelParams = [ "quiet" "udev.log_priority=3" ];</literal></para></listitem> + </itemizedlist> + ''; + }; + boot.loader.supportsInitrdSecrets = mkOption { internal = true; default = false; @@ -555,7 +604,7 @@ in }; fileSystems = mkOption { - type = with lib.types; loaOf (submodule { + type = with lib.types; attrsOf (submodule { options.neededForBoot = mkOption { default = false; type = types.bool; diff --git a/nixos/modules/system/boot/stage-2-init.sh b/nixos/modules/system/boot/stage-2-init.sh index 936077b9df1..50ee0b8841e 100644 --- a/nixos/modules/system/boot/stage-2-init.sh +++ b/nixos/modules/system/boot/stage-2-init.sh @@ -167,6 +167,7 @@ exec {logOutFd}>&- {logErrFd}>&- # Start systemd. echo "starting systemd..." + PATH=/run/current-system/systemd/lib/systemd:@fsPackagesPath@ \ - LOCALE_ARCHIVE=/run/current-system/sw/lib/locale/locale-archive \ + LOCALE_ARCHIVE=/run/current-system/sw/lib/locale/locale-archive @systemdUnitPathEnvVar@ \ exec @systemdExecutable@ diff --git a/nixos/modules/system/boot/stage-2.nix b/nixos/modules/system/boot/stage-2.nix index dd6d83ee009..f6b6a8e4b0b 100644 --- a/nixos/modules/system/boot/stage-2.nix +++ b/nixos/modules/system/boot/stage-2.nix @@ -10,16 +10,20 @@ let src = ./stage-2-init.sh; shellDebug = "${pkgs.bashInteractive}/bin/bash"; shell = "${pkgs.bash}/bin/bash"; - inherit (config.boot) systemdExecutable; + inherit (config.boot) systemdExecutable extraSystemdUnitPaths; isExecutable = true; inherit (config.nix) readOnlyStore; inherit useHostResolvConf; inherit (config.system.build) earlyMountScript; path = lib.makeBinPath ([ pkgs.coreutils - pkgs.utillinux + pkgs.util-linux ] ++ lib.optional useHostResolvConf pkgs.openresolv); fsPackagesPath = lib.makeBinPath config.system.fsPackages; + systemdUnitPathEnvVar = lib.optionalString (config.boot.extraSystemdUnitPaths != []) + ("SYSTEMD_UNIT_PATH=" + + builtins.concatStringsSep ":" config.boot.extraSystemdUnitPaths + + ":"); # If SYSTEMD_UNIT_PATH ends with an empty component (":"), the usual unit load path will be appended to the contents of the variable postBootCommands = pkgs.writeText "local-cmds" '' ${config.boot.postBootCommands} @@ -82,6 +86,15 @@ in PATH. ''; }; + + extraSystemdUnitPaths = mkOption { + default = []; + type = types.listOf types.str; + description = '' + Additional paths that get appended to the SYSTEMD_UNIT_PATH environment variable + that can contain mutable unit files. + ''; + }; }; }; diff --git a/nixos/modules/system/boot/systemd-lib.nix b/nixos/modules/system/boot/systemd-lib.nix index fa109394fed..2dbf15031a0 100644 --- a/nixos/modules/system/boot/systemd-lib.nix +++ b/nixos/modules/system/boot/systemd-lib.nix @@ -92,10 +92,12 @@ in rec { checkUnitConfig = group: checks: attrs: let # We're applied at the top-level type (attrsOf unitOption), so the actual - # unit options might contain attributes from mkOverride that we need to + # unit options might contain attributes from mkOverride and mkIf that we need to # convert into single values before checking them. defs = mapAttrs (const (v: - if v._type or "" == "override" then v.content else v + if v._type or "" == "override" then v.content + else if v._type or "" == "if" then v.content + else v )) attrs; errors = concatMap (c: c group defs) checks; in if errors == [] then true diff --git a/nixos/modules/system/boot/systemd-unit-options.nix b/nixos/modules/system/boot/systemd-unit-options.nix index ac6fed440a2..4154389b2ce 100644 --- a/nixos/modules/system/boot/systemd-unit-options.nix +++ b/nixos/modules/system/boot/systemd-unit-options.nix @@ -210,12 +210,21 @@ in rec { ''; }; + startLimitBurst = mkOption { + type = types.int; + description = '' + Configure unit start rate limiting. Units which are started + more than startLimitBurst times within an interval time + interval are not permitted to start any more. + ''; + }; + startLimitIntervalSec = mkOption { type = types.int; description = '' Configure unit start rate limiting. Units which are started - more than burst times within an interval time interval are - not permitted to start any more. + more than startLimitBurst times within an interval time + interval are not permitted to start any more. ''; }; @@ -234,7 +243,6 @@ in rec { path = mkOption { default = []; type = with types; listOf (oneOf [ package str ]); - apply = ps: "${makeBinPath ps}:${makeSearchPathOutput "bin" "sbin" ps}"; description = '' Packages added to the service's <envar>PATH</envar> environment variable. Both the <filename>bin</filename> @@ -246,8 +254,7 @@ in rec { serviceConfig = mkOption { default = {}; example = - { StartLimitInterval = 10; - RestartSec = 5; + { RestartSec = 5; }; type = types.addCheck (types.attrsOf unitOption) checkService; description = '' diff --git a/nixos/modules/system/boot/systemd.nix b/nixos/modules/system/boot/systemd.nix index b215392f250..58064e5de86 100644 --- a/nixos/modules/system/boot/systemd.nix +++ b/nixos/modules/system/boot/systemd.nix @@ -84,11 +84,13 @@ let # Kernel module loading. "systemd-modules-load.service" "kmod-static-nodes.service" + "modprobe@.service" # Filesystems. "systemd-fsck@.service" "systemd-fsck-root.service" "systemd-remount-fs.service" + "systemd-pstore.service" "local-fs.target" "local-fs-pre.target" "remote-fs.target" @@ -175,8 +177,10 @@ let "timers.target.wants" ]; - upstreamUserUnits = - [ "basic.target" + upstreamUserUnits = [ + "app.slice" + "background.slice" + "basic.target" "bluetooth.target" "default.target" "exit.target" @@ -184,6 +188,7 @@ let "graphical-session.target" "paths.target" "printer.target" + "session.slice" "shutdown.target" "smartcard.target" "sockets.target" @@ -193,6 +198,7 @@ let "systemd-tmpfiles-clean.timer" "systemd-tmpfiles-setup.service" "timers.target" + "xdg-desktop-autostart.target" ]; makeJobScript = name: text: @@ -243,6 +249,8 @@ let OnFailure = toString config.onFailure; } // optionalAttrs (options.startLimitIntervalSec.isDefined) { StartLimitIntervalSec = toString config.startLimitIntervalSec; + } // optionalAttrs (options.startLimitBurst.isDefined) { + StartLimitBurst = toString config.startLimitBurst; }; }; }; @@ -257,11 +265,11 @@ let pkgs.gnused systemd ]; - environment.PATH = config.path; + environment.PATH = "${makeBinPath config.path}:${makeSearchPathOutput "bin" "sbin" config.path}"; } (mkIf (config.preStart != "") { serviceConfig.ExecStartPre = - makeJobScript "${name}-pre-start" config.preStart; + [ (makeJobScript "${name}-pre-start" config.preStart) ]; }) (mkIf (config.script != "") { serviceConfig.ExecStart = @@ -269,7 +277,7 @@ let }) (mkIf (config.postStart != "") { serviceConfig.ExecStartPost = - makeJobScript "${name}-post-start" config.postStart; + [ (makeJobScript "${name}-post-start" config.postStart) ]; }) (mkIf (config.reload != "") { serviceConfig.ExecReload = @@ -548,6 +556,14 @@ in ''; }; + systemd.enableUnifiedCgroupHierarchy = mkOption { + default = true; + type = types.bool; + description = '' + Whether to enable the unified cgroup hierarchy (cgroupsv2). + ''; + }; + systemd.coredump.enable = mkOption { default = true; type = types.bool; @@ -739,7 +755,7 @@ in default = []; example = [ "d /tmp 1777 root root 10d" ]; description = '' - Rules for creating and cleaning up temporary files + Rules for creation, deletion and cleaning of volatile and temporary files automatically. See <citerefentry><refentrytitle>tmpfiles.d</refentrytitle><manvolnum>5</manvolnum></citerefentry> for the exact format. @@ -884,30 +900,38 @@ in config = { - warnings = concatLists (mapAttrsToList (name: service: - let - type = service.serviceConfig.Type or ""; - restart = service.serviceConfig.Restart or "no"; - in optional - (type == "oneshot" && (restart == "always" || restart == "on-success")) - "Service '${name}.service' with 'Type=oneshot' cannot have 'Restart=always' or 'Restart=on-success'") - cfg.services); + warnings = concatLists ( + mapAttrsToList + (name: service: + let + type = service.serviceConfig.Type or ""; + restart = service.serviceConfig.Restart or "no"; + hasDeprecated = builtins.hasAttr "StartLimitInterval" service.serviceConfig; + in + concatLists [ + (optional (type == "oneshot" && (restart == "always" || restart == "on-success")) + "Service '${name}.service' with 'Type=oneshot' cannot have 'Restart=always' or 'Restart=on-success'" + ) + (optional hasDeprecated + "Service '${name}.service' uses the attribute 'StartLimitInterval' in the Service section, which is deprecated. See https://github.com/NixOS/nixpkgs/issues/45786." + ) + ] + ) + cfg.services + ); system.build.units = cfg.units; system.nssModules = [ systemd.out ]; system.nssDatabases = { hosts = (mkMerge [ - [ "mymachines" ] - (mkOrder 1600 [ "myhostname" ] # 1600 to ensure it's always the last - ) + (mkOrder 400 ["mymachines"]) # 400 to ensure it comes before resolve (which is mkBefore'd) + (mkOrder 999 ["myhostname"]) # after files (which is 998), but before regular nss modules ]); passwd = (mkMerge [ - [ "mymachines" ] (mkAfter [ "systemd" ]) ]); group = (mkMerge [ - [ "mymachines" ] (mkAfter [ "systemd" ]) ]); }; @@ -1008,7 +1032,7 @@ in "sysctl.d/50-coredump.conf".source = "${systemd}/example/sysctl.d/50-coredump.conf"; "sysctl.d/50-default.conf".source = "${systemd}/example/sysctl.d/50-default.conf"; - "tmpfiles.d".source = pkgs.symlinkJoin { + "tmpfiles.d".source = (pkgs.symlinkJoin { name = "tmpfiles.d"; paths = map (p: p + "/lib/tmpfiles.d") cfg.tmpfiles.packages; postBuild = '' @@ -1018,8 +1042,10 @@ in exit 1 ) done - ''; - }; + '' + concatMapStrings (name: optionalString (hasPrefix "tmpfiles.d/" name) '' + rm -f $out/${removePrefix "tmpfiles.d/" name} + '') config.system.build.etc.targets; + }) + "/*"; "systemd/system-generators" = { source = hooks "generators" cfg.generators; }; "systemd/system-shutdown" = { source = hooks "shutdown" cfg.shutdown; }; @@ -1157,14 +1183,19 @@ in systemd.targets.remote-fs.unitConfig.X-StopOnReconfiguration = true; systemd.targets.network-online.wantedBy = [ "multi-user.target" ]; systemd.services.systemd-importd.environment = proxy_env; + systemd.services.systemd-pstore.wantedBy = [ "sysinit.target" ]; # see #81138 # Don't bother with certain units in containers. systemd.services.systemd-remount-fs.unitConfig.ConditionVirtualization = "!container"; systemd.services.systemd-random-seed.unitConfig.ConditionVirtualization = "!container"; - boot.kernel.sysctl = mkIf (!cfg.coredump.enable) { - "kernel.core_pattern" = "core"; - }; + boot.kernel.sysctl."kernel.core_pattern" = mkIf (!cfg.coredump.enable) "core"; + + # Increase numeric PID range (set directly instead of copying a one-line file from systemd) + # https://github.com/systemd/systemd/pull/12226 + boot.kernel.sysctl."kernel.pid_max" = mkIf pkgs.stdenv.is64bit (lib.mkDefault 4194304); + + boot.kernelParams = optional (!cfg.enableUnifiedCgroupHierarchy) "systemd.unified_cgroup_hierarchy=0"; }; # FIXME: Remove these eventually. diff --git a/nixos/modules/system/boot/timesyncd.nix b/nixos/modules/system/boot/timesyncd.nix index 35fb5578b07..692315dbe99 100644 --- a/nixos/modules/system/boot/timesyncd.nix +++ b/nixos/modules/system/boot/timesyncd.nix @@ -16,6 +16,7 @@ with lib; }; servers = mkOption { default = config.networking.timeServers; + type = types.listOf types.str; description = '' The set of NTP servers from which to synchronise. ''; diff --git a/nixos/modules/system/boot/tmp.nix b/nixos/modules/system/boot/tmp.nix index 26eb172210e..5bb299adb15 100644 --- a/nixos/modules/system/boot/tmp.nix +++ b/nixos/modules/system/boot/tmp.nix @@ -30,7 +30,14 @@ with lib; config = { - systemd.additionalUpstreamSystemUnits = optional config.boot.tmpOnTmpfs "tmp.mount"; + systemd.mounts = mkIf config.boot.tmpOnTmpfs [ + { + what = "tmpfs"; + where = "/tmp"; + type = "tmpfs"; + mountConfig.Options = [ "mode=1777" "strictatime" "rw" "nosuid" "nodev" "size=50%" ]; + } + ]; systemd.tmpfiles.rules = optional config.boot.cleanTmpDir "D! /tmp 1777 root root"; diff --git a/nixos/modules/system/etc/etc.nix b/nixos/modules/system/etc/etc.nix index 1f4d54a1ae2..a450f303572 100644 --- a/nixos/modules/system/etc/etc.nix +++ b/nixos/modules/system/etc/etc.nix @@ -46,7 +46,7 @@ in Set of files that have to be linked in <filename>/etc</filename>. ''; - type = with types; loaOf (submodule ( + type = with types; attrsOf (submodule ( { name, config, ... }: { options = { @@ -154,7 +154,7 @@ in '' # Set up the statically computed bits of /etc. echo "setting up /etc..." - ${pkgs.perl}/bin/perl -I${pkgs.perlPackages.FileSlurp}/${pkgs.perl.libPrefix} ${./setup-etc.pl} ${etc}/etc + ${pkgs.perl.withPackages (p: [ p.FileSlurp ])}/bin/perl ${./setup-etc.pl} ${etc}/etc ''; }; |