diff options
author | Ivan Shapovalov <intelfx@intelfx.name> | 2016-09-13 03:04:35 +0300 |
---|---|---|
committer | Ivan Shapovalov <intelfx@intelfx.name> | 2016-09-15 06:36:42 +0300 |
commit | fb8b0869a7bc30e23be175cf978df23192d59118 (patch) | |
tree | 9524b559719dd9a03e100739f68123a4f4dcea8b /src/update-done | |
parent | 3a730176b36bc1191c54b149a8147bbf6ec8e482 (diff) |
update-done, condition: write the timestamp to the file as well and use it to prevent false-positives
This fixes https://bugs.freedesktop.org/show_bug.cgi?id=90192 and #4130
for real. Also, remove timestamp check in update-done.c altogether since
the whole operation is idempotent.
Diffstat (limited to 'src/update-done')
-rw-r--r-- | src/update-done/update-done.c | 76 |
1 files changed, 33 insertions, 43 deletions
diff --git a/src/update-done/update-done.c b/src/update-done/update-done.c index da306a4444..5cc5abfddf 100644 --- a/src/update-done/update-done.c +++ b/src/update-done/update-done.c @@ -23,67 +23,57 @@ #include "util.h" #define MESSAGE \ - "This file was created by systemd-update-done. Its only \n" \ - "purpose is to hold a timestamp of the time this directory\n" \ - "was updated. See systemd-update-done.service(8).\n" + "# This file was created by systemd-update-done. Its only \n" \ + "# purpose is to hold a timestamp of the time this directory\n" \ + "# was updated. See systemd-update-done.service(8).\n" static int apply_timestamp(const char *path, struct timespec *ts) { struct timespec twice[2] = { *ts, *ts }; - struct stat st; + int fd = -1; + _cleanup_fclose_ FILE *f = NULL; + int r; assert(path); assert(ts); - if (stat(path, &st) >= 0) { - /* Is the timestamp file already newer than the OS? If - * so, there's nothing to do. We ignore the nanosecond - * component of the timestamp, since some file systems - * do not support any better accuracy than 1s and we - * have no way to identify the accuracy - * available. Most notably ext4 on small disks (where - * 128 byte inodes are used) does not support better - * accuracy than 1s. */ - if (st.st_mtim.tv_sec > ts->tv_sec) - return 0; - - /* It is older? Then let's update it */ - if (utimensat(AT_FDCWD, path, twice, AT_SYMLINK_NOFOLLOW) < 0) { - - if (errno == EROFS) - return log_debug("Can't update timestamp file %s, file system is read-only.", path); + /* + * We store the timestamp both as mtime of the file and in the file itself, + * to support filesystems which cannot store nanosecond-precision timestamps. + * Hence, don't bother updating the file, let's just rewrite it. + */ - return log_error_errno(errno, "Failed to update timestamp on %s: %m", path); - } + r = mac_selinux_create_file_prepare(path, S_IFREG); + if (r < 0) + return log_error_errno(r, "Failed to set SELinux context for %s: %m", path); - } else if (errno == ENOENT) { - _cleanup_close_ int fd = -1; - int r; + fd = open(path, O_CREAT|O_WRONLY|O_TRUNC|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW, 0644); + mac_selinux_create_file_clear(); - /* The timestamp file doesn't exist yet? Then let's create it. */ + if (fd < 0) { + if (errno == EROFS) + return log_debug("Can't create timestamp file %s, file system is read-only.", path); - r = mac_selinux_create_file_prepare(path, S_IFREG); - if (r < 0) - return log_error_errno(r, "Failed to set SELinux context for %s: %m", path); - - fd = open(path, O_CREAT|O_EXCL|O_WRONLY|O_TRUNC|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW, 0644); - mac_selinux_create_file_clear(); + return log_error_errno(errno, "Failed to create/open timestamp file %s: %m", path); + } - if (fd < 0) { - if (errno == EROFS) - return log_debug("Can't create timestamp file %s, file system is read-only.", path); + f = fdopen(fd, "w"); + 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 create timestamp file %s: %m", path); - } + (void) fprintf(f, + "%s" + "TimestampNSec=" NSEC_FMT "\n", + MESSAGE, timespec_load_nsec(ts)); - (void) loop_write(fd, MESSAGE, strlen(MESSAGE), false); + fflush(f); - if (futimens(fd, twice) < 0) - return log_error_errno(errno, "Failed to update timestamp on %s: %m", path); - } else - log_error_errno(errno, "Failed to stat() timestamp file %s: %m", path); + if (futimens(fd, twice) < 0) + return log_error_errno(errno, "Failed to update timestamp on %s: %m", path); return 0; } |