Update lean 4.15 (#373564)
[NixPkgs.git] / nixos / modules / system / boot / systemd / user.nix
blob8f1d92c409b33a811a276e36ddc8afd57ca9ede1
2   config,
3   lib,
4   pkgs,
5   utils,
6   ...
7 }:
8 with utils;
9 with systemdUtils.unitOptions;
10 with lib;
12 let
13   cfg = config.systemd.user;
15   systemd = config.systemd.package;
17   inherit (systemdUtils.lib)
18     makeUnit
19     generateUnits
20     targetToUnit
21     serviceToUnit
22     sliceToUnit
23     socketToUnit
24     timerToUnit
25     pathToUnit
26     ;
28   upstreamUserUnits = [
29     "app.slice"
30     "background.slice"
31     "basic.target"
32     "bluetooth.target"
33     "default.target"
34     "exit.target"
35     "graphical-session-pre.target"
36     "graphical-session.target"
37     "paths.target"
38     "printer.target"
39     "session.slice"
40     "shutdown.target"
41     "smartcard.target"
42     "sockets.target"
43     "sound.target"
44     "systemd-exit.service"
45     "timers.target"
46     "xdg-desktop-autostart.target"
47   ] ++ config.systemd.additionalUpstreamUserUnits;
49   writeTmpfiles =
50     {
51       rules,
52       user ? null,
53     }:
54     let
55       suffix = optionalString (user != null) "-${user}";
56     in
57     pkgs.writeTextFile {
58       name = "nixos-user-tmpfiles.d${suffix}";
59       destination = "/etc/xdg/user-tmpfiles.d/00-nixos${suffix}.conf";
60       text = ''
61         # This file is created automatically and should not be modified.
62         # Please change the options ‘systemd.user.tmpfiles’ instead.
63         ${concatStringsSep "\n" rules}
64       '';
65     };
68   options = {
69     systemd.user.extraConfig = mkOption {
70       default = "";
71       type = types.lines;
72       example = "DefaultCPUAccounting=yes";
73       description = ''
74         Extra config options for systemd user instances. See {manpage}`systemd-user.conf(5)` for
75         available options.
76       '';
77     };
79     systemd.user.units = mkOption {
80       description = "Definition of systemd per-user units.";
81       default = { };
82       type = systemdUtils.types.units;
83     };
85     systemd.user.paths = mkOption {
86       default = { };
87       type = systemdUtils.types.paths;
88       description = "Definition of systemd per-user path units.";
89     };
91     systemd.user.services = mkOption {
92       default = { };
93       type = systemdUtils.types.services;
94       description = "Definition of systemd per-user service units.";
95     };
97     systemd.user.slices = mkOption {
98       default = { };
99       type = systemdUtils.types.slices;
100       description = "Definition of systemd per-user slice units.";
101     };
103     systemd.user.sockets = mkOption {
104       default = { };
105       type = systemdUtils.types.sockets;
106       description = "Definition of systemd per-user socket units.";
107     };
109     systemd.user.targets = mkOption {
110       default = { };
111       type = systemdUtils.types.targets;
112       description = "Definition of systemd per-user target units.";
113     };
115     systemd.user.timers = mkOption {
116       default = { };
117       type = systemdUtils.types.timers;
118       description = "Definition of systemd per-user timer units.";
119     };
121     systemd.user.tmpfiles = {
122       rules = mkOption {
123         type = types.listOf types.str;
124         default = [ ];
125         example = [ "D %C - - - 7d" ];
126         description = ''
127           Global user rules for creation, deletion and cleaning of volatile and
128           temporary files automatically. See
129           {manpage}`tmpfiles.d(5)`
130           for the exact format.
131         '';
132       };
134       users = mkOption {
135         description = ''
136           Per-user rules for creation, deletion and cleaning of volatile and
137           temporary files automatically.
138         '';
139         default = { };
140         type = types.attrsOf (
141           types.submodule {
142             options = {
143               rules = mkOption {
144                 type = types.listOf types.str;
145                 default = [ ];
146                 example = [ "D %C - - - 7d" ];
147                 description = ''
148                   Per-user rules for creation, deletion and cleaning of volatile and
149                   temporary files automatically. See
150                   {manpage}`tmpfiles.d(5)`
151                   for the exact format.
152                 '';
153               };
154             };
155           }
156         );
157       };
158     };
160     systemd.user.generators = mkOption {
161       type = types.attrsOf types.path;
162       default = { };
163       example = {
164         systemd-gpt-auto-generator = "/dev/null";
165       };
166       description = ''
167         Definition of systemd generators; see {manpage}`systemd.generator(5)`.
169         For each `NAME = VALUE` pair of the attrSet, a link is generated from
170         `/etc/systemd/user-generators/NAME` to `VALUE`.
171       '';
172     };
174     systemd.additionalUpstreamUserUnits = mkOption {
175       default = [ ];
176       type = types.listOf types.str;
177       example = [ ];
178       description = ''
179         Additional units shipped with systemd that should be enabled for per-user systemd instances.
180       '';
181       internal = true;
182     };
183   };
185   config = {
186     systemd.additionalUpstreamSystemUnits = [
187       "user.slice"
188     ];
190     environment.etc = {
191       "systemd/user".source = generateUnits {
192         type = "user";
193         inherit (cfg) units;
194         upstreamUnits = upstreamUserUnits;
195         upstreamWants = [ ];
196       };
198       "systemd/user.conf".text = ''
199         [Manager]
200         ${cfg.extraConfig}
201       '';
202     };
204     systemd.user.units =
205       mapAttrs' (n: v: nameValuePair "${n}.path" (pathToUnit v)) cfg.paths
206       // mapAttrs' (n: v: nameValuePair "${n}.service" (serviceToUnit v)) cfg.services
207       // mapAttrs' (n: v: nameValuePair "${n}.slice" (sliceToUnit v)) cfg.slices
208       // mapAttrs' (n: v: nameValuePair "${n}.socket" (socketToUnit v)) cfg.sockets
209       // mapAttrs' (n: v: nameValuePair "${n}.target" (targetToUnit v)) cfg.targets
210       // mapAttrs' (n: v: nameValuePair "${n}.timer" (timerToUnit v)) cfg.timers;
212     # Generate timer units for all services that have a ‘startAt’ value.
213     systemd.user.timers = mapAttrs (name: service: {
214       wantedBy = [ "timers.target" ];
215       timerConfig.OnCalendar = service.startAt;
216     }) (filterAttrs (name: service: service.startAt != [ ]) cfg.services);
218     # Provide the systemd-user PAM service, required to run systemd
219     # user instances.
220     security.pam.services.systemd-user = {
221       # Ensure that pam_systemd gets included. This is special-cased
222       # in systemd to provide XDG_RUNTIME_DIR.
223       startSession = true;
224       # Disable pam_mount in systemd-user to prevent it from being called
225       # multiple times during login, because it will prevent pam_mount from
226       # unmounting the previously mounted volumes.
227       pamMount = false;
228     };
230     # Some overrides to upstream units.
231     systemd.services."user@".restartIfChanged = false;
232     systemd.services.systemd-user-sessions.restartIfChanged = false; # Restart kills all active sessions.
234     # enable systemd user tmpfiles
235     systemd.user.services.systemd-tmpfiles-setup.wantedBy = optional (
236       cfg.tmpfiles.rules != [ ] || any (cfg': cfg'.rules != [ ]) (attrValues cfg.tmpfiles.users)
237     ) "basic.target";
239     # /run/current-system/sw/etc/xdg is in systemd's $XDG_CONFIG_DIRS so we can
240     # write the tmpfiles.d rules for everyone there
241     environment.systemPackages = optional (cfg.tmpfiles.rules != [ ]) (writeTmpfiles {
242       inherit (cfg.tmpfiles) rules;
243     });
245     # /etc/profiles/per-user/$USER/etc/xdg is in systemd's $XDG_CONFIG_DIRS so
246     # we can write a single user's tmpfiles.d rules there
247     users.users = mapAttrs (user: cfg': {
248       packages = optional (cfg'.rules != [ ]) (writeTmpfiles {
249         inherit (cfg') rules;
250         inherit user;
251       });
252     }) cfg.tmpfiles.users;
254     system.userActivationScripts.tmpfiles = ''
255       ${config.systemd.package}/bin/systemd-tmpfiles --user --create --remove
256     '';
257   };