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