How to clean temporary files automatically using systemd-tmpfiles in RHEL 7 / CentOS 7

Have you also come across a situation when your filesystem gets piled up with unwanted files and you have to step in manually clean up all the unwanted temporary files and directories.

With Red Hat Enterprise Linux 7 we have a new systemd unit file (systemd-tmpfiles) introduced which can do the dirty work for you automatically.

In RHEL 6 we had a similar solution namely tmpwatch which used to clean up temporary files, the tmpwatch utility recursively searches through specified directories and removes files which have not been accessed in a specified period of time.

systemd-tmpfiles creates, deletes, and cleans up volatile and temporary files and directories, based on the configuration file format and location specified in tmpfiles.d

In my last article I have given an overview of systemd with examples.

The configuration files are located in different places and they have a hierarchical priority process. The configuration locations for systemd-tmpfiles service have the following order priority (Highest to lower):

/etc/tmpfiles.d/*.conf
/run/tmpfiles.d/*.conf
/usr/lib/tmpfiles.d/*.conf
  • Supposing that a configuration file with the same name is placed under all the three configuration directories, the file with highest priority will be the one in /etc.
  • The configuration files placed under /run are created at runtime by services/daemons to control temporary directory cleaning processes.
  • And, as usual, configuration files under /usr/lib/* should be never edited directly because they’re vendor-provided you should override them using this priority mechanism, placing a custom file under /etc/tmpfiles.d/*.

Looking at configuration file syntax, a systemd-tmpfiles configuration contains:

Type, Path, Mode, UID, GID, Age, and Arguments

  Remove a file or directory if it exists. This may not be used to remove non-empty directories, use R for that. Lines of this type accept shell-style globs in place of normal path names.

For example I create a configuration file inside "/etc/tmpfiles.d"

# cat tmp.conf
# Remove /tmp/test directory and its content
r /tmp/test/

Before running this I will create a directory

# mkdir /tmp/test

Lets manually run systemd-tmpfiles to check if this work

# env SYSTEMD_LOG_LEVEL=debug systemd-tmpfiles --remove
Skipping overridden file: /usr/lib/tmpfiles.d/tmp.conf.
Reading config file "/etc/tmpfiles.d/tmp.conf".
Running remove action for entry r /tmp/test

The 'test' directory is removed

# ls /tmp/test
ls: cannot access /tmp/test: No such file or directory

But what if the directory has some content

# env SYSTEMD_LOG_LEVEL=debug systemd-tmpfiles --remove
Skipping overridden file: /usr/lib/tmpfiles.d/tmp.conf.
Reading config file "/etc/tmpfiles.d/tmp.conf".
Running remove action for entry r /tmp/test
rm(/tmp/test): Directory not empty

For this situation we need different variable

R    Recursively remove a path and all its subdirectories (if it is a directory). Lines of this type accept shell-style globs in place of normal path names.

Looks like it works

# env SYSTEMD_LOG_LEVEL=debug systemd-tmpfiles --remove
Skipping overridden file: /usr/lib/tmpfiles.d/tmp.conf.
Reading config file "/etc/tmpfiles.d/tmp.conf".
Running remove action for entry R /tmp/test
rm -rf "/tmp/test"

When does the clean up happens automatically?

Systemd gives you the timer unit for controlling scheduled and cyclic actions to be performed in the running system.

You can inspect the behaviour of the timer unit by querying the systemd daemon

# systemctl status systemd-tmpfiles-clean.timer
â systemd-tmpfiles-clean.timer - Daily Cleanup of Temporary Directories
   Loaded: loaded (/usr/lib/systemd/system/systemd-tmpfiles-clean.timer; static; vendor preset: disabled)
   Active: active (waiting) since Sat 2018-01-20 23:55:24 IST; 15h ago
     Docs: man:tmpfiles.d(5)
           man:systemd-tmpfiles(8)

Jan 20 23:55:24 Ban17-rds01-b systemd[1]: Started Daily Cleanup of Temporary Directories.
Jan 20 23:55:24 Ban17-rds01-b systemd[1]: Starting Daily Cleanup of Temporary Directories.

If you check the systemd unit file for this service it will give you more details

# systemctl cat systemd-tmpfiles-clean.timer
# /usr/lib/systemd/system/systemd-tmpfiles-clean.timer
#  This file is part of systemd.
#
#  systemd is free software; you can redistribute it and/or modify it
#  under the terms of the GNU Lesser General Public License as published by
#  the Free Software Foundation; either version 2.1 of the License, or
#  (at your option) any later version.

[Unit]
Description=Daily Cleanup of Temporary Directories
Documentation=man:tmpfiles.d(5) man:systemd-tmpfiles(8)

[Timer]
OnBootSec=15min
OnUnitActiveSec=1d

As you’ll find on the timer unit, it will run just 15 minutes after systemd start, and then every 24 hours from that time onward. The command, in this case, will only affect files/directories purging/cleaning.

Once the system boots up, a special unit file is executed: systemd-tmpfiles-setup, this unit will execute the systemd-tmpfile --create --remove command.

I will create a test directory again under /tmp and create a configuration file to clear this directory as above

# cat /etc/tmpfiles.d/tmp.conf
# Remove /tmp/test directory and its content
r /tmp/test/

Next reboot my system to validate the changes

# reboot

Next monitor the logs

Jan 20 16:44:24 Ban17-adm-a systemd: Stopped Daily Cleanup of Temporary Directories.
Jan 20 16:44:24 Ban17-adm-a systemd: Stopping Daily Cleanup of Temporary Directories.

While starting up the system

Jan 20 16:49:14 Ban17-adm-a systemd: Started Daily Cleanup of Temporary Directories.
Jan 20 16:49:14 Ban17-adm-a systemd: Starting Daily Cleanup of Temporary Directories.

Once the system is accessible again lets check if '/tmp/test' exists

# ls /tmp/test
ls: cannot access /tmp/test: No such file or directory

So this is cleaned automatically.

I hope the article was useful.