diff options
author | Kay Sievers <kay@vrfy.org> | 2014-05-22 21:31:46 +0900 |
---|---|---|
committer | Kay Sievers <kay@vrfy.org> | 2014-05-24 08:04:56 +0800 |
commit | d636d376796ec61c1c14fa619c80d4ac62e08a19 (patch) | |
tree | dd32fcbe307c6defcf36e18890ce20810e951607 /src/timesync/timesyncd.c | |
parent | c38dfac9ed6c1c3beb3dd88ebf82a13d1e561ff8 (diff) |
timesyncd: only update stamp file when we are synchronized
Create initial stamp file with compiled-in time to prevent bootups
with clocks in the future from storing invalid timestamps.
At shutdown, only update the timestamp if we got an authoritative
time to store.
Diffstat (limited to 'src/timesync/timesyncd.c')
-rw-r--r-- | src/timesync/timesyncd.c | 124 |
1 files changed, 53 insertions, 71 deletions
diff --git a/src/timesync/timesyncd.c b/src/timesync/timesyncd.c index 13cdef7708..b28beadd31 100644 --- a/src/timesync/timesyncd.c +++ b/src/timesync/timesyncd.c @@ -52,6 +52,7 @@ #include "sd-network.h" #include "event-util.h" #include "network-util.h" +#include "clock-util.h" #include "capability.h" #include "mkdir.h" #include "timesyncd.h" @@ -135,9 +136,27 @@ static int manager_clock_watch_setup(Manager *m); static int manager_connect(Manager *m); static void manager_disconnect(Manager *m); -static int load_clock(uid_t uid, gid_t gid) { - usec_t nt = TIME_EPOCH * USEC_PER_SEC, ct; +static double ntp_ts_to_d(const struct ntp_ts *ts) { + return be32toh(ts->sec) + ((double)be32toh(ts->frac) / UINT_MAX); +} + +static double ts_to_d(const struct timespec *ts) { + return ts->tv_sec + (1.0e-9 * ts->tv_nsec); +} + +static double tv_to_d(const struct timeval *tv) { + return tv->tv_sec + (1.0e-6 * tv->tv_usec); +} + +static double square(double d) { + return d * d; +} + +static int load_clock_timestamp(uid_t uid, gid_t gid) { _cleanup_close_ int fd = -1; + usec_t min = TIME_EPOCH * USEC_PER_SEC; + usec_t ct; + int r; /* Let's try to make sure that the clock is always * monotonically increasing, by saving the clock whenever we @@ -146,83 +165,43 @@ static int load_clock(uid_t uid, gid_t gid) { * systems lacking a battery backed RTC. We also will adjust * the time to at least the build time of systemd. */ - mkdir_p("/var/lib/systemd", 0755); - - /* First, we try to create the clock file if it doesn't exist yet */ - fd = open("/var/lib/systemd/clock", O_RDWR|O_CLOEXEC|O_EXCL, 0644); - if (fd < 0) { - - fd = open("/var/lib/systemd/clock", O_RDWR|O_CLOEXEC|O_CREAT, 0644); - if (fd < 0) { - log_error("Failed to create /var/lib/systemd/clock: %m"); - return -errno; - } - - } else { + fd = open("/var/lib/systemd/clock", O_RDWR|O_CLOEXEC, 0644); + if (fd >= 0) { struct stat st; - usec_t ft; - - if (fstat(fd, &st) < 0) { - log_error("fstat() failed: %m"); - return -errno; + usec_t stamp; + + /* check if the recorded time is later than the compiled-in one */ + r = fstat(fd, &st); + if (r >= 0) { + stamp = timespec_load(&st.st_mtim); + if (stamp > min) + min = stamp; } - ft = timespec_load(&st.st_mtim); - if (ft > nt) - nt = ft; - } + /* Try to fix the access mode, so that we can still + touch the file after dropping priviliges */ + fchmod(fd, 0644); + fchown(fd, uid, gid); + + } else + /* create stamp file with the compiled-in date */ + touch_file("/var/lib/systemd/clock", true, min, uid, gid, 0644); ct = now(CLOCK_REALTIME); - if (nt > ct) { + if (ct < min) { struct timespec ts; - log_info("System clock time unset or jumped backwards, restoring."); - - if (clock_settime(CLOCK_REALTIME, timespec_store(&ts, nt)) < 0) - log_error("Failed to restore system clock: %m"); - } - - /* Try to fix the access mode, so that we can still - touch the file after dropping priviliges */ - fchmod(fd, 0644); - fchown(fd, uid, gid); + char date[FORMAT_TIMESTAMP_MAX]; - return 0; -} - -static int save_clock(void) { - - static const struct timespec ts[2] = { - { .tv_sec = 0, .tv_nsec = UTIME_NOW }, - { .tv_sec = 0, .tv_nsec = UTIME_NOW }, - }; - - int r; + log_info("System clock time unset or jumped backwards, restoring from recorded timestamp: %s", + format_timestamp(date, sizeof(date), min)); - r = utimensat(-1, "/var/lib/systemd/clock", ts, AT_SYMLINK_NOFOLLOW); - if (r < 0) { - log_warning("Failed to touch /var/lib/systemd/clock: %m"); - return -errno; + if (clock_settime(CLOCK_REALTIME, timespec_store(&ts, min)) < 0) + log_error("Failed to restore system clock: %m"); } return 0; } -static double ntp_ts_to_d(const struct ntp_ts *ts) { - return be32toh(ts->sec) + ((double)be32toh(ts->frac) / UINT_MAX); -} - -static double ts_to_d(const struct timespec *ts) { - return ts->tv_sec + (1.0e-9 * ts->tv_nsec); -} - -static double tv_to_d(const struct timeval *tv) { - return tv->tv_sec + (1.0e-6 * tv->tv_usec); -} - -static double square(double d) { - return d * d; -} - static int manager_timeout(sd_event_source *source, usec_t usec, void *userdata) { _cleanup_free_ char *pretty = NULL; Manager *m = userdata; @@ -446,12 +425,11 @@ static int manager_adjust_clock(Manager *m, double offset, int leap_sec) { } r = clock_adjtime(CLOCK_REALTIME, &tmx); - - save_clock(); - if (r < 0) return r; + touch("/var/lib/systemd/clock"); + m->drift_ppm = tmx.freq / 65536; log_debug(" status : %04i %s\n" @@ -744,6 +722,7 @@ static int manager_receive_response(sd_event_source *source, int fd, uint32_t re m->poll_interval_usec / USEC_PER_SEC); if (!spike) { + m->sync = true; r = manager_adjust_clock(m, offset, leap_sec); if (r < 0) log_error("Failed to call clock_adjtime(): %m"); @@ -1308,7 +1287,7 @@ int main(int argc, char *argv[]) { return r; } - r = load_clock(uid, gid); + r = load_clock_timestamp(uid, gid); if (r < 0) goto out; @@ -1349,7 +1328,10 @@ int main(int argc, char *argv[]) { } sd_event_get_exit_code(m->event, &r); - save_clock(); + + /* if we got an authoritative time, store it in the file system */ + if (m->sync) + touch("/var/lib/systemd/clock"); out: sd_notify(false, "STATUS=Shutting down..."); |