summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>2014-01-02 00:02:31 -0500
committerZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>2015-01-24 23:38:59 -0500
commitdf99a9ef5bb7a89b92ccfb103b2f3e7046c62ef5 (patch)
tree5d85f21a5c7e922e384f9b74006b6ea04cea4920
parent582deb8446b7c76f945bb3174a8059d56b5edb65 (diff)
tmpfiles: do not bump access times of directories we are cleaning up
Both plain opendir() and glob() will bump access time. Privileged option O_NOATIME can be used to prevent the access time from being updated. We already used it for subdirectories of the directories which we were cleaning up. But for the directories specified directly in the config files, we wouldn't do that. This means that, paradoxically, our own temporary directories for PrivateTmp would stay around forever, as long as one let systemd-tmpfiles-clean.service run regularly, because they had their own glob patterns specified. https://bugzilla.redhat.com/show_bug.cgi?id=1183684
-rw-r--r--man/systemd-tmpfiles.xml13
-rw-r--r--src/shared/macro.h4
-rw-r--r--src/tmpfiles/tmpfiles.c46
3 files changed, 55 insertions, 8 deletions
diff --git a/man/systemd-tmpfiles.xml b/man/systemd-tmpfiles.xml
index 9a9bf17136..d4c5bf26e4 100644
--- a/man/systemd-tmpfiles.xml
+++ b/man/systemd-tmpfiles.xml
@@ -185,6 +185,19 @@
</refsect1>
<refsect1>
+ <title>Unprivileged --cleanup operation</title>
+
+ <para><command>systemd-tmpfiles</command> tries to
+ avoid changing the access and modification times on
+ the directories it accesses, which requires
+ <constant>CAP_ADMIN</constant> privileges. When
+ running as non-root, directories which are checked for
+ files to clean up will have their access time bumped,
+ which might prevent their cleanup.
+ </para>
+ </refsect1>
+
+ <refsect1>
<title>Exit status</title>
<para>On success, 0 is returned, a non-zero failure
diff --git a/src/shared/macro.h b/src/shared/macro.h
index ae2971fad1..e88630fa04 100644
--- a/src/shared/macro.h
+++ b/src/shared/macro.h
@@ -67,6 +67,10 @@
_Pragma("GCC diagnostic push"); \
_Pragma("GCC diagnostic ignored \"-Wshadow\"")
+#define DISABLE_WARNING_INCOMPATIBLE_POINTER_TYPES \
+ _Pragma("GCC diagnostic push"); \
+ _Pragma("GCC diagnostic ignored \"-Wincompatible-pointer-types\"")
+
#define REENABLE_WARNING \
_Pragma("GCC diagnostic pop")
diff --git a/src/tmpfiles/tmpfiles.c b/src/tmpfiles/tmpfiles.c
index 5bd7cfecfe..d70dbc4707 100644
--- a/src/tmpfiles/tmpfiles.c
+++ b/src/tmpfiles/tmpfiles.c
@@ -308,6 +308,28 @@ static int dir_is_mount_point(DIR *d, const char *subdir) {
return r;
}
+static DIR* xopendirat_nomod(int dirfd, const char *path) {
+ DIR *dir;
+
+ dir = xopendirat(dirfd, path, O_NOFOLLOW|O_NOATIME);
+ if (!dir) {
+ log_debug_errno(errno, "Cannot open %sdirectory \"%s\": %m",
+ dirfd == AT_FDCWD ? "" : "sub", path);
+ if (errno == EPERM) {
+ dir = xopendirat(dirfd, path, O_NOFOLLOW);
+ if (!dir)
+ log_debug_errno(errno, "Cannot open %sdirectory \"%s\": %m",
+ dirfd == AT_FDCWD ? "" : "sub", path);
+ }
+ }
+
+ return dir;
+}
+
+static DIR* opendir_nomod(const char *path) {
+ return xopendirat_nomod(AT_FDCWD, path);
+}
+
static int dir_cleanup(
Item *i,
const char *p,
@@ -398,7 +420,7 @@ static int dir_cleanup(
_cleanup_closedir_ DIR *sub_dir;
int q;
- sub_dir = xopendirat(dirfd(d), dent->d_name, O_NOFOLLOW|O_NOATIME);
+ 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);
@@ -817,11 +839,9 @@ static int item_do_children(Item *i, const char *path, action_t action) {
/* This returns the first error we run into, but nevertheless
* tries to go on */
- d = opendir(path);
- if (!d) {
- log_debug_errno(errno, "Cannot open directory \"%s\": %m", path);
+ d = opendir_nomod(path);
+ if (!d)
return errno == ENOENT || errno == ENOTDIR ? 0 : -errno;
- }
for (;;) {
_cleanup_free_ char *p = NULL;
@@ -859,12 +879,22 @@ static int item_do_children(Item *i, const char *path, action_t action) {
}
static int glob_item(Item *i, action_t action, bool recursive) {
- _cleanup_globfree_ glob_t g = {};
+DISABLE_WARNING_INCOMPATIBLE_POINTER_TYPES
+DISABLE_WARNING_DECLARATION_AFTER_STATEMENT
+ _cleanup_globfree_ glob_t g = {
+ .gl_closedir = closedir,
+ .gl_readdir = readdir,
+ .gl_opendir = opendir_nomod,
+ .gl_lstat = lstat,
+ .gl_stat = stat,
+ };
+REENABLE_WARNING
+REENABLE_WARNING
int r = 0, k;
char **fn;
errno = 0;
- k = glob(i->path, GLOB_NOSORT|GLOB_BRACE, NULL, &g);
+ k = glob(i->path, GLOB_NOSORT|GLOB_BRACE|GLOB_ALTDIRFUNC, NULL, &g);
if (k != 0 && k != GLOB_NOMATCH)
return log_error_errno(errno ?: EIO, "glob(%s) failed: %m", i->path);
@@ -1248,7 +1278,7 @@ static int clean_item_instance(Item *i, const char* instance) {
cutoff = n - i->age;
- d = opendir(instance);
+ d = opendir_nomod(instance);
if (!d) {
if (errno == ENOENT || errno == ENOTDIR) {
log_debug_errno(errno, "Directory \"%s\": %m", instance);