int step_systime( double step ) { time_t pivot; /* for ntp era unfolding */ struct timeval timetv, tvlast, tvdiff; struct timespec timets; struct calendar jd; l_fp fp_ofs, fp_sys; /* offset and target system time in FP */ /* * Get pivot time for NTP era unfolding. Since we don't step * very often, we can afford to do the whole calculation from * scratch. And we're not in the time-critical path yet. */ #if SIZEOF_TIME_T > 4 /* * This code makes sure the resulting time stamp for the new * system time is in the 2^32 seconds starting at 1970-01-01, * 00:00:00 UTC. */ pivot = 0x80000000; #if USE_COMPILETIME_PIVOT /* * Add the compile time minus 10 years to get a possible target * area of (compile time - 10 years) to (compile time + 126 * years). This should be sufficient for a given binary of * NTPD. */ if (ntpcal_get_build_date(&jd)) { jd.year -= 10; pivot += ntpcal_date_to_time(&jd); } else { msyslog(LOG_ERR, "step-systime: assume 1970-01-01 as build date"); } #else UNUSED_LOCAL(jd); #endif /* USE_COMPILETIME_PIVOT */ #else UNUSED_LOCAL(jd); /* This makes sure the resulting time stamp is on or after * 1969-12-31/23:59:59 UTC and gives us additional two years, * from the change of NTP era in 2036 to the UNIX rollover in * 2038. (Minus one second, but that won't hurt.) We *really* * need a longer 'time_t' after that! Or a different baseline, * but that would cause other serious trouble, too. */ pivot = 0x7FFFFFFF; #endif /* get the complete jump distance as l_fp */ DTOLFP(sys_residual, &fp_sys); DTOLFP(step, &fp_ofs); L_ADD(&fp_ofs, &fp_sys); /* ---> time-critical path starts ---> */ /* get the current time as l_fp (without fuzz) and as struct timeval */ get_ostime(&timets); fp_sys = tspec_stamp_to_lfp(timets); tvlast.tv_sec = timets.tv_sec; tvlast.tv_usec = (timets.tv_nsec + 500) / 1000; /* get the target time as l_fp */ L_ADD(&fp_sys, &fp_ofs); /* unfold the new system time */ timetv = lfp_stamp_to_tval(fp_sys, &pivot); /* now set new system time */ if (ntp_set_tod(&timetv, NULL) != 0) { msyslog(LOG_ERR, "step-systime: %m"); return FALSE; } /* <--- time-critical path ended with 'ntp_set_tod()' <--- */ sys_residual = 0; lamport_violated = (step < 0); if (step_callback) (*step_callback)(); #ifdef NEED_HPUX_ADJTIME /* * CHECKME: is this correct when called by ntpdate????? */ _clear_adjtime(); #endif /* * FreeBSD, for example, has: * struct utmp { * char ut_line[UT_LINESIZE]; * char ut_name[UT_NAMESIZE]; * char ut_host[UT_HOSTSIZE]; * long ut_time; * }; * and appends line="|", name="date", host="", time for the OLD * and appends line="{", name="date", host="", time for the NEW * to _PATH_WTMP . * * Some OSes have utmp, some have utmpx. */ /* * Write old and new time entries in utmp and wtmp if step * adjustment is greater than one second. * * This might become even Uglier... */ tvdiff = abs_tval(sub_tval(timetv, tvlast)); if (tvdiff.tv_sec > 0) { #ifdef HAVE_UTMP_H struct utmp ut; #endif #ifdef HAVE_UTMPX_H struct utmpx utx; #endif #ifdef HAVE_UTMP_H ZERO(ut); #endif #ifdef HAVE_UTMPX_H ZERO(utx); #endif /* UTMP */ #ifdef UPDATE_UTMP # ifdef HAVE_PUTUTLINE # ifndef _PATH_UTMP # define _PATH_UTMP UTMP_FILE # endif utmpname(_PATH_UTMP); ut.ut_type = OLD_TIME; strlcpy(ut.ut_line, OTIME_MSG, sizeof(ut.ut_line)); ut.ut_time = tvlast.tv_sec; setutent(); pututline(&ut); ut.ut_type = NEW_TIME; strlcpy(ut.ut_line, NTIME_MSG, sizeof(ut.ut_line)); ut.ut_time = timetv.tv_sec; setutent(); pututline(&ut); endutent(); # else /* not HAVE_PUTUTLINE */ # endif /* not HAVE_PUTUTLINE */ #endif /* UPDATE_UTMP */ /* UTMPX */ #ifdef UPDATE_UTMPX # ifdef HAVE_PUTUTXLINE utx.ut_type = OLD_TIME; strlcpy(utx.ut_line, OTIME_MSG, sizeof(utx.ut_line)); utx.ut_tv = tvlast; setutxent(); pututxline(&utx); utx.ut_type = NEW_TIME; strlcpy(utx.ut_line, NTIME_MSG, sizeof(utx.ut_line)); utx.ut_tv = timetv; setutxent(); pututxline(&utx); endutxent(); # else /* not HAVE_PUTUTXLINE */ # endif /* not HAVE_PUTUTXLINE */ #endif /* UPDATE_UTMPX */ /* WTMP */ #ifdef UPDATE_WTMP # ifdef HAVE_PUTUTLINE # ifndef _PATH_WTMP # define _PATH_WTMP WTMP_FILE # endif utmpname(_PATH_WTMP); ut.ut_type = OLD_TIME; strlcpy(ut.ut_line, OTIME_MSG, sizeof(ut.ut_line)); ut.ut_time = tvlast.tv_sec; setutent(); pututline(&ut); ut.ut_type = NEW_TIME; strlcpy(ut.ut_line, NTIME_MSG, sizeof(ut.ut_line)); ut.ut_time = timetv.tv_sec; setutent(); pututline(&ut); endutent(); # else /* not HAVE_PUTUTLINE */ # endif /* not HAVE_PUTUTLINE */ #endif /* UPDATE_WTMP */ /* WTMPX */ #ifdef UPDATE_WTMPX # ifdef HAVE_PUTUTXLINE utx.ut_type = OLD_TIME; utx.ut_tv = tvlast; strlcpy(utx.ut_line, OTIME_MSG, sizeof(utx.ut_line)); # ifdef HAVE_UPDWTMPX updwtmpx(WTMPX_FILE, &utx); # else /* not HAVE_UPDWTMPX */ # endif /* not HAVE_UPDWTMPX */ # else /* not HAVE_PUTUTXLINE */ # endif /* not HAVE_PUTUTXLINE */ # ifdef HAVE_PUTUTXLINE utx.ut_type = NEW_TIME; utx.ut_tv = timetv; strlcpy(utx.ut_line, NTIME_MSG, sizeof(utx.ut_line)); # ifdef HAVE_UPDWTMPX updwtmpx(WTMPX_FILE, &utx); # else /* not HAVE_UPDWTMPX */ # endif /* not HAVE_UPDWTMPX */ # else /* not HAVE_PUTUTXLINE */ # endif /* not HAVE_PUTUTXLINE */ #endif /* UPDATE_WTMPX */ } return TRUE; }
/* --------------------------------------------------------------------- * Load a leap second file and check expiration on the go */ int/*BOOL*/ leapsec_load( leap_table_t * pt , leapsec_reader func, void * farg, int use_build_limit) { char *cp, *ep, linebuf[50]; vint64 ttime, limit; long taiof; struct calendar build; leapsec_clear(pt); if (use_build_limit && ntpcal_get_build_date(&build)) limit = ntpcal_date_to_ntp64(&build); else memset(&limit, 0, sizeof(limit)); while (get_line(func, farg, linebuf, sizeof(linebuf))) { cp = linebuf; if (*cp == '#') { cp++; if (*cp == '@') { cp = skipws(cp+1); pt->head.expire = strtouv64(cp, &ep, 10); if (parsefail(cp, ep)) goto fail_read; pt->lsig.etime = pt->head.expire.D_s.lo; } else if (*cp == '$') { cp = skipws(cp+1); pt->head.update = strtouv64(cp, &ep, 10); if (parsefail(cp, ep)) goto fail_read; } } else if (isdigit((u_char)*cp)) { ttime = strtouv64(cp, &ep, 10); if (parsefail(cp, ep)) goto fail_read; cp = skipws(ep); taiof = strtol(cp, &ep, 10); if ( parsefail(cp, ep) || taiof > SHRT_MAX || taiof < SHRT_MIN) goto fail_read; if (ucmpv64(&ttime, &limit) >= 0) { if (!leapsec_raw(pt, &ttime, taiof, FALSE)) goto fail_insn; } else { pt->head.base_tai = (int16_t)taiof; } pt->lsig.ttime = ttime.D_s.lo; pt->lsig.taiof = (int16_t)taiof; } } return TRUE; fail_read: errno = EILSEQ; fail_insn: leapsec_clear(pt); return FALSE; }
/* --------------------------------------------------------------------- * Load a leap second file and check expiration on the go */ bool leapsec_load( leap_table_t * pt , leapsec_reader func, void * farg, int use_build_limit) { char *cp, *ep, linebuf[50]; time64_t ttime, limit; long taiof; struct calendar build; leapsec_clear(pt); if (use_build_limit && ntpcal_get_build_date(&build)) limit = ntpcal_date_to_ntp64(&build); else memset(&limit, 0, sizeof(limit)); while (get_line(func, farg, linebuf, sizeof(linebuf))) { cp = linebuf; if (*cp == '#') { cp++; if (*cp == '@') { cp = skipws(cp+1); settime64u(pt->head.expire, strtoull(cp, &ep, 10)); if (parsefail(cp, ep)) goto fail_read; pt->lsig.etime = time64lo(pt->head.expire); } else if (*cp == '$') { cp = skipws(cp+1); settime64u(pt->head.update, strtoull(cp, &ep, 10)); if (parsefail(cp, ep)) goto fail_read; } } else if (isdigit((uint8_t)*cp)) { settime64u(ttime, strtoull(cp, &ep, 10)); if (parsefail(cp, ep)) goto fail_read; cp = skipws(ep); taiof = strtol(cp, &ep, 10); if ( parsefail(cp, ep) || taiof > SHRT_MAX || taiof < SHRT_MIN) goto fail_read; if (ttime >= limit) { if (!leapsec_raw(pt, ttime, taiof, false)) goto fail_insn; } else { pt->head.base_tai = (int16_t)taiof; } pt->lsig.ttime = time64lo(ttime); pt->lsig.taiof = (int16_t)taiof; } } return true; fail_read: errno = EILSEQ; fail_insn: leapsec_clear(pt); return false; }