1{ config, lib }:
2
3with lib;
4with import ./systemd-lib.nix { inherit config lib pkgs; };
5
6let
7 checkService = checkUnitConfig "Service" [
8 (assertValueOneOf "Type" [
9 "simple" "forking" "oneshot" "dbus" "notify" "idle"
10 ])
11 (assertValueOneOf "Restart" [
12 "no" "on-success" "on-failure" "on-abnormal" "on-abort" "always"
13 ])
14 ];
15
16in rec {
17
18 unitOption = mkOptionType {
19 name = "systemd option";
20 merge = loc: defs:
21 let
22 defs' = filterOverrides defs;
23 defs'' = getValues defs';
24 in
25 if isList (head defs'')
26 then concatLists defs''
27 else mergeOneOption loc defs';
28 };
29
30 sharedOptions = {
31
32 enable = mkOption {
33 default = true;
34 type = types.bool;
35 description = ''
36 If set to false, this unit will be a symlink to
37 /dev/null. This is primarily useful to prevent specific
38 template instances (e.g. <literal>serial-getty@ttyS0</literal>)
39 from being started.
40 '';
41 };
42
43 requiredBy = mkOption {
44 default = [];
45 type = types.listOf types.str;
46 description = "Units that require (i.e. depend on and need to go down with) this unit.";
47 };
48
49 wantedBy = mkOption {
50 default = [];
51 type = types.listOf types.str;
52 description = "Units that want (i.e. depend on) this unit.";
53 };
54
55 };
56
57 concreteUnitOptions = sharedOptions // {
58
59 text = mkOption {
60 type = types.nullOr types.str;
61 default = null;
62 description = "Text of this systemd unit.";
63 };
64
65 unit = mkOption {
66 internal = true;
67 description = "The generated unit.";
68 };
69
70 };
71
72 commonUnitOptions = sharedOptions // {
73
74 description = mkOption {
75 default = "";
76 type = types.str;
77 description = "Description of this unit used in systemd messages and progress indicators.";
78 };
79
80 requires = mkOption {
81 default = [];
82 type = types.listOf types.str;
83 description = ''
84 Start the specified units when this unit is started, and stop
85 this unit when the specified units are stopped or fail.
86 '';
87 };
88
89 wants = mkOption {
90 default = [];
91 type = types.listOf types.str;
92 description = ''
93 Start the specified units when this unit is started.
94 '';
95 };
96
97 after = mkOption {
98 default = [];
99 type = types.listOf types.str;
100 description = ''
101 If the specified units are started at the same time as
102 this unit, delay this unit until they have started.
103 '';
104 };
105
106 before = mkOption {
107 default = [];
108 type = types.listOf types.str;
109 description = ''
110 If the specified units are started at the same time as
111 this unit, delay them until this unit has started.
112 '';
113 };
114
115 bindsTo = mkOption {
116 default = [];
117 type = types.listOf types.str;
118 description = ''
119 Like ‘requires’, but in addition, if the specified units
120 unexpectedly disappear, this unit will be stopped as well.
121 '';
122 };
123
124 partOf = mkOption {
125 default = [];
126 type = types.listOf types.str;
127 description = ''
128 If the specified units are stopped or restarted, then this
129 unit is stopped or restarted as well.
130 '';
131 };
132
133 conflicts = mkOption {
134 default = [];
135 type = types.listOf types.str;
136 description = ''
137 If the specified units are started, then this unit is stopped
138 and vice versa.
139 '';
140 };
141
142 requisite = mkOption {
143 default = [];
144 type = types.listOf types.str;
145 description = ''
146 Similar to requires. However if the units listed are not started,
147 they will not be started and the transaction will fail.
148 '';
149 };
150
151 unitConfig = mkOption {
152 default = {};
153 example = { RequiresMountsFor = "/data"; };
154 type = types.attrsOf unitOption;
155 description = ''
156 Each attribute in this set specifies an option in the
157 <literal>[Unit]</literal> section of the unit. See
158 <citerefentry><refentrytitle>systemd.unit</refentrytitle>
159 <manvolnum>5</manvolnum></citerefentry> for details.
160 '';
161 };
162
163 restartTriggers = mkOption {
164 default = [];
165 type = types.listOf types.unspecified;
166 description = ''
167 An arbitrary list of items such as derivations. If any item
168 in the list changes between reconfigurations, the service will
169 be restarted.
170 '';
171 };
172
173 };
174
175
176 serviceOptions = commonUnitOptions // {
177
178 environment = mkOption {
179 default = {};
180 type = types.attrs; # FIXME
181 example = { PATH = "/foo/bar/bin"; LANG = "nl_NL.UTF-8"; };
182 description = "Environment variables passed to the service's processes.";
183 };
184
185 path = mkOption {
186 default = [];
187 apply = ps: "${makeSearchPath "bin" ps}:${makeSearchPath "sbin" ps}";
188 description = ''
189 Packages added to the service's <envar>PATH</envar>
190 environment variable. Both the <filename>bin</filename>
191 and <filename>sbin</filename> subdirectories of each
192 package are added.
193 '';
194 };
195
196 serviceConfig = mkOption {
197 default = {};
198 example =
199 { StartLimitInterval = 10;
200 RestartSec = 5;
201 };
202 type = types.addCheck (types.attrsOf unitOption) checkService;
203 description = ''
204 Each attribute in this set specifies an option in the
205 <literal>[Service]</literal> section of the unit. See
206 <citerefentry><refentrytitle>systemd.service</refentrytitle>
207 <manvolnum>5</manvolnum></citerefentry> for details.
208 '';
209 };
210
211 script = mkOption {
212 type = types.lines;
213 default = "";
214 description = "Shell commands executed as the service's main process.";
215 };
216
217 scriptArgs = mkOption {
218 type = types.str;
219 default = "";
220 description = "Arguments passed to the main process script.";
221 };
222
223 preStart = mkOption {
224 type = types.lines;
225 default = "";
226 description = ''
227 Shell commands executed before the service's main process
228 is started.
229 '';
230 };
231
232 postStart = mkOption {
233 type = types.lines;
234 default = "";
235 description = ''
236 Shell commands executed after the service's main process
237 is started.
238 '';
239 };
240
241 reload = mkOption {
242 type = types.lines;
243 default = "";
244 description = ''
245 Shell commands executed when the service's main process
246 is reloaded.
247 '';
248 };
249
250 preStop = mkOption {
251 type = types.lines;
252 default = "";
253 description = ''
254 Shell commands executed to stop the service.
255 '';
256 };
257
258 postStop = mkOption {
259 type = types.lines;
260 default = "";
261 description = ''
262 Shell commands executed after the service's main process
263 has exited.
264 '';
265 };
266
267 restartIfChanged = mkOption {
268 type = types.bool;
269 default = true;
270 description = ''
271 Whether the service should be restarted during a NixOS
272 configuration switch if its definition has changed.
273 '';
274 };
275
276 reloadIfChanged = mkOption {
277 type = types.bool;
278 default = false;
279 description = ''
280 Whether the service should be reloaded during a NixOS
281 configuration switch if its definition has changed. If
282 enabled, the value of <option>restartIfChanged</option> is
283 ignored.
284 '';
285 };
286
287 stopIfChanged = mkOption {
288 type = types.bool;
289 default = true;
290 description = ''
291 If set, a changed unit is restarted by calling
292 <command>systemctl stop</command> in the old configuration,
293 then <command>systemctl start</command> in the new one.
294 Otherwise, it is restarted in a single step using
295 <command>systemctl restart</command> in the new configuration.
296 The latter is less correct because it runs the
297 <literal>ExecStop</literal> commands from the new
298 configuration.
299 '';
300 };
301
302 startAt = mkOption {
303 type = types.str;
304 default = "";
305 example = "Sun 14:00:00";
306 description = ''
307 Automatically start this unit at the given date/time, which
308 must be in the format described in
309 <citerefentry><refentrytitle>systemd.time</refentrytitle>
310 <manvolnum>5</manvolnum></citerefentry>. This is equivalent
311 to adding a corresponding timer unit with
312 <option>OnCalendar</option> set to the value given here.
313 '';
314 };
315
316 };
317
318
319 socketOptions = commonUnitOptions // {
320
321 listenStreams = mkOption {
322 default = [];
323 type = types.listOf types.str;
324 example = [ "0.0.0.0:993" "/run/my-socket" ];
325 description = ''
326 For each item in this list, a <literal>ListenStream</literal>
327 option in the <literal>[Socket]</literal> section will be created.
328 '';
329 };
330
331 socketConfig = mkOption {
332 default = {};
333 example = { ListenStream = "/run/my-socket"; };
334 type = types.attrsOf unitOption;
335 description = ''
336 Each attribute in this set specifies an option in the
337 <literal>[Socket]</literal> section of the unit. See
338 <citerefentry><refentrytitle>systemd.socket</refentrytitle>
339 <manvolnum>5</manvolnum></citerefentry> for details.
340 '';
341 };
342
343 };
344
345
346 timerOptions = commonUnitOptions // {
347
348 timerConfig = mkOption {
349 default = {};
350 example = { OnCalendar = "Sun 14:00:00"; Unit = "foo.service"; };
351 type = types.attrsOf unitOption;
352 description = ''
353 Each attribute in this set specifies an option in the
354 <literal>[Timer]</literal> section of the unit. See
355 <citerefentry><refentrytitle>systemd.timer</refentrytitle>
356 <manvolnum>5</manvolnum></citerefentry> and
357 <citerefentry><refentrytitle>systemd.time</refentrytitle>
358 <manvolnum>5</manvolnum></citerefentry> for details.
359 '';
360 };
361
362 };
363
364
365 pathOptions = commonUnitOptions // {
366
367 pathConfig = mkOption {
368 default = {};
369 example = { PathChanged = "/some/path"; Unit = "changedpath.service"; };
370 type = types.attrsOf unitOption;
371 description = ''
372 Each attribute in this set specifies an option in the
373 <literal>[Path]</literal> section of the unit. See
374 <citerefentry><refentrytitle>systemd.path</refentrytitle>
375 <manvolnum>5</manvolnum></citerefentry> for details.
376 '';
377 };
378
379 };
380
381
382 mountOptions = commonUnitOptions // {
383
384 what = mkOption {
385 example = "/dev/sda1";
386 type = types.str;
387 description = "Absolute path of device node, file or other resource. (Mandatory)";
388 };
389
390 where = mkOption {
391 example = "/mnt";
392 type = types.str;
393 description = ''
394 Absolute path of a directory of the mount point.
395 Will be created if it doesn't exist. (Mandatory)
396 '';
397 };
398
399 type = mkOption {
400 default = "";
401 example = "ext4";
402 type = types.str;
403 description = "File system type.";
404 };
405
406 options = mkOption {
407 default = "";
408 example = "noatime";
409 type = types.commas;
410 description = "Options used to mount the file system.";
411 };
412
413 mountConfig = mkOption {
414 default = {};
415 example = { DirectoryMode = "0775"; };
416 type = types.attrsOf unitOption;
417 description = ''
418 Each attribute in this set specifies an option in the
419 <literal>[Mount]</literal> section of the unit. See
420 <citerefentry><refentrytitle>systemd.mount</refentrytitle>
421 <manvolnum>5</manvolnum></citerefentry> for details.
422 '';
423 };
424 };
425
426 automountOptions = commonUnitOptions // {
427
428 where = mkOption {
429 example = "/mnt";
430 type = types.str;
431 description = ''
432 Absolute path of a directory of the mount point.
433 Will be created if it doesn't exist. (Mandatory)
434 '';
435 };
436
437 automountConfig = mkOption {
438 default = {};
439 example = { DirectoryMode = "0775"; };
440 type = types.attrsOf unitOption;
441 description = ''
442 Each attribute in this set specifies an option in the
443 <literal>[Automount]</literal> section of the unit. See
444 <citerefentry><refentrytitle>systemd.automount</refentrytitle>
445 <manvolnum>5</manvolnum></citerefentry> for details.
446 '';
447 };
448 };
449
450 targetOptions = commonUnitOptions;
451
452}