From ed23f7cbcb5457be32a5fc133280fb56bfe043d2 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Wed, 5 Jun 2024 12:50:52 +0200 Subject: [PATCH] manager: use max of: compile epoch, epoch file, timesyncd file Previously systemd would not use /var/lib/systemd/timesync/clock. This means that even if /var/ is mounted when systemd is started and the file is available, we would potentially make one time jump and than another time jump. From a user's POV, this doesn't seem useful at all. Also, we would always let /usr/lib/clock-epoch take priority over the built-in epoch. But there is no guarantee that this file is actually fresh. In particular, a user may touch /usr/lib/clock-epoch to work around a broken clock during installation (as recommended in [1]), and then this file will grow stale over time. So just load the three timestamps and use the highest one as the epoch. [1] https://discussion.fedoraproject.org/t/f38-to-f39-40-dnf-system-upgrade-can-fail-on-raspberry-pi/92403 --- src/core/clock-warp.c | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/src/core/clock-warp.c b/src/core/clock-warp.c index d4dcc0440f1..eff06ea1b8e 100644 --- a/src/core/clock-warp.c +++ b/src/core/clock-warp.c @@ -19,18 +19,28 @@ int clock_reset_timewarp(void) { } void clock_apply_epoch(void) { - usec_t epoch_usec; + usec_t epoch_usec = 0, timesyncd_usec = 0; struct stat st; int r; + r = RET_NERRNO(stat(TIMESYNCD_CLOCK_FILE, &st)); + if (r >= 0) + epoch_usec = timespec_load(&st.st_mtim); + else if (r != -ENOENT) + log_warning_errno(r, "Could not stat %s, ignoring: %m", TIMESYNCD_CLOCK_FILE); + r = RET_NERRNO(stat(EPOCH_CLOCK_FILE, &st)); - if (r < 0) { - if (r != -ENOENT) - log_warning_errno(r, "Cannot stat " EPOCH_CLOCK_FILE ": %m"); + if (r >= 0) + timesyncd_usec = timespec_load(&st.st_mtim); + else if (r != -ENOENT) + log_warning_errno(r, "Could not stat %s, ignoring: %m", EPOCH_CLOCK_FILE); - epoch_usec = (usec_t) TIME_EPOCH * USEC_PER_SEC; - } else - epoch_usec = timespec_load(&st.st_mtim); + epoch_usec = MAX3(epoch_usec, + timesyncd_usec, + (usec_t) TIME_EPOCH * USEC_PER_SEC); + + if (epoch_usec == 0) /* Weird, but may happen if mtimes were reset to 0 during compilation. */ + return log_debug("Clock epoch is 0, skipping clock adjustment."); usec_t now_usec = now(CLOCK_REALTIME); bool advance; -- 2.47.3