uboot: (firmwareOdroidC2/C4) don't invoke patch tool, use patches = [] instead
https://github.com/NixOS/nixpkgs/blob/master/pkgs/stdenv/generic/setup.sh#L948 this can do it nicely. Signed-off-by: Anton Arapov <anton@deadbeef.mx>
This commit is contained in:
commit
56de2bcd43
30691 changed files with 3076956 additions and 0 deletions
57
nixos/modules/system/boot/systemd/coredump.nix
Normal file
57
nixos/modules/system/boot/systemd/coredump.nix
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
{ config, lib, pkgs, utils, ... }:
|
||||
|
||||
with lib;
|
||||
|
||||
let
|
||||
cfg = config.systemd.coredump;
|
||||
systemd = config.systemd.package;
|
||||
in {
|
||||
options = {
|
||||
systemd.coredump.enable = mkOption {
|
||||
default = true;
|
||||
type = types.bool;
|
||||
description = ''
|
||||
Whether core dumps should be processed by
|
||||
<command>systemd-coredump</command>. If disabled, core dumps
|
||||
appear in the current directory of the crashing process.
|
||||
'';
|
||||
};
|
||||
|
||||
systemd.coredump.extraConfig = mkOption {
|
||||
default = "";
|
||||
type = types.lines;
|
||||
example = "Storage=journal";
|
||||
description = ''
|
||||
Extra config options for systemd-coredump. See coredump.conf(5) man page
|
||||
for available options.
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
config = {
|
||||
systemd.additionalUpstreamSystemUnits = [
|
||||
"systemd-coredump.socket"
|
||||
"systemd-coredump@.service"
|
||||
];
|
||||
|
||||
environment.etc = {
|
||||
"systemd/coredump.conf".text =
|
||||
''
|
||||
[Coredump]
|
||||
${cfg.extraConfig}
|
||||
'';
|
||||
|
||||
# install provided sysctl snippets
|
||||
"sysctl.d/50-coredump.conf".source = "${systemd}/example/sysctl.d/50-coredump.conf";
|
||||
"sysctl.d/50-default.conf".source = "${systemd}/example/sysctl.d/50-default.conf";
|
||||
};
|
||||
|
||||
users.users.systemd-coredump = {
|
||||
uid = config.ids.uids.systemd-coredump;
|
||||
group = "systemd-coredump";
|
||||
};
|
||||
users.groups.systemd-coredump = {};
|
||||
|
||||
boot.kernel.sysctl."kernel.core_pattern" = mkIf (!cfg.enable) "core";
|
||||
};
|
||||
}
|
||||
36
nixos/modules/system/boot/systemd/initrd-secrets.nix
Normal file
36
nixos/modules/system/boot/systemd/initrd-secrets.nix
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
{ config, pkgs, lib, ... }:
|
||||
|
||||
{
|
||||
config = lib.mkIf (config.boot.initrd.enable && config.boot.initrd.systemd.enable) {
|
||||
# Copy secrets into the initrd if they cannot be appended
|
||||
boot.initrd.systemd.contents = lib.mkIf (!config.boot.loader.supportsInitrdSecrets)
|
||||
(lib.mapAttrs' (dest: source: lib.nameValuePair "/.initrd-secrets/${dest}" { source = if source == null then dest else source; }) config.boot.initrd.secrets);
|
||||
|
||||
# Copy secrets to their respective locations
|
||||
boot.initrd.systemd.services.initrd-nixos-copy-secrets = lib.mkIf (config.boot.initrd.secrets != {}) {
|
||||
description = "Copy secrets into place";
|
||||
# Run as early as possible
|
||||
wantedBy = [ "sysinit.target" ];
|
||||
before = [ "cryptsetup-pre.target" ];
|
||||
unitConfig.DefaultDependencies = false;
|
||||
|
||||
# We write the secrets to /.initrd-secrets and move them because this allows
|
||||
# secrets to be written to /run. If we put the secret directly to /run and
|
||||
# drop this service, we'd mount the /run tmpfs over the secret, making it
|
||||
# invisible in stage 2.
|
||||
script = ''
|
||||
for secret in $(cd /.initrd-secrets; find . -type f); do
|
||||
mkdir -p "$(dirname "/$secret")"
|
||||
cp "/.initrd-secrets/$secret" "/$secret"
|
||||
done
|
||||
'';
|
||||
|
||||
unitConfig = {
|
||||
Type = "oneshot";
|
||||
RemainAfterExit = true;
|
||||
};
|
||||
};
|
||||
# The script needs this
|
||||
boot.initrd.systemd.extraBin.find = "${pkgs.findutils}/bin/find";
|
||||
};
|
||||
}
|
||||
502
nixos/modules/system/boot/systemd/initrd.nix
Normal file
502
nixos/modules/system/boot/systemd/initrd.nix
Normal file
|
|
@ -0,0 +1,502 @@
|
|||
{ 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"
|
||||
"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-reboot.service"
|
||||
"systemd-sysctl.service"
|
||||
"systemd-tmpfiles-setup-dev.service"
|
||||
"systemd-tmpfiles-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;
|
||||
jobScripts = concatLists (mapAttrsToList (_: unit: unit.jobScripts or []) (filterAttrs (_: v: v.enable) cfg.services));
|
||||
|
||||
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 "initrd-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);
|
||||
|
||||
needMakefs = lib.any (fs: fs.autoFormat) fileSystems;
|
||||
needGrowfs = lib.any (fs: fs.autoResize) 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-bin-env";
|
||||
paths = map getBin cfg.initrdBin;
|
||||
pathsToLink = ["/bin" "/sbin"];
|
||||
postBuild = concatStringsSep "\n" (mapAttrsToList (n: v: "ln -s '${v}' $out/bin/'${n}'") cfg.extraBin);
|
||||
};
|
||||
|
||||
initialRamdisk = pkgs.makeInitrdNG {
|
||||
name = "initrd-${kernel-name}";
|
||||
inherit (config.boot.initrd) compressor compressorArgs prepend;
|
||||
|
||||
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 = "systemdStage1";
|
||||
}) // {
|
||||
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 = utils.systemdUtils.types.initrdContents;
|
||||
};
|
||||
|
||||
storePaths = mkOption {
|
||||
description = ''
|
||||
Store paths to copy into the initrd as well.
|
||||
'';
|
||||
type = with types; listOf (oneOf [ singleLineStr package ]);
|
||||
default = [];
|
||||
};
|
||||
|
||||
extraBin = mkOption {
|
||||
description = ''
|
||||
Tools to add to /bin
|
||||
'';
|
||||
example = literalExpression ''
|
||||
{
|
||||
umount = ''${pkgs.util-linux}/bin/umount;
|
||||
}
|
||||
'';
|
||||
type = types.attrsOf types.path;
|
||||
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.availableKernelModules = [ "autofs4" ]; # systemd needs this for some features
|
||||
|
||||
boot.initrd.systemd = {
|
||||
initrdBin = [pkgs.bash pkgs.coreutils cfg.package.kmod cfg.package] ++ config.system.fsPackages;
|
||||
extraBin = {
|
||||
less = "${pkgs.less}/bin/less";
|
||||
mount = "${cfg.package.util-linux}/bin/mount";
|
||||
umount = "${cfg.package.util-linux}/bin/umount";
|
||||
};
|
||||
|
||||
contents = {
|
||||
"/init".source = "${cfg.package}/lib/systemd/systemd";
|
||||
"/etc/systemd/system".source = stage1Units;
|
||||
|
||||
"/etc/systemd/system.conf".text = ''
|
||||
[Manager]
|
||||
DefaultEnvironment=PATH=/bin:/sbin ${optionalString (isBool cfg.emergencyAccess && cfg.emergencyAccess) "SYSTEMD_SULOGIN_FORCE=1"}
|
||||
'';
|
||||
|
||||
"/etc/fstab".source = fstab;
|
||||
|
||||
"/lib/modules".source = "${modulesClosure}/lib/modules";
|
||||
"/lib/firmware".source = "${modulesClosure}/lib/firmware";
|
||||
|
||||
"/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";
|
||||
"/etc/modprobe.d/systemd.conf".source = "${cfg.package}/lib/modprobe.d/systemd.conf";
|
||||
"/etc/modprobe.d/ubuntu.conf".source = pkgs.runCommand "initrd-kmod-blacklist-ubuntu" { } ''
|
||||
${pkgs.buildPackages.perl}/bin/perl -0pe 's/## file: iwlwifi.conf(.+?)##/##/s;' $src > $out
|
||||
'';
|
||||
"/etc/modprobe.d/debian.conf".source = pkgs.kmod-debian-aliases;
|
||||
|
||||
};
|
||||
|
||||
storePaths = [
|
||||
# systemd tooling
|
||||
"${cfg.package}/lib/systemd/systemd-fsck"
|
||||
(lib.mkIf needGrowfs "${cfg.package}/lib/systemd/systemd-growfs")
|
||||
"${cfg.package}/lib/systemd/systemd-hibernate-resume"
|
||||
"${cfg.package}/lib/systemd/systemd-journald"
|
||||
(lib.mkIf needMakefs "${cfg.package}/lib/systemd/systemd-makefs")
|
||||
"${cfg.package}/lib/systemd/systemd-modules-load"
|
||||
"${cfg.package}/lib/systemd/systemd-remount-fs"
|
||||
"${cfg.package}/lib/systemd/systemd-shutdown"
|
||||
"${cfg.package}/lib/systemd/systemd-sulogin-shell"
|
||||
"${cfg.package}/lib/systemd/systemd-sysctl"
|
||||
|
||||
# generators
|
||||
"${cfg.package}/lib/systemd/system-generators/systemd-debug-generator"
|
||||
"${cfg.package}/lib/systemd/system-generators/systemd-fstab-generator"
|
||||
"${cfg.package}/lib/systemd/system-generators/systemd-gpt-auto-generator"
|
||||
"${cfg.package}/lib/systemd/system-generators/systemd-hibernate-resume-generator"
|
||||
"${cfg.package}/lib/systemd/system-generators/systemd-run-generator"
|
||||
|
||||
# utilities needed by systemd
|
||||
"${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.2"
|
||||
] ++ jobScripts;
|
||||
|
||||
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);
|
||||
|
||||
# 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@" = lib.mkIf needMakefs { unitConfig.IgnoreOnIsolate = true; };
|
||||
services."systemd-growfs@" = lib.mkIf needGrowfs { unitConfig.IgnoreOnIsolate = true; };
|
||||
|
||||
services.initrd-nixos-activation = {
|
||||
after = [ "initrd-fs.target" ];
|
||||
requiredBy = [ "initrd.target" ];
|
||||
unitConfig.AssertPathExists = "/etc/initrd-release";
|
||||
serviceConfig.Type = "oneshot";
|
||||
description = "NixOS Activation";
|
||||
|
||||
script = /* bash */ ''
|
||||
set -uo pipefail
|
||||
export PATH="/bin:${cfg.package.util-linux}/bin"
|
||||
|
||||
# Figure out what closure to boot
|
||||
closure=
|
||||
for o in $(< /proc/cmdline); do
|
||||
case $o in
|
||||
init=*)
|
||||
IFS== read -r -a initParam <<< "$o"
|
||||
closure="$(dirname "''${initParam[1]}")"
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
# Sanity check
|
||||
if [ -z "''${closure:-}" ]; then
|
||||
echo 'No init= parameter on the kernel command line' >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# If we are not booting a NixOS closure (e.g. init=/bin/sh),
|
||||
# we don't know what root to prepare so we don't do anything
|
||||
if ! [ -x "/sysroot$closure/prepare-root" ]; then
|
||||
echo "NEW_INIT=''${initParam[1]}" > /etc/switch-root.conf
|
||||
echo "$closure does not look like a NixOS installation - not activating"
|
||||
exit 0
|
||||
fi
|
||||
echo 'NEW_INIT=' > /etc/switch-root.conf
|
||||
|
||||
|
||||
# We need to propagate /run for things like /run/booted-system
|
||||
# and /run/current-system.
|
||||
mkdir -p /sysroot/run
|
||||
mount --bind /run /sysroot/run
|
||||
|
||||
# Initialize the system
|
||||
export IN_NIXOS_SYSTEMD_STAGE1=true
|
||||
exec chroot /sysroot $closure/prepare-root
|
||||
'';
|
||||
};
|
||||
|
||||
# This will either call systemctl with the new init as the last parameter (which
|
||||
# is the case when not booting a NixOS system) or with an empty string, causing
|
||||
# systemd to bypass its verification code that checks whether the next file is a systemd
|
||||
# and using its compiled-in value
|
||||
services.initrd-switch-root.serviceConfig = {
|
||||
EnvironmentFile = "-/etc/switch-root.conf";
|
||||
ExecStart = [
|
||||
""
|
||||
''systemctl --no-block switch-root /sysroot "''${NEW_INIT}"''
|
||||
];
|
||||
};
|
||||
|
||||
services.panic-on-fail = {
|
||||
wantedBy = ["emergency.target"];
|
||||
unitConfig = {
|
||||
DefaultDependencies = false;
|
||||
ConditionKernelCommandLine = [
|
||||
"|boot.panic_on_fail"
|
||||
"|stage1panic"
|
||||
];
|
||||
};
|
||||
script = ''
|
||||
echo c > /proc/sysrq-trigger
|
||||
'';
|
||||
serviceConfig.Type = "oneshot";
|
||||
};
|
||||
};
|
||||
|
||||
boot.kernelParams = lib.mkIf (config.boot.resumeDevice != "") [ "resume=${config.boot.resumeDevice}" ];
|
||||
};
|
||||
}
|
||||
131
nixos/modules/system/boot/systemd/journald.nix
Normal file
131
nixos/modules/system/boot/systemd/journald.nix
Normal file
|
|
@ -0,0 +1,131 @@
|
|||
{ config, lib, pkgs, ... }:
|
||||
|
||||
with lib;
|
||||
|
||||
let
|
||||
cfg = config.services.journald;
|
||||
in {
|
||||
options = {
|
||||
services.journald.console = mkOption {
|
||||
default = "";
|
||||
type = types.str;
|
||||
description = "If non-empty, write log messages to the specified TTY device.";
|
||||
};
|
||||
|
||||
services.journald.rateLimitInterval = mkOption {
|
||||
default = "30s";
|
||||
type = types.str;
|
||||
description = ''
|
||||
Configures the rate limiting interval that is applied to all
|
||||
messages generated on the system. This rate limiting is applied
|
||||
per-service, so that two services which log do not interfere with
|
||||
each other's limit. The value may be specified in the following
|
||||
units: s, min, h, ms, us. To turn off any kind of rate limiting,
|
||||
set either value to 0.
|
||||
|
||||
See <option>services.journald.rateLimitBurst</option> for important
|
||||
considerations when setting this value.
|
||||
'';
|
||||
};
|
||||
|
||||
services.journald.rateLimitBurst = mkOption {
|
||||
default = 10000;
|
||||
type = types.int;
|
||||
description = ''
|
||||
Configures the rate limiting burst limit (number of messages per
|
||||
interval) that is applied to all messages generated on the system.
|
||||
This rate limiting is applied per-service, so that two services
|
||||
which log do not interfere with each other's limit.
|
||||
|
||||
Note that the effective rate limit is multiplied by a factor derived
|
||||
from the available free disk space for the journal as described on
|
||||
<link xlink:href="https://www.freedesktop.org/software/systemd/man/journald.conf.html">
|
||||
journald.conf(5)</link>.
|
||||
|
||||
Note that the total amount of logs stored is limited by journald settings
|
||||
such as <literal>SystemMaxUse</literal>, which defaults to a 4 GB cap.
|
||||
|
||||
It is thus recommended to compute what period of time that you will be
|
||||
able to store logs for when an application logs at full burst rate.
|
||||
With default settings for log lines that are 100 Bytes long, this can
|
||||
amount to just a few hours.
|
||||
'';
|
||||
};
|
||||
|
||||
services.journald.extraConfig = mkOption {
|
||||
default = "";
|
||||
type = types.lines;
|
||||
example = "Storage=volatile";
|
||||
description = ''
|
||||
Extra config options for systemd-journald. See man journald.conf
|
||||
for available options.
|
||||
'';
|
||||
};
|
||||
|
||||
services.journald.enableHttpGateway = mkOption {
|
||||
default = false;
|
||||
type = types.bool;
|
||||
description = ''
|
||||
Whether to enable the HTTP gateway to the journal.
|
||||
'';
|
||||
};
|
||||
|
||||
services.journald.forwardToSyslog = mkOption {
|
||||
default = config.services.rsyslogd.enable || config.services.syslog-ng.enable;
|
||||
defaultText = literalExpression "services.rsyslogd.enable || services.syslog-ng.enable";
|
||||
type = types.bool;
|
||||
description = ''
|
||||
Whether to forward log messages to syslog.
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
config = {
|
||||
systemd.additionalUpstreamSystemUnits = [
|
||||
"systemd-journald.socket"
|
||||
"systemd-journald@.socket"
|
||||
"systemd-journald-varlink@.socket"
|
||||
"systemd-journald.service"
|
||||
"systemd-journald@.service"
|
||||
"systemd-journal-flush.service"
|
||||
"systemd-journal-catalog-update.service"
|
||||
] ++ (optional (!config.boot.isContainer) "systemd-journald-audit.socket") ++ [
|
||||
"systemd-journald-dev-log.socket"
|
||||
"syslog.socket"
|
||||
] ++ optionals cfg.enableHttpGateway [
|
||||
"systemd-journal-gatewayd.socket"
|
||||
"systemd-journal-gatewayd.service"
|
||||
];
|
||||
|
||||
environment.etc = {
|
||||
"systemd/journald.conf".text = ''
|
||||
[Journal]
|
||||
Storage=persistent
|
||||
RateLimitInterval=${cfg.rateLimitInterval}
|
||||
RateLimitBurst=${toString cfg.rateLimitBurst}
|
||||
${optionalString (cfg.console != "") ''
|
||||
ForwardToConsole=yes
|
||||
TTYPath=${cfg.console}
|
||||
''}
|
||||
${optionalString (cfg.forwardToSyslog) ''
|
||||
ForwardToSyslog=yes
|
||||
''}
|
||||
${cfg.extraConfig}
|
||||
'';
|
||||
};
|
||||
|
||||
users.groups.systemd-journal.gid = config.ids.gids.systemd-journal;
|
||||
users.users.systemd-journal-gateway.uid = config.ids.uids.systemd-journal-gateway;
|
||||
users.users.systemd-journal-gateway.group = "systemd-journal-gateway";
|
||||
users.groups.systemd-journal-gateway.gid = config.ids.gids.systemd-journal-gateway;
|
||||
|
||||
systemd.sockets.systemd-journal-gatewayd.wantedBy =
|
||||
optional cfg.enableHttpGateway "sockets.target";
|
||||
|
||||
systemd.services.systemd-journal-flush.restartIfChanged = false;
|
||||
systemd.services.systemd-journald.restartTriggers = [ config.environment.etc."systemd/journald.conf".source ];
|
||||
systemd.services.systemd-journald.stopIfChanged = false;
|
||||
systemd.services."systemd-journald@".restartTriggers = [ config.environment.etc."systemd/journald.conf".source ];
|
||||
systemd.services."systemd-journald@".stopIfChanged = false;
|
||||
};
|
||||
}
|
||||
117
nixos/modules/system/boot/systemd/logind.nix
Normal file
117
nixos/modules/system/boot/systemd/logind.nix
Normal file
|
|
@ -0,0 +1,117 @@
|
|||
{ config, lib, pkgs, utils, ... }:
|
||||
|
||||
with lib;
|
||||
|
||||
let
|
||||
cfg = config.services.logind;
|
||||
|
||||
logindHandlerType = types.enum [
|
||||
"ignore" "poweroff" "reboot" "halt" "kexec" "suspend"
|
||||
"hibernate" "hybrid-sleep" "suspend-then-hibernate" "lock"
|
||||
];
|
||||
in
|
||||
{
|
||||
options = {
|
||||
services.logind.extraConfig = mkOption {
|
||||
default = "";
|
||||
type = types.lines;
|
||||
example = "IdleAction=lock";
|
||||
description = ''
|
||||
Extra config options for systemd-logind. See
|
||||
<link xlink:href="https://www.freedesktop.org/software/systemd/man/logind.conf.html">
|
||||
logind.conf(5)</link> for available options.
|
||||
'';
|
||||
};
|
||||
|
||||
services.logind.killUserProcesses = mkOption {
|
||||
default = false;
|
||||
type = types.bool;
|
||||
description = ''
|
||||
Specifies whether the processes of a user should be killed
|
||||
when the user logs out. If true, the scope unit corresponding
|
||||
to the session and all processes inside that scope will be
|
||||
terminated. If false, the scope is "abandoned" (see
|
||||
<link xlink:href="https://www.freedesktop.org/software/systemd/man/systemd.scope.html#">
|
||||
systemd.scope(5)</link>), and processes are not killed.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
See <link xlink:href="https://www.freedesktop.org/software/systemd/man/logind.conf.html#KillUserProcesses=">logind.conf(5)</link>
|
||||
for more details.
|
||||
'';
|
||||
};
|
||||
|
||||
services.logind.lidSwitch = mkOption {
|
||||
default = "suspend";
|
||||
example = "ignore";
|
||||
type = logindHandlerType;
|
||||
|
||||
description = ''
|
||||
Specifies what to be done when the laptop lid is closed.
|
||||
'';
|
||||
};
|
||||
|
||||
services.logind.lidSwitchDocked = mkOption {
|
||||
default = "ignore";
|
||||
example = "suspend";
|
||||
type = logindHandlerType;
|
||||
|
||||
description = ''
|
||||
Specifies what to be done when the laptop lid is closed
|
||||
and another screen is added.
|
||||
'';
|
||||
};
|
||||
|
||||
services.logind.lidSwitchExternalPower = mkOption {
|
||||
default = cfg.lidSwitch;
|
||||
defaultText = literalExpression "services.logind.lidSwitch";
|
||||
example = "ignore";
|
||||
type = logindHandlerType;
|
||||
|
||||
description = ''
|
||||
Specifies what to do when the laptop lid is closed and the system is
|
||||
on external power. By default use the same action as specified in
|
||||
services.logind.lidSwitch.
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
config = {
|
||||
systemd.additionalUpstreamSystemUnits = [
|
||||
"systemd-logind.service"
|
||||
"autovt@.service"
|
||||
"systemd-user-sessions.service"
|
||||
] ++ optionals config.systemd.package.withImportd [
|
||||
"dbus-org.freedesktop.import1.service"
|
||||
] ++ optionals config.systemd.package.withMachined [
|
||||
"dbus-org.freedesktop.machine1.service"
|
||||
] ++ [
|
||||
"dbus-org.freedesktop.login1.service"
|
||||
"user@.service"
|
||||
"user-runtime-dir@.service"
|
||||
];
|
||||
|
||||
environment.etc = {
|
||||
"systemd/logind.conf".text = ''
|
||||
[Login]
|
||||
KillUserProcesses=${if cfg.killUserProcesses then "yes" else "no"}
|
||||
HandleLidSwitch=${cfg.lidSwitch}
|
||||
HandleLidSwitchDocked=${cfg.lidSwitchDocked}
|
||||
HandleLidSwitchExternalPower=${cfg.lidSwitchExternalPower}
|
||||
${cfg.extraConfig}
|
||||
'';
|
||||
};
|
||||
|
||||
# Restarting systemd-logind breaks X11
|
||||
# - upstream commit: https://cgit.freedesktop.org/xorg/xserver/commit/?id=dc48bd653c7e101
|
||||
# - systemd announcement: https://github.com/systemd/systemd/blob/22043e4317ecd2bc7834b48a6d364de76bb26d91/NEWS#L103-L112
|
||||
# - this might be addressed in the future by xorg
|
||||
#systemd.services.systemd-logind.restartTriggers = [ config.environment.etc."systemd/logind.conf".source ];
|
||||
systemd.services.systemd-logind.restartIfChanged = false;
|
||||
systemd.services.systemd-logind.stopIfChanged = false;
|
||||
|
||||
# The user-runtime-dir@ service is managed by systemd-logind we should not touch it or else we break the users' sessions.
|
||||
systemd.services."user-runtime-dir@".stopIfChanged = false;
|
||||
systemd.services."user-runtime-dir@".restartIfChanged = false;
|
||||
};
|
||||
}
|
||||
133
nixos/modules/system/boot/systemd/nspawn.nix
Normal file
133
nixos/modules/system/boot/systemd/nspawn.nix
Normal file
|
|
@ -0,0 +1,133 @@
|
|||
{ config, lib, pkgs, utils, ...}:
|
||||
|
||||
with utils.systemdUtils.unitOptions;
|
||||
with utils.systemdUtils.lib;
|
||||
with lib;
|
||||
|
||||
let
|
||||
cfg = config.systemd.nspawn;
|
||||
|
||||
checkExec = checkUnitConfig "Exec" [
|
||||
(assertOnlyFields [
|
||||
"Boot" "ProcessTwo" "Parameters" "Environment" "User" "WorkingDirectory"
|
||||
"PivotRoot" "Capability" "DropCapability" "NoNewPrivileges" "KillSignal"
|
||||
"Personality" "MachineId" "PrivateUsers" "NotifyReady" "SystemCallFilter"
|
||||
"LimitCPU" "LimitFSIZE" "LimitDATA" "LimitSTACK" "LimitCORE" "LimitRSS"
|
||||
"LimitNOFILE" "LimitAS" "LimitNPROC" "LimitMEMLOCK" "LimitLOCKS"
|
||||
"LimitSIGPENDING" "LimitMSGQUEUE" "LimitNICE" "LimitRTPRIO" "LimitRTTIME"
|
||||
"OOMScoreAdjust" "CPUAffinity" "Hostname" "ResolvConf" "Timezone"
|
||||
"LinkJournal" "Ephemeral" "AmbientCapability"
|
||||
])
|
||||
(assertValueOneOf "Boot" boolValues)
|
||||
(assertValueOneOf "ProcessTwo" boolValues)
|
||||
(assertValueOneOf "NotifyReady" boolValues)
|
||||
];
|
||||
|
||||
checkFiles = checkUnitConfig "Files" [
|
||||
(assertOnlyFields [
|
||||
"ReadOnly" "Volatile" "Bind" "BindReadOnly" "TemporaryFileSystem"
|
||||
"Overlay" "OverlayReadOnly" "PrivateUsersChown" "BindUser"
|
||||
"Inaccessible" "PrivateUserOwnership"
|
||||
])
|
||||
(assertValueOneOf "ReadOnly" boolValues)
|
||||
(assertValueOneOf "Volatile" (boolValues ++ [ "state" ]))
|
||||
(assertValueOneOf "PrivateUsersChown" boolValues)
|
||||
(assertValueOneOf "PrivateUserOwnership" [ "off" "chown" "map" "auto" ])
|
||||
];
|
||||
|
||||
checkNetwork = checkUnitConfig "Network" [
|
||||
(assertOnlyFields [
|
||||
"Private" "VirtualEthernet" "VirtualEthernetExtra" "Interface" "MACVLAN"
|
||||
"IPVLAN" "Bridge" "Zone" "Port"
|
||||
])
|
||||
(assertValueOneOf "Private" boolValues)
|
||||
(assertValueOneOf "VirtualEthernet" boolValues)
|
||||
];
|
||||
|
||||
instanceOptions = {
|
||||
options = sharedOptions // {
|
||||
execConfig = mkOption {
|
||||
default = {};
|
||||
example = { Parameters = "/bin/sh"; };
|
||||
type = types.addCheck (types.attrsOf unitOption) checkExec;
|
||||
description = ''
|
||||
Each attribute in this set specifies an option in the
|
||||
<literal>[Exec]</literal> section of this unit. See
|
||||
<citerefentry><refentrytitle>systemd.nspawn</refentrytitle>
|
||||
<manvolnum>5</manvolnum></citerefentry> for details.
|
||||
'';
|
||||
};
|
||||
|
||||
filesConfig = mkOption {
|
||||
default = {};
|
||||
example = { Bind = [ "/home/alice" ]; };
|
||||
type = types.addCheck (types.attrsOf unitOption) checkFiles;
|
||||
description = ''
|
||||
Each attribute in this set specifies an option in the
|
||||
<literal>[Files]</literal> section of this unit. See
|
||||
<citerefentry><refentrytitle>systemd.nspawn</refentrytitle>
|
||||
<manvolnum>5</manvolnum></citerefentry> for details.
|
||||
'';
|
||||
};
|
||||
|
||||
networkConfig = mkOption {
|
||||
default = {};
|
||||
example = { Private = false; };
|
||||
type = types.addCheck (types.attrsOf unitOption) checkNetwork;
|
||||
description = ''
|
||||
Each attribute in this set specifies an option in the
|
||||
<literal>[Network]</literal> section of this unit. See
|
||||
<citerefentry><refentrytitle>systemd.nspawn</refentrytitle>
|
||||
<manvolnum>5</manvolnum></citerefentry> for details.
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
instanceToUnit = name: def:
|
||||
let base = {
|
||||
text = ''
|
||||
[Exec]
|
||||
${attrsToSection def.execConfig}
|
||||
|
||||
[Files]
|
||||
${attrsToSection def.filesConfig}
|
||||
|
||||
[Network]
|
||||
${attrsToSection def.networkConfig}
|
||||
'';
|
||||
} // def;
|
||||
in base // { unit = makeUnit name base; };
|
||||
|
||||
in {
|
||||
|
||||
options = {
|
||||
|
||||
systemd.nspawn = mkOption {
|
||||
default = {};
|
||||
type = with types; attrsOf (submodule instanceOptions);
|
||||
description = "Definition of systemd-nspawn configurations.";
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
config =
|
||||
let
|
||||
units = mapAttrs' (n: v: let nspawnFile = "${n}.nspawn"; in nameValuePair nspawnFile (instanceToUnit nspawnFile v)) cfg;
|
||||
in
|
||||
mkMerge [
|
||||
(mkIf (cfg != {}) {
|
||||
environment.etc."systemd/nspawn".source = mkIf (cfg != {}) (generateUnits {
|
||||
allowCollisions = false;
|
||||
type = "nspawn";
|
||||
inherit units;
|
||||
upstreamUnits = [];
|
||||
upstreamWants = [];
|
||||
});
|
||||
})
|
||||
{
|
||||
systemd.targets.multi-user.wants = [ "machines.target" ];
|
||||
}
|
||||
];
|
||||
}
|
||||
58
nixos/modules/system/boot/systemd/shutdown.nix
Normal file
58
nixos/modules/system/boot/systemd/shutdown.nix
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
{ config, lib, utils, pkgs, ... }: let
|
||||
|
||||
cfg = config.systemd.shutdownRamfs;
|
||||
|
||||
ramfsContents = let
|
||||
storePaths = map (p: "${p}\n") cfg.storePaths;
|
||||
contents = lib.mapAttrsToList (_: v: "${v.source}\n${v.target}") (lib.filterAttrs (_: v: v.enable) cfg.contents);
|
||||
in pkgs.writeText "shutdown-ramfs-contents" (lib.concatStringsSep "\n" (storePaths ++ contents));
|
||||
|
||||
in {
|
||||
options.systemd.shutdownRamfs = {
|
||||
enable = lib.mkEnableOption "pivoting back to an initramfs for shutdown" // { default = true; };
|
||||
contents = lib.mkOption {
|
||||
description = "Set of files that have to be linked into the shutdown ramfs";
|
||||
example = lib.literalExpression ''
|
||||
{
|
||||
"/lib/systemd/system-shutdown/zpool-sync-shutdown".source = writeShellScript "zpool" "exec ''${zfs}/bin/zpool sync"
|
||||
}
|
||||
'';
|
||||
type = utils.systemdUtils.types.initrdContents;
|
||||
};
|
||||
|
||||
storePaths = lib.mkOption {
|
||||
description = ''
|
||||
Store paths to copy into the shutdown ramfs as well.
|
||||
'';
|
||||
type = lib.types.listOf lib.types.singleLineStr;
|
||||
default = [];
|
||||
};
|
||||
};
|
||||
|
||||
config = lib.mkIf cfg.enable {
|
||||
systemd.shutdownRamfs.contents."/shutdown".source = "${config.systemd.package}/lib/systemd/systemd-shutdown";
|
||||
systemd.shutdownRamfs.storePaths = [pkgs.runtimeShell "${pkgs.coreutils}/bin"];
|
||||
|
||||
systemd.services.generate-shutdown-ramfs = {
|
||||
description = "Generate shutdown ramfs";
|
||||
wantedBy = [ "shutdown.target" ];
|
||||
before = [ "shutdown.target" ];
|
||||
unitConfig = {
|
||||
DefaultDependencies = false;
|
||||
ConditionFileIsExecutable = [
|
||||
"!/run/initramfs/shutdown"
|
||||
];
|
||||
};
|
||||
|
||||
path = [pkgs.util-linux pkgs.makeInitrdNGTool];
|
||||
serviceConfig.Type = "oneshot";
|
||||
script = ''
|
||||
mkdir -p /run/initramfs
|
||||
if ! mountpoint -q /run/initramfs; then
|
||||
mount -t tmpfs tmpfs /run/initramfs
|
||||
fi
|
||||
make-initrd-ng ${ramfsContents} /run/initramfs
|
||||
'';
|
||||
};
|
||||
};
|
||||
}
|
||||
120
nixos/modules/system/boot/systemd/tmpfiles.nix
Normal file
120
nixos/modules/system/boot/systemd/tmpfiles.nix
Normal file
|
|
@ -0,0 +1,120 @@
|
|||
{ config, lib, pkgs, utils, ... }:
|
||||
|
||||
with lib;
|
||||
|
||||
let
|
||||
cfg = config.systemd.tmpfiles;
|
||||
systemd = config.systemd.package;
|
||||
in
|
||||
{
|
||||
options = {
|
||||
systemd.tmpfiles.rules = mkOption {
|
||||
type = types.listOf types.str;
|
||||
default = [];
|
||||
example = [ "d /tmp 1777 root root 10d" ];
|
||||
description = ''
|
||||
Rules for creation, deletion and cleaning of volatile and temporary files
|
||||
automatically. See
|
||||
<citerefentry><refentrytitle>tmpfiles.d</refentrytitle><manvolnum>5</manvolnum></citerefentry>
|
||||
for the exact format.
|
||||
'';
|
||||
};
|
||||
|
||||
systemd.tmpfiles.packages = mkOption {
|
||||
type = types.listOf types.package;
|
||||
default = [];
|
||||
example = literalExpression "[ pkgs.lvm2 ]";
|
||||
apply = map getLib;
|
||||
description = ''
|
||||
List of packages containing <command>systemd-tmpfiles</command> rules.
|
||||
|
||||
All files ending in .conf found in
|
||||
<filename><replaceable>pkg</replaceable>/lib/tmpfiles.d</filename>
|
||||
will be included.
|
||||
If this folder does not exist or does not contain any files an error will be returned instead.
|
||||
|
||||
If a <filename>lib</filename> output is available, rules are searched there and only there.
|
||||
If there is no <filename>lib</filename> output it will fall back to <filename>out</filename>
|
||||
and if that does not exist either, the default output will be used.
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
config = {
|
||||
systemd.additionalUpstreamSystemUnits = [
|
||||
"systemd-tmpfiles-clean.service"
|
||||
"systemd-tmpfiles-clean.timer"
|
||||
"systemd-tmpfiles-setup.service"
|
||||
"systemd-tmpfiles-setup-dev.service"
|
||||
];
|
||||
|
||||
systemd.additionalUpstreamUserUnits = [
|
||||
"systemd-tmpfiles-clean.service"
|
||||
"systemd-tmpfiles-clean.timer"
|
||||
"systemd-tmpfiles-setup.service"
|
||||
];
|
||||
|
||||
environment.etc = {
|
||||
"tmpfiles.d".source = (pkgs.symlinkJoin {
|
||||
name = "tmpfiles.d";
|
||||
paths = map (p: p + "/lib/tmpfiles.d") cfg.packages;
|
||||
postBuild = ''
|
||||
for i in $(cat $pathsPath); do
|
||||
(test -d "$i" && test $(ls "$i"/*.conf | wc -l) -ge 1) || (
|
||||
echo "ERROR: The path '$i' from systemd.tmpfiles.packages contains no *.conf files."
|
||||
exit 1
|
||||
)
|
||||
done
|
||||
'' + concatMapStrings (name: optionalString (hasPrefix "tmpfiles.d/" name) ''
|
||||
rm -f $out/${removePrefix "tmpfiles.d/" name}
|
||||
'') config.system.build.etc.passthru.targets;
|
||||
}) + "/*";
|
||||
};
|
||||
|
||||
systemd.tmpfiles.packages = [
|
||||
# Default tmpfiles rules provided by systemd
|
||||
(pkgs.runCommand "systemd-default-tmpfiles" {} ''
|
||||
mkdir -p $out/lib/tmpfiles.d
|
||||
cd $out/lib/tmpfiles.d
|
||||
|
||||
ln -s "${systemd}/example/tmpfiles.d/home.conf"
|
||||
ln -s "${systemd}/example/tmpfiles.d/journal-nocow.conf"
|
||||
ln -s "${systemd}/example/tmpfiles.d/static-nodes-permissions.conf"
|
||||
ln -s "${systemd}/example/tmpfiles.d/systemd.conf"
|
||||
ln -s "${systemd}/example/tmpfiles.d/systemd-nologin.conf"
|
||||
ln -s "${systemd}/example/tmpfiles.d/systemd-nspawn.conf"
|
||||
ln -s "${systemd}/example/tmpfiles.d/systemd-tmp.conf"
|
||||
ln -s "${systemd}/example/tmpfiles.d/tmp.conf"
|
||||
ln -s "${systemd}/example/tmpfiles.d/var.conf"
|
||||
ln -s "${systemd}/example/tmpfiles.d/x11.conf"
|
||||
'')
|
||||
# User-specified tmpfiles rules
|
||||
(pkgs.writeTextFile {
|
||||
name = "nixos-tmpfiles.d";
|
||||
destination = "/lib/tmpfiles.d/00-nixos.conf";
|
||||
text = ''
|
||||
# This file is created automatically and should not be modified.
|
||||
# Please change the option ‘systemd.tmpfiles.rules’ instead.
|
||||
|
||||
${concatStringsSep "\n" cfg.rules}
|
||||
'';
|
||||
})
|
||||
];
|
||||
|
||||
systemd.tmpfiles.rules = [
|
||||
"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 - - - - -"
|
||||
];
|
||||
};
|
||||
}
|
||||
153
nixos/modules/system/boot/systemd/user.nix
Normal file
153
nixos/modules/system/boot/systemd/user.nix
Normal file
|
|
@ -0,0 +1,153 @@
|
|||
{ config, lib, pkgs, utils, ... }:
|
||||
with utils;
|
||||
with systemdUtils.unitOptions;
|
||||
with lib;
|
||||
|
||||
let
|
||||
cfg = config.systemd.user;
|
||||
|
||||
systemd = config.systemd.package;
|
||||
|
||||
inherit
|
||||
(systemdUtils.lib)
|
||||
makeUnit
|
||||
generateUnits
|
||||
targetToUnit
|
||||
serviceToUnit
|
||||
socketToUnit
|
||||
timerToUnit
|
||||
pathToUnit;
|
||||
|
||||
upstreamUserUnits = [
|
||||
"app.slice"
|
||||
"background.slice"
|
||||
"basic.target"
|
||||
"bluetooth.target"
|
||||
"default.target"
|
||||
"exit.target"
|
||||
"graphical-session-pre.target"
|
||||
"graphical-session.target"
|
||||
"paths.target"
|
||||
"printer.target"
|
||||
"session.slice"
|
||||
"shutdown.target"
|
||||
"smartcard.target"
|
||||
"sockets.target"
|
||||
"sound.target"
|
||||
"systemd-exit.service"
|
||||
"timers.target"
|
||||
"xdg-desktop-autostart.target"
|
||||
] ++ config.systemd.additionalUpstreamUserUnits;
|
||||
in {
|
||||
options = {
|
||||
systemd.user.extraConfig = mkOption {
|
||||
default = "";
|
||||
type = types.lines;
|
||||
example = "DefaultCPUAccounting=yes";
|
||||
description = ''
|
||||
Extra config options for systemd user instances. See man systemd-user.conf for
|
||||
available options.
|
||||
'';
|
||||
};
|
||||
|
||||
systemd.user.units = mkOption {
|
||||
description = "Definition of systemd per-user units.";
|
||||
default = {};
|
||||
type = systemdUtils.types.units;
|
||||
};
|
||||
|
||||
systemd.user.paths = mkOption {
|
||||
default = {};
|
||||
type = systemdUtils.types.paths;
|
||||
description = "Definition of systemd per-user path units.";
|
||||
};
|
||||
|
||||
systemd.user.services = mkOption {
|
||||
default = {};
|
||||
type = systemdUtils.types.services;
|
||||
description = "Definition of systemd per-user service units.";
|
||||
};
|
||||
|
||||
systemd.user.slices = mkOption {
|
||||
default = {};
|
||||
type = systemdUtils.types.slices;
|
||||
description = "Definition of systemd per-user slice units.";
|
||||
};
|
||||
|
||||
systemd.user.sockets = mkOption {
|
||||
default = {};
|
||||
type = systemdUtils.types.sockets;
|
||||
description = "Definition of systemd per-user socket units.";
|
||||
};
|
||||
|
||||
systemd.user.targets = mkOption {
|
||||
default = {};
|
||||
type = systemdUtils.types.targets;
|
||||
description = "Definition of systemd per-user target units.";
|
||||
};
|
||||
|
||||
systemd.user.timers = mkOption {
|
||||
default = {};
|
||||
type = systemdUtils.types.timers;
|
||||
description = "Definition of systemd per-user timer units.";
|
||||
};
|
||||
|
||||
systemd.additionalUpstreamUserUnits = mkOption {
|
||||
default = [];
|
||||
type = types.listOf types.str;
|
||||
example = [];
|
||||
description = ''
|
||||
Additional units shipped with systemd that should be enabled for per-user systemd instances.
|
||||
'';
|
||||
internal = true;
|
||||
};
|
||||
};
|
||||
|
||||
config = {
|
||||
systemd.additionalUpstreamSystemUnits = [
|
||||
"user.slice"
|
||||
];
|
||||
|
||||
environment.etc = {
|
||||
"systemd/user".source = generateUnits {
|
||||
type = "user";
|
||||
inherit (cfg) units;
|
||||
upstreamUnits = upstreamUserUnits;
|
||||
upstreamWants = [];
|
||||
};
|
||||
|
||||
"systemd/user.conf".text = ''
|
||||
[Manager]
|
||||
${cfg.extraConfig}
|
||||
'';
|
||||
};
|
||||
|
||||
systemd.user.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;
|
||||
|
||||
# Generate timer units for all services that have a ‘startAt’ value.
|
||||
systemd.user.timers =
|
||||
mapAttrs (name: service: {
|
||||
wantedBy = ["timers.target"];
|
||||
timerConfig.OnCalendar = service.startAt;
|
||||
})
|
||||
(filterAttrs (name: service: service.startAt != []) cfg.services);
|
||||
|
||||
# Provide the systemd-user PAM service, required to run systemd
|
||||
# user instances.
|
||||
security.pam.services.systemd-user =
|
||||
{ # Ensure that pam_systemd gets included. This is special-cased
|
||||
# in systemd to provide XDG_RUNTIME_DIR.
|
||||
startSession = true;
|
||||
};
|
||||
|
||||
# Some overrides to upstream units.
|
||||
systemd.services."user@".restartIfChanged = false;
|
||||
systemd.services.systemd-user-sessions.restartIfChanged = false; # Restart kills all active sessions.
|
||||
};
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue