]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
manager: use max of: compile epoch, epoch file, timesyncd file
authorZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
Wed, 5 Jun 2024 10:50:52 +0000 (12:50 +0200)
committerZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
Sat, 15 Jun 2024 14:20:12 +0000 (16:20 +0200)
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

index d4dcc0440f196b2a0c91d0a0d927520e96b5ec43..eff06ea1b8e24c59b7d4d6f59d41adf037c94837 100644 (file)
@@ -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;