1{
2 config,
3 lib,
4 pkgs,
5 utils,
6 ...
7}:
8
9with utils;
10with systemdUtils.unitOptions;
11with lib;
12
13let
14
15 cfg = config.systemd;
16
17 inherit (systemdUtils.lib)
18 generateUnits
19 targetToUnit
20 serviceToUnit
21 socketToUnit
22 timerToUnit
23 pathToUnit
24 mountToUnit
25 automountToUnit
26 sliceToUnit
27 ;
28
29 upstreamSystemUnits =
30 [
31 # Targets.
32 "basic.target"
33 "sysinit.target"
34 "sockets.target"
35 "exit.target"
36 "graphical.target"
37 "multi-user.target"
38 "network.target"
39 "network-pre.target"
40 "network-online.target"
41 "nss-lookup.target"
42 "nss-user-lookup.target"
43 "time-sync.target"
44 "first-boot-complete.target"
45 ]
46 ++ optionals cfg.package.withCryptsetup [
47 "cryptsetup.target"
48 "cryptsetup-pre.target"
49 "remote-cryptsetup.target"
50 ]
51 ++ [
52 "sigpwr.target"
53 "timers.target"
54 "paths.target"
55 "rpcbind.target"
56
57 # Rescue mode.
58 "rescue.target"
59 "rescue.service"
60
61 # systemd-debug-generator
62 "debug-shell.service"
63
64 # Udev.
65 "systemd-udevd-control.socket"
66 "systemd-udevd-kernel.socket"
67 "systemd-udevd.service"
68 "systemd-udev-settle.service"
69 ]
70 ++ (optional (!config.boot.isContainer) "systemd-udev-trigger.service")
71 ++ [
72 # hwdb.bin is managed by NixOS
73 # "systemd-hwdb-update.service"
74
75 # Hardware (started by udev when a relevant device is plugged in).
76 "sound.target"
77 "bluetooth.target"
78 "printer.target"
79 "smartcard.target"
80
81 # Kernel module loading.
82 "systemd-modules-load.service"
83 "kmod-static-nodes.service"
84 "modprobe@.service"
85
86 # Filesystems.
87 "systemd-fsck@.service"
88 "systemd-fsck-root.service"
89 "systemd-growfs@.service"
90 "systemd-growfs-root.service"
91 "systemd-remount-fs.service"
92 "systemd-pstore.service"
93 "local-fs.target"
94 "local-fs-pre.target"
95 "remote-fs.target"
96 "remote-fs-pre.target"
97 "swap.target"
98 "dev-hugepages.mount"
99 "dev-mqueue.mount"
100 "sys-fs-fuse-connections.mount"
101 ]
102 ++ (optional (!config.boot.isContainer) "sys-kernel-config.mount")
103 ++ [
104 "sys-kernel-debug.mount"
105 "sys-kernel-tracing.mount"
106
107 # Maintaining state across reboots.
108 "systemd-random-seed.service"
109 ]
110 ++ (optional cfg.package.withBootloader "systemd-boot-random-seed.service")
111 ++ [
112 "systemd-backlight@.service"
113 "systemd-rfkill.service"
114 "systemd-rfkill.socket"
115
116 # Hibernate / suspend.
117 "hibernate.target"
118 "suspend.target"
119 "suspend-then-hibernate.target"
120 "sleep.target"
121 "hybrid-sleep.target"
122 "systemd-hibernate.service"
123 ]
124 ++ (lib.optional cfg.package.withEfi "systemd-hibernate-clear.service")
125 ++ [
126 "systemd-hybrid-sleep.service"
127 "systemd-suspend.service"
128 "systemd-suspend-then-hibernate.service"
129
130 # Reboot stuff.
131 "reboot.target"
132 "systemd-reboot.service"
133 "poweroff.target"
134 "systemd-poweroff.service"
135 "halt.target"
136 "systemd-halt.service"
137 "shutdown.target"
138 "umount.target"
139 "final.target"
140 "kexec.target"
141 "systemd-kexec.service"
142 ]
143 ++ lib.optional cfg.package.withUtmp "systemd-update-utmp.service"
144 ++ [
145
146 # Password entry.
147 "systemd-ask-password-console.path"
148 "systemd-ask-password-console.service"
149 "systemd-ask-password-wall.path"
150 "systemd-ask-password-wall.service"
151
152 # Varlink APIs
153 ]
154 ++ lib.optionals cfg.package.withBootloader [
155 "systemd-bootctl@.service"
156 "systemd-bootctl.socket"
157 ]
158 ++ [
159 "systemd-creds@.service"
160 "systemd-creds.socket"
161 ]
162 ++ lib.optional cfg.package.withTpm2Units [
163 "systemd-pcrlock@.service"
164 "systemd-pcrlock.socket"
165 ]
166 ++ [
167
168 # Slices / containers.
169 "slices.target"
170 ]
171 ++ optionals cfg.package.withImportd [
172 "systemd-importd.service"
173 ]
174 ++ optionals cfg.package.withMachined [
175 "machine.slice"
176 "machines.target"
177 "systemd-machined.service"
178 ]
179 ++ [
180 "systemd-nspawn@.service"
181
182 # Misc.
183 "systemd-sysctl.service"
184 "systemd-machine-id-commit.service"
185 ]
186 ++ optionals cfg.package.withTimedated [
187 "dbus-org.freedesktop.timedate1.service"
188 "systemd-timedated.service"
189 ]
190 ++ optionals cfg.package.withLocaled [
191 "dbus-org.freedesktop.locale1.service"
192 "systemd-localed.service"
193 ]
194 ++ optionals cfg.package.withHostnamed [
195 "dbus-org.freedesktop.hostname1.service"
196 "systemd-hostnamed.service"
197 "systemd-hostnamed.socket"
198 ]
199 ++ optionals cfg.package.withPortabled [
200 "dbus-org.freedesktop.portable1.service"
201 "systemd-portabled.service"
202 ]
203 ++ [
204 "systemd-exit.service"
205 "systemd-update-done.service"
206 ]
207 ++ cfg.additionalUpstreamSystemUnits;
208
209 upstreamSystemWants = [
210 "sysinit.target.wants"
211 "sockets.target.wants"
212 "local-fs.target.wants"
213 "multi-user.target.wants"
214 "timers.target.wants"
215 ];
216
217 proxy_env = config.networking.proxy.envVars;
218
219in
220
221{
222 ###### interface
223
224 options.systemd = {
225
226 package = mkPackageOption pkgs "systemd" { };
227
228 enableStrictShellChecks = mkEnableOption "" // {
229 description = ''
230 Whether to run `shellcheck` on the generated scripts for systemd
231 units.
232
233 When enabled, all systemd scripts generated by NixOS will be checked
234 with `shellcheck` and any errors or warnings will cause the build to
235 fail.
236
237 This affects all scripts that have been created through the `script`,
238 `reload`, `preStart`, `postStart`, `preStop` and `postStop` options for
239 systemd services. This does not affect command lines passed directly
240 to `ExecStart`, `ExecReload`, `ExecStartPre`, `ExecStartPost`,
241 `ExecStop` or `ExecStopPost`.
242
243 It therefore also does not affect systemd units that are coming from
244 packages and that are not defined through the NixOS config. This option
245 is disabled by default, and although some services have already been
246 fixed, it is still likely that you will encounter build failures when
247 enabling this.
248
249 We encourage people to enable this option when they are willing and
250 able to submit fixes for potential build failures to Nixpkgs. The
251 option can also be enabled or disabled for individual services using
252 the `enableStrictShellChecks` option on the service itself, which will
253 take precedence over the global setting.
254 '';
255 };
256
257 units = mkOption {
258 description = "Definition of systemd units; see {manpage}`systemd.unit(5)`.";
259 default = { };
260 type = systemdUtils.types.units;
261 };
262
263 packages = mkOption {
264 default = [ ];
265 type = types.listOf types.package;
266 example = literalExpression "[ pkgs.systemd-cryptsetup-generator ]";
267 description = "Packages providing systemd units and hooks.";
268 };
269
270 targets = mkOption {
271 default = { };
272 type = systemdUtils.types.targets;
273 description = "Definition of systemd target units; see {manpage}`systemd.target(5)`";
274 };
275
276 services = mkOption {
277 default = { };
278 type = systemdUtils.types.services;
279 description = "Definition of systemd service units; see {manpage}`systemd.service(5)`.";
280 };
281
282 sockets = mkOption {
283 default = { };
284 type = systemdUtils.types.sockets;
285 description = "Definition of systemd socket units; see {manpage}`systemd.socket(5)`.";
286 };
287
288 timers = mkOption {
289 default = { };
290 type = systemdUtils.types.timers;
291 description = "Definition of systemd timer units; see {manpage}`systemd.timer(5)`.";
292 };
293
294 paths = mkOption {
295 default = { };
296 type = systemdUtils.types.paths;
297 description = "Definition of systemd path units; see {manpage}`systemd.path(5)`.";
298 };
299
300 mounts = mkOption {
301 default = [ ];
302 type = systemdUtils.types.mounts;
303 description = ''
304 Definition of systemd mount units; see {manpage}`systemd.mount(5)`.
305
306 This is a list instead of an attrSet, because systemd mandates
307 the names to be derived from the `where` attribute.
308 '';
309 };
310
311 automounts = mkOption {
312 default = [ ];
313 type = systemdUtils.types.automounts;
314 description = ''
315 Definition of systemd automount units; see {manpage}`systemd.automount(5)`.
316
317 This is a list instead of an attrSet, because systemd mandates
318 the names to be derived from the `where` attribute.
319 '';
320 };
321
322 slices = mkOption {
323 default = { };
324 type = systemdUtils.types.slices;
325 description = "Definition of slice configurations; see {manpage}`systemd.slice(5)`.";
326 };
327
328 generators = mkOption {
329 type = types.attrsOf types.path;
330 default = { };
331 example = {
332 systemd-gpt-auto-generator = "/dev/null";
333 };
334 description = ''
335 Definition of systemd generators; see {manpage}`systemd.generator(5)`.
336
337 For each `NAME = VALUE` pair of the attrSet, a link is generated from
338 `/etc/systemd/system-generators/NAME` to `VALUE`.
339 '';
340 };
341
342 shutdown = mkOption {
343 type = types.attrsOf types.path;
344 default = { };
345 description = ''
346 Definition of systemd shutdown executables.
347 For each `NAME = VALUE` pair of the attrSet, a link is generated from
348 `/etc/systemd/system-shutdown/NAME` to `VALUE`.
349 '';
350 };
351
352 defaultUnit = mkOption {
353 default = "multi-user.target";
354 type = types.str;
355 description = ''
356 Default unit started when the system boots; see {manpage}`systemd.special(7)`.
357 '';
358 };
359
360 ctrlAltDelUnit = mkOption {
361 default = "reboot.target";
362 type = types.str;
363 example = "poweroff.target";
364 description = ''
365 Target that should be started when Ctrl-Alt-Delete is pressed;
366 see {manpage}`systemd.special(7)`.
367 '';
368 };
369
370 globalEnvironment = mkOption {
371 type =
372 with types;
373 attrsOf (
374 nullOr (oneOf [
375 str
376 path
377 package
378 ])
379 );
380 default = { };
381 example = {
382 TZ = "CET";
383 };
384 description = ''
385 Environment variables passed to *all* systemd units.
386 '';
387 };
388
389 managerEnvironment = mkOption {
390 type =
391 with types;
392 attrsOf (
393 nullOr (oneOf [
394 str
395 path
396 package
397 ])
398 );
399 default = { };
400 example = {
401 SYSTEMD_LOG_LEVEL = "debug";
402 };
403 description = ''
404 Environment variables of PID 1. These variables are
405 *not* passed to started units.
406 '';
407 };
408
409 enableCgroupAccounting = mkOption {
410 default = true;
411 type = types.bool;
412 description = ''
413 Whether to enable cgroup accounting; see {manpage}`cgroups(7)`.
414 '';
415 };
416
417 extraConfig = mkOption {
418 default = "";
419 type = types.lines;
420 example = "DefaultLimitCORE=infinity";
421 description = ''
422 Extra config options for systemd. See {manpage}`systemd-system.conf(5)` man page
423 for available options.
424 '';
425 };
426
427 sleep.extraConfig = mkOption {
428 default = "";
429 type = types.lines;
430 example = "HibernateDelaySec=1h";
431 description = ''
432 Extra config options for systemd sleep state logic.
433 See {manpage}`sleep.conf.d(5)` man page for available options.
434 '';
435 };
436
437 additionalUpstreamSystemUnits = mkOption {
438 default = [ ];
439 type = types.listOf types.str;
440 example = [
441 "debug-shell.service"
442 "systemd-quotacheck.service"
443 ];
444 description = ''
445 Additional units shipped with systemd that shall be enabled.
446 '';
447 };
448
449 suppressedSystemUnits = mkOption {
450 default = [ ];
451 type = types.listOf types.str;
452 example = [ "systemd-backlight@.service" ];
453 description = ''
454 A list of units to skip when generating system systemd configuration directory. This has
455 priority over upstream units, {option}`systemd.units`, and
456 {option}`systemd.additionalUpstreamSystemUnits`. The main purpose of this is to
457 prevent a upstream systemd unit from being added to the initrd with any modifications made to it
458 by other NixOS modules.
459 '';
460 };
461
462 watchdog.device = mkOption {
463 type = types.nullOr types.path;
464 default = null;
465 example = "/dev/watchdog";
466 description = ''
467 The path to a hardware watchdog device which will be managed by systemd.
468 If not specified, systemd will default to `/dev/watchdog`.
469 '';
470 };
471
472 watchdog.runtimeTime = mkOption {
473 type = types.nullOr types.str;
474 default = null;
475 example = "30s";
476 description = ''
477 The amount of time which can elapse before a watchdog hardware device
478 will automatically reboot the system.
479
480 Valid time units include "ms", "s", "min", "h", "d", and "w";
481 see {manpage}`systemd.time(7)`.
482 '';
483 };
484
485 watchdog.rebootTime = mkOption {
486 type = types.nullOr types.str;
487 default = null;
488 example = "10m";
489 description = ''
490 The amount of time which can elapse after a reboot has been triggered
491 before a watchdog hardware device will automatically reboot the system.
492 If left `null`, systemd will use its default of 10 minutes;
493 see {manpage}`systemd-system.conf(5)`.
494
495 Valid time units include "ms", "s", "min", "h", "d", and "w";
496 see also {manpage}`systemd.time(7)`.
497 '';
498 };
499
500 watchdog.kexecTime = mkOption {
501 type = types.nullOr types.str;
502 default = null;
503 example = "10m";
504 description = ''
505 The amount of time which can elapse when `kexec` is being executed before
506 a watchdog hardware device will automatically reboot the system. This
507 option should only be enabled if `reloadTime` is also enabled;
508 see {manpage}`kexec(8)`.
509
510 Valid time units include "ms", "s", "min", "h", "d", and "w";
511 see also {manpage}`systemd.time(7)`.
512 '';
513 };
514 };
515
516 ###### implementation
517
518 config = {
519
520 warnings =
521 let
522 mkOneNetOnlineWarn =
523 typeStr: name: def:
524 lib.optional (
525 lib.elem "network-online.target" def.after
526 && !(lib.elem "network-online.target" (def.wants ++ def.requires ++ def.bindsTo))
527 ) "${name}.${typeStr} is ordered after 'network-online.target' but doesn't depend on it";
528 mkNetOnlineWarns =
529 typeStr: defs: lib.concatLists (lib.mapAttrsToList (mkOneNetOnlineWarn typeStr) defs);
530 mkMountNetOnlineWarns =
531 typeStr: defs: lib.concatLists (map (m: mkOneNetOnlineWarn typeStr m.what m) defs);
532 in
533 concatLists (
534 mapAttrsToList (
535 name: service:
536 let
537 type = service.serviceConfig.Type or "";
538 restart = service.serviceConfig.Restart or "no";
539 hasDeprecated = builtins.hasAttr "StartLimitInterval" service.serviceConfig;
540 in
541 concatLists [
542 (optional (type == "oneshot" && (restart == "always" || restart == "on-success"))
543 "Service '${name}.service' with 'Type=oneshot' cannot have 'Restart=always' or 'Restart=on-success'"
544 )
545 (optional hasDeprecated "Service '${name}.service' uses the attribute 'StartLimitInterval' in the Service section, which is deprecated. See https://github.com/NixOS/nixpkgs/issues/45786.")
546 (optional (service.reloadIfChanged && service.reloadTriggers != [ ])
547 "Service '${name}.service' has both 'reloadIfChanged' and 'reloadTriggers' set. This is probably not what you want, because 'reloadTriggers' behave the same whay as 'restartTriggers' if 'reloadIfChanged' is set."
548 )
549 ]
550 ) cfg.services
551 )
552 ++ (mkNetOnlineWarns "target" cfg.targets)
553 ++ (mkNetOnlineWarns "service" cfg.services)
554 ++ (mkNetOnlineWarns "socket" cfg.sockets)
555 ++ (mkNetOnlineWarns "timer" cfg.timers)
556 ++ (mkNetOnlineWarns "path" cfg.paths)
557 ++ (mkMountNetOnlineWarns "mount" cfg.mounts)
558 ++ (mkMountNetOnlineWarns "automount" cfg.automounts)
559 ++ (mkNetOnlineWarns "slice" cfg.slices);
560
561 assertions = concatLists (
562 mapAttrsToList (
563 name: service:
564 map
565 (message: {
566 assertion = false;
567 inherit message;
568 })
569 (concatLists [
570 (optional
571 (
572 (builtins.elem "network-interfaces.target" service.after)
573 || (builtins.elem "network-interfaces.target" service.wants)
574 )
575 "Service '${name}.service' is using the deprecated target network-interfaces.target, which no longer exists. Using network.target is recommended instead."
576 )
577 ])
578 ) cfg.services
579 );
580
581 system.build.units = cfg.units;
582
583 system.nssModules = [ cfg.package.out ];
584 system.nssDatabases = {
585 hosts = (
586 mkMerge [
587 (mkOrder 400 [ "mymachines" ]) # 400 to ensure it comes before resolve (which is 501)
588 (mkOrder 999 [ "myhostname" ]) # after files (which is 998), but before regular nss modules
589 ]
590 );
591 passwd = (
592 mkMerge [
593 (mkAfter [ "systemd" ])
594 ]
595 );
596 group = (
597 mkMerge [
598 (mkAfter [ "[success=merge] systemd" ]) # need merge so that NSS won't stop at file-based groups
599 ]
600 );
601 };
602
603 environment.systemPackages = [ cfg.package ];
604
605 environment.etc =
606 let
607 # generate contents for /etc/systemd/${dir} from attrset of links and packages
608 hooks =
609 dir: links:
610 pkgs.runCommand "${dir}"
611 {
612 preferLocalBuild = true;
613 packages = cfg.packages;
614 }
615 ''
616 set -e
617 mkdir -p $out
618 for package in $packages
619 do
620 for hook in $package/lib/systemd/${dir}/*
621 do
622 ln -s $hook $out/
623 done
624 done
625 ${concatStrings (mapAttrsToList (exec: target: "ln -s ${target} $out/${exec};\n") links)}
626 '';
627
628 enabledUpstreamSystemUnits = filter (n: !elem n cfg.suppressedSystemUnits) upstreamSystemUnits;
629 enabledUnits = filterAttrs (n: v: !elem n cfg.suppressedSystemUnits) cfg.units;
630
631 in
632 ({
633 "systemd/system".source = generateUnits {
634 type = "system";
635 units = enabledUnits;
636 upstreamUnits = enabledUpstreamSystemUnits;
637 upstreamWants = upstreamSystemWants;
638 };
639
640 "systemd/system.conf".text = ''
641 [Manager]
642 ManagerEnvironment=${
643 lib.concatStringsSep " " (
644 lib.mapAttrsToList (n: v: "${n}=${lib.escapeShellArg v}") cfg.managerEnvironment
645 )
646 }
647 ${optionalString cfg.enableCgroupAccounting ''
648 DefaultCPUAccounting=yes
649 DefaultIOAccounting=yes
650 DefaultBlockIOAccounting=yes
651 DefaultIPAccounting=yes
652 ''}
653 DefaultLimitCORE=infinity
654 ${optionalString (cfg.watchdog.device != null) ''
655 WatchdogDevice=${cfg.watchdog.device}
656 ''}
657 ${optionalString (cfg.watchdog.runtimeTime != null) ''
658 RuntimeWatchdogSec=${cfg.watchdog.runtimeTime}
659 ''}
660 ${optionalString (cfg.watchdog.rebootTime != null) ''
661 RebootWatchdogSec=${cfg.watchdog.rebootTime}
662 ''}
663 ${optionalString (cfg.watchdog.kexecTime != null) ''
664 KExecWatchdogSec=${cfg.watchdog.kexecTime}
665 ''}
666
667 ${cfg.extraConfig}
668 '';
669
670 "systemd/sleep.conf".text = ''
671 [Sleep]
672 ${cfg.sleep.extraConfig}
673 '';
674
675 "systemd/user-generators" = {
676 source = hooks "user-generators" cfg.user.generators;
677 };
678 "systemd/system-generators" = {
679 source = hooks "system-generators" cfg.generators;
680 };
681 "systemd/system-shutdown" = {
682 source = hooks "system-shutdown" cfg.shutdown;
683 };
684
685 # Ignore all other preset files so systemd doesn't try to enable/disable
686 # units during runtime.
687 "systemd/system-preset/00-nixos.preset".text = ''
688 ignore *
689 '';
690 "systemd/user-preset/00-nixos.preset".text = ''
691 ignore *
692 '';
693 });
694
695 services.dbus.enable = true;
696
697 users.users.systemd-network = {
698 uid = config.ids.uids.systemd-network;
699 group = "systemd-network";
700 };
701 users.groups.systemd-network.gid = config.ids.gids.systemd-network;
702 users.users.systemd-resolve = {
703 uid = config.ids.uids.systemd-resolve;
704 group = "systemd-resolve";
705 };
706 users.groups.systemd-resolve.gid = config.ids.gids.systemd-resolve;
707
708 # Target for ‘charon send-keys’ to hook into.
709 users.groups.keys.gid = config.ids.gids.keys;
710
711 systemd.targets.keys = {
712 description = "Security Keys";
713 unitConfig.X-StopOnReconfiguration = true;
714 };
715
716 # This target only exists so that services ordered before sysinit.target
717 # are restarted in the correct order, notably BEFORE the other services,
718 # when switching configurations.
719 systemd.targets.sysinit-reactivation = {
720 description = "Reactivate sysinit units";
721 };
722
723 systemd.units =
724 let
725 withName = cfgToUnit: cfg: lib.nameValuePair cfg.name (cfgToUnit cfg);
726 in
727 mapAttrs' (_: withName pathToUnit) cfg.paths
728 // mapAttrs' (_: withName serviceToUnit) cfg.services
729 // mapAttrs' (_: withName sliceToUnit) cfg.slices
730 // mapAttrs' (_: withName socketToUnit) cfg.sockets
731 // mapAttrs' (_: withName targetToUnit) cfg.targets
732 // mapAttrs' (_: withName timerToUnit) cfg.timers
733 // listToAttrs (map (withName mountToUnit) cfg.mounts)
734 // listToAttrs (map (withName automountToUnit) cfg.automounts);
735
736 # Environment of PID 1
737 systemd.managerEnvironment = {
738 # Doesn't contain systemd itself - everything works so it seems to use the compiled-in value for its tools
739 # util-linux is needed for the main fsck utility wrapping the fs-specific ones
740 PATH = lib.makeBinPath (
741 config.system.fsPackages
742 ++ [ cfg.package.util-linux ]
743 # systemd-ssh-generator needs sshd in PATH
744 ++ lib.optional config.services.openssh.enable config.services.openssh.package
745 );
746 LOCALE_ARCHIVE = "/run/current-system/sw/lib/locale/locale-archive";
747 TZDIR = "/etc/zoneinfo";
748 # If SYSTEMD_UNIT_PATH ends with an empty component (":"), the usual unit load path will be appended to the contents of the variable
749 SYSTEMD_UNIT_PATH = lib.mkIf (
750 config.boot.extraSystemdUnitPaths != [ ]
751 ) "${builtins.concatStringsSep ":" config.boot.extraSystemdUnitPaths}:";
752 };
753
754 system.requiredKernelConfig = map config.lib.kernelConfig.isEnabled [
755 "DEVTMPFS"
756 "CGROUPS"
757 "INOTIFY_USER"
758 "SIGNALFD"
759 "TIMERFD"
760 "EPOLL"
761 "NET"
762 "SYSFS"
763 "PROC_FS"
764 "FHANDLE"
765 "CRYPTO_USER_API_HASH"
766 "CRYPTO_HMAC"
767 "CRYPTO_SHA256"
768 "DMIID"
769 "AUTOFS_FS"
770 "TMPFS_POSIX_ACL"
771 "TMPFS_XATTR"
772 "SECCOMP"
773 ];
774
775 # Generate timer units for all services that have a ‘startAt’ value.
776 systemd.timers = mapAttrs (name: service: {
777 wantedBy = [ "timers.target" ];
778 timerConfig.OnCalendar = service.startAt;
779 }) (filterAttrs (name: service: service.enable && service.startAt != [ ]) cfg.services);
780
781 # Some overrides to upstream units.
782 systemd.services."systemd-backlight@".restartIfChanged = false;
783 systemd.services."systemd-fsck@".restartIfChanged = false;
784 systemd.services."systemd-fsck@".path = [ pkgs.util-linux ] ++ config.system.fsPackages;
785 systemd.services."systemd-makefs@" = {
786 restartIfChanged = false;
787 path = [ pkgs.util-linux ] ++ config.system.fsPackages;
788 # Since there is no /etc/systemd/system/systemd-makefs@.service
789 # file, the units generated in /run/systemd/generator would
790 # override anything we put here. But by forcing the use of a
791 # drop-in in /etc, it does apply.
792 overrideStrategy = "asDropin";
793 };
794 systemd.services."systemd-mkswap@" = {
795 restartIfChanged = false;
796 path = [ pkgs.util-linux ];
797 overrideStrategy = "asDropin";
798 };
799 systemd.services.systemd-random-seed.restartIfChanged = false;
800 systemd.services.systemd-remount-fs.restartIfChanged = false;
801 systemd.services.systemd-update-utmp.restartIfChanged = false;
802 systemd.services.systemd-udev-settle.restartIfChanged = false; # Causes long delays in nixos-rebuild
803 systemd.targets.local-fs.unitConfig.X-StopOnReconfiguration = true;
804 systemd.targets.remote-fs.unitConfig.X-StopOnReconfiguration = true;
805 systemd.services.systemd-importd.environment = proxy_env;
806 systemd.services.systemd-pstore.wantedBy = [ "sysinit.target" ]; # see #81138
807
808 # NixOS has kernel modules in a different location, so override that here.
809 systemd.services.kmod-static-nodes.unitConfig.ConditionFileNotEmpty = [
810 "" # required to unset the previous value!
811 "/run/booted-system/kernel-modules/lib/modules/%v/modules.devname"
812 ];
813
814 # Don't bother with certain units in containers.
815 systemd.services.systemd-remount-fs.unitConfig.ConditionVirtualization = "!container";
816
817 # Increase numeric PID range (set directly instead of copying a one-line file from systemd)
818 # https://github.com/systemd/systemd/pull/12226
819 boot.kernel.sysctl."kernel.pid_max" = mkIf pkgs.stdenv.hostPlatform.is64bit (lib.mkDefault 4194304);
820
821 services.logrotate.settings = {
822 "/var/log/btmp" = mapAttrs (_: mkDefault) {
823 frequency = "monthly";
824 rotate = 1;
825 create = "0660 root ${config.users.groups.utmp.name}";
826 minsize = "1M";
827 };
828 "/var/log/wtmp" = mapAttrs (_: mkDefault) {
829 frequency = "monthly";
830 rotate = 1;
831 create = "0664 root ${config.users.groups.utmp.name}";
832 minsize = "1M";
833 };
834 };
835 };
836
837 # FIXME: Remove these eventually.
838 imports = [
839 (mkRenamedOptionModule [ "boot" "systemd" "sockets" ] [ "systemd" "sockets" ])
840 (mkRenamedOptionModule [ "boot" "systemd" "targets" ] [ "systemd" "targets" ])
841 (mkRenamedOptionModule [ "boot" "systemd" "services" ] [ "systemd" "services" ])
842 (mkRenamedOptionModule [ "jobs" ] [ "systemd" "services" ])
843 (mkRemovedOptionModule [ "systemd" "generator-packages" ] "Use systemd.packages instead.")
844 (mkRemovedOptionModule [ "systemd" "enableUnifiedCgroupHierarchy" ] ''
845 In 256 support for cgroup v1 ('legacy' and 'hybrid' hierarchies) is now considered obsolete and systemd by default will refuse to boot under it.
846 To forcibly reenable cgroup v1 support, you can set boot.kernelParams = [ "systemd.unified_cgroup_hierarchy=0" "SYSTEMD_CGROUP_ENABLE_LEGACY_FORCE=1" ].
847 NixOS does not officially support this configuration and might cause your system to be unbootable in future versions. You are on your own.
848 '')
849 ];
850}