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