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:
Anton Arapov 2021-04-03 12:58:10 +02:00 committed by Alan Daniels
commit 56de2bcd43
30691 changed files with 3076956 additions and 0 deletions

View 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";
};
}

View 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";
};
}

View 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}" ];
};
}

View 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;
};
}

View 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;
};
}

View 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" ];
}
];
}

View 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
'';
};
};
}

View 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 - - - - -"
];
};
}

View 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.
};
}