depot/third_party/nixpkgs/nixos/modules/system/boot/systemd/user.nix

235 lines
7 KiB
Nix
Raw Normal View History

{ 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
sliceToUnit
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;
writeTmpfiles = { rules, user ? null }:
let
suffix = if user == null then "" else "-${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.
${concatStringsSep "\n" rules}
'';
};
in {
options = {
systemd.user.extraConfig = mkOption {
default = "";
type = types.lines;
example = "DefaultCPUAccounting=yes";
description = lib.mdDoc ''
Extra config options for systemd user instances. See {manpage}`systemd-user.conf(5)` for
available options.
'';
};
systemd.user.units = mkOption {
description = lib.mdDoc "Definition of systemd per-user units.";
default = {};
type = systemdUtils.types.units;
};
systemd.user.paths = mkOption {
default = {};
type = systemdUtils.types.paths;
description = lib.mdDoc "Definition of systemd per-user path units.";
};
systemd.user.services = mkOption {
default = {};
type = systemdUtils.types.services;
description = lib.mdDoc "Definition of systemd per-user service units.";
};
systemd.user.slices = mkOption {
default = {};
type = systemdUtils.types.slices;
description = lib.mdDoc "Definition of systemd per-user slice units.";
};
systemd.user.sockets = mkOption {
default = {};
type = systemdUtils.types.sockets;
description = lib.mdDoc "Definition of systemd per-user socket units.";
};
systemd.user.targets = mkOption {
default = {};
type = systemdUtils.types.targets;
description = lib.mdDoc "Definition of systemd per-user target units.";
};
systemd.user.timers = mkOption {
default = {};
type = systemdUtils.types.timers;
description = lib.mdDoc "Definition of systemd per-user timer units.";
};
systemd.user.tmpfiles = {
rules = mkOption {
type = types.listOf types.str;
default = [];
example = [ "D %C - - - 7d" ];
description = lib.mdDoc ''
Global user rules for creation, deletion and cleaning of volatile and
temporary files automatically. See
{manpage}`tmpfiles.d(5)`
for the exact format.
'';
};
users = mkOption {
description = mdDoc ''
Per-user rules for creation, deletion and cleaning of volatile and
temporary files automatically.
'';
default = {};
type = types.attrsOf (types.submodule {
options = {
rules = mkOption {
type = types.listOf types.str;
default = [];
example = [ "D %C - - - 7d" ];
description = mdDoc ''
Per-user rules for creation, deletion and cleaning of volatile and
temporary files automatically. See
{manpage}`tmpfiles.d(5)`
for the exact format.
'';
};
};
});
};
};
systemd.additionalUpstreamUserUnits = mkOption {
default = [];
type = types.listOf types.str;
example = [];
description = lib.mdDoc ''
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;
# 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 =
optional
(cfg.tmpfiles.rules != [] || any (cfg': cfg'.rules != []) (attrValues cfg.tmpfiles.users))
"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 =
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 =
mapAttrs
(user: cfg': {
packages = optional (cfg'.rules != []) (writeTmpfiles {
inherit (cfg') rules;
inherit user;
});
})
cfg.tmpfiles.users;
};
}