TMPFILES.D(5)
๐ tmpfiles.d(5) ๐
okay bestie, sit down, hydrate, because this is the manual page for tmpfiles.d โ the little config-file language that tells your system what files and directories to create, delete, and clean up. she's giving infrastructure. she's giving boot-time realness. let's get into it ๐ซถ
โจ NAME โจ
tmpfiles.d โ configuration for creation, deletion, and cleaning of files and directories
โจ SYNOPSIS โจ
the directories she reads from, in all her glory:
/etc/tmpfiles.d/*.conf
/run/tmpfiles.d/*.conf
/usr/local/lib/tmpfiles.d/*.conf
/usr/lib/tmpfiles.d/*.conf
~/.config/user-tmpfiles.d/*.conf
$XDG_RUNTIME_DIR/user-tmpfiles.d/*.conf
~/.local/share/user-tmpfiles.d/*.conf
...
/usr/local/share/user-tmpfiles.d/*.conf
/usr/share/user-tmpfiles.d/*.conf
and here's the whole menu of line types, the way they actually get written:
#Type Path Mode User Group Age Argument
f /file/to/create mode user group - content
f+ /file/to/create-or-truncate mode user group - content
w /file/to/write-to - - - - content
w+ /file/to/append-to - - - - content
d /directory/to/create-and-clean-up mode user group cleanup-age -
D /directory/to/create-and-remove mode user group cleanup-age -
e /directory/to/clean-up mode user group cleanup-age -
v /subvolume-or-directory/to/create mode user group cleanup-age -
q /subvolume-or-directory/to/create mode user group cleanup-age -
Q /subvolume-or-directory/to/create mode user group cleanup-age -
p /fifo/to/create mode user group - -
p+ /fifo/to/[re]create mode user group - -
L /symlink/to/create - - - - symlink/target/path
L+ /symlink/to/[re]create - - - - symlink/target/path
c /dev/char-device-to-create mode user group - major:minor
c+ /dev/char-device-to-[re]create mode user group - major:minor
b /dev/block-device-to-create mode user group - major:minor
b+ /dev/block-device-to-[re]create mode user group - major:minor
C /target/to/create - - - cleanup-age /source/to/copy
C+ /target/to/create - - - cleanup-age /source/to/copy
x /path-or-glob/to/ignore/recursively - - - cleanup-age -
X /path-or-glob/to/ignore - - - cleanup-age -
r /path-or-glob/to/remove - - - - -
R /path-or-glob/to/remove/recursively - - - - -
z /path-or-glob/to/adjust/mode mode user group - -
Z /path-or-glob/to/adjust/mode/recursively mode user group - -
t /path-or-glob/to/set/xattrs - - - - xattrs
T /path-or-glob/to/set/xattrs/recursively - - - - xattrs
h /path-or-glob/to/set/attrs - - - - file attrs
H /path-or-glob/to/set/attrs/recursively - - - - file attrs
a /path-or-glob/to/set/acls - - - - POSIX ACLs
a+ /path-or-glob/to/append/acls - - - - POSIX ACLs
A /path-or-glob/to/set/acls/recursively - - - - POSIX ACLs
A+ /path-or-glob/to/append/acls/recursively - - - - POSIX ACLs
k /path-or-glob/to/set/caps - - - - file capabilities
k+ /path-or-glob/to/adjust/caps - - - - file capabilities
K /path-or-glob/to/set/caps/recursively - - - - file capabilities
K+ /path-or-glob/to/adjust/caps/recursively - - - - file capabilities
like, that's the whole vibe in one table. iconic ๐
โจ DESCRIPTION โจ
so tmpfiles.d config files give you one generic mechanism to define: creating regular files, directories, pipes, and device nodes ๐ธ; adjusting their access mode, ownership, attributes, quota assignments, and contents ๐; and finally, removing them based on time โณ. it's most commonly used for volatile and temporary files and directories โ think stuff living under /run/, /tmp/, /var/tmp/, the API file systems like /sys/ or /proc/, plus a few other directories below /var/.
systemd-tmpfiles(8) reads all this config to create volatile files and directories during boot, and then to do periodic cleanup afterwards. head to systemd-tmpfiles(8) if you want the description of systemd-tmpfiles-setup.service, systemd-tmpfiles-clean.service, and their associated units ๐
system daemons constantly want their own private runtime directories below /run/ for communication sockets and similar. for those, it's better to use RuntimeDirectory= in their unit files (details in systemd.exec(5)) โ that is, if you don't actually need the flexibility tmpfiles.d gives you. the perks: the config the unit needs is centralized in one place, and the directory's lifetime is tied to the lifetime of the service itself ๐. same energy for StateDirectory=, CacheDirectory=, LogsDirectory=, and ConfigurationDirectory= โ those are the ones to reach for when creating directories under /var/lib/, /var/cache/, /var/log/, and /etc/. reach for tmpfiles.d when the files' lifetime is independent of any service, or when you need more complicated configuration. no cap ๐ง
โจ CONFIGURATION DIRECTORIES AND PRECEDENCE โจ
every config file gets named in the style of package.conf or package-part.conf ๐. use that second variant when you want it to be easy to override just that part of the configuration.
- files in
/etc/tmpfiles.doverride files with the same name in/usr/lib/tmpfiles.dand/run/tmpfiles.d๐ - files in
/run/tmpfiles.doverride files with the same name in/usr/lib/tmpfiles.d - packages should install their config files in
/usr/lib/tmpfiles.d๐ฆ /etc/tmpfiles.dis reserved for the local administrator, who may use this logic to override the config files installed by vendor packages
all config files get sorted by filename in lexicographic order, no matter which of the directories they live in ๐ค. if multiple files specify the same path, the entry in the file with the lexicographically earliest name wins โ and yes, note that lines suppressed because of the "!" are filtered before application, meaning that if an early line carries the exclamation mark and gets suppressed because of that, a later line matching in path will be applied ๐. every other conflicting entry gets logged as an error ๐จ. when two lines are prefix path and suffix path of each other, the prefix line is always created first and the suffix later โ and if removal applies to the line, the order flips: the suffix is removed first, the prefix later. lines that take globs get applied after those that accept no globs. if multiple operations are meant to hit the same file (like ACL, xattr, file attribute adjustments), those always happen in the same fixed order ๐. apart from those cases, files/directories are processed in the order they're listed.
if the administrator wants to disable a config file supplied by the vendor, the recommended move is to drop a symlink to /dev/null in /etc/tmpfiles.d/ with the same filename ๐ซ. bye girl.
โจ CONFIGURATION FILE FORMAT โจ
the format is one line per path, holding type, path, mode, ownership, age, and argument fields. lines are separated by newlines, fields by whitespace:
#Type Path Mode User Group Age Argument...
d /run/user 0755 root root 10d -
L /tmp/foobar - - - - /dev/null
fields may contain C-style escapes ๐ช. with the exception of the seventh field (the "argument"), all fields may be enclosed in quotes. note that any whitespace found in the line after the beginning of the argument field counts as part of the argument field. to begin the argument field with a whitespace character, use C-style escapes (e.g. "\x20") ๐. line types that don't document use of the argument field reject a non-empty argument field โ use - to leave the argument field empty.
๐ Type ๐
the type is a single letter plus optionally one or more modifier characters: a plus sign ("+"), exclamation mark ("!"), minus sign ("-"), equals sign ("="), tilde character ("~") and/or caret ("^") โจ.
here are all the line types she understands:
f,f+โfwill create a file if it does not exist yet. if the argument parameter is given and the file did not exist yet, it will be written to the file ๐.f+will create or truncate the file. if the argument parameter is given, it will be written to the file. does not follow symlinks ๐ซ๐.w,w+โ write the argument parameter to a file, if the file exists. if suffixed with+, the line will be appended to the file. if your config writes multiple lines to the same file, usew+๐. lines of this type accept shell-style globs in place of normal path names. the argument parameter will be written without a trailing newline (she's minimal like that). C-style backslash escapes are interpreted. follows symlinks ๐.dโ create a directory. the mode and ownership will be adjusted if specified ๐. contents of this directory are subject to time-based cleanup if the age argument is specified โณ.Dโ similar tod, but on top of that the contents of the directory will be removed when--removeis used ๐งน.eโ adjust the mode and ownership of existing directories and remove their contents based on age. lines of this type accept shell-style globs in place of normal path names ๐. contents of the directories are subject to time-based cleanup if the age argument is specified. if the age argument is"0", contents will be unconditionally deleted every timesystemd-tmpfiles(8)--cleanis run ๐.
for this entry to be useful, at least one of the mode, user, group, or age arguments must be specified, since otherwise this entry has no effect. as an exception, an entry with no effect may be useful when combined with ! โ see the examples ๐.
Added in version 230.
vโ create a subvolume if the path does not exist yet, the file system supports subvolumes (btrfs), and the system itself is installed into a subvolume (specifically: the root directory/is itself a subvolume) ๐ณ. otherwise, create a normal directory, the same way asd.
a subvolume created with this line type is not assigned to any higher-level quota group. for that, use q or Q, which allow creating simple quota group hierarchies โ see below ๐ฝ.
Added in version 219.
q
Okay bestie, subvolume time ๐
This one creates a subvolume or directory exactly like v would, but โ plot twist โ it assigns the subvolume to the same higher-level quota groups as the parent. Why do we care? Because it means the higher-level limits and accounting that apply to the parent subvolume also cover the one you just made. Slay, inclusive quota vibes โจ
On non-btrfs file systems, this line type is identical to d. No cap, just a lil alias moment.
If the subvolume already exists, no change to the quota hierarchy is made โ regardless of whether the subvolume is already attached to a quota group or not. Also peek at Q below ๐ and see btrfs-qgroup(8) for all the deets about the btrfs quota group concept.
Added in version 228.
Q
Same energy as q โ create the subvolume or directory like v โ but this one assigns the new subvolume to a new leaf quota group. ๐
Here's the tea on how it's different: instead of copying the higher-level quota group assignments from the parent (which is what q does), it determines the lowest quota group of the parent subvolume that is not the leaf quota group. Then an "intermediary" quota group gets inserted that is one level below this level, and it shares the same ID part as the specified subvolume. And if no higher-level quota group exists for the parent subvolume? A brand-new quota group at level 255 sharing the same ID as the specified subvolume is inserted instead. Then that new intermediary quota group is assigned to the parent subvolume's higher-level quota groups, and the specified subvolume's leaf quota group is assigned to it. Iconic little hierarchy reshuffle fr fr ๐
So effectively, this has a similar effect as q, BUT it introduces a new higher-level quota group for the specified subvolume that may be used to enforce limits and accounting on the specified subvolume and children subvolumes created within it. Which means: by creating subvolumes only via q and Q, a concept of "subtree quotas" gets implemented ๐
- Each subvolume for which
Qis set will get a"subtree"quota group created, and all child subvolumes created within it will be assigned to it. - Each subvolume for which
qis set will not get such a"subtree"quota group, but it is ensured that they are added to the same"subtree"quota group as their immediate parents.
It is recommended to use Q for subvolumes that typically contain further subvolumes, and where it is desirable to have accounting and quota limits on all child subvolumes together. Examples for Q are typically /home/ or /var/lib/machines/. In contrast, q should be used for subvolumes that either usually do not include further subvolumes or where no accounting and quota limits are needed that apply to all child subvolumes together. Examples for q are typically /var/ or /var/tmp/.
As with q, Q has no effect on the quota group hierarchy if the subvolume already exists โ regardless of whether the subvolume already belong to a quota group or not. (That's a direct quote of the grammar, don't @ me ๐)
Added in version 228.
p, p+
Creates a named pipe (FIFO) if it does not exist yet ๐ง If it's suffixed with + and a file already exists where the pipe is to be created, that file gets removed and replaced by the pipe. Out with the old, in with the pipe ๐
L, L+, L?
Create a symlink if it does not exist yet ๐ฆ
- Suffix with
+and a file or directory already exists where the symlink is to be created? It gets removed and replaced by the symlink. - Suffix with
?and the source path does not exist? The symlink is simply not created, no drama. - Omit the argument entirely? Symlinks to files with the same name residing in the directory
/usr/share/factory/are created.
Note that permissions on symlinks are ignored. We don't do permissions on symlinks here bestie, it's giving "not applicable" โจ
c, c+
Create a character device node if it does not exist yet ๐ If suffixed with + and a file already exists where the device node is to be created, it gets removed and replaced by the device node.
It is recommended to suffix this entry with an exclamation mark to only create static device nodes at boot, as udev will not manage static device nodes that are created at runtime. So like, ! or chaos, your choice ๐
b, b+
Create a block device node if it does not exist yet. Same rules as its character-device sibling: suffix with + and any pre-existing file where the device node is to be created gets removed and replaced.
Same warning, same energy: suffix this entry with an exclamation mark to only create static device nodes at boot, because udev will not manage static device nodes that are created at runtime. ๐
C, C+
Recursively copy a file or directory โ but only if the destination files or directories do not exist yet, or the destination directory is empty. Lowkey picky, highkey safe ๐
Heads up: this command will not descend into subdirectories if the destination directory already exists and is not empty โ unless the action is suffixed with +. Instead, the entire copy operation is skipped. No partial mess, periodt.
If the argument is omitted, files from the source directory /usr/share/factory/ with the same name are copied. Does not follow symlinks. Contents of the directories are subject to time-based cleanup if the age argument is specified.
Added in version 214.
x
Ignore a path during cleaning ๐งน Use this type to exclude paths from clean-up as controlled with the Age parameter. Lines of this type accept shell-style globs in place of normal path names. It's giving "do not touch, this is not yours" ๐
X
Also ignores a path during cleaning, also as controlled with the Age parameter. But here's the difference bestie: unlike x, this parameter will not exclude the content if the path is a directory โ only the directory itself ๐ Lines of this type accept shell-style globs in place of normal path names.
Added in version 198.
r
Remove a file or directory if it exists. That's it, that's the job โจ
This may not be used to remove non-empty directories โ use R for that, bestie, don't fight it.
Lines of this type accept shell-style globs in place of normal path names. Does not follow symlinks. When --clean is used, the file or directory is subject to time-based cleanup if the age argument is specified.
This age handling was added in v262.
R
Recursively remove a path and all its subdirectories (if it is a directory) ๐๏ธ Go big or go home. Lines of this type accept shell-style globs in place of normal path names. Does not follow symlinks. When --clean is used, the path is subject to time-based cleanup if the age argument is specified.
This age handling was added in v262.
z
Adjust the access mode, user and group ownership, and restore the SELinux security context of a file or directory โ if it exists ๐ A lil glow-up for your perms. Lines of this type accept shell-style globs in place of normal path names. Does not follow symlinks.
Z
Same glow-up as z, but recursively: set the access mode, user and group ownership, and restore the SELinux security context of a file or directory if it exists, as well as of its subdirectories and the files contained therein (if applicable) ๐ Lines of this type accept shell-style globs in place of normal path names. Does not follow symlinks.
t
Set extended attributes, see attr(5) for details โจ The argument field should take one or more assignment expressions in the form namespace.attribute=value โ for examples, see below. Lines of this type accept shell-style globs in place of normal path names. This can be useful for setting SMACK labels. Does not follow symlinks.
Please note that extended attributes settable with this line type are a different concept from the Linux file attributes settable withh/H, see below. Do not confuse them bestie, they are not the same thing ๐
Added in version 218.
T
Same as t, but operates recursively ๐ฆ
Added in version 219.
h
Set Linux file/directory attributes. Lines of this type accept shell-style globs in place of normal path names.
The format of the argument field is [+-=][aAcCdDeijPsStTu]. Here's the breakdown:
- The prefix
+(the default one) causes the attributes to be added. -causes the attributes to be removed.=causes the attributes to be set exactly as the following letters.- The letters
"aAcCdDeijPsStTu"select the new attributes for the files โ seechattr(1)for further information.
Passing only = as argument resets all the file attributes listed above. And it has to be pointed out that the = prefix limits itself to the attributes corresponding to the letters listed here โ all other attributes will be left untouched. Does not follow symlinks.
Please note that the Linux file attributes settable with this line type are a different concept from the extended attributes settable witht/T, see above. Yes this warning goes both ways, they really want you to know ๐
H
Sames as h, but operates recursively. (Yes, the typo is canon, we keep it ๐
)
Added in version 220.
a, a+
Set POSIX ACLs (access control lists), see acl(5). Additionally, if 'X' is used, the execute bit is set only if the file is a directory or already has execute permission for some user, as mentioned in setfacl(1).
If suffixed with +, the specified entries will be added to the existing set. systemd-tmpfiles(8) will automatically add the required base entries for user and group based on the access mode of the file โ unless base entries already exist or are explicitly specified. The mask will be added if not specified explicitly or already present. Lines of this type accept shell-style globs in place of normal path names. This can be useful for allowing additional access to certain files. Does not follow symlinks.
Added in version 219.
A, A+
Same as a and a+, but recursive. Does not follow symlinks. ๐ฆ
Added in version 219.
k, k+
Set file capabilities, see capabilities(7). Lines of this type accept shell-style globs in place of normal path names. Does not follow symlinks.
The syntax follows cap_text_formats(7). It also supports "rootuid=INT" for the user namespace root user ID ๐
If suffixed with +, current capabilities on the file that are not touched by the expression will be kept. For example, if all "cap_setuid" capabilities need to be removed but others should be kept, one can use k+ with "cap_setuid=" or "cap_setuid-eip". Chef's kiss selective editing โจ
Added in version 261.
K, K+
Same as k and k+, but recursive. Does not follow symlinks.
Added in version 261.
โจ Type Modifiers โจ
If the exclamation mark ("!") is used, this line is only safe to execute during boot, and can break a running system. ๐ญ Lines without the exclamation mark are presumed to be safe to execute at any time, e.g. on package upgrades. systemd-tmpfiles(8) will take lines with an exclamation mark only into consideration, if the --boot option is given.
For example:
# Make sure these are created by default so that nobody else can
d /tmp/.X11-unix 1777 root root 10d
# Unlink the X11 lock files
r! /tmp/.X[0-9]*-lock
The second line, in contrast to the first one, would break a running system โ so it only ever gets executed with --boot. ๐
-โ if this line fails to run successfully during create (and only create, no cap), it will not make the execution ofsystemd-tmpfiles(8)return an error. ๐ซถ
For example:
# Modify sysfs but do not fail if we are in a container with a read-only /proc
w- /proc/sys/vm/swappiness - - - - 10
=โ the file types of existing objects in the specified path get checked, and removed if they don't match. This includes any implicitly created parent directories (which can be either directories or directory symlinks). So like, if there's a FIFO sitting in place of one of the parent path components, it gets replaced with a directory. ๐งน~โ the argument (i.e. 6th) column is Base64 decoded[1] before use. This modifier is only supported on line types that can write file contents, i.e.f,f+,w,+. Super useful for writing arbitrary binary data (including newlines and NUL bytes) to files. Note that if this switch is used, the argument is not subject to specifier expansion, neither before nor after Base64 decoding.^โ the argument (i.e. 6th) column takes a service credential name to read the argument data from. See System and Service Credentials[2] for the deets on the credentials concept. This modifier is only supported on line types that can write file contents, i.e.f,f+,w,w+. Great for writing arbitrary files with contents sourced from elsewhere, including from VM or container managers further up. If the specified credential is not set for thesystemd-tmpfilesservice, the line is silently skipped. If^and~are combined, Base64 decoding is applied to the credential contents. โจ$โ the file becomes subject to removal whensystemd-tmpfilesis invoked with the--purgeswitch. Lines without this character are unaffected by that switch. ๐
Note that for all line types that result in creation of any kind of file node (i.e.f,d/D/v/q/Q,p,L,c/bandC) leading directories are implicitly created if needed, owned byrootwith an access mode of0755. In order to create them with different modes or ownership, make sure to add appropriatedlines. ๐
Path ๐ฆ
The file system path specification supports simple specifier expansion, see below. The path (after expansion) must be absolute.
Mode ๐
The file access mode to use when creating this file or directory. If omitted or when set to -, the default is used: 0755 for directories, 0644 for all other file objects. For z, Z lines, if omitted or when set to -, the file access mode will not be modified. This parameter is ignored for x, r, R, L, t, a, and k lines.
Optionally, if prefixed with ~, the access mode is masked based on the already set access bits for existing file or directories: if the existing file has all executable bits unset, all executable bits are removed from the new access mode, too. Similarly, if all read bits are removed from the old access mode, they will be removed from the new access mode too, and if all write bits are removed, they will be removed from the new access mode too. In addition, the sticky/SUID/SGID bit is removed unless applied to a directory. This functionality is particularly useful in conjunction with Z. ๐ธ
By default, the access mode of listed inodes is set to the specified mode regardless of whether it is created anew, or already existed. Optionally, if prefixed with :, the configured access mode is only applied when creating new inodes, and if the inode the line refers to already exists, its access mode is left in place unmodified. โจ
User, Group ๐ซถ
The user and group to use for this file or directory. This may either be a numeric ID or a user/group name. If omitted or when set to -, the user and group of the user who invokes systemd-tmpfiles(8) is used. For z and Z lines, when omitted or when set to -, the file ownership will not be modified. These parameters are ignored for x, r, R, t, and a lines.
This field should generally only reference system users/groups, i.e. users/groups that are guaranteed to be resolvable during early boot. If this field references users/groups that only become resolvable during later boot (i.e. after NIS, LDAP or a similar networked directory service become available), execution of the operations declared by the line will likely fail. Also see Notes on Resolvability of User and Group Names[3] for more information on requirements on system user/group definitions. ๐ญ
By default, the ownership of listed inodes is set to the specified user/group regardless of whether it is created anew, or already existed. Optionally, if prefixed with :, the configured user/group information is only applied when creating new inodes, and if the inode the line refers to already exists, its user/group is left in place unmodified.
Age โณ
The date field, when set, is used to decide what files to delete when cleaning. If a file or directory is older than the current time minus the age field, it is deleted. The field format is a series of integers each followed by one of the following suffixes for the respective time units: s, m or min, h, d, w, ms, and us, meaning seconds, minutes, hours, days, weeks, milliseconds, and microseconds, respectively. Full names of the time units can be used too. ๐
If multiple integers and units are specified, the time values are summed. If an integer is given without a unit, s is assumed.
When the age is set to zero, the files are cleaned unconditionally. ๐
The age field only applies to lines starting with d, D, e, v, q, Q, C, r, R, x and X. If omitted or set to -, no automatic clean-up is done.
If the age field starts with a tilde character ~, clean-up is only applied to files and directories one level inside the directory specified, but not the files and directories immediately inside it. For R lines, this also skips removing the specified top-level directory itself. This modifier is not supported by r lines. ๐
The age of a file system entry is determined from its last modification timestamp (mtime), its last access timestamp (atime), and (except for directories) its last status change timestamp (ctime). By default, any of these three (or two) values will prevent cleanup if it is more recent than the current time minus the age field. To restrict the deletion based on particular type of file timestamps, the age-by argument can be used.
The age-by argument overrides the timestamp types to be used for the age check. It can be specified by prefixing the age argument with a sequence of characters to specify the timestamp types and a colon (:): "age-by...:cleanup-age". The argument can consist of a (A for directories), b (B for directories), c (C for directories), or m (M for directories). Those respectively indicate access, creation, last status change, and last modification time of a file system entry. The lower-case letter signifies that the given timestamp type should be considered for files, while the upper-case letter signifies that the given timestamp type should be considered for directories. See statx(2) file timestamp fields for more details about timestamp types. ๐
If not specified, the age-by field defaults to abcmABM, i.e. by default all file timestamps are taken into consideration, with the exception of the last status change timestamp (ctime) for directories. This is because the aging logic itself will alter the ctime whenever it deletes a file inside it. To ensure that running the aging logic does not feed back into the next iteration of itself, ctime for directories is ignored by default. ๐ง โจ
For example:
# Files created and modified, and directories accessed more than
# an hour ago in "/tmp/foo/bar", are subject to time-based cleanup.
d /tmp/foo/bar - - - bmA:1h -
Note that while the aging algorithm is run an exclusive BSD file lock (see flock(2)) is taken on each directory/file the algorithm decides to remove. If the aging algorithm finds a lock (shared or exclusive) is already taken on some directory/file, it (and everything below it) is skipped. Applications may use this to temporarily exclude certain directory subtrees from the aging algorithm: the applications can take a BSD file lock themselves, and as long as they keep it, aging of the directory/file and everything below it is disabled. ๐
This behavior can be used to ensure guaranteed cleanup of files or directories whose lifetime should be aligned with the process that created them by having that process create them in a location monitored by systemd-tmpfiles with an age of "0", and having the process immediately lock the directory or file before using it. Because the BSD lock is process specific, the file is guaranteed to be unlocked as soon as the process exits, meaning that even if the process crashes, those files and directories will be unlocked and cleaned up by systemd-tmpfiles. ๐
Argument ๐
For L lines determines the destination path of the symlink. For c and b, determines the major/minor of the device node, with major and minor formatted as integers, separated by :, e.g. "1:3". For f and w, the argument may be used to specify a short string that is written to the file, suffixed by a newline. For C, specifies the source file or directory. For t and T, determines extended attributes to be set. For a and A, determines ACL attributes to be set. For h and H, determines the file attributes to set. For k and K, determines file capabilities to be set. For line types that do not document use of this field, a non-empty argument is rejected; use - to leave it unset. ๐ซ
This field can contain specifiers, see below. ๐
SPECIFIERS โจ๐
Specifiers can be used in the "path" and "argument" fields. An unknown or unresolvable specifier is treated as invalid configuration. The following expansions are understood:
okay continuing the specifier menu, bestie โ this is still Table 1. Specifiers available and it just keeps going ๐ every single one, no skips:
%aโ Architecture. A short string identifying the architecture of the local system. Like a string such asx86,x86-64orarm64. Wanna see the full list? Peep the architectures defined forConditionArchitecture=insystemd.unit(5). ๐%Aโ Operating system image version. The operating system image version identifier of the running system, read from theIMAGE_VERSION=field of/etc/os-release. If it's not set, it resolves to an empty string. More deets inos-release(5). โจ%bโ Boot ID. The boot ID of the running system, formatted as a string. Seerandom(4)for more info. ๐%Bโ Operating system build ID. The operating system build identifier of the running system, read from theBUILD_ID=field of/etc/os-release. If it's not set, it resolves to an empty string.os-release(5)has the tea. ๐%Cโ System or user cache directory. In--usermode this is the same as$XDG_CACHE_HOME, and/var/cacheotherwise. ๐%Dโ Shared data directory. This is either/usr/share/(for the system manager) or the path"$XDG_DATA_HOME"resolves to (for user managers). ๐ฆ%gโ User group. The name of the group running the command. For the system instance this resolves to"root". ๐%Gโ User GID. The numeric GID of the group running the command. For the system instance this resolves to0. ๐ฅ%hโ User home directory. The home directory of the user running the command. For the system instance this resolves to"/root". ๐ซถ%Hโ Host name. The hostname of the running system. โญ%lโ Short host name. The hostname of the running system, truncated at the first dot to remove any domain component. โ๏ธ%Lโ System or user log directory. In--usermode this is the same as$XDG_STATE_HOMEwith/logappended, and/var/logotherwise. ๐%mโ Machine ID. The machine ID of the running system, formatted as a string. Seemachine-id(5)for more. ๐ธ%Mโ Operating system image identifier. The operating system image identifier of the running system, read from theIMAGE_ID=field of/etc/os-release. If it's not set, it resolves to an empty string.os-release(5), you know the drill. ๐ญ%oโ Operating system ID. The operating system identifier of the running system, read from theID=field of/etc/os-release. Seeos-release(5)for more information. ๐%qโ Pretty host name. The pretty hostname of the running system, read from thePRETTY_HOSTNAME=field of/etc/machine-info. If it's not set, it resolves to the short hostname. Seemachine-info(5)for more. ๐ง
and bestie we are NOT done, the specifiers keep comingโฆ keep scrolling, it's giving never-ending menu ๐
%Sโ the system or user state directory โจ. In--usermode it's literally the same as$XDG_STATE_HOME, and /var/lib otherwise.%tโ the system or user runtime directory ๐ซถ. In--usermode it's the same as$XDG_RUNTIME_DIR, and /run otherwise.%Tโ the directory for temporary files ๐. This is either/tmpor whatever path$TMPDIR,$TEMPor$TMPare set to. (Quick note bestie: the directory may be specified without a trailing slash.)%uโ the user name ๐. That's the name of the user running the command. In case of the system instance this resolves toroot.%Uโ the user UID ๐ข. The numeric UID of the user running the command. In case of the system instance this resolves to0.%vโ the kernel release ๐ฆ. Identical touname -routput.%Vโ the directory for larger and persistent temporary files ๐. This is either/var/tmpor the path$TMPDIR,$TEMPor$TMPare set to. (Again: the directory may be specified without a trailing slash.)%wโ the operating system version ID โญ. That's the operating system version identifier of the running system, as read from theVERSION_ID=field of/etc/os-release. If it's not set, it resolves to an empty string. Seeos-release(5)for more information.%Wโ the operating system variant ID ๐. The operating system variant identifier of the running system, as read from theVARIANT_ID=field of/etc/os-release. If it's not set, it resolves to an empty string. Seeos-release(5)for more information.%%โ a single percent sign ๐ . Use%%in place of%to specify a single percent sign.
โจ EXAMPLES โจ
Example 1. Create directories with specific mode and ownership
screen(1) needs two directories created at boot with specific modes and ownership, and honestly? iconic behaviour:
# /usr/lib/tmpfiles.d/screen.conf
d /run/screens 1777 root screen 10d
d /run/uscreens 0755 root screen 10d12h
The contents of /run/screens and /run/uscreens will be cleaned up after 10 and 10ยฝ days, respectively. ๐
Example 2. Create a directory with a SMACK attribute
D /run/cups - - - -
t /run/cups - - - - security.SMACK64=printing user.attr-with-spaces="foo bar"
The directory will be owned by root and have default mode. Its contents are not subject to time-based cleanup, but they will be obliterated when systemd-tmpfiles --remove runs. ๐
Example 3. Create a directory and prevent its contents from cleanup
abrt(1) needs a directory created at boot with a specific mode and ownership, and its content should be preserved from the automatic cleanup applied to the contents of /var/tmp:
# /usr/lib/tmpfiles.d/tmp.conf
d /var/tmp 1777 root root 30d
# /usr/lib/tmpfiles.d/abrt.conf
d /var/tmp/abrt 0755 abrt abrt -
Example 4. Apply clean up during boot and based on time
# /usr/lib/tmpfiles.d/dnf.conf
r! /var/cache/dnf/*/*/download_lock.pid
r! /var/cache/dnf/*/*/metadata_lock.pid
r! /var/lib/dnf/rpmdb_lock.pid
e /var/cache/dnf/ - - - 30d
The lock files will be removed during boot. Any files and directories in /var/cache/dnf/ will be removed after they have not been accessed in 30 days. โณ
Example 5. Empty the contents of a cache directory on boot
# /usr/lib/tmpfiles.d/krb5rcache.conf
e! /var/cache/krb5rcache - - - 0
Any files and subdirectories in /var/cache/krb5rcache/ will be removed on boot. Heads up though โ the directory will not be created. ๐ซ
Example 6. Provision SSH public key access for root user via Credentials in QEMU
-smbios type=11,value=io.systemd.credential.binary:tmpfiles.extra=$(echo -e "d /root/.ssh 0750 root root -\nf~ /root/.ssh/authorized_keys 0600 root root - $(ssh-add -L | base64 -w 0)" | base64 -w 0)
By passing this line to QEMU, the public key of the current user will be encoded in base64, added to a tmpfiles.d line that tells systemd-tmpfiles(8) to decode it into /root/.ssh/authorized_keys, encode that line itself in base64 and pass it as a Credential that will be picked up by systemd from SMBIOS on boot. no cap, that's a whole pipeline ๐ฅ
๐ /RUN/ AND /VAR/RUN/ ๐
/var/run/ is a deprecated symlink to /run/, and applications should use the latter. systemd-tmpfiles will warn if /var/run/ is used. So likeโฆ don't, bestie. ๐
๐ SEE ALSO ๐
systemd(1), systemd-tmpfiles(8), systemd-delta(1), systemd.exec(5), attr(5), getfattr(1), setfattr(1), setfacl(1), getfacl(1), chattr(1), btrfs-subvolume(8), btrfs-qgroup(8)
๐ NOTES ๐
- Base64 decoded โ
https://www.rfc-editor.org/rfc/rfc4648.html - System and Service Credentials โ
https://systemd.io/CREDENTIALS - Notes on Resolvability of User and Group Names โ
https://systemd.io/UIDS-GIDS/#notes-on-resolvability-of-user-and-group-names
And that's the whole page, bestie!! ๐ You just read every last specifier, every example, every footnote, and you ate. ๐
This lil masterpiece comes to you courtesy of systemd 262.1, and it's the TMPFILES.D(5) manual page โ so if you ever need to find it again, that's the girl. Go forth and systemd-tmpfiles responsibly, mwah ๐โจ
๐ฆ where this page comes from
- arch rolling: systemd 262.1-1 ยท LGPL-2.1-or-later AND CC0-1.0 AND GPL-2.0-or-later AND MIT-0
- ๐ girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms