summaryrefslogtreecommitdiffstats
path: root/src/tmpfiles/tmpfiles.c
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2019-01-18 16:09:30 +0100
committerLennart Poettering <lennart@poettering.net>2019-02-15 17:16:54 +0100
commit52b32b2aac96562ae8c380d8869b667f806471e0 (patch)
tree5b2e852224a267cd135fe2f1a9ca93cec1849661 /src/tmpfiles/tmpfiles.c
parenttmpfiles: make some log messages a tiny bit less cryptic for mere mortals (diff)
downloadsystemd-52b32b2aac96562ae8c380d8869b667f806471e0.tar.xz
systemd-52b32b2aac96562ae8c380d8869b667f806471e0.zip
tmpfiles: while aging, take a BSD file lock on each directory we descent into
Let's add a fully safe way to exclude certain directories from aging, by taking a BSD file lock on them before aging them. This is useful for clients that untar tarballs into /tmp or /var/tmp, which might have really old timestamps, and to which the aging logic would be very harsh: they can simply take a BSD file lock on any directory they like and thus exclude it from automatic aging, and thus need not to be afraid of untarring stuff below it. Previously, similar functionality was already available through the sticky bit on non-directories, but it's problematic, since as soon as the bit is set no clean-up is done for it at all anymore, forever. Also, it is not suitable for untarring stuff, since the sticky bit after all is a concept denoted in the tarball itself. BSD file locking semantics are much much nicer there, as they are automatically released when the application that has them dies, and they are entirely orthogonal to data encoded in tarballs. This patch takes BSD file locks only on *directories* while descending down the tree, not on regular files. Moreover, it will do so in non-blocking mode only, i.e. if anyone else has a lock the aging for a dir and everything below it is immediately skipped for the current clean-up iteration. Of course applications might take BSD file locks for other reasons than just prevent aging (i.e for their own reasons), but that should be entirely OK, as in that case tmpfiles should step away from those files anyway too: it's a good idea to stay away from any such locked file anyway since it's apparently curretnly being manipulated. This allows us to fix bugs like this: https://github.com/systemd/mkosi/issues/252
Diffstat (limited to 'src/tmpfiles/tmpfiles.c')
-rw-r--r--src/tmpfiles/tmpfiles.c8
1 files changed, 7 insertions, 1 deletions
diff --git a/src/tmpfiles/tmpfiles.c b/src/tmpfiles/tmpfiles.c
index c1506710e6..04cd0bfa33 100644
--- a/src/tmpfiles/tmpfiles.c
+++ b/src/tmpfiles/tmpfiles.c
@@ -12,6 +12,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <sys/file.h>
#include <sys/stat.h>
#include <sys/xattr.h>
#include <sysexits.h>
@@ -579,6 +580,7 @@ static int dir_cleanup(
}
if (S_ISDIR(s.st_mode)) {
+ _cleanup_closedir_ DIR *sub_dir = NULL;
if (mountpoint &&
streq(dent->d_name, "lost+found") &&
@@ -590,7 +592,6 @@ static int dir_cleanup(
if (maxdepth <= 0)
log_warning("Reached max depth on \"%s\".", sub_path);
else {
- _cleanup_closedir_ DIR *sub_dir;
int q;
sub_dir = xopendirat_nomod(dirfd(d), dent->d_name);
@@ -601,6 +602,11 @@ static int dir_cleanup(
continue;
}
+ if (flock(dirfd(sub_dir), LOCK_EX|LOCK_NB) < 0) {
+ log_debug_errno(errno, "Couldn't acquire shared BSD lock on directory \"%s\", skipping: %m", p);
+ continue;
+ }
+
q = dir_cleanup(i, sub_path, sub_dir, &s, cutoff, rootdev, false, maxdepth-1, false);
if (q < 0)
r = q;