mirror of
https://github.com/systemd/systemd.git
synced 2024-11-27 20:23:36 +08:00
rtc in localtime: use settimeofday(NULL, tz) instead of hwclock(8)
We check for LOCAL in /etc/adjtime and if needed, ask the kernel to apply the timezone delta to the system clock. The very first call of settimeofday() without a time, but a timezone warps the system clock, so that it properly runs in UTC.
This commit is contained in:
parent
359306dfe5
commit
7948c4dfbe
@ -274,7 +274,6 @@ dist_systemunit_DATA = \
|
||||
units/sys-kernel-security.mount \
|
||||
units/var-run.mount \
|
||||
units/media.mount \
|
||||
units/hwclock-load.service \
|
||||
units/hwclock-save.service \
|
||||
units/remount-rootfs.service \
|
||||
units/printer.target \
|
||||
@ -1430,9 +1429,6 @@ endif
|
||||
( cd $(DESTDIR)$(pkgsysconfdir)/system/multi-user.target.wants && \
|
||||
rm -f remote-fs.target && \
|
||||
$(LN_S) $(systemunitdir)/remote-fs.target remote-fs.target )
|
||||
( cd $(DESTDIR)$(pkgsysconfdir)/system/sysinit.target.wants && \
|
||||
rm -f hwclock-load.service && \
|
||||
$(LN_S) $(systemunitdir)/hwclock-load.service hwclock-load.service )
|
||||
( cd $(DESTDIR)$(systemunitdir)/sysinit.target.wants && \
|
||||
rm -f dev-hugepages.automount \
|
||||
dev-mqueue.automount \
|
||||
|
@ -1049,6 +1049,13 @@ int main(int argc, char *argv[]) {
|
||||
|
||||
if (label_init() < 0)
|
||||
goto finish;
|
||||
|
||||
if (hwclock_is_localtime()) {
|
||||
int min;
|
||||
|
||||
min = hwclock_apply_localtime_delta();
|
||||
log_info("Hwclock configured in localtime, applying delta of %i minutes to system time", min);
|
||||
}
|
||||
} else {
|
||||
arg_running_as = MANAGER_USER;
|
||||
log_set_target(LOG_TARGET_CONSOLE);
|
||||
|
80
src/util.c
80
src/util.c
@ -51,6 +51,8 @@
|
||||
#include <dlfcn.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/capability.h>
|
||||
#include <sys/time.h>
|
||||
#include <linux/rtc.h>
|
||||
|
||||
#include "macro.h"
|
||||
#include "util.h"
|
||||
@ -4761,3 +4763,81 @@ finish:
|
||||
*strv = files;
|
||||
return r;
|
||||
}
|
||||
|
||||
bool hwclock_is_localtime(void) {
|
||||
FILE *f;
|
||||
char line[LINE_MAX];
|
||||
bool local = false;
|
||||
|
||||
/*
|
||||
* The third line of adjtime is "UTC" or "LOCAL" or nothing.
|
||||
* # /etc/adjtime
|
||||
* 0.0 0 0.0
|
||||
* 0
|
||||
* UTC
|
||||
*/
|
||||
f = fopen("/etc/adjtime", "re");
|
||||
if (f) {
|
||||
if (fgets(line, sizeof(line), f) &&
|
||||
fgets(line, sizeof(line), f) &&
|
||||
fgets(line, sizeof(line), f) ) {
|
||||
if (!strcmp(line, "LOCAL\n"))
|
||||
local = true;
|
||||
}
|
||||
fclose(f);
|
||||
}
|
||||
return local;
|
||||
}
|
||||
|
||||
int hwclock_apply_localtime_delta(void) {
|
||||
const struct timeval *tv_null = NULL;
|
||||
struct timeval tv;
|
||||
struct tm *tm;
|
||||
int minuteswest;
|
||||
struct timezone tz;
|
||||
|
||||
gettimeofday(&tv, NULL);
|
||||
tm = localtime(&tv.tv_sec);
|
||||
minuteswest = tm->tm_gmtoff / 60;
|
||||
|
||||
tz.tz_minuteswest = -minuteswest;
|
||||
tz.tz_dsttime = 0; /* DST_NONE*/
|
||||
|
||||
/*
|
||||
* If the hardware clock does not run in UTC, but in local time:
|
||||
* The very first time we set the kernel's timezone, it will warp
|
||||
* the clock so that it runs in UTC instead of local time.
|
||||
*/
|
||||
if (settimeofday(tv_null, &tz) < 0)
|
||||
return -errno;
|
||||
else
|
||||
return minuteswest;
|
||||
}
|
||||
|
||||
int hwclock_get_time(struct tm *tm) {
|
||||
int fd;
|
||||
int err = 0;
|
||||
|
||||
fd = open("/dev/rtc0", O_RDONLY|O_CLOEXEC);
|
||||
if (fd < 0)
|
||||
return -errno;
|
||||
if (ioctl(fd, RTC_RD_TIME, tm) < 0)
|
||||
err = -errno;
|
||||
close(fd);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
int hwclock_set_time(const struct tm *tm) {
|
||||
int fd;
|
||||
int err = 0;
|
||||
|
||||
fd = open("/dev/rtc0", O_RDONLY|O_CLOEXEC);
|
||||
if (fd < 0)
|
||||
return -errno;
|
||||
if (ioctl(fd, RTC_SET_TIME, tm) < 0)
|
||||
err = -errno;
|
||||
close(fd);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
@ -451,4 +451,13 @@ int signal_from_string(const char *s);
|
||||
int signal_from_string_try_harder(const char *s);
|
||||
|
||||
int conf_files_list(char ***strv, const char *suffix, const char *dir, ...);
|
||||
|
||||
bool hwclock_is_localtime(void);
|
||||
|
||||
int hwclock_apply_localtime_delta(void);
|
||||
|
||||
int hwclock_get_time(struct tm *tm);
|
||||
|
||||
int hwclock_set_time(const struct tm *tm);
|
||||
|
||||
#endif
|
||||
|
@ -1,34 +0,0 @@
|
||||
# This file is part of systemd.
|
||||
#
|
||||
# systemd is free software; you can redistribute it and/or modify it
|
||||
# under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
|
||||
[Unit]
|
||||
Description=Apply System Clock UTC Offset
|
||||
DefaultDependencies=no
|
||||
Wants=time-sync.target
|
||||
Conflicts=shutdown.target
|
||||
After=systemd-readahead-collect.service systemd-readahead-replay.service
|
||||
Before=sysinit.target shutdown.target udev.service time-sync.target
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
RemainAfterExit=yes
|
||||
ExecStart=/sbin/hwclock --systz
|
||||
StandardOutput=syslog
|
||||
|
||||
# Note the weird semantics of hwclock and the kernel here: the first
|
||||
# settimeofday() invocation from userspace is special and may be used
|
||||
# to set the offset from UTC of the system clock. It is independent
|
||||
# of any specific RTC device. This is mostly a crufty hack to support
|
||||
# legacy operating systems which insist on storing local time in the
|
||||
# RTC.
|
||||
|
||||
# Note that we do not run --hctosys here, we assume the kernel
|
||||
# includes a compiled in RTC module which is used to initialize the
|
||||
# system time as part of kernel setup.
|
||||
|
||||
[Install]
|
||||
WantedBy=sysinit.target
|
Loading…
Reference in New Issue
Block a user