]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
time-set: adjust system clock if rtc is far in future
authorEgor Ignatov <egori@altlinux.org>
Wed, 28 Jul 2021 09:13:31 +0000 (12:13 +0300)
committerLuca Boccassi <luca.boccassi@gmail.com>
Mon, 2 Aug 2021 19:33:01 +0000 (20:33 +0100)
meson.build
meson_options.txt
src/core/main.c
src/shared/clock-util.c
src/shared/clock-util.h

index 27dcf956f3e3c28fb8ba01c7a9a8999c69f4933b..e08a7662a7fb89d927ef2a67e0a011b4350e6fc1 100644 (file)
@@ -722,6 +722,8 @@ if time_epoch == -1
 endif
 conf.set('TIME_EPOCH', time_epoch)
 
+conf.set('CLOCK_VALID_RANGE_USEC_MAX', get_option('clock-valid-range-usec-max'))
+
 foreach tuple : [['system-alloc-uid-min', 'SYS_UID_MIN', 1],  # Also see login.defs(5).
                  ['system-uid-max',       'SYS_UID_MAX', 999],
                  ['system-alloc-gid-min', 'SYS_GID_MIN', 1],
index 0b01fb2cbf2665edcf2d88acfb731dca2f721ffb..110a471b6be47183f5b5c6396c7a73a835ce0e31 100644 (file)
@@ -208,6 +208,8 @@ option('status-unit-format-default', type : 'combo',
        description : 'use unit name or description in messages by default')
 option('time-epoch', type : 'integer', value : '-1',
        description : 'time epoch for time clients')
+option('clock-valid-range-usec-max', type : 'integer', value : '473364000000000', # 15 years
+       description : 'maximum value in microseconds for the difference between RTC and epoch, exceeding which is considered an RTC error')
 
 option('system-alloc-uid-min', type : 'integer', value : '-1',
        description : 'minimum system UID used when allocating')
index 8920d70d5d735a5f21365f0508295a22e6f84e58..473dc0920eafde93f91adacc41c0c55f34f148aa 100644 (file)
@@ -83,6 +83,7 @@
 #include "switch-root.h"
 #include "sysctl-util.h"
 #include "terminal-util.h"
+#include "time-util.h"
 #include "umask-util.h"
 #include "user-util.h"
 #include "util.h"
@@ -1598,11 +1599,18 @@ static void initialize_clock(void) {
                  */
                 (void) clock_reset_timewarp();
 
-        r = clock_apply_epoch();
-        if (r < 0)
-                log_error_errno(r, "Current system time is before build time, but cannot correct: %m");
-        else if (r > 0)
+        ClockChangeDirection change_dir;
+        r = clock_apply_epoch(&change_dir);
+        if (r > 0 && change_dir == CLOCK_CHANGE_FORWARD)
                 log_info("System time before build time, advancing clock.");
+        else if (r > 0 && change_dir == CLOCK_CHANGE_BACKWARD)
+                log_info("System time is further ahead than %s after build time, resetting clock to build time.",
+                         FORMAT_TIMESPAN(CLOCK_VALID_RANGE_USEC_MAX, USEC_PER_DAY));
+        else if (r < 0 && change_dir == CLOCK_CHANGE_FORWARD)
+                log_error_errno(r, "Current system time is before build time, but cannot correct: %m");
+        else if (r < 0 && change_dir == CLOCK_CHANGE_BACKWARD)
+                log_error_errno(r, "Current system time is further ahead %s after build time, but cannot correct: %m",
+                                FORMAT_TIMESPAN(CLOCK_VALID_RANGE_USEC_MAX, USEC_PER_DAY));
 }
 
 static void apply_clock_update(void) {
index b446daf5819731c02af0432fce2ac58b22a13e17..7c1c48d0690030db1b154cbb31540ace8da39ac1 100644 (file)
@@ -139,10 +139,15 @@ int clock_reset_timewarp(void) {
 
 #define EPOCH_FILE "/usr/lib/clock-epoch"
 
-int clock_apply_epoch(void) {
+int clock_apply_epoch(ClockChangeDirection *ret_attempted_change) {
         struct stat st;
         struct timespec ts;
-        usec_t epoch_usec;
+        usec_t epoch_usec, now_usec;
+
+        /* NB: we update *ret_attempted_change in *all* cases, both
+         * on success and failure, to indicate what we intended to do! */
+
+        assert(ret_attempted_change);
 
         if (stat(EPOCH_FILE, &st) < 0) {
                 if (errno != ENOENT)
@@ -152,8 +157,15 @@ int clock_apply_epoch(void) {
         } else
                 epoch_usec = timespec_load(&st.st_mtim);
 
-        if (now(CLOCK_REALTIME) >= epoch_usec)
+        now_usec = now(CLOCK_REALTIME);
+        if (now_usec < epoch_usec)
+                *ret_attempted_change = CLOCK_CHANGE_FORWARD;
+        else if (now_usec > usec_add(epoch_usec, CLOCK_VALID_RANGE_USEC_MAX))
+                *ret_attempted_change = CLOCK_CHANGE_BACKWARD;
+        else {
+                *ret_attempted_change = CLOCK_CHANGE_NOOP;
                 return 0;
+        }
 
         if (clock_settime(CLOCK_REALTIME, timespec_store(&ts, epoch_usec)) < 0)
                 return -errno;
index 9e96d50d963c0b2e55ecb588c42762fd0767ab4e..c8f6d1b1f1e6089fb076dde37fa102a6dce30b50 100644 (file)
@@ -1,11 +1,20 @@
 /* SPDX-License-Identifier: LGPL-2.1-or-later */
 #pragma once
 
+#include <errno.h>
 #include <time.h>
 
+typedef enum ClockChangeDirection {
+        CLOCK_CHANGE_NOOP,
+        CLOCK_CHANGE_FORWARD,
+        CLOCK_CHANGE_BACKWARD,
+        _CLOCK_CHANGE_MAX,
+        _CLOCK_CHANGE_INVALID = -EINVAL,
+} ClockChangeDirection;
+
 int clock_is_localtime(const char* adjtime_path);
 int clock_set_timezone(int *ret_minutesdelta);
 int clock_reset_timewarp(void);
 int clock_get_hwclock(struct tm *tm);
 int clock_set_hwclock(const struct tm *tm);
-int clock_apply_epoch(void);
+int clock_apply_epoch(ClockChangeDirection *ret_attempted_change);