From Fedora Project Wiki

(Clarify that this is for daemons; not run-of-the-mill scripts)
(Implement FPC trac 176)
Line 1: Line 1:
== Overview ==
== Overview ==
tmpfiles.d is a service provided by both systemd and upstart in Fedora 15 and later for managing temporary files and directories for daemons.  In this guideline we mainly concentrate on how it is used to populate <code>/var/run</code> and <code>/var/lock</code>.  In Fedora 15 and later, <code>/var/run</code> and <code>/var/lock</code> are tmpfs filesystems.  As such, they are created empty on every reboot.  For files intended to be placed into those directories, this should normally not pose any problems.  For directories, however, we often need to create the directories ahead of time.  This is best done using the tmpfiles.d mechanism that both upstart and systemd share.
tmpfiles.d is a service in Fedora 15 and later for managing temporary files and runtime directories for daemons.  In this guideline we mainly concentrate on how it is used to populate <code>/run</code> and <code>/run/lock</code>.  In Fedora 15 and later, <code>/var/run</code> and <code>/var/lock</code> are symlinks into the <code>/run</code> tmpfs filesystem.  As such, they are created empty on every reboot.  For files intended to be placed into those directories, this should normally not pose any problems.  For directories, however, we often need to create the directories ahead of time.  This is best done using the tmpfiles.d mechanism.


{{admon/note|EPEL difference| Like Fedora releases older than 15, EL-6 and older does not support tmpfiles.d.}}
{{admon/note|EPEL difference| Like Fedora releases older than 15, EL-6 and older does not support tmpfiles.d.}}
Line 6: Line 6:
== tmpfiles.d configuration ==
== tmpfiles.d configuration ==


Configuring tmpfiles.d just involves dropping a file into <code>%{_sysconfdir}/tmpfiles.d/</code> that tells the init system what directories need to be created.
Asking the tmpfiles.d mechanism to create directories for you just involves dropping a file into <code>%{_prefix}/lib/tmpfiles.d/</code>.


For example, if the package needs a few directories to be created in <code>/var/run</code> in order for it to run, the packager needs to create a file named <code>%{name}.conf</code> that is installed as <code>%{_sysconfdir}/tmpfiles.d/%{name}.conf</code>.  That file has the following lines:
For example, if the package needs a few directories to be created in <code>/run</code> in order for it to run, the packager needs to create a file named <code>%{name}.conf</code> that is installed as <code>%{_prefix}/lib/tmpfiles.d/%{name}.conf</code>.  The file has one or more lines of the following format:


<pre>
<pre>
D /var/run/NAME 0710 root GROUP -
d /run/NAME PERM USER GROUP -
</pre>
</pre>


The format of the line is as follows:
The format of the line is as follows:


* <code>D</code> specifies that a directory is to be created if it doesn't exist; empties it if it does exist.
* <code>d</code> specifies that a directory is to be created if it doesn't exist. You can use a different type specifier if you need it.  See <code>man tmpfiles.d</code> for possible values.
* <code>/var/run/NAME</code> is the filesystem path to create. Substitute NAME with the name of the directory that's needed
* <code>/run/NAME</code> is the filesystem path to create.
* <code>0710</code> are the permissions to apply to the directory when it is created
* <code>PERM</code> are the permissions (in the 4-digit octal format) to apply to the directory when it is created.
* <code>root</code> is the owner of the directory.  You can change this if needed.
* <code>USER</code> is the name of the owner of the directory.
* <code>GROUP</code> is the group that owns the directory.  GROUP with the group that should own the directory.
* <code>GROUP</code> is the name of the group of the directory.
* <code>-</code> the last field is for age (if used should be a time specification such as <code>1min</code>) which specifies to delete some files in the directory automatically in regular intervals. This is mostly useful for directories such as /tmp and is seldom used by packages.
* <code>-</code> specifies that aging should not be applied to the contents of the directory.  Aging is a mechanism for automated cleanup of files that were not used for a specified length of time. This is mostly useful for directories such as /tmp and is seldom used by packages. Feel free to use aging if it is appropriate for your directory.
 
An example:
<pre>
d /run/mysqld 0755 mysql mysql -
</pre>


Information on other options is available on the [http://0pointer.de/public/systemd-man/tmpfiles.d.html tmpfiles.d man page] should you need to do something more advanced.
Information on other options is available on the [http://0pointer.de/public/systemd-man/tmpfiles.d.html tmpfiles.d man page] should you need to do something more advanced.
Line 29: Line 34:
In the spec file, the packager needs to install the tmpfiles.d conf file and also make sure the directory is included in the rpm.
In the spec file, the packager needs to install the tmpfiles.d conf file and also make sure the directory is included in the rpm.
<pre>
<pre>
# tmpfiles.d configuration for the /var/run directory
# tmpfiles.d configuration for the /run directory
Source1:  %{name}-tmpfiles.conf
Source1:  %{name}-tmpfiles.conf
Requires: initscripts
[...]
[...]


%install
%install
mkdir -p %{buildroot}%{_sysconfdir}/tmpfiles.d
mkdir -p %{buildroot}%{_prefix}/lib/tmpfiles.d
install -m 0644 %{SOURCE1} %{buildroot}%{_sysconfdir}/tmpfiles.d/%{name}.conf
install -m 0644 %{SOURCE1} %{buildroot}%{_prefix}/lib/tmpfiles.d/%{name}.conf


# The next two lines may not be needed if the upstream's install script creates them
# The next two lines may not be needed if the upstream's install script creates them
mkdir -p %{buildroot}%{_localstatedir}/run/
mkdir -p %{buildroot}/run
install -d -m 0710 %{buildroot}%{_localstatedir}/run/%{name}/
install -d -m 0755 %{buildroot}/run/%{name}/
[...]
[...]


%files
%files
%dir %{_localstatedir}/run/%{name}/
%dir /run/%{name}/
%config(noreplace) %{_sysconfdir}/tmpfiles.d/%{name}.conf
%{_prefix}/lib/tmpfiles.d/%{name}.conf
</pre>
</pre>


Files that the program places directly into <code>/var/run</code> or <code>/var/lock</code> or into subdirectories of those may be listed in the %files section as <code>%ghost</code> but you may also omit them entirely as the files will be cleaned up on every reboot.
Note that <code>%{_prefix}/lib/tmpfiles.d/%{name}.conf</code> is '''not''' marked as a <code>%config</code> file, because it is not supposed to be edited by administrators.  They can override your <code>%{name}.conf</code> by placing an identically named file in <code>/etc/tmpfiles.d/</code>, but this should very rarely needed.
 
Files that the program places directly into <code>/run</code> or into its subdirectories may be listed in the %files section as <code>%ghost</code> but you may also omit them entirely as the files will be cleaned up on every reboot.


== Why not create the directories with XXXXXX instead? ==
== Why not create the directories with XXXXXX instead? ==
Line 54: Line 60:


===  Have the daemon create the directory when it starts up ===
===  Have the daemon create the directory when it starts up ===
Many times, daemons run as an unprivileged user who would not be allowed to create new directories directly into <code>/var/run</code> or <code>/var/lock</code>.
Many times, daemons run as an unprivileged user who would not be allowed to create new directories directly into <code>/run</code>.
If the daemon does not drop privileges, then you can patch it to create the files and directories when the daemon starts and submit the patch upstream.
If the daemon does not drop privileges, then you can patch it to create the files and directories when the daemon starts and submit the patch upstream.


Line 61: Line 67:
Since the init script is run by root, before the daemon drops privileges, why not create the directories there?
Since the init script is run by root, before the daemon drops privileges, why not create the directories there?


* This code would need to be implemented in every init script packaged.  Since both upstart and systemd support tmpfiles.d, we can cut down on the number of places we have to put code like this.
* This code would need to be implemented in every init script packaged.  Using tmpfiles.d we can cut down on the number of places we have to put code like this.
* Having to add the mkdir to the systemd unit files when tmpfiles.d is already in place introduces the need to run shell code for that init script.  Systemd is no longer able to handle starting the daemon by itself which slows things down.  The shell code also introduces imperative constructs into the otherwise declarative structure which is nice to avoid.
* Having to add the mkdir to the systemd unit files when tmpfiles.d is already in place introduces the need to run shell code for that init script.  Systemd is no longer able to handle starting the daemon by itself which slows things down.  The shell code also introduces imperative constructs into the otherwise declarative structure which is nice to avoid.
* Properly labelling the created directories is done automatically by the tmpfiles.d mechanism but would have to be manually done by the init script.
* Properly labelling the created directories is done automatically by the tmpfiles.d mechanism but would have to be manually done by the init script.

Revision as of 16:55, 6 June 2012

Overview

tmpfiles.d is a service in Fedora 15 and later for managing temporary files and runtime directories for daemons. In this guideline we mainly concentrate on how it is used to populate /run and /run/lock. In Fedora 15 and later, /var/run and /var/lock are symlinks into the /run tmpfs filesystem. As such, they are created empty on every reboot. For files intended to be placed into those directories, this should normally not pose any problems. For directories, however, we often need to create the directories ahead of time. This is best done using the tmpfiles.d mechanism.

EPEL difference
Like Fedora releases older than 15, EL-6 and older does not support tmpfiles.d.

tmpfiles.d configuration

Asking the tmpfiles.d mechanism to create directories for you just involves dropping a file into %{_prefix}/lib/tmpfiles.d/.

For example, if the package needs a few directories to be created in /run in order for it to run, the packager needs to create a file named %{name}.conf that is installed as %{_prefix}/lib/tmpfiles.d/%{name}.conf. The file has one or more lines of the following format:

d /run/NAME PERM USER GROUP -

The format of the line is as follows:

  • d specifies that a directory is to be created if it doesn't exist. You can use a different type specifier if you need it. See man tmpfiles.d for possible values.
  • /run/NAME is the filesystem path to create.
  • PERM are the permissions (in the 4-digit octal format) to apply to the directory when it is created.
  • USER is the name of the owner of the directory.
  • GROUP is the name of the group of the directory.
  • - specifies that aging should not be applied to the contents of the directory. Aging is a mechanism for automated cleanup of files that were not used for a specified length of time. This is mostly useful for directories such as /tmp and is seldom used by packages. Feel free to use aging if it is appropriate for your directory.

An example:

d /run/mysqld 0755 mysql mysql -

Information on other options is available on the tmpfiles.d man page should you need to do something more advanced.

Example spec file

In the spec file, the packager needs to install the tmpfiles.d conf file and also make sure the directory is included in the rpm.

# tmpfiles.d configuration for the /run directory
Source1:  %{name}-tmpfiles.conf
[...]

%install
mkdir -p %{buildroot}%{_prefix}/lib/tmpfiles.d
install -m 0644 %{SOURCE1} %{buildroot}%{_prefix}/lib/tmpfiles.d/%{name}.conf

# The next two lines may not be needed if the upstream's install script creates them
mkdir -p %{buildroot}/run
install -d -m 0755 %{buildroot}/run/%{name}/
[...]

%files
%dir /run/%{name}/
%{_prefix}/lib/tmpfiles.d/%{name}.conf

Note that %{_prefix}/lib/tmpfiles.d/%{name}.conf is not marked as a %config file, because it is not supposed to be edited by administrators. They can override your %{name}.conf by placing an identically named file in /etc/tmpfiles.d/, but this should very rarely needed.

Files that the program places directly into /run or into its subdirectories may be listed in the %files section as %ghost but you may also omit them entirely as the files will be cleaned up on every reboot.

Why not create the directories with XXXXXX instead?

There are multiple ways to try creating the directories but most suffer some disadvantage that tmpfiles.d addresses:

Have the daemon create the directory when it starts up

Many times, daemons run as an unprivileged user who would not be allowed to create new directories directly into /run. If the daemon does not drop privileges, then you can patch it to create the files and directories when the daemon starts and submit the patch upstream.

Have the init script create the directory when it starts up the daemon

Since the init script is run by root, before the daemon drops privileges, why not create the directories there?

  • This code would need to be implemented in every init script packaged. Using tmpfiles.d we can cut down on the number of places we have to put code like this.
  • Having to add the mkdir to the systemd unit files when tmpfiles.d is already in place introduces the need to run shell code for that init script. Systemd is no longer able to handle starting the daemon by itself which slows things down. The shell code also introduces imperative constructs into the otherwise declarative structure which is nice to avoid.
  • Properly labelling the created directories is done automatically by the tmpfiles.d mechanism but would have to be manually done by the init script.