11

I have the following configuration to clean up temporary files (default for CentOS 7), which says that files in /tmp should be removed if they are more than 10 days old.

[root]# tail -n +10 /usr/lib/tmpfiles.d/tmp.conf | head -n 3
# Clear tmp directories separately, to make them easier to override
d /tmp 1777 root root 10d
d /var/tmp 1777 root root 30d

However, even after running systemd-tmpfiles --clean, when I look at the contents of /tmp, there are files in there that are more than 10 days old.

[root]# ls -dl /tmp/backup-inspection
drwxr-xr-x 8 root root 68 Aug 29  2014 /tmp/backup-inspection

The contents of the /tmp directory is huge:

[root]# du -h /tmp | tail -n 1
3.5G    /tmp

Can anyone explain to me why the backup-inspection directory is not removed? It is nearly 1 year old?

5
  • It probably isn't a systemd tmpfile. Not everything in /tmp is, any application can create files in /tmp
    – jordanm
    Commented Aug 3, 2015 at 4:11
  • I didn't think it mattered who created the file in the /tmp directory. E.g., if I write an application that writes to /tmp, should the tempfiles daemon delete it regardless of who created it?
    – magnus
    Commented Aug 3, 2015 at 4:51
  • Quick addition: It does not matter, at least if you use the e flag.
    – Thorian93
    Commented Aug 10, 2020 at 11:32
  • Set the age-by option in Age: unix.stackexchange.com/a/782467/78336
    – Luchostein
    Commented Aug 24 at 5:06

5 Answers 5

16

I have run into the same problem recently and found this question, so i am sharing my experience.

Actually systemd-tmpfiles has full support for recursive directory tree processing as you would expect (the other answer confused me enough to check the source code). The reason files was not deleted (in my case) was atime. systemd-tmpfiles checks ctime (except for directories), mtime and atime and all three (or two) of them must be old enough for the file (or directory) to be deleted.

Actually there may be other reasons, because systemd-tmpfiles has a lot of internal rules for skipping files. To find out why some files are not deleted, run systemd-tmpfiles as following:

env SYSTEMD_LOG_LEVEL=debug systemd-tmpfiles --clean

It will probably dump a lot of output into your console. Note that if you try to redirect stdout to e.g. a file, output disappears and is sent to systemd journal (so that it can be obtained via e.g. journalctl). In my case the output was also cut in the middle (or i just do not know how to use journalctl), so my solution was to temporarily increase history buffer in my terminal emulator.

11

I've been going to great lengths lately to solve similar issues on servers under my purview.

The simple answer is basically just: systemd-tmpfiles --clean is a hot mess and you should look into alternatives

The less simple answer is a bit long.

systemd-tmpfiles performs a variety of tasks, but its main one is unrelated to the --clean option: ensuring that the state of your system is appropriately 'reset' upon reboots. That is to say, it ensures that directories and files which need to exist for various reasons are created, and ones which should not exist are removed (along with a long list of relatively esoteric things like creating filesystem subvolumes and quotas, block devices, etc., changing permissions, SELinux attributes, etc. See the manpage if you're curious about everything). These tasks are performed by systemd-tmpfiles --create (for most things) and systemd-tmpfiles --remove (for removing files and directories). These two subcommands consider, roughly, the start of each configuration line: the first field is the type of action, the second the target, the third the mode, etc. Generally, something like systemd-tmpfiles --create --remove is run shortly after boot of the system, before anything that might depend on the actions it takes. One important thing to note is that these actions don't ever look at the fifth argument, the Age parameter. That's where --clean comes in.

systemd-tmpfiles --clean essentially piggybacks on top of this infrastructure by way of a single added field: the Age field. It only considers a few of the particular types of actions the other subcommands do, though: d, D, v, q, Q, C, and also x and X (which only exist to exclude specific things from its cleanup). The ones of these that are relevant to normal use cases are just d and D, though, used for directories, creating-if-doesn't-exist and creating-if-doesn't-exist-or-emptying-if-it-does, respectively. With the ages marked, systemd-tmpfiles --clean will remove the listed path when the age is older than configured.

Here's the catch: it really means the listed path only - the age marking is not recursively applied to the contents of the folder. This means that the configuration lines in your question will only ever remove the entirety of /tmp or /var/tmp, and only if nothing has happened within them for 10 or 30 days, respectively. To make things worse, none of the things which affect the age support globs except for x and X, which are for excluding things from cleanup.

The tmpfiles.d manpage does list one interesting thing which may work for your case if you're lucky: "If the age field starts with a tilde character "~", the 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 my case, the cleanup needed to happen two levels below /tmp, so there was no way to use this to good effect.

Look into other solutions for cleaning up the contents of your /tmp directory which consider it their primary purpose, rather than being tacked-on the end like systemd-tmpfiles --clean is.

2
  • 1
    This is an older question now, but I ended up using tmpwatch which worked beautifully the first time around. I simply added it to cron's daily schedule. Easy to configure, easy to use. Very different to systemd, which tries to do too much.
    – magnus
    Commented Feb 22, 2016 at 4:07
  • tmpwatch is quite nice, but it not in the SLES default repos. For me the trick was to give the persmissions when trying to clean up a directory. Not sure if that is by design, the documentation reads otherwise.
    – Thorian93
    Commented Aug 10, 2020 at 11:34
1
  • d is for creating directories
  • r is for removing files

From tempfiles.d(5). You don't need the other stuff, try:

d /tmp      1d

   d
       Create a directory if it does not exist yet.

   D
       Create or empty a directory.
r
       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. Does not
       follow symlinks.

   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. Does not follow symlinks.
2
  • Don't forget to run #systemctl enable systemd-tmpfiles #systemctl start systemd-tmpfiles #systemd-tempfiles --clean
    – mac
    Commented Oct 18, 2015 at 21:12
  • Except the removal of files and directories based on age does not work for the "r" action, but works for "d" (and a few others.)
    – bolind
    Commented Mar 11, 2022 at 8:30
0

I also struggled with this for far longer that it should have taken.

My case was that I have a custom tmp directory (needed for a custom application, placed on a fast-ish SSD disk) that needed cleaned of files that had sat unused for seven days.

What I ended up doing was creating a file in /etc/tmpfiles.d called 'foo.conf', with the following line:

d /foo/tmp - - - 7d

What this does (I hope) is:

  1. Delete files and directories under /foo/tmp where atime, mtime and ctime are all older than 7 days.
  2. Don't delete contents in case of reboot.
  3. Create the directory if it doesn't exist (it always will.)
  4. Don't change ownership and permissions on the directory (Mode, UID and GID are all set to -)

I think it's very confusing that r isn't used to remove files due to age. From the man page:

The age field only applies to lines starting with d, D, e, v, q, Q, C, x and X.

0

The age is determined by any of the file/directory timestamps (change, access, modification). If any of them is too young (beware of "access" if you are manually accessing a directory), the item will be skipped. You may specify which timestamp to use (e.g.: "modification"). From man tmpfiles.d:

Age

...

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 -

In your case, you may use something like cC:10d or cC:30d (nevertheless I'd prefer mM).

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .