diff --git a/nixos/modules/system/boot/stage-2-init.sh b/nixos/modules/system/boot/stage-2-init.sh index a90f58042d2d..9a9d35c08db9 100755 --- a/nixos/modules/system/boot/stage-2-init.sh +++ b/nixos/modules/system/boot/stage-2-init.sh @@ -167,10 +167,6 @@ exec 1>&$logOutFd 2>&$logErrFd exec {logOutFd}>&- {logErrFd}>&- -# Start systemd. +# Start systemd in a clean environment. echo "starting systemd..." - -PATH=/run/current-system/systemd/lib/systemd:@fsPackagesPath@ \ - LOCALE_ARCHIVE=/run/current-system/sw/lib/locale/locale-archive @systemdUnitPathEnvVar@ \ - TZDIR=/etc/zoneinfo \ - exec @systemdExecutable@ +exec env - @systemdExecutable@ "$@" diff --git a/nixos/modules/system/boot/stage-2.nix b/nixos/modules/system/boot/stage-2.nix index f6b6a8e4b0b4..26fad8e7139f 100644 --- a/nixos/modules/system/boot/stage-2.nix +++ b/nixos/modules/system/boot/stage-2.nix @@ -19,11 +19,6 @@ let pkgs.coreutils pkgs.util-linux ] ++ lib.optional useHostResolvConf pkgs.openresolv); - fsPackagesPath = lib.makeBinPath config.system.fsPackages; - systemdUnitPathEnvVar = lib.optionalString (config.boot.extraSystemdUnitPaths != []) - ("SYSTEMD_UNIT_PATH=" - + builtins.concatStringsSep ":" config.boot.extraSystemdUnitPaths - + ":"); # If SYSTEMD_UNIT_PATH ends with an empty component (":"), the usual unit load path will be appended to the contents of the variable postBootCommands = pkgs.writeText "local-cmds" '' ${config.boot.postBootCommands} @@ -78,12 +73,10 @@ in }; systemdExecutable = mkOption { - default = "systemd"; + default = "/run/current-system/systemd/lib/systemd/systemd"; type = types.str; description = '' - The program to execute to start systemd. Typically - systemd, which will find systemd in the - PATH. + The program to execute to start systemd. ''; }; diff --git a/nixos/modules/system/boot/systemd.nix b/nixos/modules/system/boot/systemd.nix index 057474c607ac..297a80d4681b 100644 --- a/nixos/modules/system/boot/systemd.nix +++ b/nixos/modules/system/boot/systemd.nix @@ -302,6 +302,16 @@ in ''; }; + systemd.managerEnvironment = mkOption { + type = with types; attrsOf (nullOr (oneOf [ str path package ])); + default = {}; + example = { SYSTEMD_LOG_LEVEL = "debug"; }; + description = '' + Environment variables of PID 1. These variables are + not passed to started units. + ''; + }; + systemd.enableCgroupAccounting = mkOption { default = true; type = types.bool; @@ -470,11 +480,13 @@ in enabledUpstreamSystemUnits = filter (n: ! elem n cfg.suppressedSystemUnits) upstreamSystemUnits; enabledUnits = filterAttrs (n: v: ! elem n cfg.suppressedSystemUnits) cfg.units; + in ({ "systemd/system".source = generateUnits "system" enabledUnits enabledUpstreamSystemUnits upstreamSystemWants; "systemd/system.conf".text = '' [Manager] + ManagerEnvironment=${lib.concatStringsSep " " (lib.mapAttrsToList (n: v: "${n}=${lib.escapeShellArg v}") cfg.managerEnvironment)} ${optionalString config.systemd.enableCgroupAccounting '' DefaultCPUAccounting=yes DefaultIOAccounting=yes @@ -542,6 +554,17 @@ in (v: let n = escapeSystemdPath v.where; in nameValuePair "${n}.automount" (automountToUnit n v)) cfg.automounts); + # Environment of PID 1 + systemd.managerEnvironment = { + # Doesn't contain systemd itself - everything works so it seems to use the compiled-in value for its tools + PATH = lib.makeBinPath config.system.fsPackages; + LOCALE_ARCHIVE = "/run/current-system/sw/lib/locale/locale-archive"; + TZDIR = "/etc/zoneinfo"; + # If SYSTEMD_UNIT_PATH ends with an empty component (":"), the usual unit load path will be appended to the contents of the variable + SYSTEMD_UNIT_PATH = lib.mkIf (config.boot.extraSystemdUnitPaths != []) "${builtins.concatStringsSep ":" config.boot.extraSystemdUnitPaths}:"; + }; + + system.requiredKernelConfig = map config.lib.kernelConfig.isEnabled [ "DEVTMPFS" "CGROUPS" "INOTIFY_USER" "SIGNALFD" "TIMERFD" "EPOLL" "NET" "SYSFS" "PROC_FS" "FHANDLE" "CRYPTO_USER_API_HASH" "CRYPTO_HMAC" diff --git a/nixos/tests/systemd.nix b/nixos/tests/systemd.nix index f86daa5eea97..94805ee5781a 100644 --- a/nixos/tests/systemd.nix +++ b/nixos/tests/systemd.nix @@ -192,5 +192,9 @@ import ./make-test-python.nix ({ pkgs, ... }: { with subtest("systemd per-unit accounting works"): assert "IP traffic received: 84B" in output_ping assert "IP traffic sent: 84B" in output_ping + + with subtest("systemd environment is properly set"): + machine.systemctl("daemon-reexec") # Rewrites /proc/1/environ + machine.succeed("grep -q TZDIR=/etc/zoneinfo /proc/1/environ") ''; })