chiark / gitweb /
tmpfiles: accurately report creation results
[elogind.git] / src / tmpfiles / tmpfiles.c
index 5bd7cfecfe22d31a655d18fba9571b89282dd8b1..0e1bd86748396228bf4412ae98ea9ca9f74ad431 100644 (file)
@@ -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);
@@ -443,18 +465,12 @@ static int dir_cleanup(
                                 continue;
                         }
 
-                        if (i->type == IGNORE_DIRECTORY_PATH && streq(dent->d_name, p))
-                                log_debug("Ignoring directory \"%s\"", sub_path);
-                        else {
-                                log_debug("Removing directory \"%s\".", sub_path);
-
-                                if (unlinkat(dirfd(d), dent->d_name, AT_REMOVEDIR) < 0) {
-                                        if (errno != ENOENT && errno != ENOTEMPTY) {
-                                                log_error_errno(errno, "rmdir(%s): %m", sub_path);
-                                                r = -errno;
-                                        }
+                        log_debug("Removing directory \"%s\".", sub_path);
+                        if (unlinkat(dirfd(d), dent->d_name, AT_REMOVEDIR) < 0)
+                                if (errno != ENOENT && errno != ENOTEMPTY) {
+                                        log_error_errno(errno, "rmdir(%s): %m", sub_path);
+                                        r = -errno;
                                 }
-                        }
 
                 } else {
                         /* Skip files for which the sticky bit is
@@ -817,11 +833,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 +873,18 @@ 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 = {};
+        _cleanup_globfree_ glob_t g = {
+                .gl_closedir = (void (*)(void *)) closedir,
+                .gl_readdir = (struct dirent *(*)(void *)) readdir,
+                .gl_opendir = (void *(*)(const char *)) opendir_nomod,
+                .gl_lstat = lstat,
+                .gl_stat = stat,
+        };
         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);
 
@@ -883,9 +903,28 @@ static int glob_item(Item *i, action_t action, bool recursive) {
         return r;
 }
 
+typedef enum {
+        CREATION_NORMAL,
+        CREATION_EXISTING,
+        CREATION_FORCE,
+} CreationMode;
+
+static const char* creation_verb(CreationMode mode) {
+        switch(mode) {
+        case CREATION_NORMAL:
+                return "Created";
+        case CREATION_EXISTING:
+                return "Found existing";
+        case CREATION_FORCE:
+                return "Created replacement";
+        }
+        assert_not_reached("Bad creation");
+}
+
 static int create_item(Item *i) {
         struct stat st;
         int r = 0;
+        CreationMode creation;
 
         assert(i);
 
@@ -970,8 +1009,11 @@ static int create_item(Item *i) {
                                 log_debug("\"%s\" already exists and is not a directory.", i->path);
                                 return 0;
                         }
-                }
-                log_debug("Created directory \"%s\".", i->path);
+
+                        creation = CREATION_EXISTING;
+                } else
+                        creation = CREATION_NORMAL;
+                log_debug("%s directory \"%s\".", creation_verb(creation), i->path);
 
                 r = path_set_perms(i, i->path);
                 if (r < 0)
@@ -1006,13 +1048,16 @@ static int create_item(Item *i) {
 
                                         if (r < 0)
                                                 return log_error_errno(r, "Failed to create fifo %s: %m", i->path);
+                                        creation = CREATION_FORCE;
                                 } else {
                                         log_debug("%s is not a fifo.", i->path);
                                         return 0;
                                 }
-                        }
-                }
-                log_debug("Created fifo \"%s\".", i->path);
+                        } else
+                                creation = CREATION_EXISTING;
+                } else
+                        creation = CREATION_NORMAL;
+                log_debug("%s fifo \"%s\".", creation_verb(creation), i->path);
 
                 r = path_set_perms(i, i->path);
                 if (r < 0)
@@ -1042,13 +1087,16 @@ static int create_item(Item *i) {
 
                                         if (r < 0)
                                                 return log_error_errno(r, "symlink(%s, %s) failed: %m", i->argument, i->path);
+                                        creation = CREATION_FORCE;
                                 } else {
                                         log_debug("\"%s\" is not a symlink or does not point to the correct path.", i->path);
                                         return 0;
                                 }
-                        }
-                }
-                log_debug("Created symlink \"%s\".", i->path);
+                        } else
+                                creation = CREATION_EXISTING;
+                } else
+                        creation = CREATION_NORMAL;
+                log_debug("%s symlink \"%s\".", creation_verb(creation), i->path);
 
                 break;
 
@@ -1098,14 +1146,18 @@ static int create_item(Item *i) {
                                         }
 
                                         if (r < 0)
-                                                return log_error_errno(r, "Failed to create device node %s: %m", i->path);
+                                                return log_error_errno(r, "Failed to create device node \"%s\": %m", i->path);
+                                        creation = CREATION_FORCE;
                                 } else {
                                         log_debug("%s is not a device node.", i->path);
                                         return 0;
                                 }
-                        }
-                }
-                log_debug("Created %s device node \"%s\" %u:%u.",
+                        } else
+                                creation = CREATION_EXISTING;
+                } else
+                        creation = CREATION_NORMAL;
+                log_debug("%s %s device node \"%s\" %u:%u.",
+                          creation_verb(creation),
                           i->type == CREATE_BLOCK_DEVICE ? "block" : "char",
                           i->path, major(i->mode), minor(i->mode));
 
@@ -1248,7 +1300,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);
@@ -1723,8 +1775,8 @@ static void help(void) {
                "     --clean                Clean up marked directories\n"
                "     --remove               Remove marked files/directories\n"
                "     --boot                 Execute actions only safe at boot\n"
-               "     --prefix=PATH          Only apply rules that apply to paths with the specified prefix\n"
-               "     --exclude-prefix=PATH  Ignore rules that apply to paths with the specified prefix\n"
+               "     --prefix=PATH          Only apply rules with the specified prefix\n"
+               "     --exclude-prefix=PATH  Ignore rules with the specified prefix\n"
                "     --root=PATH            Operate on an alternate filesystem root\n",
                program_invocation_short_name);
 }