mirror of
https://github.com/NixOS/nixpkgs.git
synced 2026-08-31 12:44:44 +00:00
Replace `systemd.user.extraConfig` with a freeform `systemd.user.settings.Manager` submodule, rendered via `utils.systemdUtils.lib.settingsToSections`. `extraConfig` is removed via `mkRemovedOptionModule`. Mirrors the existing `systemd.settings.Manager` migration of the system-side manager. Updates the two in-tree consumers (`nixos/modules/testing/test-instrumentation.nix` and `nixos/tests/systemd.nix`) to the new option. Adds `nixos/tests/systemd-user-settings` to assert the rendered `user.conf` contents.
276 lines
8.2 KiB
Nix
276 lines
8.2 KiB
Nix
{
|
||
config,
|
||
lib,
|
||
pkgs,
|
||
utils,
|
||
...
|
||
}:
|
||
|
||
let
|
||
cfg = config.systemd.user;
|
||
|
||
systemd = config.systemd.package;
|
||
|
||
inherit (utils.systemdUtils.lib)
|
||
generateUnits
|
||
targetToUnit
|
||
serviceToUnit
|
||
sliceToUnit
|
||
socketToUnit
|
||
timerToUnit
|
||
pathToUnit
|
||
;
|
||
|
||
upstreamUserUnits = [
|
||
"app.slice"
|
||
"background.slice"
|
||
"basic.target"
|
||
"bluetooth.target"
|
||
"capsule@.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;
|
||
|
||
writeTmpfiles =
|
||
{
|
||
rules,
|
||
user ? null,
|
||
}:
|
||
let
|
||
suffix = lib.optionalString (user != null) "-${user}";
|
||
in
|
||
pkgs.writeTextFile {
|
||
name = "nixos-user-tmpfiles.d${suffix}";
|
||
destination = "/etc/xdg/user-tmpfiles.d/00-nixos${suffix}.conf";
|
||
text = ''
|
||
# This file is created automatically and should not be modified.
|
||
# Please change the options ‘systemd.user.tmpfiles’ instead.
|
||
${lib.concatStringsSep "\n" rules}
|
||
'';
|
||
};
|
||
in
|
||
{
|
||
imports = [
|
||
(lib.mkRemovedOptionModule [
|
||
"systemd"
|
||
"user"
|
||
"extraConfig"
|
||
] "Use systemd.user.settings.Manager instead.")
|
||
];
|
||
|
||
options = {
|
||
systemd.user.settings.Manager = lib.mkOption {
|
||
default = { };
|
||
type = lib.types.submodule {
|
||
freeformType = lib.types.attrsOf utils.systemdUtils.unitOptions.unitOption;
|
||
};
|
||
example = {
|
||
DefaultTimeoutStartSec = 60;
|
||
};
|
||
description = ''
|
||
Settings for systemd user instances. See {manpage}`systemd-user.conf(5)`
|
||
for available options.
|
||
'';
|
||
};
|
||
|
||
systemd.user.units = lib.mkOption {
|
||
description = "Definition of systemd per-user units.";
|
||
default = { };
|
||
type = utils.systemdUtils.types.units;
|
||
};
|
||
|
||
systemd.user.paths = lib.mkOption {
|
||
default = { };
|
||
type = utils.systemdUtils.types.paths;
|
||
description = "Definition of systemd per-user path units.";
|
||
};
|
||
|
||
systemd.user.services = lib.mkOption {
|
||
default = { };
|
||
type = utils.systemdUtils.types.services;
|
||
description = "Definition of systemd per-user service units.";
|
||
};
|
||
|
||
systemd.user.slices = lib.mkOption {
|
||
default = { };
|
||
type = utils.systemdUtils.types.slices;
|
||
description = "Definition of systemd per-user slice units.";
|
||
};
|
||
|
||
systemd.user.sockets = lib.mkOption {
|
||
default = { };
|
||
type = utils.systemdUtils.types.sockets;
|
||
description = "Definition of systemd per-user socket units.";
|
||
};
|
||
|
||
systemd.user.targets = lib.mkOption {
|
||
default = { };
|
||
type = utils.systemdUtils.types.targets;
|
||
description = "Definition of systemd per-user target units.";
|
||
};
|
||
|
||
systemd.user.timers = lib.mkOption {
|
||
default = { };
|
||
type = utils.systemdUtils.types.timers;
|
||
description = "Definition of systemd per-user timer units.";
|
||
};
|
||
|
||
systemd.user.tmpfiles = {
|
||
enable =
|
||
(lib.mkEnableOption "systemd user units systemd-tmpfiles-setup.service and systemd-tmpfiles-clean.timer")
|
||
// {
|
||
default = true;
|
||
example = false;
|
||
};
|
||
|
||
rules = lib.mkOption {
|
||
type = lib.types.listOf lib.types.str;
|
||
default = [ ];
|
||
example = [ "D %C - - - 7d" ];
|
||
description = ''
|
||
Global user rules for creation, deletion and cleaning of volatile and
|
||
temporary files automatically. See
|
||
{manpage}`tmpfiles.d(5)`
|
||
for the exact format.
|
||
'';
|
||
};
|
||
|
||
users = lib.mkOption {
|
||
description = ''
|
||
Per-user rules for creation, deletion and cleaning of volatile and
|
||
temporary files automatically.
|
||
'';
|
||
default = { };
|
||
type = lib.types.attrsOf (
|
||
lib.types.submodule {
|
||
options = {
|
||
rules = lib.mkOption {
|
||
type = lib.types.listOf lib.types.str;
|
||
default = [ ];
|
||
example = [ "D %C - - - 7d" ];
|
||
description = ''
|
||
Per-user rules for creation, deletion and cleaning of volatile and
|
||
temporary files automatically. See
|
||
{manpage}`tmpfiles.d(5)`
|
||
for the exact format.
|
||
'';
|
||
};
|
||
};
|
||
}
|
||
);
|
||
};
|
||
};
|
||
|
||
systemd.user.generators = lib.mkOption {
|
||
type = lib.types.attrsOf lib.types.path;
|
||
default = { };
|
||
example = {
|
||
systemd-gpt-auto-generator = "/dev/null";
|
||
};
|
||
description = ''
|
||
Definition of systemd generators; see {manpage}`systemd.generator(5)`.
|
||
|
||
For each `NAME = VALUE` pair of the attrSet, a link is generated from
|
||
`/etc/systemd/user-generators/NAME` to `VALUE`.
|
||
'';
|
||
};
|
||
|
||
systemd.additionalUpstreamUserUnits = lib.mkOption {
|
||
default = [ ];
|
||
type = lib.types.listOf lib.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 = utils.systemdUtils.lib.settingsToSections cfg.settings;
|
||
};
|
||
|
||
systemd.user.units =
|
||
lib.mapAttrs' (n: v: lib.nameValuePair "${n}.path" (pathToUnit v)) cfg.paths
|
||
// lib.mapAttrs' (n: v: lib.nameValuePair "${n}.service" (serviceToUnit v)) cfg.services
|
||
// lib.mapAttrs' (n: v: lib.nameValuePair "${n}.slice" (sliceToUnit v)) cfg.slices
|
||
// lib.mapAttrs' (n: v: lib.nameValuePair "${n}.socket" (socketToUnit v)) cfg.sockets
|
||
// lib.mapAttrs' (n: v: lib.nameValuePair "${n}.target" (targetToUnit v)) cfg.targets
|
||
// lib.mapAttrs' (n: v: lib.nameValuePair "${n}.timer" (timerToUnit v)) cfg.timers;
|
||
|
||
systemd.user.timers = {
|
||
# enable systemd user tmpfiles
|
||
systemd-tmpfiles-clean.wantedBy = lib.optional cfg.tmpfiles.enable "timers.target";
|
||
}
|
||
# Generate timer units for all services that have a ‘startAt’ value.
|
||
// (lib.mapAttrs (name: service: {
|
||
wantedBy = [ "timers.target" ];
|
||
timerConfig.OnCalendar = service.startAt;
|
||
}) (lib.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;
|
||
# Disable pam_mount in systemd-user to prevent it from being called
|
||
# multiple times during login, because it will prevent pam_mount from
|
||
# unmounting the previously mounted volumes.
|
||
pamMount = false;
|
||
};
|
||
|
||
# Some overrides to upstream units.
|
||
systemd.services."user@".restartIfChanged = false;
|
||
systemd.services.systemd-user-sessions.restartIfChanged = false; # Restart kills all active sessions.
|
||
|
||
# enable systemd user tmpfiles
|
||
systemd.user.services.systemd-tmpfiles-setup.wantedBy =
|
||
lib.optional cfg.tmpfiles.enable "basic.target";
|
||
|
||
# /run/current-system/sw/etc/xdg is in systemd's $XDG_CONFIG_DIRS so we can
|
||
# write the tmpfiles.d rules for everyone there
|
||
environment.systemPackages = lib.optional (cfg.tmpfiles.rules != [ ]) (writeTmpfiles {
|
||
inherit (cfg.tmpfiles) rules;
|
||
});
|
||
|
||
# /etc/profiles/per-user/$USER/etc/xdg is in systemd's $XDG_CONFIG_DIRS so
|
||
# we can write a single user's tmpfiles.d rules there
|
||
users.users = lib.mapAttrs (user: cfg': {
|
||
packages = lib.optional (cfg'.rules != [ ]) (writeTmpfiles {
|
||
inherit (cfg') rules;
|
||
inherit user;
|
||
});
|
||
}) cfg.tmpfiles.users;
|
||
|
||
system.userActivationScripts.tmpfiles = ''
|
||
${config.systemd.package}/bin/systemd-tmpfiles --user --create --remove
|
||
'';
|
||
};
|
||
}
|