--- /dev/null
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+
+#include <sys/stat.h>
+#include <sys/time.h>
+
+#include "clock-util.h"
+#include "clock-warp.h"
+#include "errno-util.h"
+
+int clock_reset_timewarp(void) {
+ static const struct timezone tz = {
+ .tz_minuteswest = 0,
+ .tz_dsttime = 0, /* DST_NONE */
+ };
+
+ /* The very first call to settimeofday() does time warp magic. Do a dummy call here, so the time
+ * warping is sealed and all later calls behave as expected. */
+ return RET_NERRNO(settimeofday(NULL, &tz));
+}
+
+void clock_apply_epoch(void) {
+ usec_t epoch_usec;
+ struct stat st;
+ int r;
+
+ r = RET_NERRNO(stat(EPOCH_CLOCK_FILE, &st));
+ if (r < 0) {
+ if (r != -ENOENT)
+ log_warning_errno(r, "Cannot stat " EPOCH_CLOCK_FILE ": %m");
+
+ epoch_usec = (usec_t) TIME_EPOCH * USEC_PER_SEC;
+ } else
+ epoch_usec = timespec_load(&st.st_mtim);
+
+ usec_t now_usec = now(CLOCK_REALTIME);
+ bool advance;
+
+ if (now_usec < epoch_usec)
+ advance = true;
+ else if (CLOCK_VALID_RANGE_USEC_MAX > 0 && now_usec > usec_add(epoch_usec, CLOCK_VALID_RANGE_USEC_MAX))
+ advance = false;
+ else
+ return; /* Nothing to do. */
+
+ r = RET_NERRNO(clock_settime(CLOCK_REALTIME, TIMESPEC_STORE(epoch_usec)));
+ if (r < 0 && advance)
+ return (void) log_error_errno(r, "Current system time is before build time, but cannot correct: %m");
+ else if (r < 0)
+ return (void) log_error_errno(r, "Current system time is further ahead than %s after build time, but cannot correct: %m",
+ FORMAT_TIMESPAN(CLOCK_VALID_RANGE_USEC_MAX, USEC_PER_DAY));
+ else if (advance)
+ log_info("System time was before build time, advanced clock.");
+ else
+ log_info("System time was further ahead than %s after build time, reset clock to build time.",
+ FORMAT_TIMESPAN(CLOCK_VALID_RANGE_USEC_MAX, USEC_PER_DAY));
+}
--- /dev/null
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+#pragma once
+
+int clock_reset_timewarp(void);
+void clock_apply_epoch(void);
#include "cgroup-util.h"
#include "chase.h"
#include "clock-util.h"
+#include "clock-warp.h"
#include "conf-parser.h"
#include "confidential-virt.h"
#include "copy.h"
*/
(void) clock_reset_timewarp();
- 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));
+ clock_apply_epoch();
}
static void apply_clock_update(void) {
systemd_sources = files(
'main.c',
'crash-handler.c',
+ 'clock-warp.c',
)
systemd_executor_sources = files(
/* SPDX-License-Identifier: LGPL-2.1-or-later */
-#include <errno.h>
#include <fcntl.h>
-#include <limits.h>
-#include <stdbool.h>
-#include <time.h>
#include <linux/rtc.h>
#include <stdio.h>
#include <sys/ioctl.h>
return 0;
}
-
-int clock_reset_timewarp(void) {
- static const struct timezone tz = {
- .tz_minuteswest = 0,
- .tz_dsttime = 0, /* DST_NONE */
- };
-
- /* The very first call to settimeofday() does time warp magic. Do a dummy call here, so the time
- * warping is sealed and all later calls behave as expected. */
- return RET_NERRNO(settimeofday(NULL, &tz));
-}
-
-int clock_apply_epoch(ClockChangeDirection *ret_attempted_change) {
- usec_t epoch_usec, now_usec;
- struct stat st;
-
- /* 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_CLOCK_FILE, &st) < 0) {
- if (errno != ENOENT)
- log_warning_errno(errno, "Cannot stat " EPOCH_CLOCK_FILE ": %m");
-
- epoch_usec = (usec_t) TIME_EPOCH * USEC_PER_SEC;
- } else
- epoch_usec = timespec_load(&st.st_mtim);
-
- now_usec = now(CLOCK_REALTIME);
- if (now_usec < epoch_usec)
- *ret_attempted_change = CLOCK_CHANGE_FORWARD;
- else if (CLOCK_VALID_RANGE_USEC_MAX > 0 && 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(epoch_usec)) < 0)
- return -errno;
-
- return 1;
-}
/* 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(ClockChangeDirection *ret_attempted_change);
#define EPOCH_CLOCK_FILE "/usr/lib/clock-epoch"
#define TIMESYNCD_CLOCK_FILE_DIR "/var/lib/systemd/timesync/"