···67 "systemd-poweroff.service"
68 "systemd-reboot.service"
69 "systemd-sysctl.service"
70- "systemd-tmpfiles-setup-dev.service"
71- "systemd-tmpfiles-setup.service"
72 "timers.target"
73 "tpm2.target"
74 "umount.target"
···518 (v: let n = escapeSystemdPath v.where;
519 in nameValuePair "${n}.automount" (automountToUnit v)) cfg.automounts);
520521- # make sure all the /dev nodes are set up
522- services.systemd-tmpfiles-setup-dev.wantedBy = ["sysinit.target"];
523524 services.initrd-nixos-activation = {
525 after = [ "initrd-fs.target" ];
···67 "systemd-poweroff.service"
68 "systemd-reboot.service"
69 "systemd-sysctl.service"
0070 "timers.target"
71 "tpm2.target"
72 "umount.target"
···516 (v: let n = escapeSystemdPath v.where;
517 in nameValuePair "${n}.automount" (automountToUnit v)) cfg.automounts);
51800519520 services.initrd-nixos-activation = {
521 after = [ "initrd-fs.target" ];
+179-99
nixos/modules/system/boot/systemd/tmpfiles.nix
···1-{ config, lib, pkgs, utils, ... }:
23with lib;
45let
6 cfg = config.systemd.tmpfiles;
07 systemd = config.systemd.package;
000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008in
9{
10 options = {
···20 '';
21 };
2223- systemd.tmpfiles.settings = mkOption {
0024 description = ''
25- Declare systemd-tmpfiles rules to create, delete, and clean up volatile
26- and temporary files and directories.
2728- 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- };
118119 systemd.tmpfiles.packages = mkOption {
120 type = types.listOf types.package;
···140 systemd.additionalUpstreamSystemUnits = [
141 "systemd-tmpfiles-clean.service"
142 "systemd-tmpfiles-clean.timer"
00143 "systemd-tmpfiles-setup.service"
144- "systemd-tmpfiles-setup-dev.service"
145 ];
146147 systemd.additionalUpstreamUserUnits = [
···236 '';
237 })
238 ] ++ (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 ))
244 ) cfg.settings);
245246 systemd.tmpfiles.rules = [
···256 "R! /nix/var/nix/gcroots/tmp - - - - -"
257 "R! /nix/var/nix/temproots - - - - -"
258 ];
000000000000000000000000000000000000000000000000000000000259 };
260}
···1+{ config, lib, pkgs, ... }:
23with lib;
45let
6 cfg = config.systemd.tmpfiles;
7+ initrdCfg = config.boot.initrd.systemd.tmpfiles;
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);
119in
120{
121 options = {
···131 '';
132 };
133134+ systemd.tmpfiles.settings = mkOption settingsOption;
135+136+ boot.initrd.systemd.tmpfiles.settings = mkOption (settingsOption // {
137 description = ''
138+ Similar to {option}`systemd.tmpfiles.settings` but the rules are
139+ only applied by systemd-tmpfiles before `initrd-switch-root.target`.
140141+ See {manpage}`bootup(7)`.
0142 '';
143+ });
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000144145 systemd.tmpfiles.packages = mkOption {
146 type = types.listOf types.package;
···166 systemd.additionalUpstreamSystemUnits = [
167 "systemd-tmpfiles-clean.service"
168 "systemd-tmpfiles-clean.timer"
169+ "systemd-tmpfiles-setup-dev-early.service"
170+ "systemd-tmpfiles-setup-dev.service"
171 "systemd-tmpfiles-setup.service"
0172 ];
173174 systemd.additionalUpstreamUserUnits = [
···263 '';
264 })
265 ] ++ (mapAttrsToList (name: paths:
266+ pkgs.writeTextDir "lib/tmpfiles.d/${name}.conf" (mkRuleFileContent paths)
0000267 ) cfg.settings);
268269 systemd.tmpfiles.rules = [
···279 "R! /nix/var/nix/gcroots/tmp - - - - -"
280 "R! /nix/var/nix/temproots - - - - -"
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+ };
339 };
340}