at 23.05-pre 22 kB view raw
1{ config, lib, pkgs, utils, ... }: 2 3with utils; 4with systemdUtils.unitOptions; 5with lib; 6 7let 8 9 cfg = config.systemd; 10 11 inherit (systemdUtils.lib) 12 generateUnits 13 targetToUnit 14 serviceToUnit 15 socketToUnit 16 timerToUnit 17 pathToUnit 18 mountToUnit 19 automountToUnit 20 sliceToUnit; 21 22 upstreamSystemUnits = 23 [ # Targets. 24 "basic.target" 25 "sysinit.target" 26 "sockets.target" 27 "exit.target" 28 "graphical.target" 29 "multi-user.target" 30 "network.target" 31 "network-pre.target" 32 "network-online.target" 33 "nss-lookup.target" 34 "nss-user-lookup.target" 35 "time-sync.target" 36 ] ++ optionals cfg.package.withCryptsetup [ 37 "cryptsetup.target" 38 "cryptsetup-pre.target" 39 "remote-cryptsetup.target" 40 ] ++ [ 41 "sigpwr.target" 42 "timers.target" 43 "paths.target" 44 "rpcbind.target" 45 46 # Rescue mode. 47 "rescue.target" 48 "rescue.service" 49 50 # Udev. 51 "systemd-udevd-control.socket" 52 "systemd-udevd-kernel.socket" 53 "systemd-udevd.service" 54 "systemd-udev-settle.service" 55 ] ++ (optional (!config.boot.isContainer) "systemd-udev-trigger.service") ++ [ 56 # hwdb.bin is managed by NixOS 57 # "systemd-hwdb-update.service" 58 59 # Consoles. 60 "getty.target" 61 "getty-pre.target" 62 "getty@.service" 63 "serial-getty@.service" 64 "console-getty.service" 65 "container-getty@.service" 66 "systemd-vconsole-setup.service" 67 68 # Hardware (started by udev when a relevant device is plugged in). 69 "sound.target" 70 "bluetooth.target" 71 "printer.target" 72 "smartcard.target" 73 74 # Kernel module loading. 75 "systemd-modules-load.service" 76 "kmod-static-nodes.service" 77 "modprobe@.service" 78 79 # Filesystems. 80 "systemd-fsck@.service" 81 "systemd-fsck-root.service" 82 "systemd-remount-fs.service" 83 "systemd-pstore.service" 84 "local-fs.target" 85 "local-fs-pre.target" 86 "remote-fs.target" 87 "remote-fs-pre.target" 88 "swap.target" 89 "dev-hugepages.mount" 90 "dev-mqueue.mount" 91 "sys-fs-fuse-connections.mount" 92 ] ++ (optional (!config.boot.isContainer) "sys-kernel-config.mount") ++ [ 93 "sys-kernel-debug.mount" 94 95 # Maintaining state across reboots. 96 "systemd-random-seed.service" 97 "systemd-backlight@.service" 98 "systemd-rfkill.service" 99 "systemd-rfkill.socket" 100 101 # Hibernate / suspend. 102 "hibernate.target" 103 "suspend.target" 104 "suspend-then-hibernate.target" 105 "sleep.target" 106 "hybrid-sleep.target" 107 "systemd-hibernate.service" 108 "systemd-hybrid-sleep.service" 109 "systemd-suspend.service" 110 "systemd-suspend-then-hibernate.service" 111 112 # Reboot stuff. 113 "reboot.target" 114 "systemd-reboot.service" 115 "poweroff.target" 116 "systemd-poweroff.service" 117 "halt.target" 118 "systemd-halt.service" 119 "shutdown.target" 120 "umount.target" 121 "final.target" 122 "kexec.target" 123 "systemd-kexec.service" 124 ] ++ lib.optional cfg.package.withUtmp "systemd-update-utmp.service" ++ [ 125 126 # Password entry. 127 "systemd-ask-password-console.path" 128 "systemd-ask-password-console.service" 129 "systemd-ask-password-wall.path" 130 "systemd-ask-password-wall.service" 131 132 # Slices / containers. 133 "slices.target" 134 ] ++ optionals cfg.package.withImportd [ 135 "systemd-importd.service" 136 ] ++ optionals cfg.package.withMachined [ 137 "machine.slice" 138 "machines.target" 139 "systemd-machined.service" 140 ] ++ [ 141 "systemd-nspawn@.service" 142 143 # Misc. 144 "systemd-sysctl.service" 145 ] ++ optionals cfg.package.withTimedated [ 146 "dbus-org.freedesktop.timedate1.service" 147 "systemd-timedated.service" 148 ] ++ optionals cfg.package.withLocaled [ 149 "dbus-org.freedesktop.locale1.service" 150 "systemd-localed.service" 151 ] ++ optionals cfg.package.withHostnamed [ 152 "dbus-org.freedesktop.hostname1.service" 153 "systemd-hostnamed.service" 154 ] ++ optionals cfg.package.withPortabled [ 155 "dbus-org.freedesktop.portable1.service" 156 "systemd-portabled.service" 157 ] ++ [ 158 "systemd-exit.service" 159 "systemd-update-done.service" 160 ] ++ cfg.additionalUpstreamSystemUnits; 161 162 upstreamSystemWants = 163 [ "sysinit.target.wants" 164 "sockets.target.wants" 165 "local-fs.target.wants" 166 "multi-user.target.wants" 167 "timers.target.wants" 168 ]; 169 170 proxy_env = config.networking.proxy.envVars; 171 172in 173 174{ 175 ###### interface 176 177 options = { 178 179 systemd.package = mkOption { 180 default = pkgs.systemd; 181 defaultText = literalExpression "pkgs.systemd"; 182 type = types.package; 183 description = lib.mdDoc "The systemd package."; 184 }; 185 186 systemd.units = mkOption { 187 description = lib.mdDoc "Definition of systemd units."; 188 default = {}; 189 type = systemdUtils.types.units; 190 }; 191 192 systemd.packages = mkOption { 193 default = []; 194 type = types.listOf types.package; 195 example = literalExpression "[ pkgs.systemd-cryptsetup-generator ]"; 196 description = lib.mdDoc "Packages providing systemd units and hooks."; 197 }; 198 199 systemd.targets = mkOption { 200 default = {}; 201 type = systemdUtils.types.targets; 202 description = lib.mdDoc "Definition of systemd target units."; 203 }; 204 205 systemd.services = mkOption { 206 default = {}; 207 type = systemdUtils.types.services; 208 description = lib.mdDoc "Definition of systemd service units."; 209 }; 210 211 systemd.sockets = mkOption { 212 default = {}; 213 type = systemdUtils.types.sockets; 214 description = lib.mdDoc "Definition of systemd socket units."; 215 }; 216 217 systemd.timers = mkOption { 218 default = {}; 219 type = systemdUtils.types.timers; 220 description = lib.mdDoc "Definition of systemd timer units."; 221 }; 222 223 systemd.paths = mkOption { 224 default = {}; 225 type = systemdUtils.types.paths; 226 description = lib.mdDoc "Definition of systemd path units."; 227 }; 228 229 systemd.mounts = mkOption { 230 default = []; 231 type = systemdUtils.types.mounts; 232 description = lib.mdDoc '' 233 Definition of systemd mount units. 234 This is a list instead of an attrSet, because systemd mandates the names to be derived from 235 the 'where' attribute. 236 ''; 237 }; 238 239 systemd.automounts = mkOption { 240 default = []; 241 type = systemdUtils.types.automounts; 242 description = lib.mdDoc '' 243 Definition of systemd automount units. 244 This is a list instead of an attrSet, because systemd mandates the names to be derived from 245 the 'where' attribute. 246 ''; 247 }; 248 249 systemd.slices = mkOption { 250 default = {}; 251 type = systemdUtils.types.slices; 252 description = lib.mdDoc "Definition of slice configurations."; 253 }; 254 255 systemd.generators = mkOption { 256 type = types.attrsOf types.path; 257 default = {}; 258 example = { systemd-gpt-auto-generator = "/dev/null"; }; 259 description = lib.mdDoc '' 260 Definition of systemd generators. 261 For each `NAME = VALUE` pair of the attrSet, a link is generated from 262 `/etc/systemd/system-generators/NAME` to `VALUE`. 263 ''; 264 }; 265 266 systemd.shutdown = mkOption { 267 type = types.attrsOf types.path; 268 default = {}; 269 description = lib.mdDoc '' 270 Definition of systemd shutdown executables. 271 For each `NAME = VALUE` pair of the attrSet, a link is generated from 272 `/etc/systemd/system-shutdown/NAME` to `VALUE`. 273 ''; 274 }; 275 276 systemd.defaultUnit = mkOption { 277 default = "multi-user.target"; 278 type = types.str; 279 description = lib.mdDoc "Default unit started when the system boots."; 280 }; 281 282 systemd.ctrlAltDelUnit = mkOption { 283 default = "reboot.target"; 284 type = types.str; 285 example = "poweroff.target"; 286 description = lib.mdDoc '' 287 Target that should be started when Ctrl-Alt-Delete is pressed. 288 ''; 289 }; 290 291 systemd.globalEnvironment = mkOption { 292 type = with types; attrsOf (nullOr (oneOf [ str path package ])); 293 default = {}; 294 example = { TZ = "CET"; }; 295 description = lib.mdDoc '' 296 Environment variables passed to *all* systemd units. 297 ''; 298 }; 299 300 systemd.managerEnvironment = mkOption { 301 type = with types; attrsOf (nullOr (oneOf [ str path package ])); 302 default = {}; 303 example = { SYSTEMD_LOG_LEVEL = "debug"; }; 304 description = lib.mdDoc '' 305 Environment variables of PID 1. These variables are 306 *not* passed to started units. 307 ''; 308 }; 309 310 systemd.enableCgroupAccounting = mkOption { 311 default = true; 312 type = types.bool; 313 description = lib.mdDoc '' 314 Whether to enable cgroup accounting. 315 ''; 316 }; 317 318 systemd.enableUnifiedCgroupHierarchy = mkOption { 319 default = true; 320 type = types.bool; 321 description = lib.mdDoc '' 322 Whether to enable the unified cgroup hierarchy (cgroupsv2). 323 ''; 324 }; 325 326 systemd.extraConfig = mkOption { 327 default = ""; 328 type = types.lines; 329 example = "DefaultLimitCORE=infinity"; 330 description = lib.mdDoc '' 331 Extra config options for systemd. See systemd-system.conf(5) man page 332 for available options. 333 ''; 334 }; 335 336 systemd.sleep.extraConfig = mkOption { 337 default = ""; 338 type = types.lines; 339 example = "HibernateDelaySec=1h"; 340 description = lib.mdDoc '' 341 Extra config options for systemd sleep state logic. 342 See sleep.conf.d(5) man page for available options. 343 ''; 344 }; 345 346 systemd.additionalUpstreamSystemUnits = mkOption { 347 default = [ ]; 348 type = types.listOf types.str; 349 example = [ "debug-shell.service" "systemd-quotacheck.service" ]; 350 description = lib.mdDoc '' 351 Additional units shipped with systemd that shall be enabled. 352 ''; 353 }; 354 355 systemd.suppressedSystemUnits = mkOption { 356 default = [ ]; 357 type = types.listOf types.str; 358 example = [ "systemd-backlight@.service" ]; 359 description = lib.mdDoc '' 360 A list of units to skip when generating system systemd configuration directory. This has 361 priority over upstream units, {option}`systemd.units`, and 362 {option}`systemd.additionalUpstreamSystemUnits`. The main purpose of this is to 363 prevent a upstream systemd unit from being added to the initrd with any modifications made to it 364 by other NixOS modules. 365 ''; 366 }; 367 368 systemd.watchdog.device = mkOption { 369 type = types.nullOr types.path; 370 default = null; 371 example = "/dev/watchdog"; 372 description = lib.mdDoc '' 373 The path to a hardware watchdog device which will be managed by systemd. 374 If not specified, systemd will default to /dev/watchdog. 375 ''; 376 }; 377 378 systemd.watchdog.runtimeTime = mkOption { 379 type = types.nullOr types.str; 380 default = null; 381 example = "30s"; 382 description = lib.mdDoc '' 383 The amount of time which can elapse before a watchdog hardware device 384 will automatically reboot the system. Valid time units include "ms", 385 "s", "min", "h", "d", and "w". 386 ''; 387 }; 388 389 systemd.watchdog.rebootTime = mkOption { 390 type = types.nullOr types.str; 391 default = null; 392 example = "10m"; 393 description = lib.mdDoc '' 394 The amount of time which can elapse after a reboot has been triggered 395 before a watchdog hardware device will automatically reboot the system. 396 Valid time units include "ms", "s", "min", "h", "d", and "w". 397 ''; 398 }; 399 400 systemd.watchdog.kexecTime = mkOption { 401 type = types.nullOr types.str; 402 default = null; 403 example = "10m"; 404 description = lib.mdDoc '' 405 The amount of time which can elapse when kexec is being executed before 406 a watchdog hardware device will automatically reboot the system. This 407 option should only be enabled if reloadTime is also enabled. Valid 408 time units include "ms", "s", "min", "h", "d", and "w". 409 ''; 410 }; 411 }; 412 413 414 ###### implementation 415 416 config = { 417 418 warnings = concatLists ( 419 mapAttrsToList 420 (name: service: 421 let 422 type = service.serviceConfig.Type or ""; 423 restart = service.serviceConfig.Restart or "no"; 424 hasDeprecated = builtins.hasAttr "StartLimitInterval" service.serviceConfig; 425 in 426 concatLists [ 427 (optional (type == "oneshot" && (restart == "always" || restart == "on-success")) 428 "Service '${name}.service' with 'Type=oneshot' cannot have 'Restart=always' or 'Restart=on-success'" 429 ) 430 (optional hasDeprecated 431 "Service '${name}.service' uses the attribute 'StartLimitInterval' in the Service section, which is deprecated. See https://github.com/NixOS/nixpkgs/issues/45786." 432 ) 433 (optional (service.reloadIfChanged && service.reloadTriggers != []) 434 "Service '${name}.service' has both 'reloadIfChanged' and 'reloadTriggers' set. This is probably not what you want, because 'reloadTriggers' behave the same whay as 'restartTriggers' if 'reloadIfChanged' is set." 435 ) 436 ] 437 ) 438 cfg.services 439 ); 440 441 system.build.units = cfg.units; 442 443 system.nssModules = [ cfg.package.out ]; 444 system.nssDatabases = { 445 hosts = (mkMerge [ 446 (mkOrder 400 ["mymachines"]) # 400 to ensure it comes before resolve (which is mkBefore'd) 447 (mkOrder 999 ["myhostname"]) # after files (which is 998), but before regular nss modules 448 ]); 449 passwd = (mkMerge [ 450 (mkAfter [ "systemd" ]) 451 ]); 452 group = (mkMerge [ 453 (mkAfter [ "systemd" ]) 454 ]); 455 }; 456 457 environment.systemPackages = [ cfg.package ]; 458 459 environment.etc = let 460 # generate contents for /etc/systemd/system-${type} from attrset of links and packages 461 hooks = type: links: pkgs.runCommand "system-${type}" { 462 preferLocalBuild = true; 463 packages = cfg.packages; 464 } '' 465 set -e 466 mkdir -p $out 467 for package in $packages 468 do 469 for hook in $package/lib/systemd/system-${type}/* 470 do 471 ln -s $hook $out/ 472 done 473 done 474 ${concatStrings (mapAttrsToList (exec: target: "ln -s ${target} $out/${exec};\n") links)} 475 ''; 476 477 enabledUpstreamSystemUnits = filter (n: ! elem n cfg.suppressedSystemUnits) upstreamSystemUnits; 478 enabledUnits = filterAttrs (n: v: ! elem n cfg.suppressedSystemUnits) cfg.units; 479 480 in ({ 481 "systemd/system".source = generateUnits { 482 type = "system"; 483 units = enabledUnits; 484 upstreamUnits = enabledUpstreamSystemUnits; 485 upstreamWants = upstreamSystemWants; 486 }; 487 488 "systemd/system.conf".text = '' 489 [Manager] 490 ManagerEnvironment=${lib.concatStringsSep " " (lib.mapAttrsToList (n: v: "${n}=${lib.escapeShellArg v}") cfg.managerEnvironment)} 491 ${optionalString config.systemd.enableCgroupAccounting '' 492 DefaultCPUAccounting=yes 493 DefaultIOAccounting=yes 494 DefaultBlockIOAccounting=yes 495 DefaultIPAccounting=yes 496 ''} 497 DefaultLimitCORE=infinity 498 ${optionalString (config.systemd.watchdog.device != null) '' 499 WatchdogDevice=${config.systemd.watchdog.device} 500 ''} 501 ${optionalString (config.systemd.watchdog.runtimeTime != null) '' 502 RuntimeWatchdogSec=${config.systemd.watchdog.runtimeTime} 503 ''} 504 ${optionalString (config.systemd.watchdog.rebootTime != null) '' 505 RebootWatchdogSec=${config.systemd.watchdog.rebootTime} 506 ''} 507 ${optionalString (config.systemd.watchdog.kexecTime != null) '' 508 KExecWatchdogSec=${config.systemd.watchdog.kexecTime} 509 ''} 510 511 ${config.systemd.extraConfig} 512 ''; 513 514 "systemd/sleep.conf".text = '' 515 [Sleep] 516 ${config.systemd.sleep.extraConfig} 517 ''; 518 519 "systemd/system-generators" = { source = hooks "generators" cfg.generators; }; 520 "systemd/system-shutdown" = { source = hooks "shutdown" cfg.shutdown; }; 521 }); 522 523 services.dbus.enable = true; 524 525 users.users.systemd-network = { 526 uid = config.ids.uids.systemd-network; 527 group = "systemd-network"; 528 }; 529 users.groups.systemd-network.gid = config.ids.gids.systemd-network; 530 users.users.systemd-resolve = { 531 uid = config.ids.uids.systemd-resolve; 532 group = "systemd-resolve"; 533 }; 534 users.groups.systemd-resolve.gid = config.ids.gids.systemd-resolve; 535 536 # Target for ‘charon send-keys’ to hook into. 537 users.groups.keys.gid = config.ids.gids.keys; 538 539 systemd.targets.keys = 540 { description = "Security Keys"; 541 unitConfig.X-StopOnReconfiguration = true; 542 }; 543 544 systemd.units = 545 mapAttrs' (n: v: nameValuePair "${n}.path" (pathToUnit n v)) cfg.paths 546 // mapAttrs' (n: v: nameValuePair "${n}.service" (serviceToUnit n v)) cfg.services 547 // mapAttrs' (n: v: nameValuePair "${n}.slice" (sliceToUnit n v)) cfg.slices 548 // mapAttrs' (n: v: nameValuePair "${n}.socket" (socketToUnit n v)) cfg.sockets 549 // mapAttrs' (n: v: nameValuePair "${n}.target" (targetToUnit n v)) cfg.targets 550 // mapAttrs' (n: v: nameValuePair "${n}.timer" (timerToUnit n v)) cfg.timers 551 // listToAttrs (map 552 (v: let n = escapeSystemdPath v.where; 553 in nameValuePair "${n}.mount" (mountToUnit n v)) cfg.mounts) 554 // listToAttrs (map 555 (v: let n = escapeSystemdPath v.where; 556 in nameValuePair "${n}.automount" (automountToUnit n v)) cfg.automounts); 557 558 # Environment of PID 1 559 systemd.managerEnvironment = { 560 # Doesn't contain systemd itself - everything works so it seems to use the compiled-in value for its tools 561 # util-linux is needed for the main fsck utility wrapping the fs-specific ones 562 PATH = lib.makeBinPath (config.system.fsPackages ++ [cfg.package.util-linux]); 563 LOCALE_ARCHIVE = "/run/current-system/sw/lib/locale/locale-archive"; 564 TZDIR = "/etc/zoneinfo"; 565 # If SYSTEMD_UNIT_PATH ends with an empty component (":"), the usual unit load path will be appended to the contents of the variable 566 SYSTEMD_UNIT_PATH = lib.mkIf (config.boot.extraSystemdUnitPaths != []) "${builtins.concatStringsSep ":" config.boot.extraSystemdUnitPaths}:"; 567 }; 568 569 570 system.requiredKernelConfig = map config.lib.kernelConfig.isEnabled 571 [ "DEVTMPFS" "CGROUPS" "INOTIFY_USER" "SIGNALFD" "TIMERFD" "EPOLL" "NET" 572 "SYSFS" "PROC_FS" "FHANDLE" "CRYPTO_USER_API_HASH" "CRYPTO_HMAC" 573 "CRYPTO_SHA256" "DMIID" "AUTOFS4_FS" "TMPFS_POSIX_ACL" 574 "TMPFS_XATTR" "SECCOMP" 575 ]; 576 577 # Generate timer units for all services that have a ‘startAt’ value. 578 systemd.timers = 579 mapAttrs (name: service: 580 { wantedBy = [ "timers.target" ]; 581 timerConfig.OnCalendar = service.startAt; 582 }) 583 (filterAttrs (name: service: service.enable && service.startAt != []) cfg.services); 584 585 # Some overrides to upstream units. 586 systemd.services."systemd-backlight@".restartIfChanged = false; 587 systemd.services."systemd-fsck@".restartIfChanged = false; 588 systemd.services."systemd-fsck@".path = [ config.system.path ]; 589 systemd.services.systemd-random-seed.restartIfChanged = false; 590 systemd.services.systemd-remount-fs.restartIfChanged = false; 591 systemd.services.systemd-update-utmp.restartIfChanged = false; 592 systemd.services.systemd-udev-settle.restartIfChanged = false; # Causes long delays in nixos-rebuild 593 systemd.targets.local-fs.unitConfig.X-StopOnReconfiguration = true; 594 systemd.targets.remote-fs.unitConfig.X-StopOnReconfiguration = true; 595 systemd.targets.network-online.wantedBy = [ "multi-user.target" ]; 596 systemd.services.systemd-importd.environment = proxy_env; 597 systemd.services.systemd-pstore.wantedBy = [ "sysinit.target" ]; # see #81138 598 599 # NixOS has kernel modules in a different location, so override that here. 600 systemd.services.kmod-static-nodes.unitConfig.ConditionFileNotEmpty = [ 601 "" # required to unset the previous value! 602 "/run/booted-system/kernel-modules/lib/modules/%v/modules.devname" 603 ]; 604 605 # Don't bother with certain units in containers. 606 systemd.services.systemd-remount-fs.unitConfig.ConditionVirtualization = "!container"; 607 systemd.services.systemd-random-seed.unitConfig.ConditionVirtualization = "!container"; 608 609 # Increase numeric PID range (set directly instead of copying a one-line file from systemd) 610 # https://github.com/systemd/systemd/pull/12226 611 boot.kernel.sysctl."kernel.pid_max" = mkIf pkgs.stdenv.is64bit (lib.mkDefault 4194304); 612 613 boot.kernelParams = optional (!cfg.enableUnifiedCgroupHierarchy) "systemd.unified_cgroup_hierarchy=0"; 614 615 services.logrotate.settings = { 616 "/var/log/btmp" = mapAttrs (_: mkDefault) { 617 frequency = "monthly"; 618 rotate = 1; 619 create = "0660 root ${config.users.groups.utmp.name}"; 620 minsize = "1M"; 621 }; 622 "/var/log/wtmp" = mapAttrs (_: mkDefault) { 623 frequency = "monthly"; 624 rotate = 1; 625 create = "0664 root ${config.users.groups.utmp.name}"; 626 minsize = "1M"; 627 }; 628 }; 629 }; 630 631 # FIXME: Remove these eventually. 632 imports = 633 [ (mkRenamedOptionModule [ "boot" "systemd" "sockets" ] [ "systemd" "sockets" ]) 634 (mkRenamedOptionModule [ "boot" "systemd" "targets" ] [ "systemd" "targets" ]) 635 (mkRenamedOptionModule [ "boot" "systemd" "services" ] [ "systemd" "services" ]) 636 (mkRenamedOptionModule [ "jobs" ] [ "systemd" "services" ]) 637 (mkRemovedOptionModule [ "systemd" "generator-packages" ] "Use systemd.packages instead.") 638 ]; 639}