diff options
Diffstat (limited to 'nixpkgs/nixos/modules/system')
17 files changed, 366 insertions, 127 deletions
diff --git a/nixpkgs/nixos/modules/system/activation/activation-script.nix b/nixpkgs/nixos/modules/system/activation/activation-script.nix index 704fc15fe207..8dbfe393f109 100644 --- a/nixpkgs/nixos/modules/system/activation/activation-script.nix +++ b/nixpkgs/nixos/modules/system/activation/activation-script.nix @@ -110,7 +110,7 @@ in system.activationScripts = mkOption { default = {}; - example = literalExample '' + example = literalExpression '' { stdio.text = ''' # Needed by some programs. @@ -147,7 +147,7 @@ in system.userActivationScripts = mkOption { default = {}; - example = literalExample '' + example = literalExpression '' { plasmaSetup = { text = ''' ${pkgs.libsForQt5.kservice}/bin/kbuildsycoca5" @@ -193,9 +193,8 @@ in environment.usrbinenv = mkOption { default = "${pkgs.coreutils}/bin/env"; - example = literalExample '' - "''${pkgs.busybox}/bin/env" - ''; + defaultText = literalExpression ''"''${pkgs.coreutils}/bin/env"''; + example = literalExpression ''"''${pkgs.busybox}/bin/env"''; type = types.nullOr types.path; visible = false; description = '' diff --git a/nixpkgs/nixos/modules/system/activation/switch-to-configuration.pl b/nixpkgs/nixos/modules/system/activation/switch-to-configuration.pl index b7a062755296..e105502cf3a4 100644 --- a/nixpkgs/nixos/modules/system/activation/switch-to-configuration.pl +++ b/nixpkgs/nixos/modules/system/activation/switch-to-configuration.pl @@ -2,6 +2,7 @@ use strict; use warnings; +use File::Path qw(make_path); use File::Basename; use File::Slurp; use Net::DBus; @@ -10,13 +11,23 @@ use Cwd 'abs_path'; my $out = "@out@"; -# FIXME: maybe we should use /proc/1/exe to get the current systemd. my $curSystemd = abs_path("/run/current-system/sw/bin"); # To be robust against interruption, record what units need to be started etc. -my $startListFile = "/run/systemd/start-list"; -my $restartListFile = "/run/systemd/restart-list"; -my $reloadListFile = "/run/systemd/reload-list"; +my $startListFile = "/run/nixos/start-list"; +my $restartListFile = "/run/nixos/restart-list"; +my $reloadListFile = "/run/nixos/reload-list"; + +# Parse restart/reload requests by the activation script. +# Activation scripts may write newline-separated units to this +# file and switch-to-configuration will handle them. While +# `stopIfChanged = true` is ignored, switch-to-configuration will +# handle `restartIfChanged = false` and `reloadIfChanged = true`. +# This also works for socket-activated units. +my $restartByActivationFile = "/run/nixos/activation-restart-list"; +my $dryRestartByActivationFile = "/run/nixos/dry-activation-restart-list"; + +make_path("/run/nixos", { mode => oct(755) }); my $action = shift @ARGV; @@ -138,6 +149,92 @@ sub fingerprintUnit { return abs_path($s) . (-f "${s}.d/overrides.conf" ? " " . abs_path "${s}.d/overrides.conf" : ""); } +sub handleModifiedUnit { + my ($unit, $baseName, $newUnitFile, $activePrev, $unitsToStop, $unitsToStart, $unitsToReload, $unitsToRestart, $unitsToSkip) = @_; + + if ($unit eq "sysinit.target" || $unit eq "basic.target" || $unit eq "multi-user.target" || $unit eq "graphical.target" || $unit =~ /\.slice$/ || $unit =~ /\.path$/) { + # Do nothing. These cannot be restarted directly. + # Slices and Paths don't have to be restarted since + # properties (resource limits and inotify watches) + # seem to get applied on daemon-reload. + } elsif ($unit =~ /\.mount$/) { + # Reload the changed mount unit to force a remount. + $unitsToReload->{$unit} = 1; + recordUnit($reloadListFile, $unit); + } else { + my $unitInfo = parseUnit($newUnitFile); + if (boolIsTrue($unitInfo->{'X-ReloadIfChanged'} // "no")) { + $unitsToReload->{$unit} = 1; + recordUnit($reloadListFile, $unit); + } + elsif (!boolIsTrue($unitInfo->{'X-RestartIfChanged'} // "yes") || boolIsTrue($unitInfo->{'RefuseManualStop'} // "no") || boolIsTrue($unitInfo->{'X-OnlyManualStart'} // "no")) { + $unitsToSkip->{$unit} = 1; + } else { + # If this unit is socket-activated, then stop it instead + # of restarting it to make sure the new version of it is + # socket-activated. + my $socketActivated = 0; + if ($unit =~ /\.service$/) { + my @sockets = split / /, ($unitInfo->{Sockets} // ""); + if (scalar @sockets == 0) { + @sockets = ("$baseName.socket"); + } + foreach my $socket (@sockets) { + if (-e "$out/etc/systemd/system/$socket") { + $socketActivated = 1; + $unitsToStop->{$unit} = 1; + # If the socket was not running previously, + # start it now. + if (not defined $activePrev->{$socket}) { + $unitsToStart->{$socket} = 1; + } + } + } + } + + # Don't do the rest of this for socket-activated units + # because we handled these above where we stop the unit. + # Since only services can be socket-activated, the + # following condition always evaluates to `true` for + # non-service units. + if ($socketActivated) { + return; + } + + # If we are restarting a socket, also stop the corresponding + # service. This is required because restarting a socket + # when the service is already activated fails. + if ($unit =~ /\.socket$/) { + my $service = $unitInfo->{Service} // ""; + if ($service eq "") { + $service = "$baseName.service"; + } + if (defined $activePrev->{$service}) { + $unitsToStop->{$service} = 1; + } + $unitsToRestart->{$unit} = 1; + recordUnit($restartListFile, $unit); + } else { + # Always restart non-services instead of stopping and starting them + # because it doesn't make sense to stop them with a config from + # the old evaluation. + if (!boolIsTrue($unitInfo->{'X-StopIfChanged'} // "yes") || $unit !~ /\.service$/) { + # This unit should be restarted instead of + # stopped and started. + $unitsToRestart->{$unit} = 1; + recordUnit($restartListFile, $unit); + } else { + # We write to a file to ensure that the + # service gets restarted if we're interrupted. + $unitsToStart->{$unit} = 1; + recordUnit($startListFile, $unit); + $unitsToStop->{$unit} = 1; + } + } + } + } +} + # Figure out what units need to be stopped, started, restarted or reloaded. my (%unitsToStop, %unitsToSkip, %unitsToStart, %unitsToRestart, %unitsToReload); @@ -150,7 +247,7 @@ $unitsToRestart{$_} = 1 foreach split('\n', read_file($restartListFile, err_mode => 'quiet') // ""); $unitsToReload{$_} = 1 foreach - split '\n', read_file($reloadListFile, err_mode => 'quiet') // ""; + split('\n', read_file($reloadListFile, err_mode => 'quiet') // ""); my $activePrev = getActiveUnits; while (my ($unit, $state) = each %{$activePrev}) { @@ -210,65 +307,7 @@ while (my ($unit, $state) = each %{$activePrev}) { } elsif (fingerprintUnit($prevUnitFile) ne fingerprintUnit($newUnitFile)) { - if ($unit eq "sysinit.target" || $unit eq "basic.target" || $unit eq "multi-user.target" || $unit eq "graphical.target") { - # Do nothing. These cannot be restarted directly. - } elsif ($unit =~ /\.mount$/) { - # Reload the changed mount unit to force a remount. - $unitsToReload{$unit} = 1; - recordUnit($reloadListFile, $unit); - } elsif ($unit =~ /\.socket$/ || $unit =~ /\.path$/ || $unit =~ /\.slice$/) { - # FIXME: do something? - } else { - my $unitInfo = parseUnit($newUnitFile); - if (boolIsTrue($unitInfo->{'X-ReloadIfChanged'} // "no")) { - $unitsToReload{$unit} = 1; - recordUnit($reloadListFile, $unit); - } - elsif (!boolIsTrue($unitInfo->{'X-RestartIfChanged'} // "yes") || boolIsTrue($unitInfo->{'RefuseManualStop'} // "no") || boolIsTrue($unitInfo->{'X-OnlyManualStart'} // "no")) { - $unitsToSkip{$unit} = 1; - } else { - if (!boolIsTrue($unitInfo->{'X-StopIfChanged'} // "yes")) { - # This unit should be restarted instead of - # stopped and started. - $unitsToRestart{$unit} = 1; - recordUnit($restartListFile, $unit); - } else { - # If this unit is socket-activated, then stop the - # socket unit(s) as well, and restart the - # socket(s) instead of the service. - my $socketActivated = 0; - if ($unit =~ /\.service$/) { - my @sockets = split / /, ($unitInfo->{Sockets} // ""); - if (scalar @sockets == 0) { - @sockets = ("$baseName.socket"); - } - foreach my $socket (@sockets) { - if (defined $activePrev->{$socket}) { - $unitsToStop{$socket} = 1; - # Only restart sockets that actually - # exist in new configuration: - if (-e "$out/etc/systemd/system/$socket") { - $unitsToStart{$socket} = 1; - recordUnit($startListFile, $socket); - $socketActivated = 1; - } - } - } - } - - # If the unit is not socket-activated, record - # that this unit needs to be started below. - # We write this to a file to ensure that the - # service gets restarted if we're interrupted. - if (!$socketActivated) { - $unitsToStart{$unit} = 1; - recordUnit($startListFile, $unit); - } - - $unitsToStop{$unit} = 1; - } - } - } + handleModifiedUnit($unit, $baseName, $newUnitFile, $activePrev, \%unitsToStop, \%unitsToStart, \%unitsToReload, \%unitsToRestart, %unitsToSkip); } } } @@ -353,8 +392,6 @@ sub filterUnits { } my @unitsToStopFiltered = filterUnits(\%unitsToStop); -my @unitsToStartFiltered = filterUnits(\%unitsToStart); - # Show dry-run actions. if ($action eq "dry-activate") { @@ -366,13 +403,44 @@ if ($action eq "dry-activate") { print STDERR "would activate the configuration...\n"; system("$out/dry-activate", "$out"); + # Handle the activation script requesting the restart or reload of a unit. + my %unitsToAlsoStop; + my %unitsToAlsoSkip; + foreach (split('\n', read_file($dryRestartByActivationFile, err_mode => 'quiet') // "")) { + my $unit = $_; + my $baseUnit = $unit; + my $newUnitFile = "$out/etc/systemd/system/$baseUnit"; + + # Detect template instances. + if (!-e $newUnitFile && $unit =~ /^(.*)@[^\.]*\.(.*)$/) { + $baseUnit = "$1\@.$2"; + $newUnitFile = "$out/etc/systemd/system/$baseUnit"; + } + + my $baseName = $baseUnit; + $baseName =~ s/\.[a-z]*$//; + + handleModifiedUnit($unit, $baseName, $newUnitFile, $activePrev, \%unitsToAlsoStop, \%unitsToStart, \%unitsToReload, \%unitsToRestart, %unitsToAlsoSkip); + } + unlink($dryRestartByActivationFile); + + my @unitsToAlsoStopFiltered = filterUnits(\%unitsToAlsoStop); + if (scalar(keys %unitsToAlsoStop) > 0) { + print STDERR "would stop the following units as well: ", join(", ", @unitsToAlsoStopFiltered), "\n" + if scalar @unitsToAlsoStopFiltered; + } + + print STDERR "would NOT restart the following changed units as well: ", join(", ", sort(keys %unitsToAlsoSkip)), "\n" + if scalar(keys %unitsToAlsoSkip) > 0; + print STDERR "would restart systemd\n" if $restartSystemd; + print STDERR "would reload the following units: ", join(", ", sort(keys %unitsToReload)), "\n" + if scalar(keys %unitsToReload) > 0; print STDERR "would restart the following units: ", join(", ", sort(keys %unitsToRestart)), "\n" if scalar(keys %unitsToRestart) > 0; + my @unitsToStartFiltered = filterUnits(\%unitsToStart); print STDERR "would start the following units: ", join(", ", @unitsToStartFiltered), "\n" if scalar @unitsToStartFiltered; - print STDERR "would reload the following units: ", join(", ", sort(keys %unitsToReload)), "\n" - if scalar(keys %unitsToReload) > 0; exit 0; } @@ -383,7 +451,7 @@ if (scalar (keys %unitsToStop) > 0) { print STDERR "stopping the following units: ", join(", ", @unitsToStopFiltered), "\n" if scalar @unitsToStopFiltered; # Use current version of systemctl binary before daemon is reexeced. - system("$curSystemd/systemctl", "stop", "--", sort(keys %unitsToStop)); # FIXME: ignore errors? + system("$curSystemd/systemctl", "stop", "--", sort(keys %unitsToStop)); } print STDERR "NOT restarting the following changed units: ", join(", ", sort(keys %unitsToSkip)), "\n" @@ -395,6 +463,41 @@ my $res = 0; print STDERR "activating the configuration...\n"; system("$out/activate", "$out") == 0 or $res = 2; +# Handle the activation script requesting the restart or reload of a unit. +# We can only restart and reload (not stop/start) because the units to be +# stopped are already stopped before the activation script is run. We do however +# make an exception for services that are socket-activated and that have to be stopped +# instead of being restarted. +my %unitsToAlsoStop; +my %unitsToAlsoSkip; +foreach (split('\n', read_file($restartByActivationFile, err_mode => 'quiet') // "")) { + my $unit = $_; + my $baseUnit = $unit; + my $newUnitFile = "$out/etc/systemd/system/$baseUnit"; + + # Detect template instances. + if (!-e $newUnitFile && $unit =~ /^(.*)@[^\.]*\.(.*)$/) { + $baseUnit = "$1\@.$2"; + $newUnitFile = "$out/etc/systemd/system/$baseUnit"; + } + + my $baseName = $baseUnit; + $baseName =~ s/\.[a-z]*$//; + + handleModifiedUnit($unit, $baseName, $newUnitFile, $activePrev, \%unitsToAlsoStop, \%unitsToStart, \%unitsToReload, \%unitsToRestart, %unitsToAlsoSkip); +} +unlink($restartByActivationFile); + +my @unitsToAlsoStopFiltered = filterUnits(\%unitsToAlsoStop); +if (scalar(keys %unitsToAlsoStop) > 0) { + print STDERR "stopping the following units as well: ", join(", ", @unitsToAlsoStopFiltered), "\n" + if scalar @unitsToAlsoStopFiltered; + system("$curSystemd/systemctl", "stop", "--", sort(keys %unitsToAlsoStop)); +} + +print STDERR "NOT restarting the following changed units as well: ", join(", ", sort(keys %unitsToAlsoSkip)), "\n" + if scalar(keys %unitsToAlsoSkip) > 0; + # Restart systemd if necessary. Note that this is done using the # current version of systemd, just in case the new one has trouble # communicating with the running pid 1. @@ -440,8 +543,36 @@ if (scalar(keys %unitsToReload) > 0) { # than stopped and started). if (scalar(keys %unitsToRestart) > 0) { print STDERR "restarting the following units: ", join(", ", sort(keys %unitsToRestart)), "\n"; - system("@systemd@/bin/systemctl", "restart", "--", sort(keys %unitsToRestart)) == 0 or $res = 4; + + # We split the units to be restarted into sockets and non-sockets. + # This is because restarting sockets may fail which is not bad by + # itself but which will prevent changes on the sockets. We usually + # restart the socket and stop the service before that. Restarting + # the socket will fail however when the service was re-activated + # in the meantime. There is no proper way to prevent that from happening. + my @unitsWithErrorHandling = grep { $_ !~ /\.socket$/ } sort(keys %unitsToRestart); + my @unitsWithoutErrorHandling = grep { $_ =~ /\.socket$/ } sort(keys %unitsToRestart); + + if (scalar(@unitsWithErrorHandling) > 0) { + system("@systemd@/bin/systemctl", "restart", "--", @unitsWithErrorHandling) == 0 or $res = 4; + } + if (scalar(@unitsWithoutErrorHandling) > 0) { + # Don't print warnings from systemctl + no warnings 'once'; + open(OLDERR, ">&", \*STDERR); + close(STDERR); + + my $ret = system("@systemd@/bin/systemctl", "restart", "--", @unitsWithoutErrorHandling); + + # Print stderr again + open(STDERR, ">&OLDERR"); + + if ($ret ne 0) { + print STDERR "warning: some sockets failed to restart. Please check your journal (journalctl -eb) and act accordingly.\n"; + } + } unlink($restartListFile); + unlink($restartByActivationFile); } # Start all active targets, as well as changed units we stopped above. @@ -450,6 +581,7 @@ if (scalar(keys %unitsToRestart) > 0) { # that are symlinks to other units. We shouldn't start both at the # same time because we'll get a "Failed to add path to set" error from # systemd. +my @unitsToStartFiltered = filterUnits(\%unitsToStart); print STDERR "starting the following units: ", join(", ", @unitsToStartFiltered), "\n" if scalar @unitsToStartFiltered; system("@systemd@/bin/systemctl", "start", "--", sort(keys %unitsToStart)) == 0 or $res = 4; @@ -457,7 +589,7 @@ unlink($startListFile); # Print failed and new units. -my (@failed, @new, @restarting); +my (@failed, @new); my $activeNew = getActiveUnits; while (my ($unit, $state) = each %{$activeNew}) { if ($state->{state} eq "failed") { @@ -473,7 +605,9 @@ while (my ($unit, $state) = each %{$activeNew}) { push @failed, $unit; } } - elsif ($state->{state} ne "failed" && !defined $activePrev->{$unit}) { + # Ignore scopes since they are not managed by this script but rather + # created and managed by third-party services via the systemd dbus API. + elsif ($state->{state} ne "failed" && !defined $activePrev->{$unit} && $unit !~ /\.scope$/) { push @new, $unit; } } diff --git a/nixpkgs/nixos/modules/system/activation/top-level.nix b/nixpkgs/nixos/modules/system/activation/top-level.nix index dad9acba91af..68da910d29cc 100644 --- a/nixpkgs/nixos/modules/system/activation/top-level.nix +++ b/nixpkgs/nixos/modules/system/activation/top-level.nix @@ -84,6 +84,13 @@ let export localeArchive="${config.i18n.glibcLocales}/lib/locale/locale-archive" substituteAll ${./switch-to-configuration.pl} $out/bin/switch-to-configuration chmod +x $out/bin/switch-to-configuration + ${optionalString (pkgs.stdenv.hostPlatform == pkgs.stdenv.buildPlatform) '' + if ! output=$($perl/bin/perl -c $out/bin/switch-to-configuration 2>&1); then + echo "switch-to-configuration syntax is not valid:" + echo "$output" + exit 1 + fi + ''} echo -n "${toString config.system.extraDependencies}" > $out/extra-dependencies @@ -155,7 +162,7 @@ in specialisation = mkOption { default = {}; - example = lib.literalExample "{ fewJobsManyCores.configuration = { nix.buildCores = 0; nix.maxJobs = 1; }; }"; + example = lib.literalExpression "{ fewJobsManyCores.configuration = { nix.buildCores = 0; nix.maxJobs = 1; }; }"; description = '' Additional configurations to build. If <literal>inheritParentConfig</literal> is true, the system @@ -243,7 +250,7 @@ in system.replaceRuntimeDependencies = mkOption { default = []; - example = lib.literalExample "[ ({ original = pkgs.openssl; replacement = pkgs.callPackage /path/to/openssl { }; }) ]"; + example = lib.literalExpression "[ ({ original = pkgs.openssl; replacement = pkgs.callPackage /path/to/openssl { }; }) ]"; type = types.listOf (types.submodule ( { ... }: { options.original = mkOption { @@ -274,7 +281,11 @@ in if config.networking.hostName == "" then "unnamed" else config.networking.hostName; - defaultText = '''networking.hostName' if non empty else "unnamed"''; + defaultText = literalExpression '' + if config.networking.hostName == "" + then "unnamed" + else config.networking.hostName; + ''; description = '' The name of the system used in the <option>system.build.toplevel</option> derivation. </para><para> diff --git a/nixpkgs/nixos/modules/system/boot/initrd-openvpn.nix b/nixpkgs/nixos/modules/system/boot/initrd-openvpn.nix index b35fb0b57c05..9b52d4bbdb1e 100644 --- a/nixpkgs/nixos/modules/system/boot/initrd-openvpn.nix +++ b/nixpkgs/nixos/modules/system/boot/initrd-openvpn.nix @@ -35,7 +35,7 @@ in </para> </warning> ''; - example = "./configuration.ovpn"; + example = literalExpression "./configuration.ovpn"; }; }; diff --git a/nixpkgs/nixos/modules/system/boot/initrd-ssh.nix b/nixpkgs/nixos/modules/system/boot/initrd-ssh.nix index 00ac83a18972..0999142de86e 100644 --- a/nixpkgs/nixos/modules/system/boot/initrd-ssh.nix +++ b/nixpkgs/nixos/modules/system/boot/initrd-ssh.nix @@ -78,7 +78,7 @@ in authorizedKeys = mkOption { type = types.listOf types.str; default = config.users.users.root.openssh.authorizedKeys.keys; - defaultText = "config.users.users.root.openssh.authorizedKeys.keys"; + defaultText = literalExpression "config.users.users.root.openssh.authorizedKeys.keys"; description = '' Authorized keys for the root user on initrd. ''; diff --git a/nixpkgs/nixos/modules/system/boot/kernel.nix b/nixpkgs/nixos/modules/system/boot/kernel.nix index 15a5fd236092..4a9da9394519 100644 --- a/nixpkgs/nixos/modules/system/boot/kernel.nix +++ b/nixpkgs/nixos/modules/system/boot/kernel.nix @@ -23,7 +23,7 @@ in boot.kernel.features = mkOption { default = {}; - example = literalExample "{ debug = true; }"; + example = literalExpression "{ debug = true; }"; internal = true; description = '' This option allows to enable or disable certain kernel features. @@ -46,8 +46,8 @@ in }); # We don't want to evaluate all of linuxPackages for the manual # - some of it might not even evaluate correctly. - defaultText = "pkgs.linuxPackages"; - example = literalExample "pkgs.linuxKernel.packages.linux_5_10"; + defaultText = literalExpression "pkgs.linuxPackages"; + example = literalExpression "pkgs.linuxKernel.packages.linux_5_10"; description = '' This option allows you to override the Linux kernel used by NixOS. Since things like external kernel module packages are @@ -65,7 +65,7 @@ in boot.kernelPatches = mkOption { type = types.listOf types.attrs; default = []; - example = literalExample "[ pkgs.kernelPatches.ubuntu_fan_4_4 ]"; + example = literalExpression "[ pkgs.kernelPatches.ubuntu_fan_4_4 ]"; description = "A list of additional patches to apply to the kernel."; }; @@ -83,7 +83,10 @@ in }; boot.kernelParams = mkOption { - type = types.listOf types.str; + type = types.listOf (types.strMatching ''([^"[:space:]]|"[^"]*")+'' // { + name = "kernelParam"; + description = "string, with spaces inside double quotes"; + }); default = [ ]; description = "Parameters added to the kernel command line."; }; @@ -113,7 +116,7 @@ in boot.extraModulePackages = mkOption { type = types.listOf types.package; default = []; - example = literalExample "[ config.boot.kernelPackages.nvidia_x11 ]"; + example = literalExpression "[ config.boot.kernelPackages.nvidia_x11 ]"; description = "A list of additional packages supplying kernel modules."; }; @@ -181,7 +184,7 @@ in system.requiredKernelConfig = mkOption { default = []; - example = literalExample '' + example = literalExpression '' with config.lib.kernelConfig; [ (isYes "MODULES") (isEnabled "FB_CON_DECOR") diff --git a/nixpkgs/nixos/modules/system/boot/kernel_config.nix b/nixpkgs/nixos/modules/system/boot/kernel_config.nix index 5d9534024b06..495fe74bc21e 100644 --- a/nixpkgs/nixos/modules/system/boot/kernel_config.nix +++ b/nixpkgs/nixos/modules/system/boot/kernel_config.nix @@ -100,7 +100,7 @@ in settings = mkOption { type = types.attrsOf kernelItem; - example = literalExample '' with lib.kernel; { + example = literalExpression '' with lib.kernel; { "9P_NET" = yes; USB = option yes; MMC_BLOCK_MINORS = freeform "32"; diff --git a/nixpkgs/nixos/modules/system/boot/loader/grub/grub.nix b/nixpkgs/nixos/modules/system/boot/loader/grub/grub.nix index 1be663670384..fa8500dd42bd 100644 --- a/nixpkgs/nixos/modules/system/boot/loader/grub/grub.nix +++ b/nixpkgs/nixos/modules/system/boot/loader/grub/grub.nix @@ -329,7 +329,7 @@ in extraInstallCommands = mkOption { default = ""; - example = literalExample '' + example = '' # 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 @@ -392,7 +392,7 @@ in extraFiles = mkOption { type = types.attrsOf types.path; default = {}; - example = literalExample '' + example = literalExpression '' { "memtest.bin" = "''${pkgs.memtest86plus}/memtest.bin"; } ''; description = '' @@ -413,7 +413,7 @@ in splashImage = mkOption { type = types.nullOr types.path; - example = literalExample "./my-background.png"; + example = literalExpression "./my-background.png"; description = '' Background image used for GRUB. Set to <literal>null</literal> to run GRUB in text mode. @@ -449,7 +449,7 @@ in theme = mkOption { type = types.nullOr types.path; - example = literalExample "pkgs.nixos-grub2-theme"; + example = literalExpression "pkgs.nixos-grub2-theme"; default = null; description = '' Grub theme to be used. @@ -475,7 +475,7 @@ in font = mkOption { type = types.nullOr types.path; default = "${realGrub}/share/grub/unicode.pf2"; - defaultText = ''"''${pkgs.grub2}/share/grub/unicode.pf2"''; + defaultText = literalExpression ''"''${pkgs.grub2}/share/grub/unicode.pf2"''; description = '' Path to a TrueType, OpenType, or pf2 font to be used by Grub. ''; @@ -483,7 +483,7 @@ in fontSize = mkOption { type = types.nullOr types.int; - example = literalExample 16; + example = 16; default = null; description = '' Font size for the grub menu. Ignored unless <literal>font</literal> diff --git a/nixpkgs/nixos/modules/system/boot/loader/grub/ipxe.nix b/nixpkgs/nixos/modules/system/boot/loader/grub/ipxe.nix index 249c2761934d..ef8595592f41 100644 --- a/nixpkgs/nixos/modules/system/boot/loader/grub/ipxe.nix +++ b/nixpkgs/nixos/modules/system/boot/loader/grub/ipxe.nix @@ -33,7 +33,7 @@ in booting from the GRUB boot menu. ''; default = { }; - example = literalExample '' + example = literalExpression '' { demo = ''' #!ipxe dhcp diff --git a/nixpkgs/nixos/modules/system/boot/loader/systemd-boot/systemd-boot-builder.py b/nixpkgs/nixos/modules/system/boot/loader/systemd-boot/systemd-boot-builder.py index 7134b4321630..6c26b4e0f87a 100644 --- a/nixpkgs/nixos/modules/system/boot/loader/systemd-boot/systemd-boot-builder.py +++ b/nixpkgs/nixos/modules/system/boot/loader/systemd-boot/systemd-boot-builder.py @@ -208,10 +208,15 @@ def main() -> None: if os.path.exists("@efiSysMountPoint@/loader/loader.conf"): os.unlink("@efiSysMountPoint@/loader/loader.conf") - if "@canTouchEfiVariables@" == "1": - subprocess.check_call(["@systemd@/bin/bootctl", "--path=@efiSysMountPoint@", "install"]) - else: - subprocess.check_call(["@systemd@/bin/bootctl", "--path=@efiSysMountPoint@", "--no-variables", "install"]) + flags = [] + + if "@canTouchEfiVariables@" != "1": + flags.append("--no-variables") + + if "@graceful@" == "1": + flags.append("--graceful") + + subprocess.check_call(["@systemd@/bin/bootctl", "--path=@efiSysMountPoint@"] + flags + ["install"]) else: # Update bootloader to latest if needed systemd_version = subprocess.check_output(["@systemd@/bin/bootctl", "--version"], universal_newlines=True).split()[1] diff --git a/nixpkgs/nixos/modules/system/boot/loader/systemd-boot/systemd-boot.nix b/nixpkgs/nixos/modules/system/boot/loader/systemd-boot/systemd-boot.nix index ff304f570d35..0f76d7d6b24a 100644 --- a/nixpkgs/nixos/modules/system/boot/loader/systemd-boot/systemd-boot.nix +++ b/nixpkgs/nixos/modules/system/boot/loader/systemd-boot/systemd-boot.nix @@ -24,7 +24,7 @@ let configurationLimit = if cfg.configurationLimit == null then 0 else cfg.configurationLimit; - inherit (cfg) consoleMode; + inherit (cfg) consoleMode graceful; inherit (efi) efiSysMountPoint canTouchEfiVariables; @@ -126,6 +126,22 @@ in { ''; }; }; + + graceful = mkOption { + default = false; + + type = types.bool; + + description = '' + Invoke <literal>bootctl install</literal> with the <literal>--graceful</literal> option, + which ignores errors when EFI variables cannot be written or when the EFI System Partition + cannot be found. Currently only applies to random seed operations. + + Only enable this option if <literal>systemd-boot</literal> otherwise fails to install, as the + scope or implication of the <literal>--graceful</literal> option may change in the future. + ''; + }; + }; config = mkIf cfg.enable { diff --git a/nixpkgs/nixos/modules/system/boot/luksroot.nix b/nixpkgs/nixos/modules/system/boot/luksroot.nix index f87d3b07a360..fb5269e43d08 100644 --- a/nixpkgs/nixos/modules/system/boot/luksroot.nix +++ b/nixpkgs/nixos/modules/system/boot/luksroot.nix @@ -663,13 +663,11 @@ in }; encryptedPass = mkOption { - default = ""; type = types.path; description = "Path to the GPG encrypted passphrase."; }; publicKey = mkOption { - default = ""; type = types.path; description = "Path to the Public Key."; }; diff --git a/nixpkgs/nixos/modules/system/boot/networkd.nix b/nixpkgs/nixos/modules/system/boot/networkd.nix index bf254be1341b..662dfe2db989 100644 --- a/nixpkgs/nixos/modules/system/boot/networkd.nix +++ b/nixpkgs/nixos/modules/system/boot/networkd.nix @@ -250,6 +250,16 @@ let (assertRange "ERSPANIndex" 1 1048575) ]; + sectionFooOverUDP = checkUnitConfig "FooOverUDP" [ + (assertOnlyFields [ + "Port" + "Encapsulation" + "Protocol" + ]) + (assertPort "Port") + (assertValueOneOf "Encapsulation" ["FooOverUDP" "GenericUDPEncapsulation"]) + ]; + sectionPeer = checkUnitConfig "Peer" [ (assertOnlyFields [ "Name" @@ -668,6 +678,9 @@ let "SendOption" "UserClass" "VendorClass" + "DUIDType" + "DUIDRawData" + "IAID" ]) (assertValueOneOf "UseAddress" boolValues) (assertValueOneOf "UseDNS" boolValues) @@ -677,6 +690,7 @@ let (assertValueOneOf "ForceDHCPv6PDOtherInformation" boolValues) (assertValueOneOf "WithoutRA" ["solicit" "information-request"]) (assertRange "SendOption" 1 65536) + (assertInt "IAID") ]; sectionDHCPv6PrefixDelegation = checkUnitConfig "DHCPv6PrefixDelegation" [ @@ -844,7 +858,6 @@ let options = { wireguardPeerConfig = mkOption { default = {}; - example = { }; type = types.addCheck (types.attrsOf unitOption) check.netdev.sectionWireGuardPeer; description = '' Each attribute in this set specifies an option in the @@ -859,7 +872,6 @@ let netdevOptions = commonNetworkOptions // { netdevConfig = mkOption { - default = {}; example = { Name = "mybridge"; Kind = "bridge"; }; type = types.addCheck (types.attrsOf unitOption) check.netdev.sectionNetdev; description = '' @@ -896,7 +908,6 @@ let vxlanConfig = mkOption { default = {}; - example = { Id = "4"; }; type = types.addCheck (types.attrsOf unitOption) check.netdev.sectionVXLAN; description = '' Each attribute in this set specifies an option in the @@ -918,6 +929,18 @@ let ''; }; + fooOverUDPConfig = mkOption { + default = { }; + example = { Port = 9001; }; + type = types.addCheck (types.attrsOf unitOption) check.netdev.sectionFooOverUDP; + description = '' + Each attribute in this set specifies an option in the + <literal>[FooOverUDP]</literal> section of the unit. See + <citerefentry><refentrytitle>systemd.netdev</refentrytitle> + <manvolnum>5</manvolnum></citerefentry> for details. + ''; + }; + peerConfig = mkOption { default = {}; example = { Name = "veth2"; }; @@ -959,7 +982,7 @@ let example = { PrivateKeyFile = "/etc/wireguard/secret.key"; ListenPort = 51820; - FwMark = 42; + FirewallMark = 42; }; type = types.addCheck (types.attrsOf unitOption) check.netdev.sectionWireGuard; description = '' @@ -1038,7 +1061,6 @@ let addressOptions = { options = { addressConfig = mkOption { - default = {}; example = { Address = "192.168.0.100/24"; }; type = types.addCheck (types.attrsOf unitOption) check.network.sectionAddress; description = '' @@ -1055,7 +1077,7 @@ let options = { routingPolicyRuleConfig = mkOption { default = { }; - example = { routingPolicyRuleConfig = { Table = 10; IncomingInterface = "eth1"; Family = "both"; } ;}; + example = { Table = 10; IncomingInterface = "eth1"; Family = "both"; }; type = types.addCheck (types.attrsOf unitOption) check.network.sectionRoutingPolicyRule; description = '' Each attribute in this set specifies an option in the @@ -1146,7 +1168,7 @@ let dhcpV6Config = mkOption { default = {}; - example = { UseDNS = true; UseRoutes = true; }; + example = { UseDNS = true; }; type = types.addCheck (types.attrsOf unitOption) check.network.sectionDHCPv6; description = '' Each attribute in this set specifies an option in the @@ -1213,7 +1235,7 @@ let ipv6Prefixes = mkOption { default = []; - example = { AddressAutoconfiguration = true; OnLink = true; }; + example = [ { AddressAutoconfiguration = true; OnLink = true; } ]; type = with types; listOf (submodule ipv6PrefixOptions); description = '' A list of ipv6Prefix sections to be added to the unit. See @@ -1449,6 +1471,10 @@ let [Tunnel] ${attrsToSection def.tunnelConfig} '' + + optionalString (def.fooOverUDPConfig != { }) '' + [FooOverUDP] + ${attrsToSection def.fooOverUDPConfig} + '' + optionalString (def.peerConfig != { }) '' [Peer] ${attrsToSection def.peerConfig} diff --git a/nixpkgs/nixos/modules/system/boot/plymouth.nix b/nixpkgs/nixos/modules/system/boot/plymouth.nix index 2a545e552513..4b8194d2f85c 100644 --- a/nixpkgs/nixos/modules/system/boot/plymouth.nix +++ b/nixpkgs/nixos/modules/system/boot/plymouth.nix @@ -62,6 +62,7 @@ in font = mkOption { default = "${pkgs.dejavu_fonts.minimal}/share/fonts/truetype/DejaVuSans.ttf"; + defaultText = literalExpression ''"''${pkgs.dejavu_fonts.minimal}/share/fonts/truetype/DejaVuSans.ttf"''; type = types.path; description = '' Font file made available for displaying text on the splash screen. @@ -88,7 +89,7 @@ in type = types.path; # Dimensions are 48x48 to match GDM logo default = "${nixos-icons}/share/icons/hicolor/48x48/apps/nix-snowflake-white.png"; - defaultText = ''pkgs.fetchurl { + defaultText = literalExpression ''pkgs.fetchurl { url = "https://nixos.org/logo/nixos-hires.png"; sha256 = "1ivzgd7iz0i06y36p8m5w48fd8pjqwxhdaavc0pxs7w1g7mcy5si"; }''; diff --git a/nixpkgs/nixos/modules/system/boot/stage-1.nix b/nixpkgs/nixos/modules/system/boot/stage-1.nix index 03133fa1bc43..adbed9d8d58e 100644 --- a/nixpkgs/nixos/modules/system/boot/stage-1.nix +++ b/nixpkgs/nixos/modules/system/boot/stage-1.nix @@ -137,6 +137,14 @@ let copy_bin_and_libs ${pkgs.e2fsprogs}/sbin/resize2fs ''} + # Copy multipath. + ${optionalString config.services.multipath.enable '' + copy_bin_and_libs ${config.services.multipath.package}/bin/multipath + copy_bin_and_libs ${config.services.multipath.package}/bin/multipathd + # Copy lib/multipath manually. + cp -rpv ${config.services.multipath.package}/lib/multipath $out/lib + ''} + # Copy secrets if needed. # # TODO: move out to a separate script; see #85000. @@ -199,6 +207,10 @@ let $out/bin/dmsetup --version 2>&1 | tee -a log | grep -q "version:" LVM_SYSTEM_DIR=$out $out/bin/lvm version 2>&1 | tee -a log | grep -q "LVM" $out/bin/mdadm --version + ${optionalString config.services.multipath.enable '' + ($out/bin/multipath || true) 2>&1 | grep -q 'need to be root' + ($out/bin/multipathd || true) 2>&1 | grep -q 'need to be root' + ''} ${config.boot.initrd.extraUtilsCommandsTest} fi @@ -338,7 +350,26 @@ let { object = pkgs.kmod-debian-aliases; symlink = "/etc/modprobe.d/debian.conf"; } - ]; + ] ++ lib.optionals config.services.multipath.enable [ + { object = pkgs.runCommand "multipath.conf" { + src = config.environment.etc."multipath.conf".text; + preferLocalBuild = true; + } '' + target=$out + printf "$src" > $out + substituteInPlace $out \ + --replace ${config.services.multipath.package}/lib ${extraUtils}/lib + ''; + symlink = "/etc/multipath.conf"; + } + ] ++ (lib.mapAttrsToList + (symlink: options: + { + inherit symlink; + object = options.source; + } + ) + config.boot.initrd.extraFiles); }; # Script to add secret files to the initrd at bootloader update time @@ -411,7 +442,7 @@ in boot.initrd.enable = mkOption { type = types.bool; default = !config.boot.isContainer; - defaultText = "!config.boot.isContainer"; + defaultText = literalExpression "!config.boot.isContainer"; description = '' Whether to enable the NixOS initial RAM disk (initrd). This may be needed to perform some initialisation tasks (like mounting @@ -419,6 +450,22 @@ in ''; }; + boot.initrd.extraFiles = mkOption { + default = { }; + type = types.attrsOf + (types.submodule { + options = { + source = mkOption { + type = types.package; + description = "The object to make available inside the initrd."; + }; + }; + }); + description = '' + Extra files to link and copy in to the initrd. + ''; + }; + boot.initrd.prepend = mkOption { default = [ ]; type = types.listOf types.str; @@ -527,7 +574,7 @@ in then "zstd" else "gzip" ); - defaultText = "zstd if the kernel supports it (5.9+), gzip if not."; + defaultText = literalDocBook "<literal>zstd</literal> if the kernel supports it (5.9+), <literal>gzip</literal> 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: @@ -559,7 +606,7 @@ in is the path it should be copied from (or null for the same path inside and out). ''; - example = literalExample + example = literalExpression '' { "/etc/dropbear/dropbear_rsa_host_key" = ./secret-dropbear-key; diff --git a/nixpkgs/nixos/modules/system/boot/systemd.nix b/nixpkgs/nixos/modules/system/boot/systemd.nix index f4413188187e..a2b9da2f72e5 100644 --- a/nixpkgs/nixos/modules/system/boot/systemd.nix +++ b/nixpkgs/nixos/modules/system/boot/systemd.nix @@ -426,7 +426,7 @@ in systemd.package = mkOption { default = pkgs.systemd; - defaultText = "pkgs.systemd"; + defaultText = literalExpression "pkgs.systemd"; type = types.package; description = "The systemd package."; }; @@ -446,7 +446,7 @@ in systemd.packages = mkOption { default = []; type = types.listOf types.package; - example = literalExample "[ pkgs.systemd-cryptsetup-generator ]"; + example = literalExpression "[ pkgs.systemd-cryptsetup-generator ]"; description = "Packages providing systemd units and hooks."; }; @@ -663,7 +663,7 @@ in services.journald.forwardToSyslog = mkOption { default = config.services.rsyslogd.enable || config.services.syslog-ng.enable; - defaultText = "services.rsyslogd.enable || services.syslog-ng.enable"; + defaultText = literalExpression "services.rsyslogd.enable || services.syslog-ng.enable"; type = types.bool; description = '' Whether to forward log messages to syslog. @@ -722,7 +722,7 @@ in services.logind.lidSwitchExternalPower = mkOption { default = config.services.logind.lidSwitch; - defaultText = "services.logind.lidSwitch"; + defaultText = literalExpression "services.logind.lidSwitch"; example = "ignore"; type = logindHandlerType; @@ -768,7 +768,7 @@ in systemd.tmpfiles.packages = mkOption { type = types.listOf types.package; default = []; - example = literalExample "[ pkgs.lvm2 ]"; + example = literalExpression "[ pkgs.lvm2 ]"; apply = map getLib; description = '' List of packages containing <command>systemd-tmpfiles</command> rules. diff --git a/nixpkgs/nixos/modules/system/etc/etc.nix b/nixpkgs/nixos/modules/system/etc/etc.nix index 84468ea31f74..8f14f04a1f64 100644 --- a/nixpkgs/nixos/modules/system/etc/etc.nix +++ b/nixpkgs/nixos/modules/system/etc/etc.nix @@ -6,9 +6,7 @@ with lib; let - # if the source is a local file, it should be imported to the store - localToStore = mapAttrs (name: value: if name == "source" then "${value}" else value); - etc' = map localToStore (filter (f: f.enable) (attrValues config.environment.etc)); + etc' = filter (f: f.enable) (attrValues config.environment.etc); etc = pkgs.runCommandLocal "etc" { # This is needed for the systemd module @@ -55,7 +53,8 @@ let mkdir -p "$out/etc" ${concatMapStringsSep "\n" (etcEntry: escapeShellArgs [ "makeEtcEntry" - etcEntry.source + # Force local source paths to be added to the store + "${etcEntry.source}" etcEntry.target etcEntry.mode etcEntry.user @@ -73,7 +72,7 @@ in environment.etc = mkOption { default = {}; - example = literalExample '' + example = literalExpression '' { example-configuration-file = { source = "/nix/store/.../etc/dir/file.conf.example"; mode = "0440"; |