]> git.ipfire.org Git - thirdparty/systemd.git/blobdiff - src/tmpfiles/tmpfiles.c
tmpfiles: make the stat struct parameter in fd_set_*() optional
[thirdparty/systemd.git] / src / tmpfiles / tmpfiles.c
index c8d7532b7291cbf5d869812d54c601ac3acb9016..8b6342b2e446968eeb90d0c252beeada9063d8c7 100644 (file)
@@ -1,7 +1,4 @@
 /* SPDX-License-Identifier: LGPL-2.1+ */
-/***
-  Copyright © 2010 Kay Sievers
-***/
 
 #include <errno.h>
 #include <fcntl.h>
@@ -775,6 +772,7 @@ static bool hardlink_vulnerable(const struct stat *st) {
 
 static int fd_set_perms(Item *i, int fd, const struct stat *st) {
         _cleanup_free_ char *path = NULL;
+        struct stat stbuf;
         int r;
 
         assert(i);
@@ -787,6 +785,12 @@ static int fd_set_perms(Item *i, int fd, const struct stat *st) {
         if (!i->mode_set && !i->uid_set && !i->gid_set)
                 goto shortcut;
 
+        if (!st) {
+                if (fstat(fd, &stbuf) < 0)
+                        return log_error_errno(errno, "fstat(%s) failed: %m", path);
+                st = &stbuf;
+        }
+
         if (hardlink_vulnerable(st)) {
                 log_error("Refusing to set permissions on hardlinked file %s while the fs.protected_hardlinks sysctl is turned off.", path);
                 return -EPERM;
@@ -840,7 +844,7 @@ shortcut:
 
 static int path_set_perms(Item *i, const char *path) {
         _cleanup_close_ int fd = -1;
-        struct stat st;
+        struct stat stbuf, *st = NULL;
 
         assert(i);
         assert(path);
@@ -860,13 +864,20 @@ static int path_set_perms(Item *i, const char *path) {
                 return r;
         }
 
-        if (fstat(fd, &st) < 0)
-                return log_error_errno(errno, "Failed to fstat() file %s: %m", path);
+        if (i->type == EMPTY_DIRECTORY) {
+                /* FIXME: introduce fd_is_dir() helper ? */
+                if (fstat(fd, &stbuf) < 0)
+                        return log_error_errno(errno, "Failed to fstat() file %s: %m", path);
+
+                if (!S_ISDIR(stbuf.st_mode)) {
+                        log_error("'%s' already exists and is not a directory. ", path);
+                        return -EEXIST;
+                }
 
-        if (i->type == EMPTY_DIRECTORY && !S_ISDIR(st.st_mode))
-                return log_error_errno(EEXIST, "'%s' already exists and is not a directory. ", path);
+                st = &stbuf;
+        }
 
-        return fd_set_perms(i, fd, &st);
+        return fd_set_perms(i, fd, st);
 }
 
 static int parse_xattrs_from_arg(Item *i) {
@@ -1014,15 +1025,21 @@ static int fd_set_acls(Item *item, int fd, const struct stat *st) {
 #if HAVE_ACL
         char procfs_path[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int)];
         _cleanup_free_ char *path = NULL;
+        struct stat stbuf;
 
         assert(item);
         assert(fd);
-        assert(st);
 
         r = fd_get_path(fd, &path);
         if (r < 0)
                 return r;
 
+        if (!st) {
+                if (fstat(fd, &stbuf) < 0)
+                        return log_error_errno(errno, "fstat(%s) failed: %m", path);
+                st = &stbuf;
+        }
+
         if (hardlink_vulnerable(st)) {
                 log_error("Refusing to set ACLs on hardlinked file %s while the fs.protected_hardlinks sysctl is turned off.", path);
                 return -EPERM;
@@ -1038,7 +1055,8 @@ static int fd_set_acls(Item *item, int fd, const struct stat *st) {
         if (item->acl_access)
                 r = path_set_acl(procfs_path, path, ACL_TYPE_ACCESS, item->acl_access, item->force);
 
-        if (r == 0 && item->acl_default)
+        /* set only default acls to folders */
+        if (r == 0 && item->acl_default && S_ISDIR(st->st_mode))
                 r = path_set_acl(procfs_path, path, ACL_TYPE_DEFAULT, item->acl_default, item->force);
 
         if (r > 0)
@@ -1055,9 +1073,8 @@ static int fd_set_acls(Item *item, int fd, const struct stat *st) {
 
 static int path_set_acls(Item *item, const char *path) {
         int r = 0;
-#ifdef HAVE_ACL
+#if HAVE_ACL
         _cleanup_close_ int fd = -1;
-        struct stat st;
 
         assert(item);
         assert(path);
@@ -1066,13 +1083,10 @@ static int path_set_acls(Item *item, const char *path) {
         if (fd < 0)
                 return log_error_errno(errno, "Adjusting ACL of %s failed: %m", path);
 
-        if (fstat(fd, &st) < 0)
-                return log_error_errno(errno, "Failed to fstat() file %s: %m", path);
-
-        r = fd_set_acls(item, fd, &st);
- #endif
-         return r;
- }
+        r = fd_set_acls(item, fd, NULL);
+#endif
+        return r;
+}
 
 #define ATTRIBUTES_ALL                          \
         (FS_NOATIME_FL      |                   \
@@ -1176,6 +1190,7 @@ static int parse_attribute_from_arg(Item *item) {
 static int fd_set_attribute(Item *item, int fd, const struct stat *st) {
         _cleanup_close_ int procfs_fd = -1;
         _cleanup_free_ char *path = NULL;
+        struct stat stbuf;
         unsigned f;
         int r;
 
@@ -1186,6 +1201,12 @@ static int fd_set_attribute(Item *item, int fd, const struct stat *st) {
         if (r < 0)
                 return r;
 
+        if (!st) {
+                if (fstat(fd, &stbuf) < 0)
+                        return log_error_errno(errno, "fstat(%s) failed: %m", path);
+                st = &stbuf;
+        }
+
         /* Issuing the file attribute ioctls on device nodes is not
          * safe, as that will be delivered to the drivers, not the
          * file system containing the device node. */
@@ -1216,7 +1237,6 @@ static int fd_set_attribute(Item *item, int fd, const struct stat *st) {
 
 static int path_set_attribute(Item *item, const char *path) {
         _cleanup_close_ int fd = -1;
-        struct stat st;
 
         if (!item->attribute_set || item->attribute_mask == 0)
                 return 0;
@@ -1225,10 +1245,7 @@ static int path_set_attribute(Item *item, const char *path) {
         if (fd < 0)
                 return log_error_errno(errno, "Cannot open '%s': %m", path);
 
-        if (fstat(fd, &st) < 0)
-                return log_error_errno(errno, "Cannot stat '%s': %m", path);
-
-        return fd_set_attribute(item, fd, &st);
+        return fd_set_attribute(item, fd, NULL);
 }
 
 static int write_one_file(Item *i, const char *path) {
@@ -1297,18 +1314,23 @@ static int write_one_file(Item *i, const char *path) {
 typedef int (*action_t)(Item *, const char *);
 typedef int (*fdaction_t)(Item *, int fd, const struct stat *st);
 
-static int item_do(Item *i, int fd, const struct stat *st, fdaction_t action) {
+static int item_do(Item *i, int fd, fdaction_t action) {
+        struct stat st;
         int r = 0, q;
 
         assert(i);
         assert(fd >= 0);
-        assert(st);
+
+        if (fstat(fd, &st) < 0) {
+                r = -errno;
+                goto finish;
+        }
 
         /* This returns the first error we run into, but nevertheless
          * tries to go on */
-        r = action(i, fd, st);
+        r = action(i, fd, &st);
 
-        if (S_ISDIR(st->st_mode)) {
+        if (S_ISDIR(st.st_mode)) {
                 char procfs_path[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int)];
                 _cleanup_closedir_ DIR *d = NULL;
                 struct dirent *de;
@@ -1324,16 +1346,15 @@ static int item_do(Item *i, int fd, const struct stat *st, fdaction_t action) {
                 }
 
                 FOREACH_DIRENT_ALL(de, d, q = -errno; goto finish) {
-                        struct stat de_st;
                         int de_fd;
 
                         if (dot_or_dot_dot(de->d_name))
                                 continue;
 
                         de_fd = openat(fd, de->d_name, O_NOFOLLOW|O_CLOEXEC|O_PATH);
-                        if (de_fd >= 0 && fstat(de_fd, &de_st) >= 0)
+                        if (de_fd >= 0)
                                 /* pass ownership of dirent fd over  */
-                                q = item_do(i, de_fd, &de_st, action);
+                                q = item_do(i, de_fd, action);
                         else
                                 q = -errno;
 
@@ -1379,7 +1400,6 @@ static int glob_item_recursively(Item *i, fdaction_t action) {
 
         STRV_FOREACH(fn, g.gl_pathv) {
                 _cleanup_close_ int fd = -1;
-                struct stat st;
 
                 /* Make sure we won't trigger/follow file object (such as
                  * device nodes, automounts, ...) pointed out by 'fn' with
@@ -1392,12 +1412,7 @@ static int glob_item_recursively(Item *i, fdaction_t action) {
                         continue;
                 }
 
-                if (fstat(fd, &st) < 0) {
-                        r = r ?: -errno;
-                        continue;
-                }
-
-                k = item_do(i, fd, &st, action);
+                k = item_do(i, fd, action);
                 if (k < 0 && r == 0)
                         r = k;