2022-03-30 09:31:56 +00:00
|
|
|
|
{ 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
|
2022-07-14 12:49:19 +00:00
|
|
|
|
sliceToUnit
|
2022-03-30 09:31:56 +00:00
|
|
|
|
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;
|
2023-01-20 10:41:00 +00:00
|
|
|
|
|
|
|
|
|
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}
|
|
|
|
|
'';
|
|
|
|
|
};
|
2022-03-30 09:31:56 +00:00
|
|
|
|
in {
|
|
|
|
|
options = {
|
|
|
|
|
systemd.user.extraConfig = mkOption {
|
|
|
|
|
default = "";
|
|
|
|
|
type = types.lines;
|
|
|
|
|
example = "DefaultCPUAccounting=yes";
|
2022-08-12 12:06:08 +00:00
|
|
|
|
description = lib.mdDoc ''
|
2023-01-11 07:51:40 +00:00
|
|
|
|
Extra config options for systemd user instances. See {manpage}`systemd-user.conf(5)` for
|
2022-03-30 09:31:56 +00:00
|
|
|
|
available options.
|
|
|
|
|
'';
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
systemd.user.units = mkOption {
|
2022-08-12 12:06:08 +00:00
|
|
|
|
description = lib.mdDoc "Definition of systemd per-user units.";
|
2022-03-30 09:31:56 +00:00
|
|
|
|
default = {};
|
2022-04-03 18:54:34 +00:00
|
|
|
|
type = systemdUtils.types.units;
|
2022-03-30 09:31:56 +00:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
systemd.user.paths = mkOption {
|
|
|
|
|
default = {};
|
2022-04-03 18:54:34 +00:00
|
|
|
|
type = systemdUtils.types.paths;
|
2022-08-12 12:06:08 +00:00
|
|
|
|
description = lib.mdDoc "Definition of systemd per-user path units.";
|
2022-03-30 09:31:56 +00:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
systemd.user.services = mkOption {
|
|
|
|
|
default = {};
|
2022-04-03 18:54:34 +00:00
|
|
|
|
type = systemdUtils.types.services;
|
2022-08-12 12:06:08 +00:00
|
|
|
|
description = lib.mdDoc "Definition of systemd per-user service units.";
|
2022-03-30 09:31:56 +00:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
systemd.user.slices = mkOption {
|
|
|
|
|
default = {};
|
2022-04-03 18:54:34 +00:00
|
|
|
|
type = systemdUtils.types.slices;
|
2022-08-12 12:06:08 +00:00
|
|
|
|
description = lib.mdDoc "Definition of systemd per-user slice units.";
|
2022-03-30 09:31:56 +00:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
systemd.user.sockets = mkOption {
|
|
|
|
|
default = {};
|
2022-04-03 18:54:34 +00:00
|
|
|
|
type = systemdUtils.types.sockets;
|
2022-08-12 12:06:08 +00:00
|
|
|
|
description = lib.mdDoc "Definition of systemd per-user socket units.";
|
2022-03-30 09:31:56 +00:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
systemd.user.targets = mkOption {
|
|
|
|
|
default = {};
|
2022-04-03 18:54:34 +00:00
|
|
|
|
type = systemdUtils.types.targets;
|
2022-08-12 12:06:08 +00:00
|
|
|
|
description = lib.mdDoc "Definition of systemd per-user target units.";
|
2022-03-30 09:31:56 +00:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
systemd.user.timers = mkOption {
|
|
|
|
|
default = {};
|
2022-04-03 18:54:34 +00:00
|
|
|
|
type = systemdUtils.types.timers;
|
2022-08-12 12:06:08 +00:00
|
|
|
|
description = lib.mdDoc "Definition of systemd per-user timer units.";
|
2022-03-30 09:31:56 +00:00
|
|
|
|
};
|
|
|
|
|
|
2023-01-20 10:41:00 +00:00
|
|
|
|
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.
|
|
|
|
|
'';
|
|
|
|
|
};
|
|
|
|
|
};
|
|
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
};
|
|
|
|
|
|
2022-03-30 09:31:56 +00:00
|
|
|
|
systemd.additionalUpstreamUserUnits = mkOption {
|
|
|
|
|
default = [];
|
|
|
|
|
type = types.listOf types.str;
|
|
|
|
|
example = [];
|
2022-09-09 14:08:57 +00:00
|
|
|
|
description = lib.mdDoc ''
|
2022-03-30 09:31:56 +00:00
|
|
|
|
Additional units shipped with systemd that should be enabled for per-user systemd instances.
|
|
|
|
|
'';
|
|
|
|
|
internal = true;
|
|
|
|
|
};
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
config = {
|
|
|
|
|
systemd.additionalUpstreamSystemUnits = [
|
|
|
|
|
"user.slice"
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
environment.etc = {
|
2022-04-03 18:54:34 +00:00
|
|
|
|
"systemd/user".source = generateUnits {
|
|
|
|
|
type = "user";
|
|
|
|
|
inherit (cfg) units;
|
|
|
|
|
upstreamUnits = upstreamUserUnits;
|
|
|
|
|
upstreamWants = [];
|
|
|
|
|
};
|
2022-03-30 09:31:56 +00:00
|
|
|
|
|
|
|
|
|
"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;
|
2022-08-12 12:06:08 +00:00
|
|
|
|
# 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;
|
2022-03-30 09:31:56 +00:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
# Some overrides to upstream units.
|
|
|
|
|
systemd.services."user@".restartIfChanged = false;
|
|
|
|
|
systemd.services.systemd-user-sessions.restartIfChanged = false; # Restart kills all active sessions.
|
2023-01-20 10:41:00 +00:00
|
|
|
|
|
|
|
|
|
# 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;
|
2022-03-30 09:31:56 +00:00
|
|
|
|
};
|
|
|
|
|
}
|