at 22.05-pre 44 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 "cryptsetup-pre.target" 30 "remote-cryptsetup.target" 31 "sigpwr.target" 32 "timers.target" 33 "paths.target" 34 "rpcbind.target" 35 36 # Rescue mode. 37 "rescue.target" 38 "rescue.service" 39 40 # Udev. 41 "systemd-udevd-control.socket" 42 "systemd-udevd-kernel.socket" 43 "systemd-udevd.service" 44 "systemd-udev-settle.service" 45 ] ++ (optional (!config.boot.isContainer) "systemd-udev-trigger.service") ++ [ 46 # hwdb.bin is managed by NixOS 47 # "systemd-hwdb-update.service" 48 49 # Consoles. 50 "getty.target" 51 "getty-pre.target" 52 "getty@.service" 53 "serial-getty@.service" 54 "console-getty.service" 55 "container-getty@.service" 56 "systemd-vconsole-setup.service" 57 58 # Hardware (started by udev when a relevant device is plugged in). 59 "sound.target" 60 "bluetooth.target" 61 "printer.target" 62 "smartcard.target" 63 64 # Login stuff. 65 "systemd-logind.service" 66 "autovt@.service" 67 "systemd-user-sessions.service" 68 "dbus-org.freedesktop.import1.service" 69 "dbus-org.freedesktop.machine1.service" 70 "dbus-org.freedesktop.login1.service" 71 "user@.service" 72 "user-runtime-dir@.service" 73 74 # Journal. 75 "systemd-journald.socket" 76 "systemd-journald@.socket" 77 "systemd-journald-varlink@.socket" 78 "systemd-journald.service" 79 "systemd-journald@.service" 80 "systemd-journal-flush.service" 81 "systemd-journal-catalog-update.service" 82 ] ++ (optional (!config.boot.isContainer) "systemd-journald-audit.socket") ++ [ 83 "systemd-journald-dev-log.socket" 84 "syslog.socket" 85 86 # Coredumps. 87 "systemd-coredump.socket" 88 "systemd-coredump@.service" 89 90 # Kernel module loading. 91 "systemd-modules-load.service" 92 "kmod-static-nodes.service" 93 "modprobe@.service" 94 95 # Filesystems. 96 "systemd-fsck@.service" 97 "systemd-fsck-root.service" 98 "systemd-remount-fs.service" 99 "systemd-pstore.service" 100 "local-fs.target" 101 "local-fs-pre.target" 102 "remote-fs.target" 103 "remote-fs-pre.target" 104 "swap.target" 105 "dev-hugepages.mount" 106 "dev-mqueue.mount" 107 "sys-fs-fuse-connections.mount" 108 ] ++ (optional (!config.boot.isContainer) "sys-kernel-config.mount") ++ [ 109 "sys-kernel-debug.mount" 110 111 # Maintaining state across reboots. 112 "systemd-random-seed.service" 113 "systemd-backlight@.service" 114 "systemd-rfkill.service" 115 "systemd-rfkill.socket" 116 117 # Hibernate / suspend. 118 "hibernate.target" 119 "suspend.target" 120 "suspend-then-hibernate.target" 121 "sleep.target" 122 "hybrid-sleep.target" 123 "systemd-hibernate.service" 124 "systemd-hybrid-sleep.service" 125 "systemd-suspend.service" 126 "systemd-suspend-then-hibernate.service" 127 128 # Reboot stuff. 129 "reboot.target" 130 "systemd-reboot.service" 131 "poweroff.target" 132 "systemd-poweroff.service" 133 "halt.target" 134 "systemd-halt.service" 135 "shutdown.target" 136 "umount.target" 137 "final.target" 138 "kexec.target" 139 "systemd-kexec.service" 140 "systemd-update-utmp.service" 141 142 # Password entry. 143 "systemd-ask-password-console.path" 144 "systemd-ask-password-console.service" 145 "systemd-ask-password-wall.path" 146 "systemd-ask-password-wall.service" 147 148 # Slices / containers. 149 "slices.target" 150 "user.slice" 151 "machine.slice" 152 "machines.target" 153 "systemd-importd.service" 154 "systemd-machined.service" 155 "systemd-nspawn@.service" 156 157 # Temporary file creation / cleanup. 158 "systemd-tmpfiles-clean.service" 159 "systemd-tmpfiles-clean.timer" 160 "systemd-tmpfiles-setup.service" 161 "systemd-tmpfiles-setup-dev.service" 162 163 # Misc. 164 "systemd-sysctl.service" 165 "dbus-org.freedesktop.timedate1.service" 166 "dbus-org.freedesktop.locale1.service" 167 "dbus-org.freedesktop.hostname1.service" 168 "systemd-timedated.service" 169 "systemd-localed.service" 170 "systemd-hostnamed.service" 171 "systemd-exit.service" 172 "systemd-update-done.service" 173 ] ++ optionals config.services.journald.enableHttpGateway [ 174 "systemd-journal-gatewayd.socket" 175 "systemd-journal-gatewayd.service" 176 ] ++ cfg.additionalUpstreamSystemUnits; 177 178 upstreamSystemWants = 179 [ "sysinit.target.wants" 180 "sockets.target.wants" 181 "local-fs.target.wants" 182 "multi-user.target.wants" 183 "timers.target.wants" 184 ]; 185 186 upstreamUserUnits = [ 187 "app.slice" 188 "background.slice" 189 "basic.target" 190 "bluetooth.target" 191 "default.target" 192 "exit.target" 193 "graphical-session-pre.target" 194 "graphical-session.target" 195 "paths.target" 196 "printer.target" 197 "session.slice" 198 "shutdown.target" 199 "smartcard.target" 200 "sockets.target" 201 "sound.target" 202 "systemd-exit.service" 203 "systemd-tmpfiles-clean.service" 204 "systemd-tmpfiles-clean.timer" 205 "systemd-tmpfiles-setup.service" 206 "timers.target" 207 "xdg-desktop-autostart.target" 208 ]; 209 210 makeJobScript = name: text: 211 let 212 scriptName = replaceChars [ "\\" "@" ] [ "-" "_" ] (shellEscape name); 213 out = pkgs.writeTextFile { 214 # The derivation name is different from the script file name 215 # to keep the script file name short to avoid cluttering logs. 216 name = "unit-script-${scriptName}"; 217 executable = true; 218 destination = "/bin/${scriptName}"; 219 text = '' 220 #!${pkgs.runtimeShell} -e 221 ${text} 222 ''; 223 checkPhase = '' 224 ${pkgs.stdenv.shell} -n "$out/bin/${scriptName}" 225 ''; 226 }; 227 in "${out}/bin/${scriptName}"; 228 229 unitConfig = { config, options, ... }: { 230 config = { 231 unitConfig = 232 optionalAttrs (config.requires != []) 233 { Requires = toString config.requires; } 234 // optionalAttrs (config.wants != []) 235 { Wants = toString config.wants; } 236 // optionalAttrs (config.after != []) 237 { After = toString config.after; } 238 // optionalAttrs (config.before != []) 239 { Before = toString config.before; } 240 // optionalAttrs (config.bindsTo != []) 241 { BindsTo = toString config.bindsTo; } 242 // optionalAttrs (config.partOf != []) 243 { PartOf = toString config.partOf; } 244 // optionalAttrs (config.conflicts != []) 245 { Conflicts = toString config.conflicts; } 246 // optionalAttrs (config.requisite != []) 247 { Requisite = toString config.requisite; } 248 // optionalAttrs (config.restartTriggers != []) 249 { X-Restart-Triggers = toString config.restartTriggers; } 250 // optionalAttrs (config.description != "") { 251 Description = config.description; } 252 // optionalAttrs (config.documentation != []) { 253 Documentation = toString config.documentation; } 254 // optionalAttrs (config.onFailure != []) { 255 OnFailure = toString config.onFailure; } 256 // optionalAttrs (options.startLimitIntervalSec.isDefined) { 257 StartLimitIntervalSec = toString config.startLimitIntervalSec; 258 } // optionalAttrs (options.startLimitBurst.isDefined) { 259 StartLimitBurst = toString config.startLimitBurst; 260 }; 261 }; 262 }; 263 264 serviceConfig = { name, config, ... }: { 265 config = mkMerge 266 [ { # Default path for systemd services. Should be quite minimal. 267 path = mkAfter 268 [ pkgs.coreutils 269 pkgs.findutils 270 pkgs.gnugrep 271 pkgs.gnused 272 systemd 273 ]; 274 environment.PATH = "${makeBinPath config.path}:${makeSearchPathOutput "bin" "sbin" config.path}"; 275 } 276 (mkIf (config.preStart != "") 277 { serviceConfig.ExecStartPre = 278 [ (makeJobScript "${name}-pre-start" config.preStart) ]; 279 }) 280 (mkIf (config.script != "") 281 { serviceConfig.ExecStart = 282 makeJobScript "${name}-start" config.script + " " + config.scriptArgs; 283 }) 284 (mkIf (config.postStart != "") 285 { serviceConfig.ExecStartPost = 286 [ (makeJobScript "${name}-post-start" config.postStart) ]; 287 }) 288 (mkIf (config.reload != "") 289 { serviceConfig.ExecReload = 290 makeJobScript "${name}-reload" config.reload; 291 }) 292 (mkIf (config.preStop != "") 293 { serviceConfig.ExecStop = 294 makeJobScript "${name}-pre-stop" config.preStop; 295 }) 296 (mkIf (config.postStop != "") 297 { serviceConfig.ExecStopPost = 298 makeJobScript "${name}-post-stop" config.postStop; 299 }) 300 ]; 301 }; 302 303 mountConfig = { config, ... }: { 304 config = { 305 mountConfig = 306 { What = config.what; 307 Where = config.where; 308 } // optionalAttrs (config.type != "") { 309 Type = config.type; 310 } // optionalAttrs (config.options != "") { 311 Options = config.options; 312 }; 313 }; 314 }; 315 316 automountConfig = { config, ... }: { 317 config = { 318 automountConfig = 319 { Where = config.where; 320 }; 321 }; 322 }; 323 324 commonUnitText = def: '' 325 [Unit] 326 ${attrsToSection def.unitConfig} 327 ''; 328 329 targetToUnit = name: def: 330 { inherit (def) aliases wantedBy requiredBy enable; 331 text = 332 '' 333 [Unit] 334 ${attrsToSection def.unitConfig} 335 ''; 336 }; 337 338 serviceToUnit = name: def: 339 { inherit (def) aliases wantedBy requiredBy enable; 340 text = commonUnitText def + 341 '' 342 [Service] 343 ${let env = cfg.globalEnvironment // def.environment; 344 in concatMapStrings (n: 345 let s = optionalString (env.${n} != null) 346 "Environment=${builtins.toJSON "${n}=${env.${n}}"}\n"; 347 # systemd max line length is now 1MiB 348 # https://github.com/systemd/systemd/commit/e6dde451a51dc5aaa7f4d98d39b8fe735f73d2af 349 in if stringLength s >= 1048576 then throw "The value of the environment variable ${n} in systemd service ${name}.service is too long." else s) (attrNames env)} 350 ${if def.reloadIfChanged then '' 351 X-ReloadIfChanged=true 352 '' else if !def.restartIfChanged then '' 353 X-RestartIfChanged=false 354 '' else ""} 355 ${optionalString (!def.stopIfChanged) "X-StopIfChanged=false"} 356 ${attrsToSection def.serviceConfig} 357 ''; 358 }; 359 360 socketToUnit = name: def: 361 { inherit (def) aliases wantedBy requiredBy enable; 362 text = commonUnitText def + 363 '' 364 [Socket] 365 ${attrsToSection def.socketConfig} 366 ${concatStringsSep "\n" (map (s: "ListenStream=${s}") def.listenStreams)} 367 ${concatStringsSep "\n" (map (s: "ListenDatagram=${s}") def.listenDatagrams)} 368 ''; 369 }; 370 371 timerToUnit = name: def: 372 { inherit (def) aliases wantedBy requiredBy enable; 373 text = commonUnitText def + 374 '' 375 [Timer] 376 ${attrsToSection def.timerConfig} 377 ''; 378 }; 379 380 pathToUnit = name: def: 381 { inherit (def) aliases wantedBy requiredBy enable; 382 text = commonUnitText def + 383 '' 384 [Path] 385 ${attrsToSection def.pathConfig} 386 ''; 387 }; 388 389 mountToUnit = name: def: 390 { inherit (def) aliases wantedBy requiredBy enable; 391 text = commonUnitText def + 392 '' 393 [Mount] 394 ${attrsToSection def.mountConfig} 395 ''; 396 }; 397 398 automountToUnit = name: def: 399 { inherit (def) aliases wantedBy requiredBy enable; 400 text = commonUnitText def + 401 '' 402 [Automount] 403 ${attrsToSection def.automountConfig} 404 ''; 405 }; 406 407 sliceToUnit = name: def: 408 { inherit (def) aliases wantedBy requiredBy enable; 409 text = commonUnitText def + 410 '' 411 [Slice] 412 ${attrsToSection def.sliceConfig} 413 ''; 414 }; 415 416 logindHandlerType = types.enum [ 417 "ignore" "poweroff" "reboot" "halt" "kexec" "suspend" 418 "hibernate" "hybrid-sleep" "suspend-then-hibernate" "lock" 419 ]; 420 421 proxy_env = config.networking.proxy.envVars; 422 423in 424 425{ 426 ###### interface 427 428 options = { 429 430 systemd.package = mkOption { 431 default = pkgs.systemd; 432 defaultText = literalExpression "pkgs.systemd"; 433 type = types.package; 434 description = "The systemd package."; 435 }; 436 437 systemd.units = mkOption { 438 description = "Definition of systemd units."; 439 default = {}; 440 type = with types; attrsOf (submodule ( 441 { name, config, ... }: 442 { options = concreteUnitOptions; 443 config = { 444 unit = mkDefault (makeUnit name config); 445 }; 446 })); 447 }; 448 449 systemd.packages = mkOption { 450 default = []; 451 type = types.listOf types.package; 452 example = literalExpression "[ pkgs.systemd-cryptsetup-generator ]"; 453 description = "Packages providing systemd units and hooks."; 454 }; 455 456 systemd.targets = mkOption { 457 default = {}; 458 type = with types; attrsOf (submodule [ { options = targetOptions; } unitConfig] ); 459 description = "Definition of systemd target units."; 460 }; 461 462 systemd.services = mkOption { 463 default = {}; 464 type = with types; attrsOf (submodule [ { options = serviceOptions; } unitConfig serviceConfig ]); 465 description = "Definition of systemd service units."; 466 }; 467 468 systemd.sockets = mkOption { 469 default = {}; 470 type = with types; attrsOf (submodule [ { options = socketOptions; } unitConfig ]); 471 description = "Definition of systemd socket units."; 472 }; 473 474 systemd.timers = mkOption { 475 default = {}; 476 type = with types; attrsOf (submodule [ { options = timerOptions; } unitConfig ]); 477 description = "Definition of systemd timer units."; 478 }; 479 480 systemd.paths = mkOption { 481 default = {}; 482 type = with types; attrsOf (submodule [ { options = pathOptions; } unitConfig ]); 483 description = "Definition of systemd path units."; 484 }; 485 486 systemd.mounts = mkOption { 487 default = []; 488 type = with types; listOf (submodule [ { options = mountOptions; } unitConfig mountConfig ]); 489 description = '' 490 Definition of systemd mount units. 491 This is a list instead of an attrSet, because systemd mandates the names to be derived from 492 the 'where' attribute. 493 ''; 494 }; 495 496 systemd.automounts = mkOption { 497 default = []; 498 type = with types; listOf (submodule [ { options = automountOptions; } unitConfig automountConfig ]); 499 description = '' 500 Definition of systemd automount units. 501 This is a list instead of an attrSet, because systemd mandates the names to be derived from 502 the 'where' attribute. 503 ''; 504 }; 505 506 systemd.slices = mkOption { 507 default = {}; 508 type = with types; attrsOf (submodule [ { options = sliceOptions; } unitConfig] ); 509 description = "Definition of slice configurations."; 510 }; 511 512 systemd.generators = mkOption { 513 type = types.attrsOf types.path; 514 default = {}; 515 example = { systemd-gpt-auto-generator = "/dev/null"; }; 516 description = '' 517 Definition of systemd generators. 518 For each <literal>NAME = VALUE</literal> pair of the attrSet, a link is generated from 519 <literal>/etc/systemd/system-generators/NAME</literal> to <literal>VALUE</literal>. 520 ''; 521 }; 522 523 systemd.shutdown = mkOption { 524 type = types.attrsOf types.path; 525 default = {}; 526 description = '' 527 Definition of systemd shutdown executables. 528 For each <literal>NAME = VALUE</literal> pair of the attrSet, a link is generated from 529 <literal>/etc/systemd/system-shutdown/NAME</literal> to <literal>VALUE</literal>. 530 ''; 531 }; 532 533 systemd.defaultUnit = mkOption { 534 default = "multi-user.target"; 535 type = types.str; 536 description = "Default unit started when the system boots."; 537 }; 538 539 systemd.ctrlAltDelUnit = mkOption { 540 default = "reboot.target"; 541 type = types.str; 542 example = "poweroff.target"; 543 description = '' 544 Target that should be started when Ctrl-Alt-Delete is pressed. 545 ''; 546 }; 547 548 systemd.globalEnvironment = mkOption { 549 type = with types; attrsOf (nullOr (oneOf [ str path package ])); 550 default = {}; 551 example = { TZ = "CET"; }; 552 description = '' 553 Environment variables passed to <emphasis>all</emphasis> systemd units. 554 ''; 555 }; 556 557 systemd.enableCgroupAccounting = mkOption { 558 default = true; 559 type = types.bool; 560 description = '' 561 Whether to enable cgroup accounting. 562 ''; 563 }; 564 565 systemd.enableUnifiedCgroupHierarchy = mkOption { 566 default = true; 567 type = types.bool; 568 description = '' 569 Whether to enable the unified cgroup hierarchy (cgroupsv2). 570 ''; 571 }; 572 573 systemd.coredump.enable = mkOption { 574 default = true; 575 type = types.bool; 576 description = '' 577 Whether core dumps should be processed by 578 <command>systemd-coredump</command>. If disabled, core dumps 579 appear in the current directory of the crashing process. 580 ''; 581 }; 582 583 systemd.coredump.extraConfig = mkOption { 584 default = ""; 585 type = types.lines; 586 example = "Storage=journal"; 587 description = '' 588 Extra config options for systemd-coredump. See coredump.conf(5) man page 589 for available options. 590 ''; 591 }; 592 593 systemd.extraConfig = mkOption { 594 default = ""; 595 type = types.lines; 596 example = "DefaultLimitCORE=infinity"; 597 description = '' 598 Extra config options for systemd. See man systemd-system.conf for 599 available options. 600 ''; 601 }; 602 603 services.journald.console = mkOption { 604 default = ""; 605 type = types.str; 606 description = "If non-empty, write log messages to the specified TTY device."; 607 }; 608 609 services.journald.rateLimitInterval = mkOption { 610 default = "30s"; 611 type = types.str; 612 description = '' 613 Configures the rate limiting interval that is applied to all 614 messages generated on the system. This rate limiting is applied 615 per-service, so that two services which log do not interfere with 616 each other's limit. The value may be specified in the following 617 units: s, min, h, ms, us. To turn off any kind of rate limiting, 618 set either value to 0. 619 620 See <option>services.journald.rateLimitBurst</option> for important 621 considerations when setting this value. 622 ''; 623 }; 624 625 services.journald.rateLimitBurst = mkOption { 626 default = 10000; 627 type = types.int; 628 description = '' 629 Configures the rate limiting burst limit (number of messages per 630 interval) that is applied to all messages generated on the system. 631 This rate limiting is applied per-service, so that two services 632 which log do not interfere with each other's limit. 633 634 Note that the effective rate limit is multiplied by a factor derived 635 from the available free disk space for the journal as described on 636 <link xlink:href="https://www.freedesktop.org/software/systemd/man/journald.conf.html"> 637 journald.conf(5)</link>. 638 639 Note that the total amount of logs stored is limited by journald settings 640 such as <literal>SystemMaxUse</literal>, which defaults to a 4 GB cap. 641 642 It is thus recommended to compute what period of time that you will be 643 able to store logs for when an application logs at full burst rate. 644 With default settings for log lines that are 100 Bytes long, this can 645 amount to just a few hours. 646 ''; 647 }; 648 649 services.journald.extraConfig = mkOption { 650 default = ""; 651 type = types.lines; 652 example = "Storage=volatile"; 653 description = '' 654 Extra config options for systemd-journald. See man journald.conf 655 for available options. 656 ''; 657 }; 658 659 services.journald.enableHttpGateway = mkOption { 660 default = false; 661 type = types.bool; 662 description = '' 663 Whether to enable the HTTP gateway to the journal. 664 ''; 665 }; 666 667 services.journald.forwardToSyslog = mkOption { 668 default = config.services.rsyslogd.enable || config.services.syslog-ng.enable; 669 defaultText = literalExpression "services.rsyslogd.enable || services.syslog-ng.enable"; 670 type = types.bool; 671 description = '' 672 Whether to forward log messages to syslog. 673 ''; 674 }; 675 676 services.logind.extraConfig = mkOption { 677 default = ""; 678 type = types.lines; 679 example = "IdleAction=lock"; 680 description = '' 681 Extra config options for systemd-logind. See 682 <link xlink:href="https://www.freedesktop.org/software/systemd/man/logind.conf.html"> 683 logind.conf(5)</link> for available options. 684 ''; 685 }; 686 687 services.logind.killUserProcesses = mkOption { 688 default = false; 689 type = types.bool; 690 description = '' 691 Specifies whether the processes of a user should be killed 692 when the user logs out. If true, the scope unit corresponding 693 to the session and all processes inside that scope will be 694 terminated. If false, the scope is "abandoned" (see 695 <link xlink:href="https://www.freedesktop.org/software/systemd/man/systemd.scope.html#"> 696 systemd.scope(5)</link>), and processes are not killed. 697 </para> 698 699 <para> 700 See <link xlink:href="https://www.freedesktop.org/software/systemd/man/logind.conf.html#KillUserProcesses=">logind.conf(5)</link> 701 for more details. 702 ''; 703 }; 704 705 services.logind.lidSwitch = mkOption { 706 default = "suspend"; 707 example = "ignore"; 708 type = logindHandlerType; 709 710 description = '' 711 Specifies what to be done when the laptop lid is closed. 712 ''; 713 }; 714 715 services.logind.lidSwitchDocked = mkOption { 716 default = "ignore"; 717 example = "suspend"; 718 type = logindHandlerType; 719 720 description = '' 721 Specifies what to be done when the laptop lid is closed 722 and another screen is added. 723 ''; 724 }; 725 726 services.logind.lidSwitchExternalPower = mkOption { 727 default = config.services.logind.lidSwitch; 728 defaultText = literalExpression "services.logind.lidSwitch"; 729 example = "ignore"; 730 type = logindHandlerType; 731 732 description = '' 733 Specifies what to do when the laptop lid is closed and the system is 734 on external power. By default use the same action as specified in 735 services.logind.lidSwitch. 736 ''; 737 }; 738 739 systemd.sleep.extraConfig = mkOption { 740 default = ""; 741 type = types.lines; 742 example = "HibernateDelaySec=1h"; 743 description = '' 744 Extra config options for systemd sleep state logic. 745 See sleep.conf.d(5) man page for available options. 746 ''; 747 }; 748 749 systemd.user.extraConfig = mkOption { 750 default = ""; 751 type = types.lines; 752 example = "DefaultCPUAccounting=yes"; 753 description = '' 754 Extra config options for systemd user instances. See man systemd-user.conf for 755 available options. 756 ''; 757 }; 758 759 systemd.tmpfiles.rules = mkOption { 760 type = types.listOf types.str; 761 default = []; 762 example = [ "d /tmp 1777 root root 10d" ]; 763 description = '' 764 Rules for creation, deletion and cleaning of volatile and temporary files 765 automatically. See 766 <citerefentry><refentrytitle>tmpfiles.d</refentrytitle><manvolnum>5</manvolnum></citerefentry> 767 for the exact format. 768 ''; 769 }; 770 771 systemd.tmpfiles.packages = mkOption { 772 type = types.listOf types.package; 773 default = []; 774 example = literalExpression "[ pkgs.lvm2 ]"; 775 apply = map getLib; 776 description = '' 777 List of packages containing <command>systemd-tmpfiles</command> rules. 778 779 All files ending in .conf found in 780 <filename><replaceable>pkg</replaceable>/lib/tmpfiles.d</filename> 781 will be included. 782 If this folder does not exist or does not contain any files an error will be returned instead. 783 784 If a <filename>lib</filename> output is available, rules are searched there and only there. 785 If there is no <filename>lib</filename> output it will fall back to <filename>out</filename> 786 and if that does not exist either, the default output will be used. 787 ''; 788 }; 789 790 systemd.user.units = mkOption { 791 description = "Definition of systemd per-user units."; 792 default = {}; 793 type = with types; attrsOf (submodule ( 794 { name, config, ... }: 795 { options = concreteUnitOptions; 796 config = { 797 unit = mkDefault (makeUnit name config); 798 }; 799 })); 800 }; 801 802 systemd.user.paths = mkOption { 803 default = {}; 804 type = with types; attrsOf (submodule [ { options = pathOptions; } unitConfig ]); 805 description = "Definition of systemd per-user path units."; 806 }; 807 808 systemd.user.services = mkOption { 809 default = {}; 810 type = with types; attrsOf (submodule [ { options = serviceOptions; } unitConfig serviceConfig ] ); 811 description = "Definition of systemd per-user service units."; 812 }; 813 814 systemd.user.slices = mkOption { 815 default = {}; 816 type = with types; attrsOf (submodule [ { options = sliceOptions; } unitConfig ] ); 817 description = "Definition of systemd per-user slice units."; 818 }; 819 820 systemd.user.sockets = mkOption { 821 default = {}; 822 type = with types; attrsOf (submodule [ { options = socketOptions; } unitConfig ] ); 823 description = "Definition of systemd per-user socket units."; 824 }; 825 826 systemd.user.targets = mkOption { 827 default = {}; 828 type = with types; attrsOf (submodule [ { options = targetOptions; } unitConfig] ); 829 description = "Definition of systemd per-user target units."; 830 }; 831 832 systemd.user.timers = mkOption { 833 default = {}; 834 type = with types; attrsOf (submodule [ { options = timerOptions; } unitConfig ] ); 835 description = "Definition of systemd per-user timer units."; 836 }; 837 838 systemd.additionalUpstreamSystemUnits = mkOption { 839 default = [ ]; 840 type = types.listOf types.str; 841 example = [ "debug-shell.service" "systemd-quotacheck.service" ]; 842 description = '' 843 Additional units shipped with systemd that shall be enabled. 844 ''; 845 }; 846 847 systemd.suppressedSystemUnits = mkOption { 848 default = [ ]; 849 type = types.listOf types.str; 850 example = [ "systemd-backlight@.service" ]; 851 description = '' 852 A list of units to suppress when generating system systemd configuration directory. This has 853 priority over upstream units, <option>systemd.units</option>, and 854 <option>systemd.additionalUpstreamSystemUnits</option>. The main purpose of this is to 855 suppress a upstream systemd unit with any modifications made to it by other NixOS modules. 856 ''; 857 }; 858 859 systemd.watchdog.device = mkOption { 860 type = types.nullOr types.path; 861 default = null; 862 example = "/dev/watchdog"; 863 description = '' 864 The path to a hardware watchdog device which will be managed by systemd. 865 If not specified, systemd will default to /dev/watchdog. 866 ''; 867 }; 868 869 systemd.watchdog.runtimeTime = mkOption { 870 type = types.nullOr types.str; 871 default = null; 872 example = "30s"; 873 description = '' 874 The amount of time which can elapse before a watchdog hardware device 875 will automatically reboot the system. Valid time units include "ms", 876 "s", "min", "h", "d", and "w". 877 ''; 878 }; 879 880 systemd.watchdog.rebootTime = mkOption { 881 type = types.nullOr types.str; 882 default = null; 883 example = "10m"; 884 description = '' 885 The amount of time which can elapse after a reboot has been triggered 886 before a watchdog hardware device will automatically reboot the system. 887 Valid time units include "ms", "s", "min", "h", "d", and "w". 888 ''; 889 }; 890 891 systemd.watchdog.kexecTime = mkOption { 892 type = types.nullOr types.str; 893 default = null; 894 example = "10m"; 895 description = '' 896 The amount of time which can elapse when kexec is being executed before 897 a watchdog hardware device will automatically reboot the system. This 898 option should only be enabled if reloadTime is also enabled. Valid 899 time units include "ms", "s", "min", "h", "d", and "w". 900 ''; 901 }; 902 }; 903 904 905 ###### implementation 906 907 config = { 908 909 warnings = concatLists ( 910 mapAttrsToList 911 (name: service: 912 let 913 type = service.serviceConfig.Type or ""; 914 restart = service.serviceConfig.Restart or "no"; 915 hasDeprecated = builtins.hasAttr "StartLimitInterval" service.serviceConfig; 916 in 917 concatLists [ 918 (optional (type == "oneshot" && (restart == "always" || restart == "on-success")) 919 "Service '${name}.service' with 'Type=oneshot' cannot have 'Restart=always' or 'Restart=on-success'" 920 ) 921 (optional hasDeprecated 922 "Service '${name}.service' uses the attribute 'StartLimitInterval' in the Service section, which is deprecated. See https://github.com/NixOS/nixpkgs/issues/45786." 923 ) 924 ] 925 ) 926 cfg.services 927 ); 928 929 system.build.units = cfg.units; 930 931 system.nssModules = [ systemd.out ]; 932 system.nssDatabases = { 933 hosts = (mkMerge [ 934 (mkOrder 400 ["mymachines"]) # 400 to ensure it comes before resolve (which is mkBefore'd) 935 (mkOrder 999 ["myhostname"]) # after files (which is 998), but before regular nss modules 936 ]); 937 passwd = (mkMerge [ 938 (mkAfter [ "systemd" ]) 939 ]); 940 group = (mkMerge [ 941 (mkAfter [ "systemd" ]) 942 ]); 943 }; 944 945 environment.systemPackages = [ systemd ]; 946 947 environment.etc = let 948 # generate contents for /etc/systemd/system-${type} from attrset of links and packages 949 hooks = type: links: pkgs.runCommand "system-${type}" { 950 preferLocalBuild = true; 951 packages = cfg.packages; 952 } '' 953 set -e 954 mkdir -p $out 955 for package in $packages 956 do 957 for hook in $package/lib/systemd/system-${type}/* 958 do 959 ln -s $hook $out/ 960 done 961 done 962 ${concatStrings (mapAttrsToList (exec: target: "ln -s ${target} $out/${exec};\n") links)} 963 ''; 964 965 enabledUpstreamSystemUnits = filter (n: ! elem n cfg.suppressedSystemUnits) upstreamSystemUnits; 966 enabledUnits = filterAttrs (n: v: ! elem n cfg.suppressedSystemUnits) cfg.units; 967 in ({ 968 "systemd/system".source = generateUnits "system" enabledUnits enabledUpstreamSystemUnits upstreamSystemWants; 969 970 "systemd/user".source = generateUnits "user" cfg.user.units upstreamUserUnits []; 971 972 "systemd/system.conf".text = '' 973 [Manager] 974 ${optionalString config.systemd.enableCgroupAccounting '' 975 DefaultCPUAccounting=yes 976 DefaultIOAccounting=yes 977 DefaultBlockIOAccounting=yes 978 DefaultIPAccounting=yes 979 ''} 980 DefaultLimitCORE=infinity 981 ${optionalString (config.systemd.watchdog.device != null) '' 982 WatchdogDevice=${config.systemd.watchdog.device} 983 ''} 984 ${optionalString (config.systemd.watchdog.runtimeTime != null) '' 985 RuntimeWatchdogSec=${config.systemd.watchdog.runtimeTime} 986 ''} 987 ${optionalString (config.systemd.watchdog.rebootTime != null) '' 988 RebootWatchdogSec=${config.systemd.watchdog.rebootTime} 989 ''} 990 ${optionalString (config.systemd.watchdog.kexecTime != null) '' 991 KExecWatchdogSec=${config.systemd.watchdog.kexecTime} 992 ''} 993 994 ${config.systemd.extraConfig} 995 ''; 996 997 "systemd/user.conf".text = '' 998 [Manager] 999 ${config.systemd.user.extraConfig} 1000 ''; 1001 1002 "systemd/journald.conf".text = '' 1003 [Journal] 1004 Storage=persistent 1005 RateLimitInterval=${config.services.journald.rateLimitInterval} 1006 RateLimitBurst=${toString config.services.journald.rateLimitBurst} 1007 ${optionalString (config.services.journald.console != "") '' 1008 ForwardToConsole=yes 1009 TTYPath=${config.services.journald.console} 1010 ''} 1011 ${optionalString (config.services.journald.forwardToSyslog) '' 1012 ForwardToSyslog=yes 1013 ''} 1014 ${config.services.journald.extraConfig} 1015 ''; 1016 1017 "systemd/coredump.conf".text = 1018 '' 1019 [Coredump] 1020 ${config.systemd.coredump.extraConfig} 1021 ''; 1022 1023 "systemd/logind.conf".text = '' 1024 [Login] 1025 KillUserProcesses=${if config.services.logind.killUserProcesses then "yes" else "no"} 1026 HandleLidSwitch=${config.services.logind.lidSwitch} 1027 HandleLidSwitchDocked=${config.services.logind.lidSwitchDocked} 1028 HandleLidSwitchExternalPower=${config.services.logind.lidSwitchExternalPower} 1029 ${config.services.logind.extraConfig} 1030 ''; 1031 1032 "systemd/sleep.conf".text = '' 1033 [Sleep] 1034 ${config.systemd.sleep.extraConfig} 1035 ''; 1036 1037 # install provided sysctl snippets 1038 "sysctl.d/50-coredump.conf".source = "${systemd}/example/sysctl.d/50-coredump.conf"; 1039 "sysctl.d/50-default.conf".source = "${systemd}/example/sysctl.d/50-default.conf"; 1040 1041 "tmpfiles.d".source = (pkgs.symlinkJoin { 1042 name = "tmpfiles.d"; 1043 paths = map (p: p + "/lib/tmpfiles.d") cfg.tmpfiles.packages; 1044 postBuild = '' 1045 for i in $(cat $pathsPath); do 1046 (test -d "$i" && test $(ls "$i"/*.conf | wc -l) -ge 1) || ( 1047 echo "ERROR: The path '$i' from systemd.tmpfiles.packages contains no *.conf files." 1048 exit 1 1049 ) 1050 done 1051 '' + concatMapStrings (name: optionalString (hasPrefix "tmpfiles.d/" name) '' 1052 rm -f $out/${removePrefix "tmpfiles.d/" name} 1053 '') config.system.build.etc.passthru.targets; 1054 }) + "/*"; 1055 1056 "systemd/system-generators" = { source = hooks "generators" cfg.generators; }; 1057 "systemd/system-shutdown" = { source = hooks "shutdown" cfg.shutdown; }; 1058 }); 1059 1060 services.dbus.enable = true; 1061 1062 users.users.systemd-coredump = { 1063 uid = config.ids.uids.systemd-coredump; 1064 group = "systemd-coredump"; 1065 }; 1066 users.groups.systemd-coredump = {}; 1067 users.users.systemd-network = { 1068 uid = config.ids.uids.systemd-network; 1069 group = "systemd-network"; 1070 }; 1071 users.groups.systemd-network.gid = config.ids.gids.systemd-network; 1072 users.users.systemd-resolve = { 1073 uid = config.ids.uids.systemd-resolve; 1074 group = "systemd-resolve"; 1075 }; 1076 users.groups.systemd-resolve.gid = config.ids.gids.systemd-resolve; 1077 1078 # Target for ‘charon send-keys’ to hook into. 1079 users.groups.keys.gid = config.ids.gids.keys; 1080 1081 systemd.targets.keys = 1082 { description = "Security Keys"; 1083 unitConfig.X-StopOnReconfiguration = true; 1084 }; 1085 1086 systemd.tmpfiles.packages = [ 1087 # Default tmpfiles rules provided by systemd 1088 (pkgs.runCommand "systemd-default-tmpfiles" {} '' 1089 mkdir -p $out/lib/tmpfiles.d 1090 cd $out/lib/tmpfiles.d 1091 1092 ln -s "${systemd}/example/tmpfiles.d/home.conf" 1093 ln -s "${systemd}/example/tmpfiles.d/journal-nocow.conf" 1094 ln -s "${systemd}/example/tmpfiles.d/static-nodes-permissions.conf" 1095 ln -s "${systemd}/example/tmpfiles.d/systemd.conf" 1096 ln -s "${systemd}/example/tmpfiles.d/systemd-nologin.conf" 1097 ln -s "${systemd}/example/tmpfiles.d/systemd-nspawn.conf" 1098 ln -s "${systemd}/example/tmpfiles.d/systemd-tmp.conf" 1099 ln -s "${systemd}/example/tmpfiles.d/tmp.conf" 1100 ln -s "${systemd}/example/tmpfiles.d/var.conf" 1101 ln -s "${systemd}/example/tmpfiles.d/x11.conf" 1102 '') 1103 # User-specified tmpfiles rules 1104 (pkgs.writeTextFile { 1105 name = "nixos-tmpfiles.d"; 1106 destination = "/lib/tmpfiles.d/00-nixos.conf"; 1107 text = '' 1108 # This file is created automatically and should not be modified. 1109 # Please change the option systemd.tmpfiles.rules instead. 1110 1111 ${concatStringsSep "\n" cfg.tmpfiles.rules} 1112 ''; 1113 }) 1114 ]; 1115 1116 systemd.units = 1117 mapAttrs' (n: v: nameValuePair "${n}.path" (pathToUnit n v)) cfg.paths 1118 // mapAttrs' (n: v: nameValuePair "${n}.service" (serviceToUnit n v)) cfg.services 1119 // mapAttrs' (n: v: nameValuePair "${n}.slice" (sliceToUnit n v)) cfg.slices 1120 // mapAttrs' (n: v: nameValuePair "${n}.socket" (socketToUnit n v)) cfg.sockets 1121 // mapAttrs' (n: v: nameValuePair "${n}.target" (targetToUnit n v)) cfg.targets 1122 // mapAttrs' (n: v: nameValuePair "${n}.timer" (timerToUnit n v)) cfg.timers 1123 // listToAttrs (map 1124 (v: let n = escapeSystemdPath v.where; 1125 in nameValuePair "${n}.mount" (mountToUnit n v)) cfg.mounts) 1126 // listToAttrs (map 1127 (v: let n = escapeSystemdPath v.where; 1128 in nameValuePair "${n}.automount" (automountToUnit n v)) cfg.automounts); 1129 1130 systemd.user.units = 1131 mapAttrs' (n: v: nameValuePair "${n}.path" (pathToUnit n v)) cfg.user.paths 1132 // mapAttrs' (n: v: nameValuePair "${n}.service" (serviceToUnit n v)) cfg.user.services 1133 // mapAttrs' (n: v: nameValuePair "${n}.slice" (sliceToUnit n v)) cfg.user.slices 1134 // mapAttrs' (n: v: nameValuePair "${n}.socket" (socketToUnit n v)) cfg.user.sockets 1135 // mapAttrs' (n: v: nameValuePair "${n}.target" (targetToUnit n v)) cfg.user.targets 1136 // mapAttrs' (n: v: nameValuePair "${n}.timer" (timerToUnit n v)) cfg.user.timers; 1137 1138 system.requiredKernelConfig = map config.lib.kernelConfig.isEnabled 1139 [ "DEVTMPFS" "CGROUPS" "INOTIFY_USER" "SIGNALFD" "TIMERFD" "EPOLL" "NET" 1140 "SYSFS" "PROC_FS" "FHANDLE" "CRYPTO_USER_API_HASH" "CRYPTO_HMAC" 1141 "CRYPTO_SHA256" "DMIID" "AUTOFS4_FS" "TMPFS_POSIX_ACL" 1142 "TMPFS_XATTR" "SECCOMP" 1143 ]; 1144 1145 users.groups.systemd-journal.gid = config.ids.gids.systemd-journal; 1146 users.users.systemd-journal-gateway.uid = config.ids.uids.systemd-journal-gateway; 1147 users.users.systemd-journal-gateway.group = "systemd-journal-gateway"; 1148 users.groups.systemd-journal-gateway.gid = config.ids.gids.systemd-journal-gateway; 1149 1150 # Generate timer units for all services that have a ‘startAt’ value. 1151 systemd.timers = 1152 mapAttrs (name: service: 1153 { wantedBy = [ "timers.target" ]; 1154 timerConfig.OnCalendar = service.startAt; 1155 }) 1156 (filterAttrs (name: service: service.enable && service.startAt != []) cfg.services); 1157 1158 # Generate timer units for all services that have a ‘startAt’ value. 1159 systemd.user.timers = 1160 mapAttrs (name: service: 1161 { wantedBy = [ "timers.target" ]; 1162 timerConfig.OnCalendar = service.startAt; 1163 }) 1164 (filterAttrs (name: service: service.startAt != []) cfg.user.services); 1165 1166 systemd.sockets.systemd-journal-gatewayd.wantedBy = 1167 optional config.services.journald.enableHttpGateway "sockets.target"; 1168 1169 # Provide the systemd-user PAM service, required to run systemd 1170 # user instances. 1171 security.pam.services.systemd-user = 1172 { # Ensure that pam_systemd gets included. This is special-cased 1173 # in systemd to provide XDG_RUNTIME_DIR. 1174 startSession = true; 1175 }; 1176 1177 # Some overrides to upstream units. 1178 systemd.services."systemd-backlight@".restartIfChanged = false; 1179 systemd.services."systemd-fsck@".restartIfChanged = false; 1180 systemd.services."systemd-fsck@".path = [ config.system.path ]; 1181 systemd.services."user@".restartIfChanged = false; 1182 systemd.services.systemd-journal-flush.restartIfChanged = false; 1183 systemd.services.systemd-random-seed.restartIfChanged = false; 1184 systemd.services.systemd-remount-fs.restartIfChanged = false; 1185 systemd.services.systemd-update-utmp.restartIfChanged = false; 1186 systemd.services.systemd-user-sessions.restartIfChanged = false; # Restart kills all active sessions. 1187 systemd.services.systemd-udev-settle.restartIfChanged = false; # Causes long delays in nixos-rebuild 1188 # Restarting systemd-logind breaks X11 1189 # - upstream commit: https://cgit.freedesktop.org/xorg/xserver/commit/?id=dc48bd653c7e101 1190 # - systemd announcement: https://github.com/systemd/systemd/blob/22043e4317ecd2bc7834b48a6d364de76bb26d91/NEWS#L103-L112 1191 # - this might be addressed in the future by xorg 1192 #systemd.services.systemd-logind.restartTriggers = [ config.environment.etc."systemd/logind.conf".source ]; 1193 systemd.services.systemd-logind.restartIfChanged = false; 1194 systemd.services.systemd-logind.stopIfChanged = false; 1195 # The user-runtime-dir@ service is managed by systemd-logind we should not touch it or else we break the users' sessions. 1196 systemd.services."user-runtime-dir@".stopIfChanged = false; 1197 systemd.services."user-runtime-dir@".restartIfChanged = false; 1198 systemd.services.systemd-journald.restartTriggers = [ config.environment.etc."systemd/journald.conf".source ]; 1199 systemd.services.systemd-journald.stopIfChanged = false; 1200 systemd.services."systemd-journald@".restartTriggers = [ config.environment.etc."systemd/journald.conf".source ]; 1201 systemd.services."systemd-journald@".stopIfChanged = false; 1202 systemd.targets.local-fs.unitConfig.X-StopOnReconfiguration = true; 1203 systemd.targets.remote-fs.unitConfig.X-StopOnReconfiguration = true; 1204 systemd.targets.network-online.wantedBy = [ "multi-user.target" ]; 1205 systemd.services.systemd-importd.environment = proxy_env; 1206 systemd.services.systemd-pstore.wantedBy = [ "sysinit.target" ]; # see #81138 1207 1208 # Don't bother with certain units in containers. 1209 systemd.services.systemd-remount-fs.unitConfig.ConditionVirtualization = "!container"; 1210 systemd.services.systemd-random-seed.unitConfig.ConditionVirtualization = "!container"; 1211 1212 boot.kernel.sysctl."kernel.core_pattern" = mkIf (!cfg.coredump.enable) "core"; 1213 1214 # Increase numeric PID range (set directly instead of copying a one-line file from systemd) 1215 # https://github.com/systemd/systemd/pull/12226 1216 boot.kernel.sysctl."kernel.pid_max" = mkIf pkgs.stdenv.is64bit (lib.mkDefault 4194304); 1217 1218 boot.kernelParams = optional (!cfg.enableUnifiedCgroupHierarchy) "systemd.unified_cgroup_hierarchy=0"; 1219 }; 1220 1221 # FIXME: Remove these eventually. 1222 imports = 1223 [ (mkRenamedOptionModule [ "boot" "systemd" "sockets" ] [ "systemd" "sockets" ]) 1224 (mkRenamedOptionModule [ "boot" "systemd" "targets" ] [ "systemd" "targets" ]) 1225 (mkRenamedOptionModule [ "boot" "systemd" "services" ] [ "systemd" "services" ]) 1226 (mkRenamedOptionModule [ "jobs" ] [ "systemd" "services" ]) 1227 (mkRemovedOptionModule [ "systemd" "generator-packages" ] "Use systemd.packages instead.") 1228 ]; 1229}