[systemd-devel] [PATCH] tmpfiles: only execute chmod()/chown() when needed

Michael Olbrich m.olbrich at pengutronix.de
Fri Jul 11 06:05:05 PDT 2014


This avoids errors like this, when the paths are already there with the
correct permissions and owner:

chmod(/var/spool) failed: Read-only file system
---
 src/tmpfiles/tmpfiles.c | 36 +++++++++++++++++++++---------------
 1 file changed, 21 insertions(+), 15 deletions(-)

diff --git a/src/tmpfiles/tmpfiles.c b/src/tmpfiles/tmpfiles.c
index 68cfa55..4f41f28 100644
--- a/src/tmpfiles/tmpfiles.c
+++ b/src/tmpfiles/tmpfiles.c
@@ -453,35 +453,41 @@ finish:
 }
 
 static int item_set_perms(Item *i, const char *path) {
+        struct stat st;
+        mode_t old_m = ~0;
+        uid_t old_uid = -1;
+        gid_t old_gid = -1;
+
         assert(i);
         assert(path);
 
+        if (stat(path, &st) >= 0) {
+                old_m = st.st_mode & 07777;
+                old_uid = st.st_uid;
+                old_gid = st.st_gid;
+        }
         /* not using i->path directly because it may be a glob */
         if (i->mode_set) {
                 mode_t m = i->mode;
 
-                if (i->mask_perms) {
-                        struct stat st;
-
-                        if (stat(path, &st) >= 0) {
-                                if (!(st.st_mode & 0111))
-                                        m &= ~0111;
-                                if (!(st.st_mode & 0222))
-                                        m &= ~0222;
-                                if (!(st.st_mode & 0444))
-                                        m &= ~0444;
-                                if (!S_ISDIR(st.st_mode))
-                                        m &= ~07000; /* remove sticky/sgid/suid bit, unless directory */
-                        }
+                if (i->mask_perms && old_m != ~0) {
+                        if (!(st.st_mode & 0111))
+                                m &= ~0111;
+                        if (!(st.st_mode & 0222))
+                                m &= ~0222;
+                        if (!(st.st_mode & 0444))
+                                m &= ~0444;
+                        if (!S_ISDIR(st.st_mode))
+                                m &= ~07000; /* remove sticky/sgid/suid bit, unless directory */
                 }
 
-                if (chmod(path, m) < 0) {
+                if (m != old_m && chmod(path, m) < 0) {
                         log_error("chmod(%s) failed: %m", path);
                         return -errno;
                 }
         }
 
-        if (i->uid_set || i->gid_set)
+        if ((i->uid_set || i->gid_set) && (i->uid != old_uid || i->gid != old_gid))
                 if (chown(path,
                           i->uid_set ? i->uid : (uid_t) -1,
                           i->gid_set ? i->gid : (gid_t) -1) < 0) {
-- 
2.0.1



More information about the systemd-devel mailing list