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}