at 24.11-pre 9.2 kB view raw
1{ config, lib, pkgs, utils, ... }: 2 3with lib; 4 5let 6 cfg = config.systemd.tmpfiles; 7 systemd = config.systemd.package; 8in 9{ 10 options = { 11 systemd.tmpfiles.rules = mkOption { 12 type = types.listOf types.str; 13 default = []; 14 example = [ "d /tmp 1777 root root 10d" ]; 15 description = '' 16 Rules for creation, deletion and cleaning of volatile and temporary files 17 automatically. See 18 {manpage}`tmpfiles.d(5)` 19 for the exact format. 20 ''; 21 }; 22 23 systemd.tmpfiles.settings = mkOption { 24 description = '' 25 Declare systemd-tmpfiles rules to create, delete, and clean up volatile 26 and temporary files and directories. 27 28 Even though the service is called `*tmp*files` you can also create 29 persistent files. 30 ''; 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 }; 118 119 systemd.tmpfiles.packages = mkOption { 120 type = types.listOf types.package; 121 default = []; 122 example = literalExpression "[ pkgs.lvm2 ]"; 123 apply = map getLib; 124 description = '' 125 List of packages containing {command}`systemd-tmpfiles` rules. 126 127 All files ending in .conf found in 128 {file}`«pkg»/lib/tmpfiles.d` 129 will be included. 130 If this folder does not exist or does not contain any files an error will be returned instead. 131 132 If a {file}`lib` output is available, rules are searched there and only there. 133 If there is no {file}`lib` output it will fall back to {file}`out` 134 and if that does not exist either, the default output will be used. 135 ''; 136 }; 137 }; 138 139 config = { 140 systemd.additionalUpstreamSystemUnits = [ 141 "systemd-tmpfiles-clean.service" 142 "systemd-tmpfiles-clean.timer" 143 "systemd-tmpfiles-setup.service" 144 "systemd-tmpfiles-setup-dev.service" 145 ]; 146 147 systemd.additionalUpstreamUserUnits = [ 148 "systemd-tmpfiles-clean.service" 149 "systemd-tmpfiles-clean.timer" 150 "systemd-tmpfiles-setup.service" 151 ]; 152 153 # Allow systemd-tmpfiles to be restarted by switch-to-configuration. This 154 # service is not pulled into the normal boot process. It only exists for 155 # switch-to-configuration. 156 # 157 # This needs to be a separate unit because it does not execute 158 # systemd-tmpfiles with `--boot` as that is supposed to only be executed 159 # once at boot time. 160 # 161 # Keep this aligned with the upstream `systemd-tmpfiles-setup.service` unit. 162 systemd.services."systemd-tmpfiles-resetup" = { 163 description = "Re-setup tmpfiles on a system that is already running."; 164 165 requiredBy = [ "sysinit-reactivation.target" ]; 166 after = [ "local-fs.target" "systemd-sysusers.service" "systemd-journald.service" ]; 167 before = [ "sysinit-reactivation.target" "shutdown.target" ]; 168 conflicts = [ "shutdown.target" ]; 169 restartTriggers = [ config.environment.etc."tmpfiles.d".source ]; 170 171 unitConfig.DefaultDependencies = false; 172 173 serviceConfig = { 174 Type = "oneshot"; 175 RemainAfterExit = true; 176 ExecStart = "systemd-tmpfiles --create --remove --exclude-prefix=/dev"; 177 SuccessExitStatus = "DATAERR CANTCREAT"; 178 ImportCredential = [ 179 "tmpfiles.*" 180 "loging.motd" 181 "login.issue" 182 "network.hosts" 183 "ssh.authorized_keys.root" 184 ]; 185 }; 186 }; 187 188 environment.etc = { 189 "tmpfiles.d".source = (pkgs.symlinkJoin { 190 name = "tmpfiles.d"; 191 paths = map (p: p + "/lib/tmpfiles.d") cfg.packages; 192 postBuild = '' 193 for i in $(cat $pathsPath); do 194 (test -d "$i" && test $(ls "$i"/*.conf | wc -l) -ge 1) || ( 195 echo "ERROR: The path '$i' from systemd.tmpfiles.packages contains no *.conf files." 196 exit 1 197 ) 198 done 199 '' + concatMapStrings (name: optionalString (hasPrefix "tmpfiles.d/" name) '' 200 rm -f $out/${removePrefix "tmpfiles.d/" name} 201 '') config.system.build.etc.passthru.targets; 202 }) + "/*"; 203 }; 204 205 systemd.tmpfiles.packages = [ 206 # Default tmpfiles rules provided by systemd 207 (pkgs.runCommand "systemd-default-tmpfiles" {} '' 208 mkdir -p $out/lib/tmpfiles.d 209 cd $out/lib/tmpfiles.d 210 211 ln -s "${systemd}/example/tmpfiles.d/home.conf" 212 ln -s "${systemd}/example/tmpfiles.d/journal-nocow.conf" 213 ln -s "${systemd}/example/tmpfiles.d/portables.conf" 214 ln -s "${systemd}/example/tmpfiles.d/static-nodes-permissions.conf" 215 ln -s "${systemd}/example/tmpfiles.d/systemd.conf" 216 ln -s "${systemd}/example/tmpfiles.d/systemd-nologin.conf" 217 ln -s "${systemd}/example/tmpfiles.d/systemd-nspawn.conf" 218 ln -s "${systemd}/example/tmpfiles.d/systemd-tmp.conf" 219 ln -s "${systemd}/example/tmpfiles.d/tmp.conf" 220 ln -s "${systemd}/example/tmpfiles.d/var.conf" 221 ln -s "${systemd}/example/tmpfiles.d/x11.conf" 222 '') 223 # User-specified tmpfiles rules 224 (pkgs.writeTextFile { 225 name = "nixos-tmpfiles.d"; 226 destination = "/lib/tmpfiles.d/00-nixos.conf"; 227 text = '' 228 # This file is created automatically and should not be modified. 229 # Please change the option systemd.tmpfiles.rules instead. 230 231 ${concatStringsSep "\n" cfg.rules} 232 ''; 233 }) 234 ] ++ (mapAttrsToList (name: paths: 235 pkgs.writeTextDir "lib/tmpfiles.d/${name}.conf" (concatStrings (mapAttrsToList (path: types: 236 concatStrings (mapAttrsToList (_type: entry: '' 237 '${entry.type}' '${path}' '${entry.mode}' '${entry.user}' '${entry.group}' '${entry.age}' ${entry.argument} 238 '') types) 239 ) paths )) 240 ) cfg.settings); 241 242 systemd.tmpfiles.rules = [ 243 "d /nix/var 0755 root root - -" 244 "L+ /nix/var/nix/gcroots/booted-system 0755 root root - /run/booted-system" 245 "d /run/lock 0755 root root - -" 246 "d /var/db 0755 root root - -" 247 "L /etc/mtab - - - - ../proc/mounts" 248 "L /var/lock - - - - ../run/lock" 249 # Boot-time cleanup 250 "R! /etc/group.lock - - - - -" 251 "R! /etc/passwd.lock - - - - -" 252 "R! /etc/shadow.lock - - - - -" 253 "R! /etc/mtab* - - - - -" 254 "R! /nix/var/nix/gcroots/tmp - - - - -" 255 "R! /nix/var/nix/temproots - - - - -" 256 ]; 257 }; 258}