mirror of
https://github.com/systemd/systemd.git
synced 2025-03-31 14:50:15 +03:00
Merge pull request #11482 from poettering/tmpfiles-bsd-lock
adds a fully safe way how apps can pin files into /tmp temporarily, excepting them from the tmpfiles aging algorithm, based on BSD file locks on dirs we descend into
This commit is contained in:
commit
ac5c138137
@ -545,6 +545,14 @@ w- /proc/sys/vm/swappiness - - - - 10</programlisting></para>
|
||||
(ctime). Any of these three (or two) values will prevent cleanup
|
||||
if it is more recent than the current time minus the age
|
||||
field.</para>
|
||||
|
||||
<para>Note that while the aging algorithm is run a 'shared' BSD file lock (see <citerefentry
|
||||
project='man-pages'><refentrytitle>flock</refentrytitle><manvolnum>2</manvolnum></citerefentry>) is
|
||||
taken on each directory the algorithm descends into (and each directory below that, and so on). If the
|
||||
aging algorithm finds a lock is already taken on some directory, it (and everything below it) is
|
||||
skipped. Applications may use this to temporarily exclude certain directory subtrees from the aging
|
||||
algorithm: the applications can take a BSD file lock themselves, and as long as they keep it aging of
|
||||
the directory and everything below it is disabled.</para>
|
||||
</refsect2>
|
||||
|
||||
<refsect2>
|
||||
|
@ -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>
|
||||
@ -48,6 +49,7 @@
|
||||
#include "path-lookup.h"
|
||||
#include "path-util.h"
|
||||
#include "pretty-print.h"
|
||||
#include "rlimit-util.h"
|
||||
#include "rm-rf.h"
|
||||
#include "selinux-util.h"
|
||||
#include "set.h"
|
||||
@ -525,7 +527,6 @@ static int dir_cleanup(
|
||||
bool keep_this_level) {
|
||||
|
||||
struct dirent *dent;
|
||||
struct timespec times[2];
|
||||
bool deleted = false;
|
||||
int r = 0;
|
||||
|
||||
@ -580,42 +581,45 @@ static int dir_cleanup(
|
||||
}
|
||||
|
||||
if (S_ISDIR(s.st_mode)) {
|
||||
_cleanup_closedir_ DIR *sub_dir = NULL;
|
||||
|
||||
if (mountpoint &&
|
||||
streq(dent->d_name, "lost+found") &&
|
||||
s.st_uid == 0) {
|
||||
log_debug("Ignoring \"%s\".", sub_path);
|
||||
log_debug("Ignoring directory \"%s\".", sub_path);
|
||||
continue;
|
||||
}
|
||||
|
||||
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);
|
||||
if (!sub_dir) {
|
||||
if (errno != ENOENT)
|
||||
r = log_error_errno(errno, "opendir(%s) failed: %m", sub_path);
|
||||
r = log_warning_errno(errno, "Opening directory \"%s\" failed, ignoring: %m", sub_path);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/* Note: if you are wondering why we don't
|
||||
* support the sticky bit for excluding
|
||||
* directories from cleaning like we do it for
|
||||
* other file system objects: well, the sticky
|
||||
* bit already has a meaning for directories,
|
||||
* so we don't want to overload that. */
|
||||
/* Note: if you are wondering why we don't support the sticky bit for excluding
|
||||
* directories from cleaning like we do it for other file system objects: well, the
|
||||
* sticky bit already has a meaning for directories, so we don't want to overload
|
||||
* that. */
|
||||
|
||||
if (keep_this_level) {
|
||||
log_debug("Keeping \"%s\".", sub_path);
|
||||
log_debug("Keeping directory \"%s\".", sub_path);
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -642,13 +646,11 @@ static int dir_cleanup(
|
||||
log_debug("Removing directory \"%s\".", sub_path);
|
||||
if (unlinkat(dirfd(d), dent->d_name, AT_REMOVEDIR) < 0)
|
||||
if (!IN_SET(errno, ENOENT, ENOTEMPTY))
|
||||
r = log_error_errno(errno, "rmdir(%s): %m", sub_path);
|
||||
r = log_warning_errno(errno, "Failed to remove directory \"%s\", ignoring: %m", sub_path);
|
||||
|
||||
} else {
|
||||
/* Skip files for which the sticky bit is
|
||||
* set. These are semantics we define, and are
|
||||
* unknown elsewhere. See XDG_RUNTIME_DIR
|
||||
* specification for details. */
|
||||
/* Skip files for which the sticky bit is set. These are semantics we define, and are
|
||||
* unknown elsewhere. See XDG_RUNTIME_DIR specification for details. */
|
||||
if (s.st_mode & S_ISVTX) {
|
||||
log_debug("Skipping \"%s\": sticky bit set.", sub_path);
|
||||
continue;
|
||||
@ -675,8 +677,7 @@ static int dir_cleanup(
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Keep files on this level around if this is
|
||||
* requested */
|
||||
/* Keep files on this level around if this is requested */
|
||||
if (keep_this_level) {
|
||||
log_debug("Keeping \"%s\".", sub_path);
|
||||
continue;
|
||||
@ -710,11 +711,10 @@ static int dir_cleanup(
|
||||
continue;
|
||||
}
|
||||
|
||||
log_debug("unlink \"%s\"", sub_path);
|
||||
|
||||
log_debug("Removing \"%s\".", sub_path);
|
||||
if (unlinkat(dirfd(d), dent->d_name, 0) < 0)
|
||||
if (errno != ENOENT)
|
||||
r = log_error_errno(errno, "unlink(%s): %m", sub_path);
|
||||
r = log_warning_errno(errno, "Failed to remove \"%s\", ignoring: %m", sub_path);
|
||||
|
||||
deleted = true;
|
||||
}
|
||||
@ -722,21 +722,22 @@ static int dir_cleanup(
|
||||
|
||||
finish:
|
||||
if (deleted) {
|
||||
usec_t age1, age2;
|
||||
char a[FORMAT_TIMESTAMP_MAX], b[FORMAT_TIMESTAMP_MAX];
|
||||
|
||||
/* Restore original directory timestamps */
|
||||
times[0] = ds->st_atim;
|
||||
times[1] = ds->st_mtim;
|
||||
usec_t age1, age2;
|
||||
|
||||
age1 = timespec_load(&ds->st_atim);
|
||||
age2 = timespec_load(&ds->st_mtim);
|
||||
|
||||
log_debug("Restoring access and modification time on \"%s\": %s, %s",
|
||||
p,
|
||||
format_timestamp_us(a, sizeof(a), age1),
|
||||
format_timestamp_us(b, sizeof(b), age2));
|
||||
if (futimens(dirfd(d), times) < 0)
|
||||
log_error_errno(errno, "utimensat(%s): %m", p);
|
||||
|
||||
/* Restore original directory timestamps */
|
||||
if (futimens(dirfd(d), (struct timespec[]) {
|
||||
ds->st_atim,
|
||||
ds->st_mtim }) < 0)
|
||||
log_warning_errno(errno, "Failed to revert timestamps of '%s', ignoring: %m", p);
|
||||
}
|
||||
|
||||
return r;
|
||||
@ -3175,6 +3176,9 @@ static int run(int argc, char *argv[]) {
|
||||
|
||||
log_setup_service();
|
||||
|
||||
/* Descending down file system trees might take a lot of fds */
|
||||
(void) rlimit_nofile_bump(HIGH_RLIMIT_NOFILE);
|
||||
|
||||
if (arg_user) {
|
||||
r = user_config_paths(&config_dirs);
|
||||
if (r < 0)
|
||||
|
Loading…
x
Reference in New Issue
Block a user