diff options
Diffstat (limited to 'nixos/modules')
-rw-r--r-- | nixos/modules/misc/version.nix | 40 | ||||
-rw-r--r-- | nixos/modules/module-list.nix | 2 | ||||
-rw-r--r-- | nixos/modules/programs/adb.nix | 3 | ||||
-rw-r--r-- | nixos/modules/rename.nix | 1 | ||||
-rw-r--r-- | nixos/modules/services/development/jupyter/default.nix | 1 | ||||
-rw-r--r-- | nixos/modules/services/monitoring/collectd.nix | 56 | ||||
-rw-r--r-- | nixos/modules/services/networking/kea.nix | 82 | ||||
-rw-r--r-- | nixos/modules/services/networking/openfire.nix | 56 | ||||
-rw-r--r-- | nixos/modules/services/x11/desktop-managers/xfce.nix | 2 | ||||
-rw-r--r-- | nixos/modules/system/boot/stage-1.nix | 8 | ||||
-rwxr-xr-x | nixos/modules/system/boot/stage-2-init.sh | 55 | ||||
-rw-r--r-- | nixos/modules/system/boot/systemd.nix | 43 | ||||
-rw-r--r-- | nixos/modules/system/boot/systemd/initrd.nix | 417 | ||||
-rw-r--r-- | nixos/modules/system/boot/systemd/nspawn.nix | 8 | ||||
-rw-r--r-- | nixos/modules/system/boot/systemd/tmpfiles.nix | 17 | ||||
-rw-r--r-- | nixos/modules/system/boot/systemd/user.nix | 31 | ||||
-rw-r--r-- | nixos/modules/tasks/filesystems.nix | 2 | ||||
-rw-r--r-- | nixos/modules/virtualisation/qemu-vm.nix | 24 |
18 files changed, 641 insertions, 207 deletions
diff --git a/nixos/modules/misc/version.nix b/nixos/modules/misc/version.nix index d825f4beb30..931201ade29 100644 --- a/nixos/modules/misc/version.nix +++ b/nixos/modules/misc/version.nix @@ -15,6 +15,26 @@ let mapAttrsToList (n: v: ''${n}=${escapeIfNeccessary (toString v)}'') attrs ); + osReleaseContents = { + NAME = "NixOS"; + ID = "nixos"; + VERSION = "${cfg.release} (${cfg.codeName})"; + VERSION_CODENAME = toLower cfg.codeName; + VERSION_ID = cfg.release; + BUILD_ID = cfg.version; + PRETTY_NAME = "NixOS ${cfg.release} (${cfg.codeName})"; + LOGO = "nix-snowflake"; + HOME_URL = "https://nixos.org/"; + DOCUMENTATION_URL = "https://nixos.org/learn.html"; + SUPPORT_URL = "https://nixos.org/community.html"; + BUG_REPORT_URL = "https://github.com/NixOS/nixpkgs/issues"; + }; + + initrdReleaseContents = osReleaseContents // { + PRETTY_NAME = "${osReleaseContents.PRETTY_NAME} (Initrd)"; + }; + initrdRelease = pkgs.writeText "initrd-release" (attrsToText initrdReleaseContents); + in { imports = [ @@ -119,20 +139,12 @@ in DISTRIB_DESCRIPTION = "NixOS ${cfg.release} (${cfg.codeName})"; }; - "os-release".text = attrsToText { - NAME = "NixOS"; - ID = "nixos"; - VERSION = "${cfg.release} (${cfg.codeName})"; - VERSION_CODENAME = toLower cfg.codeName; - VERSION_ID = cfg.release; - BUILD_ID = cfg.version; - PRETTY_NAME = "NixOS ${cfg.release} (${cfg.codeName})"; - LOGO = "nix-snowflake"; - HOME_URL = "https://nixos.org/"; - DOCUMENTATION_URL = "https://nixos.org/learn.html"; - SUPPORT_URL = "https://nixos.org/community.html"; - BUG_REPORT_URL = "https://github.com/NixOS/nixpkgs/issues"; - }; + "os-release".text = attrsToText osReleaseContents; + }; + + boot.initrd.systemd.contents = { + "/etc/os-release".source = initrdRelease; + "/etc/initrd-release".source = initrdRelease; }; }; diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix index c4958c36ea0..d6c65251c62 100644 --- a/nixos/modules/module-list.nix +++ b/nixos/modules/module-list.nix @@ -850,7 +850,6 @@ ./services/networking/ofono.nix ./services/networking/oidentd.nix ./services/networking/onedrive.nix - ./services/networking/openfire.nix ./services/networking/openvpn.nix ./services/networking/ostinato.nix ./services/networking/owamp.nix @@ -1181,6 +1180,7 @@ ./system/boot/systemd/nspawn.nix ./system/boot/systemd/tmpfiles.nix ./system/boot/systemd/user.nix + ./system/boot/systemd/initrd.nix ./system/boot/timesyncd.nix ./system/boot/tmp.nix ./system/etc/etc-activation.nix diff --git a/nixos/modules/programs/adb.nix b/nixos/modules/programs/adb.nix index 83bcfe886aa..9e9e37f92a8 100644 --- a/nixos/modules/programs/adb.nix +++ b/nixos/modules/programs/adb.nix @@ -23,8 +23,7 @@ with lib; ###### implementation config = mkIf config.programs.adb.enable { services.udev.packages = [ pkgs.android-udev-rules ]; - # Give platform-tools lower priority so mke2fs+friends are taken from other packages first - environment.systemPackages = [ (lowPrio pkgs.androidenv.androidPkgs_9_0.platform-tools) ]; + environment.systemPackages = [ pkgs.android-tools ]; users.groups.adbusers = {}; }; } diff --git a/nixos/modules/rename.nix b/nixos/modules/rename.nix index 195cf87e6a8..72395b2ee86 100644 --- a/nixos/modules/rename.nix +++ b/nixos/modules/rename.nix @@ -91,6 +91,7 @@ with lib; (mkRemovedOptionModule [ "services" "shellinabox" ] "The corresponding package was removed from nixpkgs.") (mkRemovedOptionModule [ "services" "gogoclient" ] "The corresponding package was removed from nixpkgs.") (mkRemovedOptionModule [ "services" "virtuoso" ] "The corresponding package was removed from nixpkgs.") + (mkRemovedOptionModule [ "services" "openfire" ] "The corresponding package was removed from nixpkgs.") # Do NOT add any option renames here, see top of the file ]; diff --git a/nixos/modules/services/development/jupyter/default.nix b/nixos/modules/services/development/jupyter/default.nix index bebb3c3f13f..4eacc4782a9 100644 --- a/nixos/modules/services/development/jupyter/default.nix +++ b/nixos/modules/services/development/jupyter/default.nix @@ -194,6 +194,7 @@ in { extraGroups = [ cfg.group ]; home = "/var/lib/jupyter"; createHome = true; + isSystemUser = true; useDefaultShell = true; # needed so that the user can start a terminal. }; }) diff --git a/nixos/modules/services/monitoring/collectd.nix b/nixos/modules/services/monitoring/collectd.nix index 8d81737a3ef..1b9af585756 100644 --- a/nixos/modules/services/monitoring/collectd.nix +++ b/nixos/modules/services/monitoring/collectd.nix @@ -5,36 +5,15 @@ with lib; let cfg = config.services.collectd; - unvalidated_conf = pkgs.writeText "collectd-unvalidated.conf" '' - BaseDir "${cfg.dataDir}" - AutoLoadPlugin ${boolToString cfg.autoLoadPlugin} - Hostname "${config.networking.hostName}" - - LoadPlugin syslog - <Plugin "syslog"> - LogLevel "info" - NotifyLevel "OKAY" - </Plugin> - - ${concatStrings (mapAttrsToList (plugin: pluginConfig: '' - LoadPlugin ${plugin} - <Plugin "${plugin}"> - ${pluginConfig} - </Plugin> - '') cfg.plugins)} - - ${concatMapStrings (f: '' - Include "${f}" - '') cfg.include} - - ${cfg.extraConfig} - ''; + baseDirLine = ''BaseDir "${cfg.dataDir}"''; + unvalidated_conf = pkgs.writeText "collectd-unvalidated.conf" cfg.extraConfig; conf = if cfg.validateConfig then pkgs.runCommand "collectd.conf" {} '' echo testing ${unvalidated_conf} + cp ${unvalidated_conf} collectd.conf # collectd -t fails if BaseDir does not exist. - sed '1s/^BaseDir.*$/BaseDir "."/' ${unvalidated_conf} > collectd.conf + substituteInPlace collectd.conf --replace ${lib.escapeShellArgs [ baseDirLine ]} 'BaseDir "."' ${package}/bin/collectd -t -C collectd.conf cp ${unvalidated_conf} $out '' else unvalidated_conf; @@ -123,7 +102,8 @@ in { extraConfig = mkOption { default = ""; description = '' - Extra configuration for collectd. + Extra configuration for collectd. Use mkBefore to add lines before the + default config, and mkAfter to add them below. ''; type = lines; }; @@ -131,6 +111,30 @@ in { }; config = mkIf cfg.enable { + # 1200 is after the default (1000) but before mkAfter (1500). + services.collectd.extraConfig = lib.mkOrder 1200 '' + ${baseDirLine} + AutoLoadPlugin ${boolToString cfg.autoLoadPlugin} + Hostname "${config.networking.hostName}" + + LoadPlugin syslog + <Plugin "syslog"> + LogLevel "info" + NotifyLevel "OKAY" + </Plugin> + + ${concatStrings (mapAttrsToList (plugin: pluginConfig: '' + LoadPlugin ${plugin} + <Plugin "${plugin}"> + ${pluginConfig} + </Plugin> + '') cfg.plugins)} + + ${concatMapStrings (f: '' + Include "${f}" + '') cfg.include} + ''; + systemd.tmpfiles.rules = [ "d '${cfg.dataDir}' - ${cfg.user} - - -" ]; diff --git a/nixos/modules/services/networking/kea.nix b/nixos/modules/services/networking/kea.nix index 17b4eb2e283..994c511bdc2 100644 --- a/nixos/modules/services/networking/kea.nix +++ b/nixos/modules/services/networking/kea.nix @@ -9,20 +9,26 @@ with lib; let cfg = config.services.kea; + xor = x: y: (!x && y) || (x && !y); format = pkgs.formats.json {}; - ctrlAgentConfig = format.generate "kea-ctrl-agent.conf" { + chooseNotNull = x: y: if x != null then x else y; + + ctrlAgentConfig = chooseNotNull cfg.ctrl-agent.configFile (format.generate "kea-ctrl-agent.conf" { Control-agent = cfg.ctrl-agent.settings; - }; - dhcp4Config = format.generate "kea-dhcp4.conf" { + }); + + dhcp4Config = chooseNotNull cfg.dhcp4.configFile (format.generate "kea-dhcp4.conf" { Dhcp4 = cfg.dhcp4.settings; - }; - dhcp6Config = format.generate "kea-dhcp6.conf" { + }); + + dhcp6Config = chooseNotNull cfg.dhcp6.configFile (format.generate "kea-dhcp6.conf" { Dhcp6 = cfg.dhcp6.settings; - }; - dhcpDdnsConfig = format.generate "kea-dhcp-ddns.conf" { + }); + + dhcpDdnsConfig = chooseNotNull cfg.dhcp-ddns.configFile (format.generate "kea-dhcp-ddns.conf" { DhcpDdns = cfg.dhcp-ddns.settings; - }; + }); package = pkgs.kea; in @@ -45,6 +51,17 @@ in ''; }; + configFile = mkOption { + type = nullOr path; + default = null; + description = '' + Kea Control Agent configuration as a path, see <link xlink:href="https://kea.readthedocs.io/en/kea-${package.version}/arm/agent.html"/>. + + Takes preference over <link linkend="opt-services.kea.ctrl-agent.settings">settings</link>. + Most users should prefer using <link linkend="opt-services.kea.ctrl-agent.settings">settings</link> instead. + ''; + }; + settings = mkOption { type = format.type; default = null; @@ -73,6 +90,17 @@ in ''; }; + configFile = mkOption { + type = nullOr path; + default = null; + description = '' + Kea DHCP4 configuration as a path, see <link xlink:href="https://kea.readthedocs.io/en/kea-${package.version}/arm/dhcp4-srv.html"/>. + + Takes preference over <link linkend="opt-services.kea.dhcp4.settings">settings</link>. + Most users should prefer using <link linkend="opt-services.kea.dhcp4.settings">settings</link> instead. + ''; + }; + settings = mkOption { type = format.type; default = null; @@ -122,6 +150,17 @@ in ''; }; + configFile = mkOption { + type = nullOr path; + default = null; + description = '' + Kea DHCP6 configuration as a path, see <link xlink:href="https://kea.readthedocs.io/en/kea-${package.version}/arm/dhcp6-srv.html"/>. + + Takes preference over <link linkend="opt-services.kea.dhcp6.settings">settings</link>. + Most users should prefer using <link linkend="opt-services.kea.dhcp6.settings">settings</link> instead. + ''; + }; + settings = mkOption { type = format.type; default = null; @@ -172,6 +211,17 @@ in ''; }; + configFile = mkOption { + type = nullOr path; + default = null; + description = '' + Kea DHCP-DDNS configuration as a path, see <link xlink:href="https://kea.readthedocs.io/en/kea-${package.version}/arm/ddns.html"/>. + + Takes preference over <link linkend="opt-services.kea.dhcp-ddns.settings">settings</link>. + Most users should prefer using <link linkend="opt-services.kea.dhcp-ddns.settings">settings</link> instead. + ''; + }; + settings = mkOption { type = format.type; default = null; @@ -214,6 +264,10 @@ in } (mkIf cfg.ctrl-agent.enable { + assertions = [{ + assertion = xor (cfg.ctrl-agent.settings == null) (cfg.ctrl-agent.configFile == null); + message = "Either services.kea.ctrl-agent.settings or services.kea.ctrl-agent.configFile must be set to a non-null value."; + }]; environment.etc."kea/ctrl-agent.conf".source = ctrlAgentConfig; @@ -252,6 +306,10 @@ in }) (mkIf cfg.dhcp4.enable { + assertions = [{ + assertion = xor (cfg.dhcp4.settings == null) (cfg.dhcp4.configFile == null); + message = "Either services.kea.dhcp4.settings or services.kea.dhcp4.configFile must be set to a non-null value."; + }]; environment.etc."kea/dhcp4-server.conf".source = dhcp4Config; @@ -295,6 +353,10 @@ in }) (mkIf cfg.dhcp6.enable { + assertions = [{ + assertion = xor (cfg.dhcp6.settings == null) (cfg.dhcp6.configFile == null); + message = "Either services.kea.dhcp6.settings or services.kea.dhcp6.configFile must be set to a non-null value."; + }]; environment.etc."kea/dhcp6-server.conf".source = dhcp6Config; @@ -336,6 +398,10 @@ in }) (mkIf cfg.dhcp-ddns.enable { + assertions = [{ + assertion = xor (cfg.dhcp-ddns.settings == null) (cfg.dhcp-ddns.configFile == null); + message = "Either services.kea.dhcp-ddns.settings or services.kea.dhcp-ddns.configFile must be set to a non-null value."; + }]; environment.etc."kea/dhcp-ddns.conf".source = dhcpDdnsConfig; diff --git a/nixos/modules/services/networking/openfire.nix b/nixos/modules/services/networking/openfire.nix deleted file mode 100644 index fe0499d5232..00000000000 --- a/nixos/modules/services/networking/openfire.nix +++ /dev/null @@ -1,56 +0,0 @@ -{ config, lib, pkgs, ... }: - -with lib; - -{ - ###### interface - - options = { - - services.openfire = { - - enable = mkEnableOption "OpenFire XMPP server"; - - usePostgreSQL = mkOption { - type = types.bool; - default = true; - description = " - Whether you use PostgreSQL service for your storage back-end. - "; - }; - - }; - - }; - - - ###### implementation - - config = mkIf config.services.openfire.enable { - - assertions = singleton - { assertion = !(config.services.openfire.usePostgreSQL -> config.services.postgresql.enable); - message = "OpenFire configured to use PostgreSQL but services.postgresql.enable is not enabled."; - }; - - systemd.services.openfire = { - description = "OpenFire XMPP server"; - wantedBy = [ "multi-user.target" ]; - after = [ "networking.target" ] ++ - optional config.services.openfire.usePostgreSQL "postgresql.service"; - path = with pkgs; [ jre openfire coreutils which gnugrep gawk gnused ]; - script = '' - export HOME=/tmp - mkdir /var/log/openfire || true - mkdir /etc/openfire || true - for i in ${pkgs.openfire}/conf.inst/*; do - if ! test -f /etc/openfire/$(basename $i); then - cp $i /etc/openfire/ - fi - done - openfire start - ''; # */ - }; - }; - -} diff --git a/nixos/modules/services/x11/desktop-managers/xfce.nix b/nixos/modules/services/x11/desktop-managers/xfce.nix index 3cf92f98c56..0bb5c1268ca 100644 --- a/nixos/modules/services/x11/desktop-managers/xfce.nix +++ b/nixos/modules/services/x11/desktop-managers/xfce.nix @@ -99,6 +99,7 @@ in ristretto xfce4-appfinder xfce4-notifyd + xfce4-screensaver xfce4-screenshooter xfce4-session xfce4-settings @@ -168,5 +169,6 @@ in xfce4-notifyd ]; + security.pam.services.xfce4-screensaver.unixAuth = true; }; } diff --git a/nixos/modules/system/boot/stage-1.nix b/nixos/modules/system/boot/stage-1.nix index 7e93d62aa76..04753a6767d 100644 --- a/nixos/modules/system/boot/stage-1.nix +++ b/nixos/modules/system/boot/stage-1.nix @@ -723,8 +723,12 @@ in } ]; - system.build = - { inherit bootStage1 initialRamdisk initialRamdiskSecretAppender extraUtils; }; + system.build = mkMerge [ + { inherit bootStage1 initialRamdiskSecretAppender extraUtils; } + + # generated in nixos/modules/system/boot/systemd/initrd.nix + (mkIf (!config.boot.initrd.systemd.enable) { inherit initialRamdisk; }) + ]; system.requiredKernelConfig = with config.lib.kernelConfig; [ (isYes "TMPFS") diff --git a/nixos/modules/system/boot/stage-2-init.sh b/nixos/modules/system/boot/stage-2-init.sh index 9a9d35c08db..9f8d86da6b0 100755 --- a/nixos/modules/system/boot/stage-2-init.sh +++ b/nixos/modules/system/boot/stage-2-init.sh @@ -12,10 +12,6 @@ for o in $(</proc/cmdline); do # Show each command. set -x ;; - resume=*) - set -- $(IFS==; echo $o) - resumeDevice=$2 - ;; esac done @@ -72,46 +68,12 @@ if [ -n "@readOnlyStore@" ]; then fi -# Provide a /etc/mtab. -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 - - -# 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 -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 - - -# Miscellaneous boot time cleanup. -rm -rf /var/run /var/lock -rm -f /etc/{group,passwd,shadow}.lock - - -# Also get rid of temporary GC roots. -rm -rf /nix/var/nix/gcroots/tmp /nix/var/nix/temproots - - -# For backwards compatibility, symlink /var/run to /run, and /var/lock -# to /run/lock. -ln -s /run /var/run -ln -s /run/lock /var/lock - - -# Clear the resume device. -if test -n "$resumeDevice"; then - mkswap "$resumeDevice" || echo 'Failed to clear saved image.' -fi - - # Use /etc/resolv.conf supplied by systemd-nspawn, if applicable. if [ -n "@useHostResolvConf@" ] && [ -e /etc/resolv.conf ]; then resolvconf -m 1000 -a host </etc/resolv.conf fi + # Log the script output to /dev/kmsg or /run/log/stage-2-init.log. # Only at this point are all the necessary prerequisites ready for these commands. exec {logOutFd}>&1 {logErrFd}>&2 @@ -133,22 +95,9 @@ echo "running activation script..." $systemConfig/activate -# Restore the system time from the hardware clock. We do this after -# running the activation script to be sure that /etc/localtime points -# at the current time zone. -if [ -e /dev/rtc ]; then - hwclock --hctosys -fi - - # Record the boot configuration. ln -sfn "$systemConfig" /run/booted-system -# Prevent the booted system from being garbage-collected. If it weren't -# a gcroot, if we were running a different kernel, switched system, -# and garbage collected all, we could not load kernel modules anymore. -ln -sfn /run/booted-system /nix/var/nix/gcroots/booted-system - # Run any user-specified commands. @shell@ @postBootCommands@ @@ -169,4 +118,4 @@ exec {logOutFd}>&- {logErrFd}>&- # Start systemd in a clean environment. echo "starting systemd..." -exec env - @systemdExecutable@ "$@" +exec @systemdExecutable@ "$@" diff --git a/nixos/modules/system/boot/systemd.nix b/nixos/modules/system/boot/systemd.nix index f69c5d3d5a6..844a6793c15 100644 --- a/nixos/modules/system/boot/systemd.nix +++ b/nixos/modules/system/boot/systemd.nix @@ -11,14 +11,7 @@ let systemd = cfg.package; inherit (systemdUtils.lib) - makeUnit generateUnits - makeJobScript - unitConfig - serviceConfig - mountConfig - automountConfig - commonUnitText targetToUnit serviceToUnit socketToUnit @@ -185,13 +178,7 @@ in systemd.units = mkOption { description = "Definition of systemd units."; default = {}; - type = with types; attrsOf (submodule ( - { name, config, ... }: - { options = concreteUnitOptions; - config = { - unit = mkDefault (makeUnit name config); - }; - })); + type = systemdUtils.types.units; }; systemd.packages = mkOption { @@ -203,37 +190,37 @@ in systemd.targets = mkOption { default = {}; - type = with types; attrsOf (submodule [ { options = targetOptions; } unitConfig] ); + type = systemdUtils.types.targets; description = "Definition of systemd target units."; }; systemd.services = mkOption { default = {}; - type = with types; attrsOf (submodule [ { options = serviceOptions; } unitConfig serviceConfig ]); + type = systemdUtils.types.services; description = "Definition of systemd service units."; }; systemd.sockets = mkOption { default = {}; - type = with types; attrsOf (submodule [ { options = socketOptions; } unitConfig ]); + type = systemdUtils.types.sockets; description = "Definition of systemd socket units."; }; systemd.timers = mkOption { default = {}; - type = with types; attrsOf (submodule [ { options = timerOptions; } unitConfig ]); + type = systemdUtils.types.timers; description = "Definition of systemd timer units."; }; systemd.paths = mkOption { default = {}; - type = with types; attrsOf (submodule [ { options = pathOptions; } unitConfig ]); + type = systemdUtils.types.paths; description = "Definition of systemd path units."; }; systemd.mounts = mkOption { default = []; - type = with types; listOf (submodule [ { options = mountOptions; } unitConfig mountConfig ]); + type = systemdUtils.types.mounts; description = '' Definition of systemd mount units. This is a list instead of an attrSet, because systemd mandates the names to be derived from @@ -243,7 +230,7 @@ in systemd.automounts = mkOption { default = []; - type = with types; listOf (submodule [ { options = automountOptions; } unitConfig automountConfig ]); + type = systemdUtils.types.automounts; description = '' Definition of systemd automount units. This is a list instead of an attrSet, because systemd mandates the names to be derived from @@ -253,7 +240,7 @@ in systemd.slices = mkOption { default = {}; - type = with types; attrsOf (submodule [ { options = sliceOptions; } unitConfig] ); + type = systemdUtils.types.slices; description = "Definition of slice configurations."; }; @@ -362,10 +349,11 @@ in type = types.listOf types.str; example = [ "systemd-backlight@.service" ]; description = '' - A list of units to suppress when generating system systemd configuration directory. This has + A list of units to skip when generating system systemd configuration directory. This has priority over upstream units, <option>systemd.units</option>, and <option>systemd.additionalUpstreamSystemUnits</option>. The main purpose of this is to - suppress a upstream systemd unit with any modifications made to it by other NixOS modules. + prevent a upstream systemd unit from being added to the initrd with any modifications made to it + by other NixOS modules. ''; }; @@ -482,7 +470,12 @@ in enabledUnits = filterAttrs (n: v: ! elem n cfg.suppressedSystemUnits) cfg.units; in ({ - "systemd/system".source = generateUnits "system" enabledUnits enabledUpstreamSystemUnits upstreamSystemWants; + "systemd/system".source = generateUnits { + type = "system"; + units = enabledUnits; + upstreamUnits = enabledUpstreamSystemUnits; + upstreamWants = upstreamSystemWants; + }; "systemd/system.conf".text = '' [Manager] diff --git a/nixos/modules/system/boot/systemd/initrd.nix b/nixos/modules/system/boot/systemd/initrd.nix new file mode 100644 index 00000000000..30bdc9a3422 --- /dev/null +++ b/nixos/modules/system/boot/systemd/initrd.nix @@ -0,0 +1,417 @@ +{ lib, config, utils, pkgs, ... }: + +with lib; + +let + inherit (utils) systemdUtils escapeSystemdPath; + inherit (systemdUtils.lib) + generateUnits + pathToUnit + serviceToUnit + sliceToUnit + socketToUnit + targetToUnit + timerToUnit + mountToUnit + automountToUnit; + + + cfg = config.boot.initrd.systemd; + + # Copied from fedora + upstreamUnits = [ + "basic.target" + "ctrl-alt-del.target" + "emergency.service" + "emergency.target" + "final.target" + "halt.target" + "initrd-cleanup.service" + "initrd-fs.target" + "initrd-parse-etc.service" + "initrd-root-device.target" + "initrd-root-fs.target" + "initrd-switch-root.service" + "initrd-switch-root.target" + "initrd.target" + "initrd-udevadm-cleanup-db.service" + "kexec.target" + "kmod-static-nodes.service" + "local-fs-pre.target" + "local-fs.target" + "multi-user.target" + "paths.target" + "poweroff.target" + "reboot.target" + "rescue.service" + "rescue.target" + "rpcbind.target" + "shutdown.target" + "sigpwr.target" + "slices.target" + "sockets.target" + "swap.target" + "sysinit.target" + "sys-kernel-config.mount" + "syslog.socket" + "systemd-ask-password-console.path" + "systemd-ask-password-console.service" + "systemd-fsck@.service" + "systemd-halt.service" + "systemd-hibernate-resume@.service" + "systemd-journald-audit.socket" + "systemd-journald-dev-log.socket" + "systemd-journald.service" + "systemd-journald.socket" + "systemd-kexec.service" + "systemd-modules-load.service" + "systemd-poweroff.service" + "systemd-random-seed.service" + "systemd-reboot.service" + "systemd-sysctl.service" + "systemd-tmpfiles-setup-dev.service" + "systemd-tmpfiles-setup.service" + "systemd-udevd-control.socket" + "systemd-udevd-kernel.socket" + "systemd-udevd.service" + "systemd-udev-settle.service" + "systemd-udev-trigger.service" + "systemd-vconsole-setup.service" + "timers.target" + "umount.target" + + # TODO: Networking + # "network-online.target" + # "network-pre.target" + # "network.target" + # "nss-lookup.target" + # "nss-user-lookup.target" + # "remote-fs-pre.target" + # "remote-fs.target" + ] ++ cfg.additionalUpstreamUnits; + + upstreamWants = [ + "sysinit.target.wants" + ]; + + enabledUpstreamUnits = filter (n: ! elem n cfg.suppressedUnits) upstreamUnits; + enabledUnits = filterAttrs (n: v: ! elem n cfg.suppressedUnits) cfg.units; + + stage1Units = generateUnits { + type = "initrd"; + units = enabledUnits; + upstreamUnits = enabledUpstreamUnits; + inherit upstreamWants; + inherit (cfg) packages package; + }; + + fileSystems = filter utils.fsNeededForBoot config.system.build.fileSystems; + + fstab = pkgs.writeText "fstab" (lib.concatMapStringsSep "\n" + ({ fsType, mountPoint, device, options, autoFormat, autoResize, ... }@fs: let + opts = options ++ optional autoFormat "x-systemd.makefs" ++ optional autoResize "x-systemd.growfs"; + in "${device} /sysroot${mountPoint} ${fsType} ${lib.concatStringsSep "," opts}") fileSystems); + + kernel-name = config.boot.kernelPackages.kernel.name or "kernel"; + modulesTree = config.system.modulesTree.override { name = kernel-name + "-modules"; }; + 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 = false; + }; + + initrdBinEnv = pkgs.buildEnv { + name = "initrd-emergency-env"; + paths = map getBin cfg.initrdBin; + pathsToLink = ["/bin" "/sbin"]; + # Make recovery easier + postBuild = '' + ln -s ${cfg.package.util-linux}/bin/mount $out/bin/ + ln -s ${cfg.package.util-linux}/bin/umount $out/bin/ + ''; + }; + + initialRamdisk = pkgs.makeInitrdNG { + contents = map (path: { object = path; symlink = ""; }) (subtractLists cfg.suppressedStorePaths cfg.storePaths) + ++ mapAttrsToList (_: v: { object = v.source; symlink = v.target; }) (filterAttrs (_: v: v.enable) cfg.contents); + }; + +in { + options.boot.initrd.systemd = { + enable = mkEnableOption ''systemd in initrd. + + Note: This is in very early development and is highly + experimental. Most of the features NixOS supports in initrd are + not yet supported by the intrd generated with this option. + ''; + + package = (mkPackageOption pkgs "systemd" { + default = "systemdMinimal"; + }) // { + visible = false; + }; + + contents = mkOption { + description = "Set of files that have to be linked into the initrd"; + example = literalExpression '' + { + "/etc/hostname".text = "mymachine"; + } + ''; + visible = false; + default = {}; + type = types.attrsOf (types.submodule ({ config, options, name, ... }: { + options = { + enable = mkEnableOption "copying of this file to initrd and symlinking it" // { default = true; }; + + target = mkOption { + type = types.path; + description = '' + Path of the symlink. + ''; + default = name; + }; + + text = mkOption { + default = null; + type = types.nullOr types.lines; + description = "Text of the file."; + }; + + source = mkOption { + type = types.path; + description = "Path of the source file."; + }; + }; + + config = { + source = mkIf (config.text != null) ( + let name' = "initrd-" + baseNameOf name; + in mkDerivedConfig options.text (pkgs.writeText name') + ); + }; + })); + }; + + storePaths = mkOption { + description = '' + Store paths to copy into the initrd as well. + ''; + type = types.listOf types.singleLineStr; + default = []; + }; + + suppressedStorePaths = mkOption { + description = '' + Store paths specified in the storePaths option that + should not be copied. + ''; + type = types.listOf types.singleLineStr; + default = []; + }; + + emergencyAccess = mkOption { + type = with types; oneOf [ bool singleLineStr ]; + visible = false; + description = '' + Set to true for unauthenticated emergency access, and false for + no emergency access. + + Can also be set to a hashed super user password to allow + authenticated access to the emergency mode. + ''; + default = false; + }; + + initrdBin = mkOption { + type = types.listOf types.package; + default = []; + visible = false; + description = '' + Packages to include in /bin for the stage 1 emergency shell. + ''; + }; + + additionalUpstreamUnits = mkOption { + default = [ ]; + type = types.listOf types.str; + visible = false; + example = [ "debug-shell.service" "systemd-quotacheck.service" ]; + description = '' + Additional units shipped with systemd that shall be enabled. + ''; + }; + + suppressedUnits = mkOption { + default = [ ]; + type = types.listOf types.str; + example = [ "systemd-backlight@.service" ]; + visible = false; + description = '' + A list of units to skip when generating system systemd configuration directory. This has + priority over upstream units, <option>boot.initrd.systemd.units</option>, and + <option>boot.initrd.systemd.additionalUpstreamUnits</option>. The main purpose of this is to + prevent a upstream systemd unit from being added to the initrd with any modifications made to it + by other NixOS modules. + ''; + }; + + units = mkOption { + description = "Definition of systemd units."; + default = {}; + visible = false; + type = systemdUtils.types.units; + }; + + packages = mkOption { + default = []; + visible = false; + type = types.listOf types.package; + example = literalExpression "[ pkgs.systemd-cryptsetup-generator ]"; + description = "Packages providing systemd units and hooks."; + }; + + targets = mkOption { + default = {}; + visible = false; + type = systemdUtils.types.initrdTargets; + description = "Definition of systemd target units."; + }; + + services = mkOption { + default = {}; + type = systemdUtils.types.initrdServices; + visible = false; + description = "Definition of systemd service units."; + }; + + sockets = mkOption { + default = {}; + type = systemdUtils.types.initrdSockets; + visible = false; + description = "Definition of systemd socket units."; + }; + + timers = mkOption { + default = {}; + type = systemdUtils.types.initrdTimers; + visible = false; + description = "Definition of systemd timer units."; + }; + + paths = mkOption { + default = {}; + type = systemdUtils.types.initrdPaths; + visible = false; + description = "Definition of systemd path units."; + }; + + mounts = mkOption { + default = []; + type = systemdUtils.types.initrdMounts; + visible = false; + description = '' + Definition of systemd mount units. + This is a list instead of an attrSet, because systemd mandates the names to be derived from + the 'where' attribute. + ''; + }; + + automounts = mkOption { + default = []; + type = systemdUtils.types.automounts; + visible = false; + description = '' + Definition of systemd automount units. + This is a list instead of an attrSet, because systemd mandates the names to be derived from + the 'where' attribute. + ''; + }; + + slices = mkOption { + default = {}; + type = systemdUtils.types.slices; + visible = false; + description = "Definition of slice configurations."; + }; + }; + + config = mkIf (config.boot.initrd.enable && cfg.enable) { + system.build = { inherit initialRamdisk; }; + boot.initrd.systemd = { + initrdBin = [pkgs.bash pkgs.coreutils pkgs.kmod cfg.package] ++ config.system.fsPackages; + + contents = { + "/init".source = "${cfg.package}/lib/systemd/systemd"; + "/etc/systemd/system".source = stage1Units; + + "/etc/systemd/system.conf".text = '' + [Manager] + DefaultEnvironment=PATH=/bin:/sbin + ''; + + "/etc/fstab".source = fstab; + + "/lib/modules".source = "${modulesClosure}/lib/modules"; + + "/etc/modules-load.d/nixos.conf".text = concatStringsSep "\n" config.boot.initrd.kernelModules; + + "/etc/passwd".source = "${pkgs.fakeNss}/etc/passwd"; + "/etc/shadow".text = "root:${if isBool cfg.emergencyAccess then "!" else cfg.emergencyAccess}:::::::"; + + "/bin".source = "${initrdBinEnv}/bin"; + "/sbin".source = "${initrdBinEnv}/sbin"; + + "/etc/sysctl.d/nixos.conf".text = "kernel.modprobe = /sbin/modprobe"; + }; + + storePaths = [ + # TODO: Limit this to the bare necessities + "${cfg.package}/lib" + + "${cfg.package.util-linux}/bin/mount" + "${cfg.package.util-linux}/bin/umount" + "${cfg.package.util-linux}/bin/sulogin" + + # so NSS can look up usernames + "${pkgs.glibc}/lib/libnss_files.so" + ]; + + targets.initrd.aliases = ["default.target"]; + units = + mapAttrs' (n: v: nameValuePair "${n}.path" (pathToUnit n v)) cfg.paths + // mapAttrs' (n: v: nameValuePair "${n}.service" (serviceToUnit n v)) cfg.services + // mapAttrs' (n: v: nameValuePair "${n}.slice" (sliceToUnit n v)) cfg.slices + // mapAttrs' (n: v: nameValuePair "${n}.socket" (socketToUnit n v)) cfg.sockets + // mapAttrs' (n: v: nameValuePair "${n}.target" (targetToUnit n v)) cfg.targets + // mapAttrs' (n: v: nameValuePair "${n}.timer" (timerToUnit n v)) cfg.timers + // listToAttrs (map + (v: let n = escapeSystemdPath v.where; + in nameValuePair "${n}.mount" (mountToUnit n v)) cfg.mounts) + // listToAttrs (map + (v: let n = escapeSystemdPath v.where; + in nameValuePair "${n}.automount" (automountToUnit n v)) cfg.automounts); + + services.emergency = mkIf (isBool cfg.emergencyAccess && cfg.emergencyAccess) { + environment.SYSTEMD_SULOGIN_FORCE = "1"; + }; + # The unit in /run/systemd/generator shadows the unit in + # /etc/systemd/system, but will still apply drop-ins from + # /etc/systemd/system/foo.service.d/ + # + # We need IgnoreOnIsolate, otherwise the Requires dependency of + # a mount unit on its makefs unit causes it to be unmounted when + # we isolate for switch-root. Use a dummy package so that + # generateUnits will generate drop-ins instead of unit files. + packages = [(pkgs.runCommand "dummy" {} '' + mkdir -p $out/etc/systemd/system + touch $out/etc/systemd/system/systemd-{makefs,growfs}@.service + '')]; + services."systemd-makefs@".unitConfig.IgnoreOnIsolate = true; + services."systemd-growfs@".unitConfig.IgnoreOnIsolate = true; + }; + }; +} diff --git a/nixos/modules/system/boot/systemd/nspawn.nix b/nixos/modules/system/boot/systemd/nspawn.nix index 0c6822319a5..bf9995d03cc 100644 --- a/nixos/modules/system/boot/systemd/nspawn.nix +++ b/nixos/modules/system/boot/systemd/nspawn.nix @@ -116,7 +116,13 @@ in { in mkMerge [ (mkIf (cfg != {}) { - environment.etc."systemd/nspawn".source = mkIf (cfg != {}) (generateUnits' false "nspawn" units [] []); + environment.etc."systemd/nspawn".source = mkIf (cfg != {}) (generateUnits { + allowCollisions = false; + type = "nspawn"; + inherit units; + upstreamUnits = []; + upstreamWants = []; + }); }) { systemd.targets.multi-user.wants = [ "machines.target" ]; diff --git a/nixos/modules/system/boot/systemd/tmpfiles.nix b/nixos/modules/system/boot/systemd/tmpfiles.nix index 57d44c8591e..edbe5996556 100644 --- a/nixos/modules/system/boot/systemd/tmpfiles.nix +++ b/nixos/modules/system/boot/systemd/tmpfiles.nix @@ -100,5 +100,22 @@ in ''; }) ]; + + systemd.tmpfiles.rules = [ + "d /etc/nixos 0755 root root - -" + "d /nix/var 0755 root root - -" + "L+ /nix/var/nix/gcroots/booted-system 0755 root root - /run/booted-system" + "d /run/lock 0755 root root - -" + "d /var/db 0755 root root - -" + "L /etc/mtab - - - - ../proc/mounts" + "L /var/lock - - - - ../run/lock" + # Boot-time cleanup + "R! /etc/group.lock - - - - -" + "R! /etc/passwd.lock - - - - -" + "R! /etc/shadow.lock - - - - -" + "R! /etc/mtab* - - - - -" + "R! /nix/var/nix/gcroots/tmp - - - - -" + "R! /nix/var/nix/temproots - - - - -" + ]; }; } diff --git a/nixos/modules/system/boot/systemd/user.nix b/nixos/modules/system/boot/systemd/user.nix index e30f83f3457..4951aef9558 100644 --- a/nixos/modules/system/boot/systemd/user.nix +++ b/nixos/modules/system/boot/systemd/user.nix @@ -12,10 +12,6 @@ let (systemdUtils.lib) makeUnit generateUnits - makeJobScript - unitConfig - serviceConfig - commonUnitText targetToUnit serviceToUnit socketToUnit @@ -57,48 +53,42 @@ in { systemd.user.units = mkOption { description = "Definition of systemd per-user units."; default = {}; - type = with types; attrsOf (submodule ( - { name, config, ... }: - { options = concreteUnitOptions; - config = { - unit = mkDefault (makeUnit name config); - }; - })); + type = systemdUtils.types.units; }; systemd.user.paths = mkOption { default = {}; - type = with types; attrsOf (submodule [ { options = pathOptions; } unitConfig ]); + type = systemdUtils.types.paths; description = "Definition of systemd per-user path units."; }; systemd.user.services = mkOption { default = {}; - type = with types; attrsOf (submodule [ { options = serviceOptions; } unitConfig serviceConfig ] ); + type = systemdUtils.types.services; description = "Definition of systemd per-user service units."; }; systemd.user.slices = mkOption { default = {}; - type = with types; attrsOf (submodule [ { options = sliceOptions; } unitConfig ] ); + type = systemdUtils.types.slices; description = "Definition of systemd per-user slice units."; }; systemd.user.sockets = mkOption { default = {}; - type = with types; attrsOf (submodule [ { options = socketOptions; } unitConfig ] ); + type = systemdUtils.types.sockets; description = "Definition of systemd per-user socket units."; }; systemd.user.targets = mkOption { default = {}; - type = with types; attrsOf (submodule [ { options = targetOptions; } unitConfig] ); + type = systemdUtils.types.targets; description = "Definition of systemd per-user target units."; }; systemd.user.timers = mkOption { default = {}; - type = with types; attrsOf (submodule [ { options = timerOptions; } unitConfig ] ); + type = systemdUtils.types.timers; description = "Definition of systemd per-user timer units."; }; @@ -119,7 +109,12 @@ in { ]; environment.etc = { - "systemd/user".source = generateUnits "user" cfg.units upstreamUserUnits []; + "systemd/user".source = generateUnits { + type = "user"; + inherit (cfg) units; + upstreamUnits = upstreamUserUnits; + upstreamWants = []; + }; "systemd/user.conf".text = '' [Manager] diff --git a/nixos/modules/tasks/filesystems.nix b/nixos/modules/tasks/filesystems.nix index d68edd8d7d3..b8afe231dd2 100644 --- a/nixos/modules/tasks/filesystems.nix +++ b/nixos/modules/tasks/filesystems.nix @@ -352,7 +352,7 @@ in unitConfig.DefaultDependencies = false; # needed to prevent a cycle serviceConfig.Type = "oneshot"; }; - in listToAttrs (map formatDevice (filter (fs: fs.autoFormat) fileSystems)) // { + in listToAttrs (map formatDevice (filter (fs: fs.autoFormat && !(utils.fsNeededForBoot fs)) fileSystems)) // { # Mount /sys/fs/pstore for evacuating panic logs and crashdumps from persistent storage onto the disk using systemd-pstore. # This cannot be done with the other special filesystems because the pstore module (which creates the mount point) is not loaded then. "mount-pstore" = { diff --git a/nixos/modules/virtualisation/qemu-vm.nix b/nixos/modules/virtualisation/qemu-vm.nix index 760f6912161..74f6521462b 100644 --- a/nixos/modules/virtualisation/qemu-vm.nix +++ b/nixos/modules/virtualisation/qemu-vm.nix @@ -923,6 +923,8 @@ in mkVMOverride (cfg.fileSystems // { "/".device = cfg.bootDevice; + "/".fsType = "ext4"; + "/".autoFormat = true; "/tmp" = mkIf config.boot.tmpOnTmpfs { device = "tmpfs"; @@ -953,6 +955,28 @@ in }; } // lib.mapAttrs' mkSharedDir cfg.sharedDirectories); + boot.initrd.systemd = lib.mkIf (config.boot.initrd.systemd.enable && cfg.writableStore) { + mounts = [{ + where = "/sysroot/nix/store"; + what = "overlay"; + type = "overlay"; + options = "lowerdir=/sysroot/nix/.ro-store,upperdir=/sysroot/nix/.rw-store/store,workdir=/sysroot/nix/.rw-store/work"; + wantedBy = ["local-fs.target"]; + before = ["local-fs.target"]; + requires = ["sysroot-nix-.ro\\x2dstore.mount" "sysroot-nix-.rw\\x2dstore.mount" "rw-store.service"]; + after = ["sysroot-nix-.ro\\x2dstore.mount" "sysroot-nix-.rw\\x2dstore.mount" "rw-store.service"]; + unitConfig.IgnoreOnIsolate = true; + }]; + services.rw-store = { + after = ["sysroot-nix-.rw\\x2dstore.mount"]; + unitConfig.DefaultDependencies = false; + serviceConfig = { + Type = "oneshot"; + ExecStart = "/bin/mkdir -p 0755 /sysroot/nix/.rw-store/store /sysroot/nix/.rw-store/work /sysroot/nix/store"; + }; + }; + }; + swapDevices = mkVMOverride [ ]; boot.initrd.luks.devices = mkVMOverride {}; |