rtc: restore time from driftfile if later than RTC time
This is useful on computers that have an RTC, but there is no battery to keep the time when they are turned off and start with the same time on each boot.
This commit is contained in:
parent
1714d3e8ae
commit
6a9c756cf0
5 changed files with 53 additions and 44 deletions
|
@ -972,13 +972,9 @@ This option is useful when restarting @code{chronyd} and can be used
|
||||||
in conjunction with the `-r' option.
|
in conjunction with the `-r' option.
|
||||||
|
|
||||||
@item -s
|
@item -s
|
||||||
This option will set the system clock from the computer's real-time
|
This option will set the system clock from the computer's real-time clock or
|
||||||
clock. This is analogous to supplying the `-s' flag to the
|
to the last modification time of the file specified by the @code{driftfile}
|
||||||
@file{/sbin/hwclock} program during the Linux boot sequence.
|
directive. Real-time clocks are supported only on Linux.
|
||||||
|
|
||||||
Support for real-time clocks is limited at present - the criteria are
|
|
||||||
described in the section on the @code{rtcfile} directive (@pxref{rtcfile
|
|
||||||
directive}).
|
|
||||||
|
|
||||||
If used in conjunction with the `-r' flag, @code{chronyd} will attempt
|
If used in conjunction with the `-r' flag, @code{chronyd} will attempt
|
||||||
to preserve the old samples after setting the system clock from the real
|
to preserve the old samples after setting the system clock from the real
|
||||||
|
@ -989,11 +985,10 @@ to work well, it relies on @code{chronyd} having been able to determine
|
||||||
accurate statistics for the difference between the RTC and
|
accurate statistics for the difference between the RTC and
|
||||||
system clock last time the computer was on.
|
system clock last time the computer was on.
|
||||||
|
|
||||||
If @code{chronyd} doesn't support the RTC on your computer or there is no RTC
|
If the last modification time of the drift file is later than the current time
|
||||||
installed, the system clock will be set with this option forward to the time of
|
and the RTC time, the system time will be set to it to restore the time when
|
||||||
the last modification of the drift file (specified by the @code{driftfile}
|
@code{chronyd} was previously stopped. This is useful on computers that have
|
||||||
directive) to restore the system time at which @code{chronyd} was previously
|
no RTC or the RTC is broken (e.g. it has no battery).
|
||||||
stopped.
|
|
||||||
@item -u <user>
|
@item -u <user>
|
||||||
This option sets the name of the system user to which @code{chronyd} will
|
This option sets the name of the system user to which @code{chronyd} will
|
||||||
switch after start in order to drop root privileges. It overrides the
|
switch after start in order to drop root privileges. It overrides the
|
||||||
|
|
19
chronyd.8.in
19
chronyd.8.in
|
@ -80,13 +80,9 @@ option is useful when restarting \fBchronyd\fR and can be used in conjunction
|
||||||
with the \fB-r\fR option.
|
with the \fB-r\fR option.
|
||||||
.TP
|
.TP
|
||||||
.B \-s
|
.B \-s
|
||||||
This option will set the system clock from the computer's real-time
|
This option will set the system clock from the computer's real-time clock or
|
||||||
clock. This is analogous to supplying the \fI-s\fR flag to the
|
to the last modification time of the file specified by the \fIdriftfile\fR
|
||||||
\fI/sbin/hwclock\fR program during the Linux boot sequence.
|
directive. Real-time clocks are supported only on Linux.
|
||||||
|
|
||||||
Support for real-time clocks is limited at present - the criteria
|
|
||||||
are described in the section on the \fIrtcfile\fR directive in the
|
|
||||||
documentation supplied with the distribution.
|
|
||||||
|
|
||||||
If used in conjunction with the \fB-r\fR flag, \fBchronyd\fR will attempt
|
If used in conjunction with the \fB-r\fR flag, \fBchronyd\fR will attempt
|
||||||
to preserve the old samples after setting the system clock from
|
to preserve the old samples after setting the system clock from
|
||||||
|
@ -97,11 +93,10 @@ not in use. For this to work well, it relies on \fBchronyd\fR having
|
||||||
been able to determine accurate statistics for the difference
|
been able to determine accurate statistics for the difference
|
||||||
between the RTC and system clock last time the computer was on.
|
between the RTC and system clock last time the computer was on.
|
||||||
|
|
||||||
If \fBchronyd\fR doesn't support the RTC on your computer or there is no RTC
|
If the last modification time of the drift file is later than the current time
|
||||||
installed, the system clock will be set with this option forward to the time of
|
and the RTC time, the system time will be set to it to restore the time when
|
||||||
the last modification of the drift file (specified by the \fIdriftfile\fR
|
\fBchronyd\fR was previously stopped. This is useful on computers that have no
|
||||||
directive) to restore the system time at which \fBchronyd\fR was previously
|
RTC or the RTC is broken (e.g. it has no battery).
|
||||||
stopped.
|
|
||||||
.TP
|
.TP
|
||||||
\fB\-u\fR \fIuser\fR
|
\fB\-u\fR \fIuser\fR
|
||||||
This option sets the name of the system user to which \fBchronyd\fR will switch
|
This option sets the name of the system user to which \fBchronyd\fR will switch
|
||||||
|
|
50
rtc.c
50
rtc.c
|
@ -44,7 +44,7 @@ static int driver_preinit_ok = 0;
|
||||||
static struct {
|
static struct {
|
||||||
int (*init)(void);
|
int (*init)(void);
|
||||||
void (*fini)(void);
|
void (*fini)(void);
|
||||||
int (*time_pre_init)(void);
|
int (*time_pre_init)(time_t driftfile_time);
|
||||||
void (*time_init)(void (*after_hook)(void*), void *anything);
|
void (*time_init)(void (*after_hook)(void*), void *anything);
|
||||||
void (*start_measurements)(void);
|
void (*start_measurements)(void);
|
||||||
int (*write_parameters)(void);
|
int (*write_parameters)(void);
|
||||||
|
@ -74,29 +74,37 @@ static struct {
|
||||||
};
|
};
|
||||||
|
|
||||||
/* ================================================== */
|
/* ================================================== */
|
||||||
/* Set the system clock to the time of last modification of driftfile
|
/* Get the last modification time of the driftfile */
|
||||||
if it's in the future */
|
|
||||||
|
|
||||||
static void
|
static time_t
|
||||||
fallback_time_init(void)
|
get_driftfile_time(void)
|
||||||
{
|
{
|
||||||
struct timeval now;
|
|
||||||
struct stat buf;
|
struct stat buf;
|
||||||
char *drift_file;
|
char *drift_file;
|
||||||
|
|
||||||
drift_file = CNF_GetDriftFile();
|
drift_file = CNF_GetDriftFile();
|
||||||
if (!drift_file)
|
if (!drift_file)
|
||||||
return;
|
return 0;
|
||||||
|
|
||||||
if (stat(drift_file, &buf))
|
if (stat(drift_file, &buf))
|
||||||
return;
|
return 0;
|
||||||
|
|
||||||
|
return buf.st_mtime;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ================================================== */
|
||||||
|
/* Set the system time to the driftfile time if it's in the future */
|
||||||
|
|
||||||
|
static void
|
||||||
|
apply_driftfile_time(time_t t)
|
||||||
|
{
|
||||||
|
struct timeval now;
|
||||||
|
|
||||||
LCL_ReadCookedTime(&now, NULL);
|
LCL_ReadCookedTime(&now, NULL);
|
||||||
|
|
||||||
if (now.tv_sec < buf.st_mtime) {
|
if (now.tv_sec < t) {
|
||||||
if (LCL_ApplyStepOffset(now.tv_sec - buf.st_mtime))
|
if (LCL_ApplyStepOffset(now.tv_sec - t))
|
||||||
LOG(LOGS_INFO, LOGF_Rtc, "System clock set from driftfile %s",
|
LOG(LOGS_INFO, LOGF_Rtc, "System time restored from driftfile");
|
||||||
drift_file);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -105,18 +113,24 @@ fallback_time_init(void)
|
||||||
void
|
void
|
||||||
RTC_Initialise(int initial_set)
|
RTC_Initialise(int initial_set)
|
||||||
{
|
{
|
||||||
|
time_t driftfile_time;
|
||||||
char *file_name;
|
char *file_name;
|
||||||
|
|
||||||
/* Do an initial read of the RTC and set the system time to it. This
|
/* If the -s option was specified, try to do an initial read of the RTC and
|
||||||
is analogous to what /sbin/hwclock -s would do on Linux. If that fails
|
set the system time to it. Also, read the last modification time of the
|
||||||
or RTC is not supported, set the clock to the time of the last
|
driftfile (i.e. system time when chronyd was previously stopped) and set
|
||||||
modification of driftfile, so we at least get closer to the truth. */
|
the system time to it if it's in the future to bring the clock closer to
|
||||||
|
the true time when the RTC is broken (e.g. it has no battery), is missing,
|
||||||
|
or there is no RTC driver. */
|
||||||
if (initial_set) {
|
if (initial_set) {
|
||||||
if (driver.time_pre_init && driver.time_pre_init()) {
|
driftfile_time = get_driftfile_time();
|
||||||
|
|
||||||
|
if (driver.time_pre_init && driver.time_pre_init(driftfile_time)) {
|
||||||
driver_preinit_ok = 1;
|
driver_preinit_ok = 1;
|
||||||
} else {
|
} else {
|
||||||
driver_preinit_ok = 0;
|
driver_preinit_ok = 0;
|
||||||
fallback_time_init();
|
if (driftfile_time)
|
||||||
|
apply_driftfile_time(driftfile_time);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -974,7 +974,7 @@ RTC_Linux_WriteParameters(void)
|
||||||
RTC behaviour than we do for the rest of the module. */
|
RTC behaviour than we do for the rest of the module. */
|
||||||
|
|
||||||
int
|
int
|
||||||
RTC_Linux_TimePreInit(void)
|
RTC_Linux_TimePreInit(time_t driftfile_time)
|
||||||
{
|
{
|
||||||
int fd, status;
|
int fd, status;
|
||||||
struct rtc_time rtc_raw, rtc_raw_retry;
|
struct rtc_time rtc_raw, rtc_raw_retry;
|
||||||
|
@ -1039,6 +1039,11 @@ RTC_Linux_TimePreInit(void)
|
||||||
|
|
||||||
UTI_AddDoubleToTimeval(&new_sys_time, -accumulated_error, &new_sys_time);
|
UTI_AddDoubleToTimeval(&new_sys_time, -accumulated_error, &new_sys_time);
|
||||||
|
|
||||||
|
if (new_sys_time.tv_sec < driftfile_time) {
|
||||||
|
LOG(LOGS_WARN, LOGF_RtcLinux, "RTC time before last driftfile modification (ignored)");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
UTI_DiffTimevalsToDouble(&sys_offset, &old_sys_time, &new_sys_time);
|
UTI_DiffTimevalsToDouble(&sys_offset, &old_sys_time, &new_sys_time);
|
||||||
|
|
||||||
/* Set system time only if the step is larger than 1 second */
|
/* Set system time only if the step is larger than 1 second */
|
||||||
|
|
|
@ -30,7 +30,7 @@
|
||||||
|
|
||||||
extern int RTC_Linux_Initialise(void);
|
extern int RTC_Linux_Initialise(void);
|
||||||
extern void RTC_Linux_Finalise(void);
|
extern void RTC_Linux_Finalise(void);
|
||||||
extern int RTC_Linux_TimePreInit(void);
|
extern int RTC_Linux_TimePreInit(time_t driftile_time);
|
||||||
extern void RTC_Linux_TimeInit(void (*after_hook)(void *), void *anything);
|
extern void RTC_Linux_TimeInit(void (*after_hook)(void *), void *anything);
|
||||||
extern void RTC_Linux_StartMeasurements(void);
|
extern void RTC_Linux_StartMeasurements(void);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue