]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
update-done: Create using a temporary file (#5789)
authorcodekipper <codekipper@gmail.com>
Wed, 26 Apr 2017 23:49:06 +0000 (01:49 +0200)
committerZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
Wed, 26 Apr 2017 23:49:06 +0000 (19:49 -0400)
'/etc/.updated' is created without using a temporary file, this can be
problematic with filesystems that cache writes. Modify so that the
timestamp is written to a temporary file and then use an atomic move
to move it to its correct place.

src/update-done/update-done.c

index d466e1b759a7c44aeb6b2d5742697a5ea5cff299..06e2d7b71b36e8f73687e84053a8c2a52f661c66 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
+#include "alloc-util.h"
 #include "fd-util.h"
 #include "fileio.h"
+#include "fs-util.h"
 #include "io-util.h"
 #include "selinux-util.h"
 #include "util.h"
@@ -36,6 +38,7 @@ static int apply_timestamp(const char *path, struct timespec *ts) {
         _cleanup_fclose_ FILE *f = NULL;
         int fd = -1;
         int r;
+        _cleanup_(unlink_and_freep) char *tmp = NULL;
 
         assert(path);
         assert(ts);
@@ -50,20 +53,20 @@ static int apply_timestamp(const char *path, struct timespec *ts) {
         if (r < 0)
                 return log_error_errno(r, "Failed to set SELinux context for %s: %m", path);
 
-        fd = open(path, O_CREAT|O_WRONLY|O_TRUNC|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW, 0644);
+        fd = open_tmpfile_linkable(path, O_WRONLY|O_CLOEXEC, &tmp);
         mac_selinux_create_file_clear();
 
         if (fd < 0) {
                 if (errno == EROFS)
-                        return log_debug("Can't create timestamp file %s, file system is read-only.", path);
+                        return log_debug("Can't create temporary timestamp file %s, file system is read-only.", tmp);
 
-                return log_error_errno(errno, "Failed to create/open timestamp file %s: %m", path);
+                return log_error_errno(errno, "Failed to create/open temporary timestamp file %s: %m", tmp);
         }
 
         f = fdopen(fd, "we");
         if (!f) {
                 safe_close(fd);
-                return log_error_errno(errno, "Failed to fdopen() timestamp file %s: %m", path);
+                return log_error_errno(errno, "Failed to fdopen() timestamp file %s: %m", tmp);
         }
 
         (void) fprintf(f,
@@ -76,7 +79,15 @@ static int apply_timestamp(const char *path, struct timespec *ts) {
                 return log_error_errno(r, "Failed to write timestamp file: %m");
 
         if (futimens(fd, twice) < 0)
-                return log_error_errno(errno, "Failed to update timestamp on %s: %m", path);
+                return log_error_errno(errno, "Failed to update timestamp on %s: %m", tmp);
+
+        /* fix permissions */
+        (void) fchmod(fd, 0644);
+        r = link_tmpfile(fd, tmp, path);
+        if (r < 0)
+                return log_error_errno(r, "Failed to move \"%s\" to \"%s\": %m", tmp, path);
+
+        tmp = mfree(tmp);
 
         return 0;
 }