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