Merge pull request #307528 from WilliButz/systemd-initrd/tmpfiles-settings

nixos/systemd-tmpfiles: add initrd support

authored by nikstur and committed by GitHub 0a810476 3e7b3a35

+179 -104
-1
nixos/modules/system/boot/systemd.nix
··· 53 53 "debug-shell.service" 54 54 55 55 # Udev. 56 - "systemd-tmpfiles-setup-dev-early.service" 57 56 "systemd-udevd-control.socket" 58 57 "systemd-udevd-kernel.socket" 59 58 "systemd-udevd.service"
-4
nixos/modules/system/boot/systemd/initrd.nix
··· 67 67 "systemd-poweroff.service" 68 68 "systemd-reboot.service" 69 69 "systemd-sysctl.service" 70 - "systemd-tmpfiles-setup-dev.service" 71 - "systemd-tmpfiles-setup.service" 72 70 "timers.target" 73 71 "tpm2.target" 74 72 "umount.target" ··· 518 516 (v: let n = escapeSystemdPath v.where; 519 517 in nameValuePair "${n}.automount" (automountToUnit v)) cfg.automounts); 520 518 521 - # make sure all the /dev nodes are set up 522 - services.systemd-tmpfiles-setup-dev.wantedBy = ["sysinit.target"]; 523 519 524 520 services.initrd-nixos-activation = { 525 521 after = [ "initrd-fs.target" ];
+179 -99
nixos/modules/system/boot/systemd/tmpfiles.nix
··· 1 - { config, lib, pkgs, utils, ... }: 1 + { config, lib, pkgs, ... }: 2 2 3 3 with lib; 4 4 5 5 let 6 6 cfg = config.systemd.tmpfiles; 7 + initrdCfg = config.boot.initrd.systemd.tmpfiles; 7 8 systemd = config.systemd.package; 9 + 10 + settingsOption = { 11 + description = '' 12 + Declare systemd-tmpfiles rules to create, delete, and clean up volatile 13 + and temporary files and directories. 14 + 15 + Even though the service is called `*tmp*files` you can also create 16 + persistent files. 17 + ''; 18 + example = { 19 + "10-mypackage" = { 20 + "/var/lib/my-service/statefolder".d = { 21 + mode = "0755"; 22 + user = "root"; 23 + group = "root"; 24 + }; 25 + }; 26 + }; 27 + default = {}; 28 + type = types.attrsOf (types.attrsOf (types.attrsOf (types.submodule ({ name, config, ... }: { 29 + options.type = mkOption { 30 + type = types.str; 31 + default = name; 32 + example = "d"; 33 + description = '' 34 + The type of operation to perform on the file. 35 + 36 + The type consists of a single letter and optionally one or more 37 + modifier characters. 38 + 39 + Please see the upstream documentation for the available types and 40 + more details: 41 + <https://www.freedesktop.org/software/systemd/man/tmpfiles.d> 42 + ''; 43 + }; 44 + options.mode = mkOption { 45 + type = types.str; 46 + default = "-"; 47 + example = "0755"; 48 + description = '' 49 + The file access mode to use when creating this file or directory. 50 + ''; 51 + }; 52 + options.user = mkOption { 53 + type = types.str; 54 + default = "-"; 55 + example = "root"; 56 + description = '' 57 + The user of the file. 58 + 59 + This may either be a numeric ID or a user/group name. 60 + 61 + If omitted or when set to `"-"`, the user and group of the user who 62 + invokes systemd-tmpfiles is used. 63 + ''; 64 + }; 65 + options.group = mkOption { 66 + type = types.str; 67 + default = "-"; 68 + example = "root"; 69 + description = '' 70 + The group of the file. 71 + 72 + This may either be a numeric ID or a user/group name. 73 + 74 + If omitted or when set to `"-"`, the user and group of the user who 75 + invokes systemd-tmpfiles is used. 76 + ''; 77 + }; 78 + options.age = mkOption { 79 + type = types.str; 80 + default = "-"; 81 + example = "10d"; 82 + description = '' 83 + Delete a file when it reaches a certain age. 84 + 85 + If a file or directory is older than the current time minus the age 86 + field, it is deleted. 87 + 88 + If set to `"-"` no automatic clean-up is done. 89 + ''; 90 + }; 91 + options.argument = mkOption { 92 + type = types.str; 93 + default = ""; 94 + example = ""; 95 + description = '' 96 + An argument whose meaning depends on the type of operation. 97 + 98 + Please see the upstream documentation for the meaning of this 99 + parameter in different situations: 100 + <https://www.freedesktop.org/software/systemd/man/tmpfiles.d> 101 + ''; 102 + }; 103 + })))); 104 + }; 105 + 106 + # generates a single entry for a tmpfiles.d rule 107 + settingsEntryToRule = path: entry: '' 108 + '${entry.type}' '${path}' '${entry.mode}' '${entry.user}' '${entry.group}' '${entry.age}' ${entry.argument} 109 + ''; 110 + 111 + # generates a list of tmpfiles.d rules from the attrs (paths) under tmpfiles.settings.<name> 112 + pathsToRules = mapAttrsToList (path: types: 113 + concatStrings ( 114 + mapAttrsToList (_type: settingsEntryToRule path) types 115 + ) 116 + ); 117 + 118 + mkRuleFileContent = paths: concatStrings (pathsToRules paths); 8 119 in 9 120 { 10 121 options = { ··· 20 131 ''; 21 132 }; 22 133 23 - systemd.tmpfiles.settings = mkOption { 134 + systemd.tmpfiles.settings = mkOption settingsOption; 135 + 136 + boot.initrd.systemd.tmpfiles.settings = mkOption (settingsOption // { 24 137 description = '' 25 - Declare systemd-tmpfiles rules to create, delete, and clean up volatile 26 - and temporary files and directories. 138 + Similar to {option}`systemd.tmpfiles.settings` but the rules are 139 + only applied by systemd-tmpfiles before `initrd-switch-root.target`. 27 140 28 - Even though the service is called `*tmp*files` you can also create 29 - persistent files. 141 + See {manpage}`bootup(7)`. 30 142 ''; 31 - example = { 32 - "10-mypackage" = { 33 - "/var/lib/my-service/statefolder".d = { 34 - mode = "0755"; 35 - user = "root"; 36 - group = "root"; 37 - }; 38 - }; 39 - }; 40 - default = {}; 41 - type = types.attrsOf (types.attrsOf (types.attrsOf (types.submodule ({ name, config, ... }: { 42 - options.type = mkOption { 43 - type = types.str; 44 - default = name; 45 - example = "d"; 46 - description = '' 47 - The type of operation to perform on the file. 48 - 49 - The type consists of a single letter and optionally one or more 50 - modifier characters. 51 - 52 - Please see the upstream documentation for the available types and 53 - more details: 54 - <https://www.freedesktop.org/software/systemd/man/tmpfiles.d> 55 - ''; 56 - }; 57 - options.mode = mkOption { 58 - type = types.str; 59 - default = "-"; 60 - example = "0755"; 61 - description = '' 62 - The file access mode to use when creating this file or directory. 63 - ''; 64 - }; 65 - options.user = mkOption { 66 - type = types.str; 67 - default = "-"; 68 - example = "root"; 69 - description = '' 70 - The user of the file. 71 - 72 - This may either be a numeric ID or a user/group name. 73 - 74 - If omitted or when set to `"-"`, the user and group of the user who 75 - invokes systemd-tmpfiles is used. 76 - ''; 77 - }; 78 - options.group = mkOption { 79 - type = types.str; 80 - default = "-"; 81 - example = "root"; 82 - description = '' 83 - The group of the file. 84 - 85 - This may either be a numeric ID or a user/group name. 86 - 87 - If omitted or when set to `"-"`, the user and group of the user who 88 - invokes systemd-tmpfiles is used. 89 - ''; 90 - }; 91 - options.age = mkOption { 92 - type = types.str; 93 - default = "-"; 94 - example = "10d"; 95 - description = '' 96 - Delete a file when it reaches a certain age. 97 - 98 - If a file or directory is older than the current time minus the age 99 - field, it is deleted. 100 - 101 - If set to `"-"` no automatic clean-up is done. 102 - ''; 103 - }; 104 - options.argument = mkOption { 105 - type = types.str; 106 - default = ""; 107 - example = ""; 108 - description = '' 109 - An argument whose meaning depends on the type of operation. 110 - 111 - Please see the upstream documentation for the meaning of this 112 - parameter in different situations: 113 - <https://www.freedesktop.org/software/systemd/man/tmpfiles.d> 114 - ''; 115 - }; 116 - })))); 117 - }; 143 + }); 118 144 119 145 systemd.tmpfiles.packages = mkOption { 120 146 type = types.listOf types.package; ··· 140 166 systemd.additionalUpstreamSystemUnits = [ 141 167 "systemd-tmpfiles-clean.service" 142 168 "systemd-tmpfiles-clean.timer" 169 + "systemd-tmpfiles-setup-dev-early.service" 170 + "systemd-tmpfiles-setup-dev.service" 143 171 "systemd-tmpfiles-setup.service" 144 - "systemd-tmpfiles-setup-dev.service" 145 172 ]; 146 173 147 174 systemd.additionalUpstreamUserUnits = [ ··· 236 263 ''; 237 264 }) 238 265 ] ++ (mapAttrsToList (name: paths: 239 - pkgs.writeTextDir "lib/tmpfiles.d/${name}.conf" (concatStrings (mapAttrsToList (path: types: 240 - concatStrings (mapAttrsToList (_type: entry: '' 241 - '${entry.type}' '${path}' '${entry.mode}' '${entry.user}' '${entry.group}' '${entry.age}' ${entry.argument} 242 - '') types) 243 - ) paths )) 266 + pkgs.writeTextDir "lib/tmpfiles.d/${name}.conf" (mkRuleFileContent paths) 244 267 ) cfg.settings); 245 268 246 269 systemd.tmpfiles.rules = [ ··· 256 279 "R! /nix/var/nix/gcroots/tmp - - - - -" 257 280 "R! /nix/var/nix/temproots - - - - -" 258 281 ]; 282 + 283 + boot.initrd.systemd = { 284 + additionalUpstreamUnits = [ 285 + "systemd-tmpfiles-setup-dev-early.service" 286 + "systemd-tmpfiles-setup-dev.service" 287 + "systemd-tmpfiles-setup.service" 288 + ]; 289 + 290 + # override to exclude the prefix /sysroot, because it is not necessarily set up when the unit starts 291 + services.systemd-tmpfiles-setup.serviceConfig = { 292 + ExecStart = [ 293 + "" 294 + "systemd-tmpfiles --create --remove --boot --exclude-prefix=/dev --exclude-prefix=/sysroot" 295 + ]; 296 + }; 297 + 298 + # sets up files under the prefix /sysroot, after the hierarchy is available and before nixos activation 299 + services.systemd-tmpfiles-setup-sysroot = { 300 + description = "Create Volatile Files and Directories in the Real Root"; 301 + after = [ "initrd-fs.target" ]; 302 + before = [ 303 + "initrd-nixos-activation.service" 304 + "shutdown.target" "initrd-switch-root.target" 305 + ]; 306 + conflicts = [ "shutdown.target" "initrd-switch-root.target" ]; 307 + wantedBy = [ "initrd.target" ]; 308 + serviceConfig = { 309 + Type = "oneshot"; 310 + RemainAfterExit = true; 311 + ExecStart = "systemd-tmpfiles --create --remove --boot --exclude-prefix=/dev --prefix=/sysroot"; 312 + SuccessExitStatus = [ "DATAERR CANTCREAT" ]; 313 + ImportCredential = [ 314 + "tmpfiles.*" 315 + "login.motd" 316 + "login.issue" 317 + "network.hosts" 318 + "ssh.authorized_keys.root" 319 + ]; 320 + }; 321 + unitConfig = { 322 + DefaultDependencies = false; 323 + RefuseManualStop = true; 324 + }; 325 + 326 + }; 327 + 328 + contents."/etc/tmpfiles.d" = mkIf (initrdCfg.settings != { }) { 329 + source = pkgs.linkFarm "initrd-tmpfiles.d" ( 330 + mapAttrsToList 331 + (name: paths: { 332 + name = "${name}.conf"; 333 + path = pkgs.writeText "${name}.conf" (mkRuleFileContent paths); 334 + } 335 + ) 336 + initrdCfg.settings); 337 + }; 338 + }; 259 339 }; 260 340 }