diff options
Diffstat (limited to 'nixos/modules/system')
22 files changed, 410 insertions, 97 deletions
diff --git a/nixos/modules/system/activation/activation-script.nix b/nixos/modules/system/activation/activation-script.nix index c2ac731d433d..c563614caaaf 100644 --- a/nixos/modules/system/activation/activation-script.nix +++ b/nixos/modules/system/activation/activation-script.nix @@ -61,7 +61,7 @@ in apply = set: { script = '' - #! ${pkgs.stdenv.shell} + #! ${pkgs.runtimeShell} systemConfig=@out@ @@ -117,14 +117,7 @@ in config = { - system.activationScripts.stdio = - '' - # 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 - ''; + system.activationScripts.stdio = ""; # obsolete system.activationScripts.var = '' diff --git a/nixos/modules/system/activation/switch-to-configuration.pl b/nixos/modules/system/activation/switch-to-configuration.pl index 29cc60b00324..87a4ab2a586d 100644 --- a/nixos/modules/system/activation/switch-to-configuration.pl +++ b/nixos/modules/system/activation/switch-to-configuration.pl @@ -16,6 +16,10 @@ my $reloadListFile = "/run/systemd/reload-list"; my $action = shift @ARGV; +if ("@localeArchive@" ne "") { + $ENV{LOCALE_ARCHIVE} = "@localeArchive@"; +} + if (!defined $action || ($action ne "switch" && $action ne "boot" && $action ne "test" && $action ne "dry-activate")) { print STDERR <<EOF; Usage: $0 [switch|boot|test] @@ -65,7 +69,8 @@ $SIG{PIPE} = "IGNORE"; sub getActiveUnits { # FIXME: use D-Bus or whatever to query this, since parsing the # output of list-units is likely to break. - my $lines = `LANG= systemctl list-units --full --no-legend`; + # Use current version of systemctl binary before daemon is reexeced. + my $lines = `LANG= /run/current-system/sw/bin/systemctl list-units --full --no-legend`; my $res = {}; foreach my $line (split '\n', $lines) { chomp $line; @@ -262,7 +267,8 @@ while (my ($unit, $state) = each %{$activePrev}) { sub pathToUnitName { my ($path) = @_; - open my $cmd, "-|", "@systemd@/bin/systemd-escape", "--suffix=mount", "-p", $path + # Use current version of systemctl binary before daemon is reexeced. + open my $cmd, "-|", "/run/current-system/sw/bin/systemd-escape", "--suffix=mount", "-p", $path or die "Unable to escape $path!\n"; my $escaped = join "", <$cmd>; chomp $escaped; @@ -364,7 +370,8 @@ syslog(LOG_NOTICE, "switching to system configuration $out"); if (scalar (keys %unitsToStop) > 0) { print STDERR "stopping the following units: ", join(", ", @unitsToStopFiltered), "\n" if scalar @unitsToStopFiltered; - system("systemctl", "stop", "--", sort(keys %unitsToStop)); # FIXME: ignore errors? + # Use current version of systemctl binary before daemon is reexeced. + system("/run/current-system/sw/bin/systemctl", "stop", "--", sort(keys %unitsToStop)); # FIXME: ignore errors? } print STDERR "NOT restarting the following changed units: ", join(", ", sort(keys %unitsToSkip)), "\n" diff --git a/nixos/modules/system/activation/top-level.nix b/nixos/modules/system/activation/top-level.nix index 67cb2264e3f3..091a2e412eed 100644 --- a/nixos/modules/system/activation/top-level.nix +++ b/nixos/modules/system/activation/top-level.nix @@ -26,11 +26,12 @@ let cloner false config.nesting.children ++ cloner true config.nesting.clone; - systemBuilder = let kernelPath = "${config.boot.kernelPackages.kernel}/" + "${config.system.boot.loader.kernelFile}"; + initrdPath = "${config.system.build.initialRamdisk}/" + + "${config.system.boot.loader.initrdFile}"; in '' mkdir $out @@ -51,7 +52,7 @@ let echo -n "$kernelParams" > $out/kernel-params - ln -s ${config.system.build.initialRamdisk}/initrd $out/initrd + ln -s ${initrdPath} $out/initrd ln -s ${config.system.build.initialRamdiskSecretAppender}/bin/append-initrd-secrets $out @@ -83,6 +84,7 @@ let done mkdir $out/bin + 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 @@ -106,7 +108,7 @@ let if [] == failed then pkgs.stdenvNoCC.mkDerivation { name = let hn = config.networking.hostName; nn = if (hn != "") then hn else "unnamed"; - in "nixos-system-${nn}-${config.system.nixosLabel}"; + in "nixos-system-${nn}-${config.system.nixos.label}"; preferLocalBuild = true; allowSubstitutes = false; buildCommand = systemBuilder; @@ -120,7 +122,7 @@ let config.system.build.installBootLoader or "echo 'Warning: do not know how to make this configuration bootable; please enable a boot loader.' 1>&2; true"; activationScript = config.system.activationScripts.script; - nixosLabel = config.system.nixosLabel; + nixosLabel = config.system.nixos.label; configurationName = config.boot.loader.grub.configurationName; @@ -179,6 +181,15 @@ in ''; }; + system.boot.loader.initrdFile = mkOption { + internal = true; + default = "initrd"; + type = types.str; + description = '' + Name of the initrd file to be passed to the bootloader. + ''; + }; + system.copySystemConfiguration = mkOption { type = types.bool; default = false; diff --git a/nixos/modules/system/boot/binfmt.nix b/nixos/modules/system/boot/binfmt.nix new file mode 100644 index 000000000000..15e84dc021e2 --- /dev/null +++ b/nixos/modules/system/boot/binfmt.nix @@ -0,0 +1,139 @@ +{ config, lib, ... }: +let + inherit (lib) mkOption types optionalString; + + cfg = config.boot.binfmtMiscRegistrations; + + makeBinfmtLine = name: { recognitionType, offset, magicOrExtension + , mask, preserveArgvZero, openBinary + , matchCredentials, fixBinary, ... + }: let + type = if recognitionType == "magic" then "M" else "E"; + offset' = toString offset; + mask' = toString mask; + interpreter = "/run/binfmt/${name}"; + flags = if !(matchCredentials -> openBinary) + then throw "boot.binfmtMiscRegistrations.${name}: you can't specify openBinary = false when matchCredentials = true." + else optionalString preserveArgvZero "P" + + optionalString (openBinary && !matchCredentials) "O" + + optionalString matchCredentials "C" + + optionalString fixBinary "F"; + in ":${name}:${type}:${offset'}:${magicOrExtension}:${mask'}:${interpreter}:${flags}"; + + binfmtFile = builtins.toFile "binfmt_nixos.conf" + (lib.concatStringsSep "\n" (lib.mapAttrsToList makeBinfmtLine cfg)); + + activationSnippet = name: { interpreter, ... }: + "ln -sf ${interpreter} /run/binfmt/${name}"; + activationScript = '' + mkdir -p -m 0755 /run/binfmt + ${lib.concatStringsSep "\n" (lib.mapAttrsToList activationSnippet cfg)} + ''; +in { + options = { + boot.binfmtMiscRegistrations = mkOption { + default = {}; + + description = '' + Extra binary formats to register with the kernel. + See https://www.kernel.org/doc/html/latest/admin-guide/binfmt-misc.html for more details. + ''; + + type = types.attrsOf (types.submodule ({ config, ... }: { + options = { + recognitionType = mkOption { + default = "magic"; + description = "Whether to recognize executables by magic number or extension."; + type = types.enum [ "magic" "extension" ]; + }; + + offset = mkOption { + default = null; + description = "The byte offset of the magic number used for recognition."; + type = types.nullOr types.int; + }; + + magicOrExtension = mkOption { + description = "The magic number or extension to match on."; + type = types.str; + }; + + mask = mkOption { + default = null; + description = + "A mask to be ANDed with the byte sequence of the file before matching"; + type = types.nullOr types.str; + }; + + interpreter = mkOption { + description = '' + The interpreter to invoke to run the program. + + Note that the actual registration will point to + /run/binfmt/''${name}, so the kernel interpreter length + limit doesn't apply. + ''; + type = types.path; + }; + + preserveArgvZero = mkOption { + default = false; + description = '' + Whether to pass the original argv[0] to the interpreter. + + See the description of the 'P' flag in the kernel docs + for more details; + ''; + type = types.bool; + }; + + openBinary = mkOption { + default = config.matchCredentials; + description = '' + Whether to pass the binary to the interpreter as an open + file descriptor, instead of a path. + ''; + type = types.bool; + }; + + matchCredentials = mkOption { + default = false; + description = '' + Whether to launch with the credentials and security + token of the binary, not the interpreter (e.g. setuid + bit). + + See the description of the 'C' flag in the kernel docs + for more details. + + Implies/requires openBinary = true. + ''; + type = types.bool; + }; + + fixBinary = mkOption { + default = false; + description = '' + Whether to open the interpreter file as soon as the + registration is loaded, rather than waiting for a + relevant file to be invoked. + + See the description of the 'F' flag in the kernel docs + for more details. + ''; + type = types.bool; + }; + }; + })); + }; + }; + + config = lib.mkIf (cfg != {}) { + environment.etc."binfmt.d/nixos.conf".source = binfmtFile; + system.activationScripts.binfmt = activationScript; + systemd.additionalUpstreamSystemUnits = + [ "proc-sys-fs-binfmt_misc.automount" + "proc-sys-fs-binfmt_misc.mount" + ]; + }; +} diff --git a/nixos/modules/system/boot/grow-partition.nix b/nixos/modules/system/boot/grow-partition.nix new file mode 100644 index 000000000000..1e6f9e442b67 --- /dev/null +++ b/nixos/modules/system/boot/grow-partition.nix @@ -0,0 +1,50 @@ +# This module automatically grows the root partition. +# This allows an instance to be created with a bigger root filesystem +# than provided by the machine image. + +{ config, lib, pkgs, ... }: + +with lib; + +{ + + options = { + boot.growPartition = mkEnableOption "grow the root partition on boot"; + }; + + config = mkIf config.boot.growPartition { + + 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 + + substitute "${pkgs.cloud-utils}/bin/.growpart-wrapped" "$out/bin/growpart" \ + --replace "${pkgs.bash}/bin/sh" "/bin/sh" \ + --replace "awk" "gawk" \ + --replace "sed" "gnused" + + ln -s sed $out/bin/gnused + ''; + + boot.initrd.postDeviceCommands = '' + rootDevice="${config.fileSystems."/".device}" + if [ -e "$rootDevice" ]; then + rootDevice="$(readlink -f "$rootDevice")" + parentDevice="$rootDevice" + while [ "''${parentDevice%[0-9]}" != "''${parentDevice}" ]; do + parentDevice="''${parentDevice%[0-9]}"; + done + partNum="''${rootDevice#''${parentDevice}}" + if [ "''${parentDevice%[0-9]p}" != "''${parentDevice}" ] && [ -b "''${parentDevice%p}" ]; then + parentDevice="''${parentDevice%p}" + fi + TMPDIR=/run sh $(type -P growpart) "$parentDevice" "$partNum" + udevadm settle + fi + ''; + + }; + +} diff --git a/nixos/modules/system/boot/initrd-network.nix b/nixos/modules/system/boot/initrd-network.nix index 6e226c190609..33862b0965cc 100644 --- a/nixos/modules/system/boot/initrd-network.nix +++ b/nixos/modules/system/boot/initrd-network.nix @@ -23,6 +23,8 @@ let fi ''; + udhcpcArgs = toString cfg.udhcpc.extraArgs; + in { @@ -40,6 +42,20 @@ in kernel documentation</link>. Otherwise, if <option>networking.useDHCP</option> is enabled, an IP address is acquired using DHCP. + + You should add the module(s) required for your network card to + boot.initrd.availableKernelModules. lspci -v -s <ethernet controller> + will tell you which. + ''; + }; + + boot.initrd.network.udhcpc.extraArgs = mkOption { + default = []; + type = types.listOf types.str; + description = '' + Additional command-line arguments passed verbatim to udhcpc if + <option>boot.initrd.network.enable</option> and <option>networking.useDHCP</option> + are enabled. ''; }; @@ -87,7 +103,7 @@ in # Acquire a DHCP lease. echo "acquiring IP address via DHCP..." - udhcpc --quit --now --script ${udhcpcScript} && hasNetwork=1 + udhcpc --quit --now --script ${udhcpcScript} ${udhcpcArgs} && hasNetwork=1 fi '' diff --git a/nixos/modules/system/boot/initrd-ssh.nix b/nixos/modules/system/boot/initrd-ssh.nix index d78775c27582..8b3dc2d90eb3 100644 --- a/nixos/modules/system/boot/initrd-ssh.nix +++ b/nixos/modules/system/boot/initrd-ssh.nix @@ -89,9 +89,6 @@ in config = mkIf (config.boot.initrd.network.enable && cfg.enable) { assertions = [ - { assertion = cfg.hostRSAKey != null || cfg.hostDSSKey != null || cfg.hostECDSAKey != null; - message = "You should specify at least one host key for initrd SSH"; - } { assertion = cfg.authorizedKeys != []; message = "You should specify at least one authorized key for initrd SSH"; } @@ -121,7 +118,7 @@ in echo ${escapeShellArg key} >> /root/.ssh/authorized_keys '') cfg.authorizedKeys)} - dropbear -s -j -k -E -m -p ${toString cfg.port} + dropbear -s -j -k -E -p ${toString cfg.port} ${optionalString (cfg.hostRSAKey == null && cfg.hostDSSKey == null && cfg.hostECDSAKey == null) "-R"} ''; boot.initrd.secrets = diff --git a/nixos/modules/system/boot/kernel.nix b/nixos/modules/system/boot/kernel.nix index 4db9631743e3..8ea05ed14687 100644 --- a/nixos/modules/system/boot/kernel.nix +++ b/nixos/modules/system/boot/kernel.nix @@ -5,7 +5,7 @@ with lib; let inherit (config.boot) kernelPatches; - + inherit (config.boot.kernel) features; inherit (config.boot.kernelPackages) kernel; kernelModulesConf = pkgs.writeText "nixos.conf" @@ -21,11 +21,25 @@ in options = { + boot.kernel.features = mkOption { + default = {}; + example = literalExample "{ debug = true; }"; + internal = true; + description = '' + This option allows to enable or disable certain kernel features. + It's not API, because it's about kernel feature sets, that + make sense for specific use cases. Mostly along with programs, + which would have separate nixos options. + `grep features pkgs/os-specific/linux/kernel/common-config.nix` + ''; + }; + boot.kernelPackages = mkOption { default = pkgs.linuxPackages; apply = kernelPackages: kernelPackages.extend (self: super: { kernel = super.kernel.override { kernelPatches = super.kernel.kernelPatches ++ kernelPatches; + features = lib.recursiveUpdate super.kernel.features features; }; }); # We don't want to evaluate all of linuxPackages for the manual @@ -63,8 +77,8 @@ in type = types.int; default = 4; description = '' - The kernel console log level. Log messages with a priority - numerically less than this will not appear on the console. + The kernel console <literal>loglevel</literal>. All Kernel Messages with a log level smaller + than this setting will be printed to the console. ''; }; @@ -170,7 +184,7 @@ in [ "loglevel=${toString config.boot.consoleLogLevel}" ] ++ optionals config.boot.vesa [ "vga=0x317" ]; - boot.kernel.sysctl."kernel.printk" = config.boot.consoleLogLevel; + boot.kernel.sysctl."kernel.printk" = mkDefault config.boot.consoleLogLevel; boot.kernelModules = [ "loop" "atkbd" ]; @@ -197,7 +211,7 @@ in "mmc_block" # Support USB keyboards, in case the boot fails and we only have - # a USB keyboard. + # a USB keyboard, or for LUKS passphrase prompt. "uhci_hcd" "ehci_hcd" "ehci_pci" @@ -207,11 +221,13 @@ in "xhci_pci" "usbhid" "hid_generic" "hid_lenovo" "hid_apple" "hid_roccat" + "hid_logitech_hidpp" "hid_logitech_dj" - # Misc. keyboard stuff. + ] ++ optionals (pkgs.stdenv.isi686 || pkgs.stdenv.isx86_64) [ + # Misc. x86 keyboard stuff. "pcips2" "atkbd" "i8042" - # Needed by the stage 2 init script. + # x86 RTC needed by the stage 2 init script. "rtc_cmos" ]; diff --git a/nixos/modules/system/boot/kexec.nix b/nixos/modules/system/boot/kexec.nix index b7821f9509f1..3fc1af28f628 100644 --- a/nixos/modules/system/boot/kexec.nix +++ b/nixos/modules/system/boot/kexec.nix @@ -1,21 +1,22 @@ -{ config, pkgs, ... }: +{ config, pkgs, lib, ... }: { - environment.systemPackages = [ pkgs.kexectools ]; + config = lib.mkIf (pkgs.kexectools.meta.available) { + environment.systemPackages = [ pkgs.kexectools ]; - systemd.services."prepare-kexec" = - { description = "Preparation for kexec"; - wantedBy = [ "kexec.target" ]; - before = [ "systemd-kexec.service" ]; - unitConfig.DefaultDependencies = false; - serviceConfig.Type = "oneshot"; - path = [ pkgs.kexectools ]; - script = - '' - p=$(readlink -f /nix/var/nix/profiles/system) - if ! [ -d $p ]; then exit 1; fi - exec kexec --load $p/kernel --initrd=$p/initrd --append="$(cat $p/kernel-params) init=$p/init" - ''; - }; - -} \ No newline at end of file + systemd.services."prepare-kexec" = + { description = "Preparation for kexec"; + wantedBy = [ "kexec.target" ]; + before = [ "systemd-kexec.service" ]; + unitConfig.DefaultDependencies = false; + serviceConfig.Type = "oneshot"; + path = [ pkgs.kexectools ]; + script = + '' + p=$(readlink -f /nix/var/nix/profiles/system) + if ! [ -d $p ]; then exit 1; fi + exec kexec --load $p/kernel --initrd=$p/initrd --append="$(cat $p/kernel-params) init=$p/init" + ''; + }; + }; +} diff --git a/nixos/modules/system/boot/loader/grub/grub.nix b/nixos/modules/system/boot/loader/grub/grub.nix index 9056121fa7d1..e2cff1c1bd94 100644 --- a/nixos/modules/system/boot/loader/grub/grub.nix +++ b/nixos/modules/system/boot/loader/grub/grub.nix @@ -40,7 +40,7 @@ let { splashImage = f cfg.splashImage; grub = f grub; grubTarget = f (grub.grubTarget or ""); - shell = "${pkgs.stdenv.shell}"; + shell = "${pkgs.runtimeShell}"; fullName = (builtins.parseDrvName realGrub.name).name; fullVersion = (builtins.parseDrvName realGrub.name).version; grubEfi = f grubEfi; @@ -110,7 +110,7 @@ in device = mkOption { default = ""; - example = "/dev/hda"; + example = "/dev/disk/by-id/wwn-0x500001234567890a"; type = types.str; description = '' The device on which the GRUB boot loader will be installed. @@ -123,7 +123,7 @@ in devices = mkOption { default = []; - example = [ "/dev/hda" ]; + example = [ "/dev/disk/by-id/wwn-0x500001234567890a" ]; type = types.listOf types.str; description = '' The devices on which the boot loader, GRUB, will be @@ -135,8 +135,8 @@ in mirroredBoots = mkOption { default = [ ]; example = [ - { path = "/boot1"; devices = [ "/dev/sda" ]; } - { path = "/boot2"; devices = [ "/dev/sdb" ]; } + { path = "/boot1"; devices = [ "/dev/disk/by-id/wwn-0x500001234567890a" ]; } + { path = "/boot2"; devices = [ "/dev/disk/by-id/wwn-0x500009876543210a" ]; } ]; description = '' Mirror the boot configuration to multiple partitions and install grub @@ -178,7 +178,7 @@ in devices = mkOption { default = [ ]; - example = [ "/dev/sda" "/dev/sdb" ]; + example = [ "/dev/disk/by-id/wwn-0x500001234567890a" "/dev/disk/by-id/wwn-0x500009876543210a" ]; type = types.listOf types.str; description = '' The path to the devices which will have the GRUB MBR written. @@ -536,9 +536,9 @@ in btrfsprogs = pkgs.btrfs-progs; }; in pkgs.writeScript "install-grub.sh" ('' - #!${pkgs.stdenv.shell} + #!${pkgs.runtimeShell} set -e - export PERL5LIB=${makePerlPath (with pkgs.perlPackages; [ FileSlurp XMLLibXML XMLSAX ListCompare ])} + export PERL5LIB=${makePerlPath (with pkgs.perlPackages; [ FileSlurp XMLLibXML XMLSAX XMLSAXBase ListCompare ])} ${optionalString cfg.enableCryptodisk "export GRUB_ENABLE_CRYPTODISK=y"} '' + flip concatMapStrings cfg.mirroredBoots (args: '' ${pkgs.perl}/bin/perl ${install-grub-pl} ${grubConfig args} $@ diff --git a/nixos/modules/system/boot/loader/grub/install-grub.pl b/nixos/modules/system/boot/loader/grub/install-grub.pl index cc03e54ead63..8bd203106f55 100644 --- a/nixos/modules/system/boot/loader/grub/install-grub.pl +++ b/nixos/modules/system/boot/loader/grub/install-grub.pl @@ -182,7 +182,7 @@ sub GrubFs { # Based on the type pull in the identifier from the system my ($status, @devInfo) = runCommand("@utillinux@/bin/blkid -o export @{[$fs->device]}"); if ($status != 0) { - die "Failed to get blkid info for @{[$fs->mount]} on @{[$fs->device]}"; + die "Failed to get blkid info (returned $status) for @{[$fs->mount]} on @{[$fs->device]}"; } my @matches = join("", @devInfo) =~ m/@{[uc $fsIdentifier]}=([^\n]*)/; if ($#matches != 0) { diff --git a/nixos/modules/system/boot/luksroot.nix b/nixos/modules/system/boot/luksroot.nix index 06f004fb06ec..54dfb53fd30f 100644 --- a/nixos/modules/system/boot/luksroot.nix +++ b/nixos/modules/system/boot/luksroot.nix @@ -5,7 +5,7 @@ with lib; let luks = config.boot.initrd.luks; - openCommand = name': { name, device, header, keyFile, keyFileSize, allowDiscards, yubikey, ... }: assert name' == name; '' + openCommand = name': { name, device, header, keyFile, keyFileSize, allowDiscards, yubikey, fallbackToPassword, ... }: assert name' == name; '' # Wait for a target (e.g. device, keyFile, header, ...) to appear. wait_target() { @@ -43,8 +43,17 @@ let open_normally() { echo luksOpen ${device} ${name} ${optionalString allowDiscards "--allow-discards"} \ ${optionalString (header != null) "--header=${header}"} \ - ${optionalString (keyFile != null) "--key-file=${keyFile} ${optionalString (keyFileSize != null) "--keyfile-size=${toString keyFileSize}"}"} \ > /.luksopen_args + ${optionalString (keyFile != null) '' + ${optionalString fallbackToPassword "if [ -e ${keyFile} ]; then"} + echo " --key-file=${keyFile} ${optionalString (keyFileSize != null) "--keyfile-size=${toString keyFileSize}"}" \ + >> /.luksopen_args + ${optionalString fallbackToPassword '' + else + echo "keyfile ${keyFile} not found -- fallback to interactive unlocking" + fi + ''} + ''} cryptsetup-askpass rm /.luksopen_args } @@ -227,6 +236,7 @@ in default = [ "aes" "aes_generic" "blowfish" "twofish" "serpent" "cbc" "xts" "lrw" "sha1" "sha256" "sha512" + (if pkgs.stdenv.system == "x86_64-linux" then "aes_x86_64" else "aes_i586") ]; description = '' @@ -323,6 +333,16 @@ in ''; }; + fallbackToPassword = mkOption { + default = false; + type = types.bool; + description = '' + Whether to fallback to interactive passphrase prompt if the keyfile + cannot be found. This will prevent unattended boot should the keyfile + go missing. + ''; + }; + yubikey = mkOption { default = null; description = '' @@ -434,7 +454,12 @@ in ["firewire_ohci" "firewire_core" "firewire_sbp2"]; # Some modules that may be needed for mounting anything ciphered - boot.initrd.availableKernelModules = [ "dm_mod" "dm_crypt" "cryptd" ] ++ luks.cryptoModules; + # Also load input_leds to get caps lock light working (#12456) + boot.initrd.availableKernelModules = [ "dm_mod" "dm_crypt" "cryptd" "input_leds" ] + ++ luks.cryptoModules + # workaround until https://marc.info/?l=linux-crypto-vger&m=148783562211457&w=4 is merged + # remove once 'modprobe --show-depends xts' shows ecb as a dependency + ++ (if builtins.elem "xts" luks.cryptoModules then ["ecb"] else []); # copy the cryptsetup binary and it's dependencies boot.initrd.extraUtilsCommands = '' diff --git a/nixos/modules/system/boot/modprobe.nix b/nixos/modules/system/boot/modprobe.nix index b915a98d5375..dee0ab470c99 100644 --- a/nixos/modules/system/boot/modprobe.nix +++ b/nixos/modules/system/boot/modprobe.nix @@ -54,7 +54,7 @@ with lib; environment.systemPackages = [ pkgs.kmod ]; - system.activationScripts.modprobe = + system.activationScripts.modprobe = stringAfter ["specialfs"] '' # Allow the kernel to find our wrapped modprobe (which searches # in the right location in the Nix store for kernel modules). diff --git a/nixos/modules/system/boot/networkd.nix b/nixos/modules/system/boot/networkd.nix index 9d2cea3ad165..eea10613ea58 100644 --- a/nixos/modules/system/boot/networkd.nix +++ b/nixos/modules/system/boot/networkd.nix @@ -94,7 +94,7 @@ let checkNetwork = checkUnitConfig "Network" [ (assertOnlyFields [ "Description" "DHCP" "DHCPServer" "IPForward" "IPMasquerade" "IPv4LL" "IPv4LLRoute" - "LLMNR" "MulticastDNS" "Domains" "Bridge" "Bond" + "LLMNR" "MulticastDNS" "Domains" "Bridge" "Bond" "IPv6PrivacyExtensions" ]) (assertValueOneOf "DHCP" ["both" "none" "v4" "v6"]) (assertValueOneOf "DHCPServer" boolValues) @@ -104,6 +104,7 @@ let (assertValueOneOf "IPv4LLRoute" boolValues) (assertValueOneOf "LLMNR" boolValues) (assertValueOneOf "MulticastDNS" boolValues) + (assertValueOneOf "IPv6PrivacyExtensions" ["yes" "no" "prefer-public" "kernel"]) ]; checkAddress = checkUnitConfig "Address" [ @@ -700,7 +701,6 @@ in systemd.additionalUpstreamSystemUnits = [ "systemd-networkd.service" "systemd-networkd-wait-online.service" - "org.freedesktop.network1.busname" ]; systemd.network.units = mapAttrs' (n: v: nameValuePair "${n}.link" (linkToUnit n v)) cfg.links diff --git a/nixos/modules/system/boot/plymouth.nix b/nixos/modules/system/boot/plymouth.nix index 4b0c498424b5..f8fb8a64cb9b 100644 --- a/nixos/modules/system/boot/plymouth.nix +++ b/nixos/modules/system/boot/plymouth.nix @@ -8,9 +8,14 @@ let cfg = config.boot.plymouth; + breezePlymouth = pkgs.breeze-plymouth.override { + nixosBranding = true; + nixosVersion = config.system.nixos.release; + }; + themesEnv = pkgs.buildEnv { name = "plymouth-themes"; - paths = [ plymouth ] ++ cfg.themePackages; + paths = [ plymouth breezePlymouth ] ++ cfg.themePackages; }; configFile = pkgs.writeText "plymouthd.conf" '' @@ -38,7 +43,7 @@ in }; theme = mkOption { - default = "fade-in"; + default = "breeze"; type = types.str; description = '' Splash screen theme. diff --git a/nixos/modules/system/boot/resolved.nix b/nixos/modules/system/boot/resolved.nix index 2147d43c4f19..4d9de020c84e 100644 --- a/nixos/modules/system/boot/resolved.nix +++ b/nixos/modules/system/boot/resolved.nix @@ -126,7 +126,7 @@ in config = mkIf cfg.enable { systemd.additionalUpstreamSystemUnits = [ - "systemd-resolved.service" "org.freedesktop.resolve1.busname" + "systemd-resolved.service" ]; systemd.services.systemd-resolved = { diff --git a/nixos/modules/system/boot/stage-1-init.sh b/nixos/modules/system/boot/stage-1-init.sh index b442386914ad..964ec68cfe2f 100644 --- a/nixos/modules/system/boot/stage-1-init.sh +++ b/nixos/modules/system/boot/stage-1-init.sh @@ -167,6 +167,7 @@ done # Load the required kernel modules. mkdir -p /lib 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)..." diff --git a/nixos/modules/system/boot/stage-1.nix b/nixos/modules/system/boot/stage-1.nix index d6e3e3a87d01..55bb6d3449c5 100644 --- a/nixos/modules/system/boot/stage-1.nix +++ b/nixos/modules/system/boot/stage-1.nix @@ -13,12 +13,14 @@ let kernelPackages = config.boot.kernelPackages; modulesTree = config.system.modulesTree; + firmware = config.hardware.firmware; # Determine the set of modules that we need to mount the root FS. modulesClosure = pkgs.makeModulesClosure { rootModules = config.boot.initrd.availableKernelModules ++ config.boot.initrd.kernelModules; kernel = modulesTree; + firmware = firmware; allowMissing = true; }; @@ -28,6 +30,50 @@ let # mounting `/`, like `/` on a loopback). fileSystems = filter utils.fsNeededForBoot config.system.build.fileSystems; + # A utility for enumerating the shared-library dependencies of a program + findLibs = pkgs.writeShellScriptBin "find-libs" '' + set -euo pipefail + + declare -A seen + declare -a left + + patchelf="${pkgs.buildPackages.patchelf}/bin/patchelf" + + function add_needed { + rpath="$($patchelf --print-rpath $1)" + dir="$(dirname $1)" + for lib in $($patchelf --print-needed $1); do + left+=("$lib" "$rpath" "$dir") + done + } + + add_needed $1 + + while [ ''${#left[@]} -ne 0 ]; do + next=''${left[0]} + rpath=''${left[1]} + ORIGIN=''${left[2]} + left=("''${left[@]:3}") + if [ -z ''${seen[$next]+x} ]; then + seen[$next]=1 + IFS=: read -ra paths <<< $rpath + res= + for path in "''${paths[@]}"; do + path=$(eval "echo $path") + if [ -f "$path/$next" ]; then + res="$path/$next" + echo "$res" + add_needed "$res" + break + fi + done + if [ -z "$res" ]; then + echo "Couldn't satisfy dependency $next" >&2 + exit 1 + fi + fi + done + ''; # Some additional utilities needed in stage 1, like mount, lvm, fsck # etc. We don't want to bring in all of those packages, so we just @@ -35,7 +81,7 @@ let # we just copy what we need from Glibc and use patchelf to make it # work. extraUtils = pkgs.runCommandCC "extra-utils" - { buildInputs = [pkgs.nukeReferences]; + { nativeBuildInputs = [pkgs.buildPackages.nukeReferences]; allowedReferences = [ "out" ]; # prevent accidents like glibc being included in the initrd } '' @@ -101,9 +147,7 @@ let # Copy all of the needed libraries find $out/bin $out/lib -type f | while read BIN; do echo "Copying libs for executable $BIN" - LDD="$(ldd $BIN)" || continue - LIBS="$(echo "$LDD" | awk '{print $3}' | sed '/^$/d')" - for LIB in $LIBS; do + for LIB in $(${findLibs}/bin/find-libs $BIN); do TGT="$out/lib/$(basename $LIB)" if [ ! -f "$TGT" ]; then SRC="$(readlink -e $LIB)" @@ -130,6 +174,7 @@ let fi done + if [ -z "${toString pkgs.stdenv.isCross}" ]; then # Make sure that the patchelf'ed binaries still work. echo "testing patched programs..." $out/bin/ash -c 'echo hello world' | grep "hello world" @@ -142,6 +187,7 @@ let $out/bin/mdadm --version ${config.boot.initrd.extraUtilsCommandsTest} + fi ''; # */ @@ -243,7 +289,7 @@ let { src = "${pkgs.kmod-blacklist-ubuntu}/modprobe.conf"; } '' target=$out - ${pkgs.perl}/bin/perl -0pe 's/## file: iwlwifi.conf(.+?)##/##/s;' $src > $out + ${pkgs.buildPackages.perl}/bin/perl -0pe 's/## file: iwlwifi.conf(.+?)##/##/s;' $src > $out ''; symlink = "/etc/modprobe.d/ubuntu.conf"; } diff --git a/nixos/modules/system/boot/stage-2-init.sh b/nixos/modules/system/boot/stage-2-init.sh index 46aed44bf10f..b83012dfda7e 100644 --- a/nixos/modules/system/boot/stage-2-init.sh +++ b/nixos/modules/system/boot/stage-2-init.sh @@ -43,7 +43,7 @@ if [ ! -e /proc/1 ]; then local options="$3" local fsType="$4" - mkdir -m 0755 -p "$mountPoint" + install -m 0755 -d "$mountPoint" mount -n -t "$fsType" -o "$options" "$device" "$mountPoint" } source @earlyMountScript@ @@ -71,7 +71,7 @@ fi # Provide a /etc/mtab. -mkdir -m 0755 -p /etc +install -m 0755 -d /etc test -e /etc/fstab || touch /etc/fstab # to shut up mount rm -f /etc/mtab* # not that we care about stale locks ln -s /proc/mounts /etc/mtab @@ -79,10 +79,9 @@ ln -s /proc/mounts /etc/mtab # More special file systems, initialise required directories. [ -e /proc/bus/usb ] && mount -t usbfs usbfs /proc/bus/usb # UML doesn't have USB by default -mkdir -m 01777 -p /tmp -mkdir -m 0755 -p /var/{log,lib,db} /nix/var /etc/nixos/ \ +install -m 01777 -d /tmp +install -m 0755 -d /var/{log,lib,db} /nix/var /etc/nixos/ \ /run/lock /home /bin # for the /bin/sh symlink -install -m 0700 -d /root # Miscellaneous boot time cleanup. diff --git a/nixos/modules/system/boot/stage-2.nix b/nixos/modules/system/boot/stage-2.nix index 8db6d2d2f734..78afbd8dbc12 100644 --- a/nixos/modules/system/boot/stage-2.nix +++ b/nixos/modules/system/boot/stage-2.nix @@ -10,6 +10,7 @@ let bootStage2 = pkgs.substituteAll { src = ./stage-2-init.sh; shellDebug = "${pkgs.bashInteractive}/bin/bash"; + shell = "${pkgs.bash}/bin/bash"; isExecutable = true; inherit (config.nix) readOnlyStore; inherit (config.networking) useHostResolvConf; diff --git a/nixos/modules/system/boot/systemd-unit-options.nix b/nixos/modules/system/boot/systemd-unit-options.nix index 43a9c28bb694..5255f1a1b97a 100644 --- a/nixos/modules/system/boot/systemd-unit-options.nix +++ b/nixos/modules/system/boot/systemd-unit-options.nix @@ -217,7 +217,7 @@ in rec { environment = mkOption { default = {}; - type = types.attrs; # FIXME + type = with types; attrsOf (nullOr (either str package)); example = { PATH = "/foo/bar/bin"; LANG = "nl_NL.UTF-8"; }; description = "Environment variables passed to the service's processes."; }; diff --git a/nixos/modules/system/boot/systemd.nix b/nixos/modules/system/boot/systemd.nix index dd9ba7104485..d2fe33488a7a 100644 --- a/nixos/modules/system/boot/systemd.nix +++ b/nixos/modules/system/boot/systemd.nix @@ -14,7 +14,6 @@ let upstreamSystemUnits = [ # Targets. "basic.target" - "busnames.target" "sysinit.target" "sockets.target" "exit.target" @@ -47,6 +46,7 @@ let # Consoles. "getty.target" + "getty-pre.target" "getty@.service" "serial-getty@.service" "console-getty.service" @@ -63,10 +63,7 @@ let "systemd-logind.service" "autovt@.service" "systemd-user-sessions.service" - "dbus-org.freedesktop.login1.service" "dbus-org.freedesktop.machine1.service" - "org.freedesktop.login1.busname" - "org.freedesktop.machine1.busname" "user@.service" # Journal. @@ -99,7 +96,6 @@ let "swap.target" "dev-hugepages.mount" "dev-mqueue.mount" - "proc-sys-fs-binfmt_misc.mount" "sys-fs-fuse-connections.mount" "sys-kernel-config.mount" "sys-kernel-debug.mount" @@ -141,7 +137,6 @@ let # Slices / containers. "slices.target" - "system.slice" "user.slice" "machine.slice" "machines.target" @@ -155,19 +150,16 @@ let "systemd-tmpfiles-setup-dev.service" # Misc. - "org.freedesktop.systemd1.busname" "systemd-sysctl.service" "dbus-org.freedesktop.timedate1.service" "dbus-org.freedesktop.locale1.service" "dbus-org.freedesktop.hostname1.service" - "org.freedesktop.timedate1.busname" - "org.freedesktop.locale1.busname" - "org.freedesktop.hostname1.busname" "systemd-timedated.service" "systemd-localed.service" "systemd-hostnamed.service" "systemd-binfmt.service" "systemd-exit.service" + "systemd-update-done.service" ] ++ cfg.additionalUpstreamSystemUnits; @@ -182,7 +174,6 @@ let upstreamUserUnits = [ "basic.target" "bluetooth.target" - "busnames.target" "default.target" "exit.target" "graphical-session-pre.target" @@ -249,37 +240,37 @@ let } (mkIf (config.preStart != "") { serviceConfig.ExecStartPre = makeJobScript "${name}-pre-start" '' - #! ${pkgs.stdenv.shell} -e + #! ${pkgs.runtimeShell} -e ${config.preStart} ''; }) (mkIf (config.script != "") { serviceConfig.ExecStart = makeJobScript "${name}-start" '' - #! ${pkgs.stdenv.shell} -e + #! ${pkgs.runtimeShell} -e ${config.script} '' + " " + config.scriptArgs; }) (mkIf (config.postStart != "") { serviceConfig.ExecStartPost = makeJobScript "${name}-post-start" '' - #! ${pkgs.stdenv.shell} -e + #! ${pkgs.runtimeShell} -e ${config.postStart} ''; }) (mkIf (config.reload != "") { serviceConfig.ExecReload = makeJobScript "${name}-reload" '' - #! ${pkgs.stdenv.shell} -e + #! ${pkgs.runtimeShell} -e ${config.reload} ''; }) (mkIf (config.preStop != "") { serviceConfig.ExecStop = makeJobScript "${name}-pre-stop" '' - #! ${pkgs.stdenv.shell} -e + #! ${pkgs.runtimeShell} -e ${config.preStop} ''; }) (mkIf (config.postStop != "") { serviceConfig.ExecStopPost = makeJobScript "${name}-post-stop" '' - #! ${pkgs.stdenv.shell} -e + #! ${pkgs.runtimeShell} -e ${config.postStop} ''; }) @@ -524,7 +515,7 @@ in }; systemd.globalEnvironment = mkOption { - type = types.attrs; + type = with types; attrsOf (nullOr (either str package)); default = {}; example = { TZ = "CET"; }; description = '' @@ -532,6 +523,14 @@ in ''; }; + systemd.enableCgroupAccounting = mkOption { + default = false; + type = types.bool; + description = '' + Whether to enable cgroup accounting. + ''; + }; + systemd.extraConfig = mkOption { default = ""; type = types.lines; @@ -733,6 +732,13 @@ in "systemd/system.conf".text = '' [Manager] + ${optionalString config.systemd.enableCgroupAccounting '' + DefaultCPUAccounting=yes + DefaultIOAccounting=yes + DefaultBlockIOAccounting=yes + DefaultMemoryAccounting=yes + DefaultTasksAccounting=yes + ''} ${config.systemd.extraConfig} ''; @@ -789,8 +795,7 @@ in # Keep a persistent journal. Note that systemd-tmpfiles will # set proper ownership/permissions. - # FIXME: revert to 0700 with systemd v233. - mkdir -m 0750 -p /var/log/journal + mkdir -m 0700 -p /var/log/journal ''; users.extraUsers.systemd-network.uid = config.ids.uids.systemd-network; @@ -830,7 +835,8 @@ in system.requiredKernelConfig = map config.lib.kernelConfig.isEnabled [ "DEVTMPFS" "CGROUPS" "INOTIFY_USER" "SIGNALFD" "TIMERFD" "EPOLL" "NET" - "SYSFS" "PROC_FS" "FHANDLE" "DMIID" "AUTOFS4_FS" "TMPFS_POSIX_ACL" + "SYSFS" "PROC_FS" "FHANDLE" "CRYPTO_USER_API_HASH" "CRYPTO_HMAC" + "CRYPTO_SHA256" "DMIID" "AUTOFS4_FS" "TMPFS_POSIX_ACL" "TMPFS_XATTR" "SECCOMP" ]; @@ -887,7 +893,7 @@ in systemd.targets.local-fs.unitConfig.X-StopOnReconfiguration = true; systemd.targets.remote-fs.unitConfig.X-StopOnReconfiguration = true; systemd.targets.network-online.wantedBy = [ "multi-user.target" ]; - systemd.services.systemd-binfmt.wants = [ "proc-sys-fs-binfmt_misc.automount" ]; + systemd.services.systemd-binfmt.wants = [ "proc-sys-fs-binfmt_misc.mount" ]; # Don't bother with certain units in containers. systemd.services.systemd-remount-fs.unitConfig.ConditionVirtualization = "!container"; |