1. Overview

Generally, we deal with temporary files a lot. Temporary files are useful for a short period of time. However, left unchecked, they can eat the resources of the system. Also, some programs require certain files in the temporary file system.

To manage temporary files programmatically, we can use the systemd-tmpfiles tool and its tmpfiles.d configuration.

This tutorial assumes we use Ubuntu or Fedora and the user baeldung. If we don’t have the baeldung user, we could create it.

2. Use Cases for the Creation or Removal of Temporary Files

There are several reasons why we’d want to create and remove temporary files automatically or programmatically.

Some daemons or scripts may want to store their working files on the tmpfs file system because accessing the files is faster there. But the files on the tmpfs file system will be wiped out after the system shuts down because the files live in memory.

Another case is that we might want to delete old log files automatically. For example, we might only want to keep log files for a month.

3. Configuration with tmpfiles.d

tmpfiles.d is neither a command nor an application. Rather, it’s a configuration rule describing how to handle temporary files. Basically, there are directories where we can put configuration files to tell how the system should manage temporary files.

Later, we’ll invoke a command called systemd-tmpfiles to read these configuration files and act accordingly.

3.1. Location of the Configuration Files

We can write configurations for managing temporary files in the /etc/tmpfiles.d directory. Configuration files can have any name but must have the .conf suffix.

3.2. Temporary File System

Some daemons or programs need a few working files. For example, a VPN program needs a socket file. To access the socket file faster, the program might save it in the tmpfs file system, meaning the socket file will be kept in memory, not on disk.

In Linux, some directories like /run and /tmp are created in the tmpfs directory. For example, in Ubuntu 20.04, the /run directory is in the tmpfs file system.

We can confirm it with the command below:

$ df -t tmpfs
Filesystem     1K-blocks   Used Available Use% Mounted on
tmpfs            6389640   2756   6386884   1% /run
tmpfs           31948200 640948  31307252   3% /dev/shm
tmpfs               5120      4      5116   1% /run/lock
tmpfs           31948200      0  31948200   0% /sys/fs/cgroup
tmpfs            6389640     20   6389620   1% /run/user/125
tmpfs            6389640    152   6389488   1% /run/user/1000

Suppose a VPN program called baeldungvpn wants to create a directory called baeldung in /run and create a socket file inside /run/baeldung. We might think we can do this manually:

$ sudo mkdir /run/baeldung
$ sudo chown baeldungvpn /run/baeldung
$ touch /run/baeldung/baeldungvpn.sock # the VPN program is creating a socket file

The problem with this approach is when we reboot the system, /run/baeldung will be gone because everything inside /run is kept in memory, not storage. So, we need to find a way to create a directory automatically after /run is ready.

3.3. File Format

Let’s create a new file inside /etc/tmpfiles.d/ and name it baeldung.conf. Then, let’s add some content to it:

d /run/baeldung

Now, let’s restart the system and log in again. We’ll see the baeldung directory in the /run directory:

$ ls /run/baeldung -la
total 8
drwxr-xr-x  2 root root 4096 Agu 12 00:32
drwxrwxrwx 20 root root 4096 Agu 12 00:32

The configuration file has a special syntax. Every line is a rule. Each line in the tmpfiles.d configuration file is separated by tabs or spaces into seven columns that define a rule. Let’s add a comment in our file to describe these columns:

#Type Path         Mode User Group Age Argument
d     /run/baeldung

The first column is Type. The value of Type in our example is d to designate a directory that will be created and cleaned up after a period of time.

The second column is Path. In this case, we want to create the /tmp/baeldung directory. The seven columns in the configuration file are Type, Path, Mode, User, Group, Age, and Argument. In our example, we only use Type and Path.

Depending on the value of Type, some columns are optional.

Let’s rewrite our baeldung.conf:

d /run/baeldung 0755 baeldung baeldung

Now, let’s restart our system again and look at the /run/baeldung directory:

$ ls /run/baeldung -la
total 8
drwxr-xr-x  2 baeldung baeldung 4096 Agu 12 00:33
drwxrwxrwx 24 root     root     4096 Agu 12 00:33

The owner and group are different now. This time, we filled in the Mode, User, and Group columns. If we hadn’t provided the values for these three columns, we would have the default values, which are 0755, root, and root.

3.4. Initial Temp File Contents

Now, let’s fill another line below the first line:

f /run/hello.txt 0755 baeldung baeldung - baeldung

Let’s restart the system and check the content of /run/hello.txt:

$ cat /run/hello.txt
baeldung

The /run/baeldung directory is still there. As stated previously, we can have many rules of temporary files in one file.

In this new example, we use f for Type, meaning a new file creation. Like the previous example, we can give values for Mode, User, and Group. But for f Type, we don’t have a valid value for the Age column. So, we set it with -, meaning no value was given. We can also give – to Mode, User, or Group. It means we’ll use default values for them.

Finally, for Argument, we gave baeldung as the value. This is the content of the file that will be created.

There are other values for Type to perform different functions.

4. The systemd-tmpfiles Tool

So far, we’ve restarted the system every time we wanted the changes from tmpfiles.d to take effect, which isn’t always desirable. But, the good news is that we don’t have to.

If we have the systemd-tmpfiles tool installed, we can invoke systemd-tmpfiles manually so that the changes from tmpfiles.d will take effect immediately. This way, we have more flexibility in managing temporary files.

We can also create a cron job to create and remove temporary files with systemd-tmpfiles.

This is useful if we have a server that we rarely reboot but, from time to time, we’d like to manage the temporary files.

systemd-tmpfiles has three modes of temporary files management – creation, removal, and cleaning:

$ systemd-tmpfiles 
You need to specify at least one of --clean, --create or --remove.

If we want to create temporary files, we need to invoke systemd-tmpfiles in the creation mode.

4.1. Creation of Temporary Files

Let’s add another line at the bottom of /etc/tmpfiles.d/baeldung.conf:

f /tmp/new_file.txt

This time, let’s not restart the system:

$ sudo systemd-tmpfiles --create

Then, we can confirm the creation of /tmp/new_file.txt:

$ ls /tmp/new_file.txt -la
-rw-r--r-- 1 root root 0 Agu 13 21:28 /tmp/new_file.txt

We can also use it for the creation of a directory. Let’s add another line at the bottom of /etc/tmpfiles.d/baeldung.conf:

d /tmp/new_directory

When we run the same command again:

$ sudo systemd-tmpfiles --create

Then, we’ll see that /tmp/new_directory has been created:

$ ls /tmp/new_directory -la
drwxr-xr-x  2 root root 4096 Agu 13 22:12
drwxrwxrwt 21 root root 4096 Agu 13 22:12

4.2. Cleaning Up of Temporary Files

Many applications create log files for their activities, and it’s common for such applications to archive their log files daily. So, for each day, we could have a log file from an application. If the application runs for a year, we could have 365 log files. We should clean up these log files automatically rather than allow them to pile up indefinitely.

As we’ve seen before, the d Type in the tmpfiles.d configuration files means creating a new directory. However, it also means files in that directory can be removed after a period of time.

Let’s add a new line at the end of /etc/tmpfiles.d/baeldung.conf:

d /tmp/dir_clean 0755 baeldung baeldung 10s

Then, let’s execute systemd-tmpfiles again using create mode:

$ sudo systemd-tmpfiles --create

As usual, the command created /tmp/dir_clean. Let’s add a file to the directory:

$ sudo touch /tmp/dir_clean/logfile1

Just like before, we have to wait for at least 10 seconds. Then, we can run systemd-tmpfiles to clean up the directory:

$ sudo systemd-tmpfiles --clean

As we can see, the file inside /tmp/dir_clean has been removed:

$ ls /tmp/dir_clean

The 10s value in Age means that the files inside the directory will be cleaned up by executing systemd-tmpfiles in clean mode after 10 seconds have elapsed since the file was last modified. The s in 10s means seconds. We can use m for minutes, h for hours, and d for days.

We should note that these clean-up operations only take place if we execute systemd-tmpfiles after the expiry time has passed.

4.3. Removal of Temporary Files

There’s also a Type value D that we can use in our tmpfiles.d configuration for the removal of temporary files. Let’s add a line to /etc/tmpfiles.d/baeldung.conf and see it in action:

D /etc/dir_remove 0755 baeldung baeldung 10s

Then, let’s execute the systemd-tmpfiles command again using create mode:

$ sudo systemd-tmpfiles --create

The command created /etc/dir_remove. Let’s add a file to the directory:

$ sudo touch /etc/dir_remove/hello.txt

As usual, we have to wait for at least 10 seconds. Then, we can remove the content of the directory with systemd-tmpfiles:

$ sudo systemd-tmpfiles --remove

In Ubuntu, the file inside /etc/dir_remove has been removed but the /etc/dir_remove directory itself is still intact:

$ ls /etc/dir_remove

But, in Fedora, /etc/dir_remove is removed as well.

In Ubuntu, if we check the content of /tmp, we can see that systemd-tmpfiles has removed all files in /tmp as well:

$ ls /tmp

In Fedora, however, the files in /tmp are not removed.

4.4. User Mode

We’ve been executing systemd-tmpfiles with sudo. But, it can also be run in user mode. In user mode, systemd-tmpfiles will read a user’s temporary files management configuration files, and it does not require root permission to run.

A server could have many users who want to manage their temporary files. The users can use the user mode of systemd-tmpfiles to achieve that purpose.

Let’s create ~/.config/user-tmpfiles.d/baeldung.conf and add some content to the file:

f /tmp/userfile.txt

Then, we can execute systemd-tmpfiles in user mode:

$ systemd-tmpfiles --user --create

Now, as we can see, the file /tmp/userfile.txt has been created:

$ ls /tmp/userfile.txt
/tmp/userfile.txt

As we can see, when executing systemd-tmpfiles in user mode, we don’t need to use sudo.

4.5. Prevention of Deletion of Temporary Files

We can prevent the deletion of temporary files by setting the value in Age. Let’s add two lines to /etc/tmpfiles.d/baeldung.conf:

d /tmp/dir 0755 baeldung baeldung 10s
d /tmp/dir/inner_dir 0755 baeldung baeldung 1d

Next, let’s execute systemd-tmpfiles in create mode:

$ sudo systemd-tmpfiles --create

After making sure those directories have been created, we put some files inside the directories:

$ sudo mkdir /tmp/dir/other_dir
$ sudo touch /tmp/dir/other_dir/file1.txt /tmp/dir/inner_dir/file2.txt

Then, let’s wait for at least 10 seconds before we clean up the files with systemd-tmpfiles:

$ sudo systemd-tmpfiles --clean

We can check that inner_dir is still intact. File file2.txt is not deleted yet, but we can see that other_dir has been deleted:

$ ls /tmp/dir
inner_dir
$ ls /tmp/dir/inner_dir
file2.txt

If we examine the rule, we’ll see that we’ve set /tmp/dir/inner_dir to 1d (1 day) in Age. It means systemd-tmpfiles will not clean all files inside this directory before 1 day has passed after the last access time of the files, even though /tmp/dir has 10s (10 seconds) in Age.

5. Behind the Scenes

We have managed temporary files by rebooting the system or executing systemd-tmpfiles manually. Actually, when we reboot the system, the system executes systemd-tmpfiles behind the scenes to achieve its goals.

5.1. systemd Unit Files

As we know, systemd manages services in Linux, including the temporary files management service. We can check the related systemd unit files:

$ cat /usr/lib/systemd/system/systemd-tmpfiles-setup.service 
[... omitted]

[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=systemd-tmpfiles --create --remove --boot --exclude-prefix=/dev
SuccessExitStatus=DATAERR CANTCREAT

Let’s look at the value for ExecStart. It specifies that the systemd-tmpfiles command will be executed with the create and remove modes.

The unit file tells us that after booting, the system will create temporary files and remove temporary files based on our configuration files. But, it will not clean up the temporary files because it doesn’t use the –clean option.

Another config file is responsible for instructing systemd-tmpfiles to run in clean-up mode:

$ cat /usr/lib/systemd/system/systemd-tmpfiles-clean.service
[... omitted]

[Service]
Type=oneshot
ExecStart=systemd-tmpfiles --clean
SuccessExitStatus=DATAERR
IOSchedulingClass=idle

ExecStart shows us that this file is concerned with running systemd-tmpfiles in clean-up mode. Let’s check the timer file to see when this service is being executed:

$ cat /usr/lib/systemd/system/systemd-tmpfiles-clean.timer 
[... omitted]

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

[Timer]
OnBootSec=15min
OnUnitActiveSec=1d

We’ll find our answer in the OnBootSec and OnUnitActiveSec properties. In this example, systemd will execute systemd-tmpfiles in clean-up mode 15 minutes after booting and then every 1 day after that.

6. Conclusion

In this article, we’ve learned about how to manage temporary files by using tmpfiles.d configuration files.

We studied the syntax of temporary file configuration files. Then, we tested some rules of temporary file management from the creation of directories to the deletion of files.

We invoked systemd-tmpfiles manually to manage temporary files instead of rebooting the system.

Finally, we learned how, when we rebooted the system, the system launched systemd-tmpfiles behind the scenes to manage temporary files.

Comments are closed on this article!