1{ config, lib, pkgs, utils, ... }:
2
3with utils;
4with lib;
5with import ./systemd-unit-options.nix { inherit config lib; };
6with import ./systemd-lib.nix { inherit config lib pkgs; };
7
8let
9
10 cfg = config.systemd;
11
12 systemd = cfg.package;
13
14 upstreamSystemUnits =
15 [ # Targets.
16 "basic.target"
17 "sysinit.target"
18 "sockets.target"
19 "graphical.target"
20 "multi-user.target"
21 "network.target"
22 "network-pre.target"
23 "network-online.target"
24 "nss-lookup.target"
25 "nss-user-lookup.target"
26 "time-sync.target"
27 #"cryptsetup.target"
28 "sigpwr.target"
29 "timers.target"
30 "paths.target"
31 "rpcbind.target"
32
33 # Rescue mode.
34 "rescue.target"
35 "rescue.service"
36
37 # Udev.
38 "systemd-udevd-control.socket"
39 "systemd-udevd-kernel.socket"
40 "systemd-udevd.service"
41 "systemd-udev-settle.service"
42 "systemd-udev-trigger.service"
43
44 # Consoles.
45 "getty.target"
46 "getty@.service"
47 "serial-getty@.service"
48 "container-getty@.service"
49 "systemd-vconsole-setup.service"
50
51 # Hardware (started by udev when a relevant device is plugged in).
52 "sound.target"
53 "bluetooth.target"
54 "printer.target"
55 "smartcard.target"
56
57 # Login stuff.
58 "systemd-logind.service"
59 "autovt@.service"
60 #"systemd-vconsole-setup.service"
61 "systemd-user-sessions.service"
62 "dbus-org.freedesktop.login1.service"
63 "dbus-org.freedesktop.machine1.service"
64 "org.freedesktop.login1.busname"
65 "org.freedesktop.machine1.busname"
66 "user@.service"
67
68 # Journal.
69 "systemd-journald.socket"
70 "systemd-journald.service"
71 "systemd-journal-flush.service"
72 "systemd-journal-gatewayd.socket"
73 "systemd-journal-gatewayd.service"
74 "systemd-journald-audit.socket"
75 "systemd-journald-dev-log.socket"
76 "syslog.socket"
77
78 # SysV init compatibility.
79 "systemd-initctl.socket"
80 "systemd-initctl.service"
81
82 # Kernel module loading.
83 "systemd-modules-load.service"
84 "kmod-static-nodes.service"
85
86 # Filesystems.
87 "systemd-fsck@.service"
88 "systemd-fsck-root.service"
89 "systemd-remount-fs.service"
90 "local-fs.target"
91 "local-fs-pre.target"
92 "remote-fs.target"
93 "remote-fs-pre.target"
94 "swap.target"
95 "dev-hugepages.mount"
96 "dev-mqueue.mount"
97 "proc-sys-fs-binfmt_misc.mount"
98 "sys-fs-fuse-connections.mount"
99 "sys-kernel-config.mount"
100 "sys-kernel-debug.mount"
101
102 # Maintaining state across reboots.
103 "systemd-random-seed.service"
104 "systemd-backlight@.service"
105 "systemd-rfkill.service"
106
107 # Hibernate / suspend.
108 "hibernate.target"
109 "suspend.target"
110 "sleep.target"
111 "hybrid-sleep.target"
112 "systemd-hibernate.service"
113 "systemd-suspend.service"
114 "systemd-hybrid-sleep.service"
115
116 # Reboot stuff.
117 "reboot.target"
118 "systemd-reboot.service"
119 "poweroff.target"
120 "systemd-poweroff.service"
121 "halt.target"
122 "systemd-halt.service"
123 "shutdown.target"
124 "umount.target"
125 "final.target"
126 "kexec.target"
127 "systemd-kexec.service"
128 "systemd-update-utmp.service"
129
130 # Password entry.
131 "systemd-ask-password-console.path"
132 "systemd-ask-password-console.service"
133 "systemd-ask-password-wall.path"
134 "systemd-ask-password-wall.service"
135
136 # Slices / containers.
137 "slices.target"
138 "-.slice"
139 "system.slice"
140 "user.slice"
141 "machine.slice"
142 "systemd-machined.service"
143
144 # Temporary file creation / cleanup.
145 "systemd-tmpfiles-clean.service"
146 "systemd-tmpfiles-clean.timer"
147 "systemd-tmpfiles-setup.service"
148 "systemd-tmpfiles-setup-dev.service"
149
150 # Misc.
151 "org.freedesktop.systemd1.busname"
152 "systemd-sysctl.service"
153 "dbus-org.freedesktop.timedate1.service"
154 "dbus-org.freedesktop.locale1.service"
155 "dbus-org.freedesktop.hostname1.service"
156 "org.freedesktop.timedate1.busname"
157 "org.freedesktop.locale1.busname"
158 "org.freedesktop.hostname1.busname"
159 "systemd-timedated.service"
160 "systemd-localed.service"
161 "systemd-hostnamed.service"
162 "systemd-binfmt.service"
163 ]
164 ++ cfg.additionalUpstreamSystemUnits;
165
166 upstreamSystemWants =
167 [ #"basic.target.wants"
168 "sysinit.target.wants"
169 "sockets.target.wants"
170 "local-fs.target.wants"
171 "multi-user.target.wants"
172 "timers.target.wants"
173 ];
174
175 upstreamUserUnits =
176 [ "basic.target"
177 "default.target"
178 "exit.target"
179 "paths.target"
180 "shutdown.target"
181 "sockets.target"
182 "systemd-exit.service"
183 "timers.target"
184 ];
185
186 makeJobScript = name: text:
187 let mkScriptName = s: (replaceChars [ "\\" ] [ "-" ] (shellEscape s) );
188 x = pkgs.writeTextFile { name = "unit-script"; executable = true; destination = "/bin/${mkScriptName name}"; inherit text; };
189 in "${x}/bin/${mkScriptName name}";
190
191 unitConfig = { name, config, ... }: {
192 config = {
193 unitConfig =
194 optionalAttrs (config.requires != [])
195 { Requires = toString config.requires; }
196 // optionalAttrs (config.wants != [])
197 { Wants = toString config.wants; }
198 // optionalAttrs (config.after != [])
199 { After = toString config.after; }
200 // optionalAttrs (config.before != [])
201 { Before = toString config.before; }
202 // optionalAttrs (config.bindsTo != [])
203 { BindsTo = toString config.bindsTo; }
204 // optionalAttrs (config.partOf != [])
205 { PartOf = toString config.partOf; }
206 // optionalAttrs (config.conflicts != [])
207 { Conflicts = toString config.conflicts; }
208 // optionalAttrs (config.requisite != [])
209 { Requisite = toString config.requisite; }
210 // optionalAttrs (config.restartTriggers != [])
211 { X-Restart-Triggers = toString config.restartTriggers; }
212 // optionalAttrs (config.description != "") {
213 Description = config.description;
214 } // optionalAttrs (config.onFailure != []) {
215 OnFailure = toString config.onFailure;
216 };
217 };
218 };
219
220 serviceConfig = { name, config, ... }: {
221 config = mkMerge
222 [ { # Default path for systemd services. Should be quite minimal.
223 path =
224 [ pkgs.coreutils
225 pkgs.findutils
226 pkgs.gnugrep
227 pkgs.gnused
228 systemd
229 ];
230 environment.PATH = config.path;
231 }
232 (mkIf (config.preStart != "")
233 { serviceConfig.ExecStartPre = makeJobScript "${name}-pre-start" ''
234 #! ${pkgs.stdenv.shell} -e
235 ${config.preStart}
236 '';
237 })
238 (mkIf (config.script != "")
239 { serviceConfig.ExecStart = makeJobScript "${name}-start" ''
240 #! ${pkgs.stdenv.shell} -e
241 ${config.script}
242 '' + " " + config.scriptArgs;
243 })
244 (mkIf (config.postStart != "")
245 { serviceConfig.ExecStartPost = makeJobScript "${name}-post-start" ''
246 #! ${pkgs.stdenv.shell} -e
247 ${config.postStart}
248 '';
249 })
250 (mkIf (config.reload != "")
251 { serviceConfig.ExecReload = makeJobScript "${name}-reload" ''
252 #! ${pkgs.stdenv.shell} -e
253 ${config.reload}
254 '';
255 })
256 (mkIf (config.preStop != "")
257 { serviceConfig.ExecStop = makeJobScript "${name}-pre-stop" ''
258 #! ${pkgs.stdenv.shell} -e
259 ${config.preStop}
260 '';
261 })
262 (mkIf (config.postStop != "")
263 { serviceConfig.ExecStopPost = makeJobScript "${name}-post-stop" ''
264 #! ${pkgs.stdenv.shell} -e
265 ${config.postStop}
266 '';
267 })
268 ];
269 };
270
271 mountConfig = { name, config, ... }: {
272 config = {
273 mountConfig =
274 { What = config.what;
275 Where = config.where;
276 } // optionalAttrs (config.type != "") {
277 Type = config.type;
278 } // optionalAttrs (config.options != "") {
279 Options = config.options;
280 };
281 };
282 };
283
284 automountConfig = { name, config, ... }: {
285 config = {
286 automountConfig =
287 { Where = config.where;
288 };
289 };
290 };
291
292 commonUnitText = def: ''
293 [Unit]
294 ${attrsToSection def.unitConfig}
295 '';
296
297 targetToUnit = name: def:
298 { inherit (def) wantedBy requiredBy enable;
299 text =
300 ''
301 [Unit]
302 ${attrsToSection def.unitConfig}
303 '';
304 };
305
306 serviceToUnit = name: def:
307 { inherit (def) wantedBy requiredBy enable;
308 text = commonUnitText def +
309 ''
310 [Service]
311 ${let env = cfg.globalEnvironment // def.environment;
312 in concatMapStrings (n:
313 let s = optionalString (env."${n}" != null)
314 "Environment=\"${n}=${env.${n}}\"\n";
315 in if stringLength s >= 2048 then throw "The value of the environment variable ‘${n}’ in systemd service ‘${name}.service’ is too long." else s) (attrNames env)}
316 ${if def.reloadIfChanged then ''
317 X-ReloadIfChanged=true
318 '' else if !def.restartIfChanged then ''
319 X-RestartIfChanged=false
320 '' else ""}
321 ${optionalString (!def.stopIfChanged) "X-StopIfChanged=false"}
322 ${attrsToSection def.serviceConfig}
323 '';
324 };
325
326 socketToUnit = name: def:
327 { inherit (def) wantedBy requiredBy enable;
328 text = commonUnitText def +
329 ''
330 [Socket]
331 ${attrsToSection def.socketConfig}
332 ${concatStringsSep "\n" (map (s: "ListenStream=${s}") def.listenStreams)}
333 '';
334 };
335
336 timerToUnit = name: def:
337 { inherit (def) wantedBy requiredBy enable;
338 text = commonUnitText def +
339 ''
340 [Timer]
341 ${attrsToSection def.timerConfig}
342 '';
343 };
344
345 pathToUnit = name: def:
346 { inherit (def) wantedBy requiredBy enable;
347 text = commonUnitText def +
348 ''
349 [Path]
350 ${attrsToSection def.pathConfig}
351 '';
352 };
353
354 mountToUnit = name: def:
355 { inherit (def) wantedBy requiredBy enable;
356 text = commonUnitText def +
357 ''
358 [Mount]
359 ${attrsToSection def.mountConfig}
360 '';
361 };
362
363 automountToUnit = name: def:
364 { inherit (def) wantedBy requiredBy enable;
365 text = commonUnitText def +
366 ''
367 [Automount]
368 ${attrsToSection def.automountConfig}
369 '';
370 };
371
372in
373
374{
375
376 ###### interface
377
378 options = {
379
380 systemd.package = mkOption {
381 default = pkgs.systemd;
382 defaultText = "pkgs.systemd";
383 type = types.package;
384 description = "The systemd package.";
385 };
386
387 systemd.units = mkOption {
388 description = "Definition of systemd units.";
389 default = {};
390 type = types.attrsOf types.optionSet;
391 options = { name, config, ... }:
392 { options = concreteUnitOptions;
393 config = {
394 unit = mkDefault (makeUnit name config);
395 };
396 };
397 };
398
399 systemd.packages = mkOption {
400 default = [];
401 type = types.listOf types.package;
402 description = "Packages providing systemd units.";
403 };
404
405 systemd.targets = mkOption {
406 default = {};
407 type = types.attrsOf types.optionSet;
408 options = [ targetOptions unitConfig ];
409 description = "Definition of systemd target units.";
410 };
411
412 systemd.services = mkOption {
413 default = {};
414 type = types.attrsOf types.optionSet;
415 options = [ serviceOptions unitConfig serviceConfig ];
416 description = "Definition of systemd service units.";
417 };
418
419 systemd.sockets = mkOption {
420 default = {};
421 type = types.attrsOf types.optionSet;
422 options = [ socketOptions unitConfig ];
423 description = "Definition of systemd socket units.";
424 };
425
426 systemd.timers = mkOption {
427 default = {};
428 type = types.attrsOf types.optionSet;
429 options = [ timerOptions unitConfig ];
430 description = "Definition of systemd timer units.";
431 };
432
433 systemd.paths = mkOption {
434 default = {};
435 type = types.attrsOf types.optionSet;
436 options = [ pathOptions unitConfig ];
437 description = "Definition of systemd path units.";
438 };
439
440 systemd.mounts = mkOption {
441 default = [];
442 type = types.listOf types.optionSet;
443 options = [ mountOptions unitConfig mountConfig ];
444 description = ''
445 Definition of systemd mount units.
446 This is a list instead of an attrSet, because systemd mandates the names to be derived from
447 the 'where' attribute.
448 '';
449 };
450
451 systemd.automounts = mkOption {
452 default = [];
453 type = types.listOf types.optionSet;
454 options = [ automountOptions unitConfig automountConfig ];
455 description = ''
456 Definition of systemd automount units.
457 This is a list instead of an attrSet, because systemd mandates the names to be derived from
458 the 'where' attribute.
459 '';
460 };
461
462 systemd.generators = mkOption {
463 type = types.attrsOf types.path;
464 default = {};
465 example = { "systemd-gpt-auto-generator" = "/dev/null"; };
466 description = ''
467 Definition of systemd generators.
468 For each <literal>NAME = VALUE</literal> pair of the attrSet, a link is generated from
469 <literal>/etc/systemd/system-generators/NAME</literal> to <literal>VALUE</literal>.
470 '';
471 };
472
473 systemd.generator-packages = mkOption {
474 default = [];
475 type = types.listOf types.package;
476 example = literalExample "[ pkgs.systemd-cryptsetup-generator ]";
477 description = "Packages providing systemd generators.";
478 };
479
480 systemd.defaultUnit = mkOption {
481 default = "multi-user.target";
482 type = types.str;
483 description = "Default unit started when the system boots.";
484 };
485
486 systemd.ctrlAltDelUnit = mkOption {
487 default = "reboot.target";
488 type = types.str;
489 example = "poweroff.target";
490 description = ''
491 Target that should be started when Ctrl-Alt-Delete is pressed.
492 '';
493 };
494
495 systemd.globalEnvironment = mkOption {
496 type = types.attrs;
497 default = {};
498 example = { TZ = "CET"; };
499 description = ''
500 Environment variables passed to <emphasis>all</emphasis> systemd units.
501 '';
502 };
503
504 systemd.extraConfig = mkOption {
505 default = "";
506 type = types.lines;
507 example = "DefaultLimitCORE=infinity";
508 description = ''
509 Extra config options for systemd. See man systemd-system.conf for
510 available options.
511 '';
512 };
513
514 services.journald.console = mkOption {
515 default = "";
516 type = types.str;
517 description = "If non-empty, write log messages to the specified TTY device.";
518 };
519
520 services.journald.rateLimitInterval = mkOption {
521 default = "10s";
522 type = types.str;
523 description = ''
524 Configures the rate limiting interval that is applied to all
525 messages generated on the system. This rate limiting is applied
526 per-service, so that two services which log do not interfere with
527 each other's limit. The value may be specified in the following
528 units: s, min, h, ms, us. To turn off any kind of rate limiting,
529 set either value to 0.
530 '';
531 };
532
533 services.journald.rateLimitBurst = mkOption {
534 default = 100;
535 type = types.int;
536 description = ''
537 Configures the rate limiting burst limit (number of messages per
538 interval) that is applied to all messages generated on the system.
539 This rate limiting is applied per-service, so that two services
540 which log do not interfere with each other's limit.
541 '';
542 };
543
544 services.journald.extraConfig = mkOption {
545 default = "";
546 type = types.lines;
547 example = "Storage=volatile";
548 description = ''
549 Extra config options for systemd-journald. See man journald.conf
550 for available options.
551 '';
552 };
553
554 services.journald.enableHttpGateway = mkOption {
555 default = false;
556 type = types.bool;
557 description = ''
558 Whether to enable the HTTP gateway to the journal.
559 '';
560 };
561
562 services.logind.extraConfig = mkOption {
563 default = "";
564 type = types.lines;
565 example = "HandleLidSwitch=ignore";
566 description = ''
567 Extra config options for systemd-logind. See man logind.conf for
568 available options.
569 '';
570 };
571
572 systemd.tmpfiles.rules = mkOption {
573 type = types.listOf types.str;
574 default = [];
575 example = [ "d /tmp 1777 root root 10d" ];
576 description = ''
577 Rules for creating and cleaning up temporary files
578 automatically. See
579 <citerefentry><refentrytitle>tmpfiles.d</refentrytitle><manvolnum>5</manvolnum></citerefentry>
580 for the exact format. You should not use this option to create
581 files required by systemd services, since there is no
582 guarantee that <command>systemd-tmpfiles</command> runs when
583 the system is reconfigured using
584 <command>nixos-rebuild</command>.
585 '';
586 };
587
588 systemd.user.units = mkOption {
589 description = "Definition of systemd per-user units.";
590 default = {};
591 type = types.attrsOf types.optionSet;
592 options = { name, config, ... }:
593 { options = concreteUnitOptions;
594 config = {
595 unit = mkDefault (makeUnit name config);
596 };
597 };
598 };
599
600 systemd.user.services = mkOption {
601 default = {};
602 type = types.attrsOf types.optionSet;
603 options = [ serviceOptions unitConfig serviceConfig ];
604 description = "Definition of systemd per-user service units.";
605 };
606
607 systemd.user.timers = mkOption {
608 default = {};
609 type = types.attrsOf types.optionSet;
610 options = [ timerOptions unitConfig ];
611 description = "Definition of systemd per-user timer units.";
612 };
613
614 systemd.user.sockets = mkOption {
615 default = {};
616 type = types.attrsOf types.optionSet;
617 options = [ socketOptions unitConfig ];
618 description = "Definition of systemd per-user socket units.";
619 };
620
621 systemd.additionalUpstreamSystemUnits = mkOption {
622 default = [ ];
623 type = types.listOf types.str;
624 example = [ "debug-shell.service" "systemd-quotacheck.service" ];
625 description = ''
626 Additional units shipped with systemd that shall be enabled.
627 '';
628 };
629
630 };
631
632
633 ###### implementation
634
635 config = {
636
637 warnings = concatLists (mapAttrsToList (name: service:
638 optional (service.serviceConfig.Type or "" == "oneshot" && service.serviceConfig.Restart or "no" != "no")
639 "Service ‘${name}.service’ with ‘Type=oneshot’ must have ‘Restart=no’") cfg.services);
640
641 system.build.units = cfg.units;
642
643 environment.systemPackages = [ systemd ];
644
645 environment.etc = let
646 # generate contents for /etc/systemd/system-generators from
647 # systemd.generators and systemd.generator-packages
648 generators = pkgs.runCommand "system-generators" { packages = cfg.generator-packages; } ''
649 mkdir -p $out
650 for package in $packages
651 do
652 ln -s $package/lib/systemd/system-generators/* $out/
653 done;
654 ${concatStrings (mapAttrsToList (generator: target: "ln -s ${target} $out/${generator};\n") cfg.generators)}
655 '';
656 in ({
657 "systemd/system".source = generateUnits "system" cfg.units upstreamSystemUnits upstreamSystemWants;
658
659 "systemd/user".source = generateUnits "user" cfg.user.units upstreamUserUnits [];
660
661 "systemd/system.conf".text = ''
662 [Manager]
663 ${config.systemd.extraConfig}
664 '';
665
666 "systemd/journald.conf".text = ''
667 [Journal]
668 RateLimitInterval=${config.services.journald.rateLimitInterval}
669 RateLimitBurst=${toString config.services.journald.rateLimitBurst}
670 ${optionalString (config.services.journald.console != "") ''
671 ForwardToConsole=yes
672 TTYPath=${config.services.journald.console}
673 ''}
674 ${config.services.journald.extraConfig}
675 '';
676
677 "systemd/logind.conf".text = ''
678 [Login]
679 KillUserProcesses=no
680 ${config.services.logind.extraConfig}
681 '';
682
683 "systemd/sleep.conf".text = ''
684 [Sleep]
685 '';
686
687 "tmpfiles.d/systemd.conf".source = "${systemd}/example/tmpfiles.d/systemd.conf";
688 "tmpfiles.d/x11.conf".source = "${systemd}/example/tmpfiles.d/x11.conf";
689
690 "tmpfiles.d/nixos.conf".text = ''
691 # This file is created automatically and should not be modified.
692 # Please change the option ‘systemd.tmpfiles.rules’ instead.
693
694 ${concatStringsSep "\n" cfg.tmpfiles.rules}
695 '';
696
697 "systemd/system-generators" = { source = generators; };
698 });
699
700 services.dbus.enable = true;
701
702 system.activationScripts.systemd = stringAfter [ "groups" ]
703 ''
704 mkdir -m 0755 -p /var/lib/udev
705
706 if ! [ -e /etc/machine-id ]; then
707 ${systemd}/bin/systemd-machine-id-setup
708 fi
709
710 # Keep a persistent journal. Note that systemd-tmpfiles will
711 # set proper ownership/permissions.
712 mkdir -m 0700 -p /var/log/journal
713 '';
714
715 users.extraUsers.systemd-network.uid = config.ids.uids.systemd-network;
716 users.extraGroups.systemd-network.gid = config.ids.gids.systemd-network;
717 users.extraUsers.systemd-resolve.uid = config.ids.uids.systemd-resolve;
718 users.extraGroups.systemd-resolve.gid = config.ids.gids.systemd-resolve;
719
720 # Target for ‘charon send-keys’ to hook into.
721 users.extraGroups.keys.gid = config.ids.gids.keys;
722
723 systemd.targets.keys =
724 { description = "Security Keys";
725 unitConfig.X-StopOnReconfiguration = true;
726 };
727
728 systemd.targets.network-online.after = [ "ip-up.target" ];
729
730 systemd.targets.network-pre = {
731 wantedBy = [ "network.target" ];
732 before = [ "network.target" ];
733 };
734
735 systemd.targets.remote-fs-pre = {
736 wantedBy = [ "remote-fs.target" ];
737 before = [ "remote-fs.target" ];
738 };
739
740 systemd.units =
741 mapAttrs' (n: v: nameValuePair "${n}.target" (targetToUnit n v)) cfg.targets
742 // mapAttrs' (n: v: nameValuePair "${n}.service" (serviceToUnit n v)) cfg.services
743 // mapAttrs' (n: v: nameValuePair "${n}.socket" (socketToUnit n v)) cfg.sockets
744 // mapAttrs' (n: v: nameValuePair "${n}.timer" (timerToUnit n v)) cfg.timers
745 // mapAttrs' (n: v: nameValuePair "${n}.path" (pathToUnit n v)) cfg.paths
746 // listToAttrs (map
747 (v: let n = escapeSystemdPath v.where;
748 in nameValuePair "${n}.mount" (mountToUnit n v)) cfg.mounts)
749 // listToAttrs (map
750 (v: let n = escapeSystemdPath v.where;
751 in nameValuePair "${n}.automount" (automountToUnit n v)) cfg.automounts);
752
753 systemd.user.units =
754 mapAttrs' (n: v: nameValuePair "${n}.service" (serviceToUnit n v)) cfg.user.services
755 // mapAttrs' (n: v: nameValuePair "${n}.socket" (socketToUnit n v)) cfg.user.sockets
756 // mapAttrs' (n: v: nameValuePair "${n}.timer" (timerToUnit n v)) cfg.user.timers;
757
758 system.requiredKernelConfig = map config.lib.kernelConfig.isEnabled
759 [ "DEVTMPFS" "CGROUPS" "INOTIFY_USER" "SIGNALFD" "TIMERFD" "EPOLL" "NET"
760 "SYSFS" "PROC_FS" "FHANDLE" "DMIID" "AUTOFS4_FS" "TMPFS_POSIX_ACL"
761 "TMPFS_XATTR" "SECCOMP"
762 ];
763
764 users.extraGroups.systemd-journal.gid = config.ids.gids.systemd-journal;
765 users.extraUsers.systemd-journal-gateway.uid = config.ids.uids.systemd-journal-gateway;
766 users.extraGroups.systemd-journal-gateway.gid = config.ids.gids.systemd-journal-gateway;
767
768 # Generate timer units for all services that have a ‘startAt’ value.
769 systemd.timers =
770 mapAttrs (name: service:
771 { wantedBy = [ "timers.target" ];
772 timerConfig.OnCalendar = service.startAt;
773 })
774 (filterAttrs (name: service: service.enable && service.startAt != "") cfg.services);
775
776 # Generate timer units for all services that have a ‘startAt’ value.
777 systemd.user.timers =
778 mapAttrs (name: service:
779 { wantedBy = [ "timers.target" ];
780 timerConfig.OnCalendar = service.startAt;
781 })
782 (filterAttrs (name: service: service.startAt != "") cfg.user.services);
783
784 systemd.sockets.systemd-journal-gatewayd.wantedBy =
785 optional config.services.journald.enableHttpGateway "sockets.target";
786
787 # Provide the systemd-user PAM service, required to run systemd
788 # user instances.
789 security.pam.services.systemd-user =
790 { # Ensure that pam_systemd gets included. This is special-cased
791 # in systemd to provide XDG_RUNTIME_DIR.
792 startSession = true;
793 };
794
795 # Some overrides to upstream units.
796 systemd.services."systemd-backlight@".restartIfChanged = false;
797 systemd.services."systemd-rfkill@".restartIfChanged = false;
798 systemd.services."user@".restartIfChanged = false;
799 systemd.services.systemd-journal-flush.restartIfChanged = false;
800 systemd.services.systemd-random-seed.restartIfChanged = false;
801 systemd.services.systemd-remount-fs.restartIfChanged = false;
802 systemd.services.systemd-update-utmp.restartIfChanged = false;
803 systemd.services.systemd-user-sessions.restartIfChanged = false; # Restart kills all active sessions.
804 systemd.services.systemd-logind.restartTriggers = [ config.environment.etc."systemd/logind.conf".source ];
805 systemd.services.systemd-logind.stopIfChanged = false;
806 systemd.targets.local-fs.unitConfig.X-StopOnReconfiguration = true;
807 systemd.targets.remote-fs.unitConfig.X-StopOnReconfiguration = true;
808 systemd.services.systemd-binfmt.wants = [ "proc-sys-fs-binfmt_misc.automount" ];
809
810 # Don't bother with certain units in containers.
811 systemd.services.systemd-remount-fs.unitConfig.ConditionVirtualization = "!container";
812 systemd.services.systemd-random-seed.unitConfig.ConditionVirtualization = "!container";
813
814 };
815
816 # FIXME: Remove these eventually.
817 imports =
818 [ (mkRenamedOptionModule [ "boot" "systemd" "sockets" ] [ "systemd" "sockets" ])
819 (mkRenamedOptionModule [ "boot" "systemd" "targets" ] [ "systemd" "targets" ])
820 (mkRenamedOptionModule [ "boot" "systemd" "services" ] [ "systemd" "services" ])
821 ];
822
823}