static void fallback_time_init(void) { struct timeval now; struct stat buf; char *drift_file; drift_file = CNF_GetDriftFile(); if (!drift_file) return; if (stat(drift_file, &buf)) return; LCL_ReadCookedTime(&now, NULL); if (now.tv_sec < buf.st_mtime) { LCL_ApplyStepOffset(now.tv_sec - buf.st_mtime); LOG(LOGS_INFO, LOGF_Rtc, "System clock set from driftfile %s", drift_file); } }
int RTC_Linux_TimePreInit(time_t driftfile_time) { int fd, status; struct rtc_time rtc_raw, rtc_raw_retry; struct tm rtc_tm; time_t rtc_t; double accumulated_error, sys_offset; struct timeval new_sys_time, old_sys_time; coefs_file_name = CNF_GetRtcFile(); setup_config(); read_coefs_from_file(); fd = open(CNF_GetRtcDevice(), O_RDONLY); if (fd < 0) { return 0; /* Can't open it, and won't be able to later */ } /* Retry reading the rtc until both read attempts give the same sec value. This way the race condition is prevented that the RTC has updated itself during the first read operation. */ do { status = ioctl(fd, RTC_RD_TIME, &rtc_raw); if (status >= 0) { status = ioctl(fd, RTC_RD_TIME, &rtc_raw_retry); } } while (status >= 0 && rtc_raw.tm_sec != rtc_raw_retry.tm_sec); /* Read system clock */ LCL_ReadCookedTime(&old_sys_time, NULL); close(fd); if (status >= 0) { /* Convert to seconds since 1970 */ rtc_tm.tm_sec = rtc_raw.tm_sec; rtc_tm.tm_min = rtc_raw.tm_min; rtc_tm.tm_hour = rtc_raw.tm_hour; rtc_tm.tm_mday = rtc_raw.tm_mday; rtc_tm.tm_mon = rtc_raw.tm_mon; rtc_tm.tm_year = rtc_raw.tm_year; rtc_t = t_from_rtc(&rtc_tm); if (rtc_t != (time_t)(-1)) { /* Work out approximatation to correct time (to about the nearest second) */ if (valid_coefs_from_file) { accumulated_error = file_ref_offset + (rtc_t - file_ref_time) * 1.0e-6 * file_rate_ppm; } else { accumulated_error = 0.0; } /* Correct time */ new_sys_time.tv_sec = rtc_t; /* Average error in the RTC reading */ new_sys_time.tv_usec = 500000; 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); /* Set system time only if the step is larger than 1 second */ if (fabs(sys_offset) >= 1.0) { if (LCL_ApplyStepOffset(sys_offset)) LOG(LOGS_INFO, LOGF_RtcLinux, "System time set from RTC"); } } else { return 0; } } else { return 0; } return 1; }