1*eabc0478Schristos /* $NetBSD: systime.c,v 1.8 2024/08/18 20:47:13 christos Exp $ */ 2abb0f93cSkardel 3abb0f93cSkardel /* 4abb0f93cSkardel * systime -- routines to fiddle a UNIX clock. 5abb0f93cSkardel * 6abb0f93cSkardel * ATTENTION: Get approval from Dave Mills on all changes to this file! 7abb0f93cSkardel * 8abb0f93cSkardel */ 98585484eSchristos #include <config.h> 104eea345dSchristos #include <math.h> 118585484eSchristos 128585484eSchristos #include "ntp.h" 134eea345dSchristos #include "ntpd.h" 14abb0f93cSkardel #include "ntp_syslog.h" 15abb0f93cSkardel #include "ntp_stdlib.h" 16abb0f93cSkardel #include "ntp_random.h" 178585484eSchristos #include "iosignal.h" 188585484eSchristos #include "timevalops.h" 198585484eSchristos #include "timespecops.h" 208585484eSchristos #include "ntp_calendar.h" 21abb0f93cSkardel 22abb0f93cSkardel #ifdef HAVE_SYS_PARAM_H 23abb0f93cSkardel # include <sys/param.h> 24abb0f93cSkardel #endif 25abb0f93cSkardel #ifdef HAVE_UTMP_H 26abb0f93cSkardel # include <utmp.h> 27abb0f93cSkardel #endif /* HAVE_UTMP_H */ 28abb0f93cSkardel #ifdef HAVE_UTMPX_H 29abb0f93cSkardel # include <utmpx.h> 30abb0f93cSkardel #endif /* HAVE_UTMPX_H */ 31abb0f93cSkardel 328b8da087Schristos int allow_panic = FALSE; /* allow panic correction (-g) */ 338b8da087Schristos int enable_panic_check = TRUE; /* Can we check allow_panic's state? */ 34abb0f93cSkardel 354eea345dSchristos u_long sys_lamport; /* Lamport violation */ 364eea345dSchristos u_long sys_tsrounding; /* timestamp rounding errors */ 374eea345dSchristos 388585484eSchristos #ifndef USE_COMPILETIME_PIVOT 398585484eSchristos # define USE_COMPILETIME_PIVOT 1 408585484eSchristos #endif 41abb0f93cSkardel 42abb0f93cSkardel /* 43abb0f93cSkardel * These routines (get_systime, step_systime, adj_systime) implement an 44abb0f93cSkardel * interface between the system independent NTP clock and the Unix 45abb0f93cSkardel * system clock in various architectures and operating systems. Time is 46abb0f93cSkardel * a precious quantity in these routines and every effort is made to 47abb0f93cSkardel * minimize errors by unbiased rounding and amortizing adjustment 48abb0f93cSkardel * residues. 49abb0f93cSkardel * 50abb0f93cSkardel * In order to improve the apparent resolution, provide unbiased 518585484eSchristos * rounding and most importantly ensure that the readings cannot be 528585484eSchristos * predicted, the low-order unused portion of the time below the minimum 538585484eSchristos * time to read the clock is filled with an unbiased random fuzz. 54abb0f93cSkardel * 558585484eSchristos * The sys_tick variable specifies the system clock tick interval in 568585484eSchristos * seconds, for stepping clocks, defined as those which return times 578585484eSchristos * less than MINSTEP greater than the previous reading. For systems that 588585484eSchristos * use a high-resolution counter such that each clock reading is always 598585484eSchristos * at least MINSTEP greater than the prior, sys_tick is the time to read 608585484eSchristos * the system clock. 618585484eSchristos * 628585484eSchristos * The sys_fuzz variable measures the minimum time to read the system 638585484eSchristos * clock, regardless of its precision. When reading the system clock 648585484eSchristos * using get_systime() after sys_tick and sys_fuzz have been determined, 658585484eSchristos * ntpd ensures each unprocessed clock reading is no less than sys_fuzz 668585484eSchristos * later than the prior unprocessed reading, and then fuzzes the bits 678585484eSchristos * below sys_fuzz in the timestamp returned, ensuring each of its 688585484eSchristos * resulting readings is strictly later than the previous. 698585484eSchristos * 708585484eSchristos * When slewing the system clock using adj_systime() (with the kernel 718585484eSchristos * loop discipline unavailable or disabled), adjtime() offsets are 728585484eSchristos * quantized to sys_tick, if sys_tick is greater than sys_fuzz, which 738585484eSchristos * is to say if the OS presents a stepping clock. Otherwise, offsets 748585484eSchristos * are quantized to the microsecond resolution of adjtime()'s timeval 758585484eSchristos * input. The remaining correction sys_residual is carried into the 768585484eSchristos * next adjtime() and meanwhile is also factored into get_systime() 778585484eSchristos * readings. 78abb0f93cSkardel */ 798585484eSchristos double sys_tick = 0; /* tick size or time to read (s) */ 808585484eSchristos double sys_fuzz = 0; /* min. time to read the clock (s) */ 818585484eSchristos long sys_fuzz_nsec = 0; /* min. time to read the clock (ns) */ 828585484eSchristos double measured_tick; /* non-overridable sys_tick (s) */ 83abb0f93cSkardel double sys_residual = 0; /* adjustment residue (s) */ 848585484eSchristos int trunc_os_clock; /* sys_tick > measured_tick */ 858585484eSchristos time_stepped_callback step_callback; 86abb0f93cSkardel 87abb0f93cSkardel #ifndef SIM 888585484eSchristos /* perlinger@ntp.org: As 'get_sysime()' does it's own check for clock 898585484eSchristos * backstepping, this could probably become a local variable in 908585484eSchristos * 'get_systime()' and the cruft associated with communicating via a 918585484eSchristos * static value could be removed after the v4.2.8 release. 928585484eSchristos */ 938585484eSchristos static int lamport_violated; /* clock was stepped back */ 948585484eSchristos #endif /* !SIM */ 958585484eSchristos 968585484eSchristos #ifdef DEBUG 978585484eSchristos static int systime_init_done; 988585484eSchristos # define DONE_SYSTIME_INIT() systime_init_done = TRUE 998585484eSchristos #else 1008585484eSchristos # define DONE_SYSTIME_INIT() do {} while (FALSE) 1018585484eSchristos #endif 1028585484eSchristos 1038585484eSchristos #ifdef HAVE_SIGNALED_IO 1048585484eSchristos int using_sigio; 1058585484eSchristos #endif 1068585484eSchristos 1078585484eSchristos #ifdef SYS_WINNT 1088585484eSchristos CRITICAL_SECTION get_systime_cs; 1098585484eSchristos #endif 1108585484eSchristos 1118585484eSchristos 1128585484eSchristos void 1138585484eSchristos set_sys_fuzz( 1148585484eSchristos double fuzz_val 1158585484eSchristos ) 1168585484eSchristos { 1178585484eSchristos sys_fuzz = fuzz_val; 1188585484eSchristos INSIST(sys_fuzz >= 0); 1198585484eSchristos INSIST(sys_fuzz <= 1.0); 1204eea345dSchristos /* [Bug 3450] ensure nsec fuzz >= sys_fuzz to reduce chance of 1214eea345dSchristos * short-falling fuzz advance 1224eea345dSchristos */ 1234eea345dSchristos sys_fuzz_nsec = (long)ceil(sys_fuzz * 1e9); 1248585484eSchristos } 1258585484eSchristos 1268585484eSchristos 1278585484eSchristos void 1288585484eSchristos init_systime(void) 1298585484eSchristos { 1308585484eSchristos INIT_GET_SYSTIME_CRITSEC(); 1318585484eSchristos INIT_WIN_PRECISE_TIME(); 1328585484eSchristos DONE_SYSTIME_INIT(); 1338585484eSchristos } 1348585484eSchristos 1358585484eSchristos 1368585484eSchristos #ifndef SIM /* ntpsim.c has get_systime() and friends for sim */ 1378585484eSchristos 1388585484eSchristos static inline void 1398585484eSchristos get_ostime( 1408585484eSchristos struct timespec * tsp 1418585484eSchristos ) 1428585484eSchristos { 1438585484eSchristos int rc; 1448585484eSchristos long ticks; 1458585484eSchristos 1468585484eSchristos #if defined(HAVE_CLOCK_GETTIME) 1478585484eSchristos rc = clock_gettime(CLOCK_REALTIME, tsp); 1488585484eSchristos #elif defined(HAVE_GETCLOCK) 1498585484eSchristos rc = getclock(TIMEOFDAY, tsp); 1508585484eSchristos #else 1518585484eSchristos struct timeval tv; 1528585484eSchristos 1538585484eSchristos rc = GETTIMEOFDAY(&tv, NULL); 1548585484eSchristos tsp->tv_sec = tv.tv_sec; 1558585484eSchristos tsp->tv_nsec = tv.tv_usec * 1000; 1568585484eSchristos #endif 1578585484eSchristos if (rc < 0) { 1588585484eSchristos msyslog(LOG_ERR, "read system clock failed: %m (%d)", 1598585484eSchristos errno); 1608585484eSchristos exit(1); 1618585484eSchristos } 1628585484eSchristos 1638585484eSchristos if (trunc_os_clock) { 1648585484eSchristos ticks = (long)((tsp->tv_nsec * 1e-9) / sys_tick); 1658585484eSchristos tsp->tv_nsec = (long)(ticks * 1e9 * sys_tick); 1668585484eSchristos } 1678585484eSchristos } 1688585484eSchristos 169abb0f93cSkardel 170abb0f93cSkardel /* 171abb0f93cSkardel * get_systime - return system time in NTP timestamp format. 172abb0f93cSkardel */ 173abb0f93cSkardel void 174abb0f93cSkardel get_systime( 175abb0f93cSkardel l_fp *now /* system time */ 176abb0f93cSkardel ) 177abb0f93cSkardel { 1788585484eSchristos static struct timespec ts_last; /* last sampled os time */ 1798585484eSchristos static struct timespec ts_prev; /* prior os time */ 1808585484eSchristos static l_fp lfp_prev; /* prior result */ 181abb0f93cSkardel struct timespec ts; /* seconds and nanoseconds */ 1828585484eSchristos struct timespec ts_min; /* earliest permissible */ 1838585484eSchristos struct timespec ts_lam; /* lamport fictional increment */ 1848585484eSchristos double dfuzz; 1858585484eSchristos l_fp result; 1868585484eSchristos l_fp lfpfuzz; 1878585484eSchristos l_fp lfpdelta; 1888585484eSchristos 1898585484eSchristos get_ostime(&ts); 1908585484eSchristos DEBUG_REQUIRE(systime_init_done); 1918585484eSchristos ENTER_GET_SYSTIME_CRITSEC(); 1928585484eSchristos 1938585484eSchristos /* First check if here was a Lamport violation, that is, two 1948585484eSchristos * successive calls to 'get_ostime()' resulted in negative 1958585484eSchristos * time difference. Use a few milliseconds of permissible 1968585484eSchristos * tolerance -- being too sharp can hurt here. (This is intented 1978585484eSchristos * for the Win32 target, where the HPC interpolation might 1988585484eSchristos * introduce small steps backward. It should not be an issue on 1998585484eSchristos * systems where get_ostime() results in a true syscall.) 2008585484eSchristos */ 2014eea345dSchristos if (cmp_tspec(add_tspec_ns(ts, 50000000), ts_last) < 0) { 2028585484eSchristos lamport_violated = 1; 2034eea345dSchristos sys_lamport++; 2044eea345dSchristos } 2058585484eSchristos ts_last = ts; 206abb0f93cSkardel 207abb0f93cSkardel /* 2088585484eSchristos * After default_get_precision() has set a nonzero sys_fuzz, 2098585484eSchristos * ensure every reading of the OS clock advances by at least 2108585484eSchristos * sys_fuzz over the prior reading, thereby assuring each 2118585484eSchristos * fuzzed result is strictly later than the prior. Limit the 2128585484eSchristos * necessary fiction to 1 second. 213abb0f93cSkardel */ 2148585484eSchristos if (!USING_SIGIO()) { 2158585484eSchristos ts_min = add_tspec_ns(ts_prev, sys_fuzz_nsec); 2168585484eSchristos if (cmp_tspec(ts, ts_min) < 0) { 2178585484eSchristos ts_lam = sub_tspec(ts_min, ts); 2188585484eSchristos if (ts_lam.tv_sec > 0 && !lamport_violated) { 2198585484eSchristos msyslog(LOG_ERR, 2208585484eSchristos "get_systime Lamport advance exceeds one second (%.9f)", 2218585484eSchristos ts_lam.tv_sec + 2228585484eSchristos 1e-9 * ts_lam.tv_nsec); 2238585484eSchristos exit(1); 224abb0f93cSkardel } 2258585484eSchristos if (!lamport_violated) 2268585484eSchristos ts = ts_min; 2278585484eSchristos } 2288585484eSchristos ts_prev = ts; 2298585484eSchristos } 230abb0f93cSkardel 2318585484eSchristos /* convert from timespec to l_fp fixed-point */ 2328585484eSchristos result = tspec_stamp_to_lfp(ts); 233abb0f93cSkardel 234abb0f93cSkardel /* 2354eea345dSchristos * Add in the fuzz. 'ntp_random()' returns [0..2**31-1] so we 2364eea345dSchristos * must scale up the result by 2.0 to cover the full fractional 2374eea345dSchristos * range. 238abb0f93cSkardel */ 239*eabc0478Schristos dfuzz = ntp_uurandom() * sys_fuzz; 2408585484eSchristos DTOLFP(dfuzz, &lfpfuzz); 2418585484eSchristos L_ADD(&result, &lfpfuzz); 242abb0f93cSkardel 2438585484eSchristos /* 2448585484eSchristos * Ensure result is strictly greater than prior result (ignoring 2458585484eSchristos * sys_residual's effect for now) once sys_fuzz has been 2468585484eSchristos * determined. 2474eea345dSchristos * 2484eea345dSchristos * [Bug 3450] Rounding errors and time slew can lead to a 2494eea345dSchristos * violation of the expected postcondition. This is bound to 2504eea345dSchristos * happen from time to time (depending on state of the random 2514eea345dSchristos * generator, the current slew and the closeness of system time 2524eea345dSchristos * stamps drawn) and does not warrant a syslog entry. Instead it 2534eea345dSchristos * makes much more sense to ensure the postcondition and hop 2544eea345dSchristos * along silently. 2558585484eSchristos */ 2568585484eSchristos if (!USING_SIGIO()) { 2574eea345dSchristos if ( !L_ISZERO(&lfp_prev) 2584eea345dSchristos && !lamport_violated 2594eea345dSchristos && (sys_fuzz > 0.0) 2604eea345dSchristos ) { 2614eea345dSchristos lfpdelta = result; 2624eea345dSchristos L_SUB(&lfpdelta, &lfp_prev); 2634eea345dSchristos L_SUBUF(&lfpdelta, 1); 2644eea345dSchristos if (lfpdelta.l_i < 0) 2654eea345dSchristos { 2664eea345dSchristos L_NEG(&lfpdelta); 2674eea345dSchristos DPRINTF(1, ("get_systime: postcond failed by %s secs, fixed\n", 2684eea345dSchristos lfptoa(&lfpdelta, 9))); 2694eea345dSchristos result = lfp_prev; 2704eea345dSchristos L_ADDUF(&result, 1); 2714eea345dSchristos sys_tsrounding++; 2728585484eSchristos } 2738585484eSchristos } 2748585484eSchristos lfp_prev = result; 2758585484eSchristos if (lamport_violated) 2768585484eSchristos lamport_violated = FALSE; 2778585484eSchristos } 2788585484eSchristos LEAVE_GET_SYSTIME_CRITSEC(); 2798585484eSchristos *now = result; 280abb0f93cSkardel } 281abb0f93cSkardel 282abb0f93cSkardel 283abb0f93cSkardel /* 284abb0f93cSkardel * adj_systime - adjust system time by the argument. 285abb0f93cSkardel */ 286abb0f93cSkardel #if !defined SYS_WINNT 287abb0f93cSkardel int /* 0 okay, 1 error */ 288abb0f93cSkardel adj_systime( 289abb0f93cSkardel double now /* adjustment (s) */ 290abb0f93cSkardel ) 291abb0f93cSkardel { 292abb0f93cSkardel struct timeval adjtv; /* new adjustment */ 293abb0f93cSkardel struct timeval oadjtv; /* residual adjustment */ 2948585484eSchristos double quant; /* quantize to multiples of */ 295abb0f93cSkardel double dtemp; 296abb0f93cSkardel long ticks; 297abb0f93cSkardel int isneg = 0; 298abb0f93cSkardel 299abb0f93cSkardel /* 3008585484eSchristos * The Windows port adj_systime() depends on being called each 3018585484eSchristos * second even when there's no additional correction, to allow 3028585484eSchristos * emulation of adjtime() behavior on top of an API that simply 3038585484eSchristos * sets the current rate. This POSIX implementation needs to 3048585484eSchristos * ignore invocations with zero correction, otherwise ongoing 3058585484eSchristos * EVNT_NSET adjtime() can be aborted by a tiny adjtime() 3068585484eSchristos * triggered by sys_residual. 3078585484eSchristos */ 3088b8da087Schristos if (0. == now) { 3098b8da087Schristos if (enable_panic_check && allow_panic) { 3108b8da087Schristos msyslog(LOG_ERR, "adj_systime: allow_panic is TRUE!"); 3118b8da087Schristos INSIST(!allow_panic); 3128b8da087Schristos } 3138585484eSchristos return TRUE; 3148b8da087Schristos } 3158585484eSchristos 3168585484eSchristos /* 317abb0f93cSkardel * Most Unix adjtime() implementations adjust the system clock 318abb0f93cSkardel * in microsecond quanta, but some adjust in 10-ms quanta. We 319abb0f93cSkardel * carefully round the adjustment to the nearest quantum, then 320abb0f93cSkardel * adjust in quanta and keep the residue for later. 321abb0f93cSkardel */ 322abb0f93cSkardel dtemp = now + sys_residual; 323abb0f93cSkardel if (dtemp < 0) { 324abb0f93cSkardel isneg = 1; 325abb0f93cSkardel dtemp = -dtemp; 326abb0f93cSkardel } 327abb0f93cSkardel adjtv.tv_sec = (long)dtemp; 328abb0f93cSkardel dtemp -= adjtv.tv_sec; 3298585484eSchristos if (sys_tick > sys_fuzz) 3308585484eSchristos quant = sys_tick; 3318585484eSchristos else 3328585484eSchristos quant = 1e-6; 3338585484eSchristos ticks = (long)(dtemp / quant + .5); 33468dbbb44Schristos adjtv.tv_usec = (long)(ticks * quant * 1.e6 + .5); 33568dbbb44Schristos /* The rounding in the conversions could us push over the 33668dbbb44Schristos * limits: make sure the result is properly normalised! 33768dbbb44Schristos * note: sign comes later, all numbers non-negative here. 33868dbbb44Schristos */ 33968dbbb44Schristos if (adjtv.tv_usec >= 1000000) { 34068dbbb44Schristos adjtv.tv_sec += 1; 34168dbbb44Schristos adjtv.tv_usec -= 1000000; 34268dbbb44Schristos dtemp -= 1.; 34368dbbb44Schristos } 34468dbbb44Schristos /* set the new residual with leftover from correction */ 34568dbbb44Schristos sys_residual = dtemp - adjtv.tv_usec * 1.e-6; 346abb0f93cSkardel 347abb0f93cSkardel /* 348abb0f93cSkardel * Convert to signed seconds and microseconds for the Unix 349abb0f93cSkardel * adjtime() system call. Note we purposely lose the adjtime() 350abb0f93cSkardel * leftover. 351abb0f93cSkardel */ 352abb0f93cSkardel if (isneg) { 353abb0f93cSkardel adjtv.tv_sec = -adjtv.tv_sec; 354abb0f93cSkardel adjtv.tv_usec = -adjtv.tv_usec; 355abb0f93cSkardel sys_residual = -sys_residual; 356abb0f93cSkardel } 357abb0f93cSkardel if (adjtv.tv_sec != 0 || adjtv.tv_usec != 0) { 358abb0f93cSkardel if (adjtime(&adjtv, &oadjtv) < 0) { 359abb0f93cSkardel msyslog(LOG_ERR, "adj_systime: %m"); 3608b8da087Schristos if (enable_panic_check && allow_panic) { 3618b8da087Schristos msyslog(LOG_ERR, "adj_systime: allow_panic is TRUE!"); 3628b8da087Schristos } 3638585484eSchristos return FALSE; 364abb0f93cSkardel } 365abb0f93cSkardel } 3668b8da087Schristos if (enable_panic_check && allow_panic) { 3678b8da087Schristos msyslog(LOG_ERR, "adj_systime: allow_panic is TRUE!"); 3688b8da087Schristos } 3698585484eSchristos return TRUE; 370abb0f93cSkardel } 371abb0f93cSkardel #endif 372abb0f93cSkardel 373abb0f93cSkardel /* 3744eea345dSchristos * helper to keep utmp/wtmp up to date 375abb0f93cSkardel */ 3764eea345dSchristos static void 3774eea345dSchristos update_uwtmp( 3784eea345dSchristos struct timeval timetv, 3794eea345dSchristos struct timeval tvlast 380abb0f93cSkardel ) 381abb0f93cSkardel { 3824eea345dSchristos struct timeval tvdiff; 383abb0f93cSkardel /* 384abb0f93cSkardel * FreeBSD, for example, has: 385abb0f93cSkardel * struct utmp { 386abb0f93cSkardel * char ut_line[UT_LINESIZE]; 387abb0f93cSkardel * char ut_name[UT_NAMESIZE]; 388abb0f93cSkardel * char ut_host[UT_HOSTSIZE]; 389abb0f93cSkardel * long ut_time; 390abb0f93cSkardel * }; 391abb0f93cSkardel * and appends line="|", name="date", host="", time for the OLD 3928b8da087Schristos * and appends line="{", name="date", host="", time for the NEW // } 393abb0f93cSkardel * to _PATH_WTMP . 394abb0f93cSkardel * 395abb0f93cSkardel * Some OSes have utmp, some have utmpx. 396abb0f93cSkardel */ 397abb0f93cSkardel 398abb0f93cSkardel /* 399abb0f93cSkardel * Write old and new time entries in utmp and wtmp if step 400abb0f93cSkardel * adjustment is greater than one second. 401abb0f93cSkardel * 402abb0f93cSkardel * This might become even Uglier... 403abb0f93cSkardel */ 4048585484eSchristos tvdiff = abs_tval(sub_tval(timetv, tvlast)); 4058585484eSchristos if (tvdiff.tv_sec > 0) { 406abb0f93cSkardel #ifdef HAVE_UTMP_H 407abb0f93cSkardel struct utmp ut; 408abb0f93cSkardel #endif 409abb0f93cSkardel #ifdef HAVE_UTMPX_H 410abb0f93cSkardel struct utmpx utx; 411abb0f93cSkardel #endif 412abb0f93cSkardel 413abb0f93cSkardel #ifdef HAVE_UTMP_H 4148585484eSchristos ZERO(ut); 415abb0f93cSkardel #endif 416abb0f93cSkardel #ifdef HAVE_UTMPX_H 4178585484eSchristos ZERO(utx); 418abb0f93cSkardel #endif 419abb0f93cSkardel 420abb0f93cSkardel /* UTMP */ 421abb0f93cSkardel 422abb0f93cSkardel #ifdef UPDATE_UTMP 423abb0f93cSkardel # ifdef HAVE_PUTUTLINE 4248585484eSchristos # ifndef _PATH_UTMP 4258585484eSchristos # define _PATH_UTMP UTMP_FILE 4268585484eSchristos # endif 4278585484eSchristos utmpname(_PATH_UTMP); 428abb0f93cSkardel ut.ut_type = OLD_TIME; 4298585484eSchristos strlcpy(ut.ut_line, OTIME_MSG, sizeof(ut.ut_line)); 4308585484eSchristos ut.ut_time = tvlast.tv_sec; 431abb0f93cSkardel setutent(); 4328585484eSchristos pututline(&ut); 433abb0f93cSkardel ut.ut_type = NEW_TIME; 4348585484eSchristos strlcpy(ut.ut_line, NTIME_MSG, sizeof(ut.ut_line)); 435abb0f93cSkardel ut.ut_time = timetv.tv_sec; 4368585484eSchristos setutent(); 437abb0f93cSkardel pututline(&ut); 438abb0f93cSkardel endutent(); 439abb0f93cSkardel # else /* not HAVE_PUTUTLINE */ 440abb0f93cSkardel # endif /* not HAVE_PUTUTLINE */ 441abb0f93cSkardel #endif /* UPDATE_UTMP */ 442abb0f93cSkardel 443abb0f93cSkardel /* UTMPX */ 444abb0f93cSkardel 445abb0f93cSkardel #ifdef UPDATE_UTMPX 446abb0f93cSkardel # ifdef HAVE_PUTUTXLINE 447abb0f93cSkardel utx.ut_type = OLD_TIME; 4488585484eSchristos strlcpy(utx.ut_line, OTIME_MSG, sizeof(utx.ut_line)); 4498585484eSchristos utx.ut_tv = tvlast; 450abb0f93cSkardel setutxent(); 4518585484eSchristos pututxline(&utx); 452abb0f93cSkardel utx.ut_type = NEW_TIME; 4538585484eSchristos strlcpy(utx.ut_line, NTIME_MSG, sizeof(utx.ut_line)); 454abb0f93cSkardel utx.ut_tv = timetv; 4558585484eSchristos setutxent(); 456abb0f93cSkardel pututxline(&utx); 457abb0f93cSkardel endutxent(); 458abb0f93cSkardel # else /* not HAVE_PUTUTXLINE */ 459abb0f93cSkardel # endif /* not HAVE_PUTUTXLINE */ 460abb0f93cSkardel #endif /* UPDATE_UTMPX */ 461abb0f93cSkardel 462abb0f93cSkardel /* WTMP */ 463abb0f93cSkardel 464abb0f93cSkardel #ifdef UPDATE_WTMP 465abb0f93cSkardel # ifdef HAVE_PUTUTLINE 4668585484eSchristos # ifndef _PATH_WTMP 4678585484eSchristos # define _PATH_WTMP WTMP_FILE 4688585484eSchristos # endif 4698585484eSchristos utmpname(_PATH_WTMP); 470abb0f93cSkardel ut.ut_type = OLD_TIME; 4718585484eSchristos strlcpy(ut.ut_line, OTIME_MSG, sizeof(ut.ut_line)); 4728585484eSchristos ut.ut_time = tvlast.tv_sec; 4738585484eSchristos setutent(); 474abb0f93cSkardel pututline(&ut); 475abb0f93cSkardel ut.ut_type = NEW_TIME; 4768585484eSchristos strlcpy(ut.ut_line, NTIME_MSG, sizeof(ut.ut_line)); 477abb0f93cSkardel ut.ut_time = timetv.tv_sec; 4788585484eSchristos setutent(); 479abb0f93cSkardel pututline(&ut); 480abb0f93cSkardel endutent(); 481abb0f93cSkardel # else /* not HAVE_PUTUTLINE */ 482abb0f93cSkardel # endif /* not HAVE_PUTUTLINE */ 483abb0f93cSkardel #endif /* UPDATE_WTMP */ 484abb0f93cSkardel 485abb0f93cSkardel /* WTMPX */ 486abb0f93cSkardel 487abb0f93cSkardel #ifdef UPDATE_WTMPX 488abb0f93cSkardel # ifdef HAVE_PUTUTXLINE 489abb0f93cSkardel utx.ut_type = OLD_TIME; 4908585484eSchristos utx.ut_tv = tvlast; 4918585484eSchristos strlcpy(utx.ut_line, OTIME_MSG, sizeof(utx.ut_line)); 492abb0f93cSkardel # ifdef HAVE_UPDWTMPX 493abb0f93cSkardel updwtmpx(WTMPX_FILE, &utx); 494abb0f93cSkardel # else /* not HAVE_UPDWTMPX */ 495abb0f93cSkardel # endif /* not HAVE_UPDWTMPX */ 496abb0f93cSkardel # else /* not HAVE_PUTUTXLINE */ 497abb0f93cSkardel # endif /* not HAVE_PUTUTXLINE */ 498abb0f93cSkardel # ifdef HAVE_PUTUTXLINE 499abb0f93cSkardel utx.ut_type = NEW_TIME; 500abb0f93cSkardel utx.ut_tv = timetv; 5018585484eSchristos strlcpy(utx.ut_line, NTIME_MSG, sizeof(utx.ut_line)); 502abb0f93cSkardel # ifdef HAVE_UPDWTMPX 503abb0f93cSkardel updwtmpx(WTMPX_FILE, &utx); 504abb0f93cSkardel # else /* not HAVE_UPDWTMPX */ 505abb0f93cSkardel # endif /* not HAVE_UPDWTMPX */ 506abb0f93cSkardel # else /* not HAVE_PUTUTXLINE */ 507abb0f93cSkardel # endif /* not HAVE_PUTUTXLINE */ 508abb0f93cSkardel #endif /* UPDATE_WTMPX */ 509abb0f93cSkardel 510abb0f93cSkardel } 5114eea345dSchristos } 5124eea345dSchristos 5134eea345dSchristos /* 5144eea345dSchristos * step_systime - step the system clock. 5154eea345dSchristos */ 5164eea345dSchristos 5174eea345dSchristos int 5184eea345dSchristos step_systime( 5194eea345dSchristos double step 5204eea345dSchristos ) 5214eea345dSchristos { 5224eea345dSchristos time_t pivot; /* for ntp era unfolding */ 5234eea345dSchristos struct timeval timetv, tvlast; 5244eea345dSchristos struct timespec timets; 5254eea345dSchristos l_fp fp_ofs, fp_sys; /* offset and target system time in FP */ 5264eea345dSchristos 5274eea345dSchristos /* 5284eea345dSchristos * Get pivot time for NTP era unfolding. Since we don't step 5294eea345dSchristos * very often, we can afford to do the whole calculation from 5304eea345dSchristos * scratch. And we're not in the time-critical path yet. 5314eea345dSchristos */ 5324eea345dSchristos #if SIZEOF_TIME_T > 4 5334eea345dSchristos pivot = basedate_get_eracenter(); 5344eea345dSchristos #else 5354eea345dSchristos /* This makes sure the resulting time stamp is on or after 5364eea345dSchristos * 1969-12-31/23:59:59 UTC and gives us additional two years, 5374eea345dSchristos * from the change of NTP era in 2036 to the UNIX rollover in 5384eea345dSchristos * 2038. (Minus one second, but that won't hurt.) We *really* 5394eea345dSchristos * need a longer 'time_t' after that! Or a different baseline, 5404eea345dSchristos * but that would cause other serious trouble, too. 5414eea345dSchristos */ 5424eea345dSchristos pivot = 0x7FFFFFFF; 5434eea345dSchristos #endif 5444eea345dSchristos 5454eea345dSchristos /* get the complete jump distance as l_fp */ 5464eea345dSchristos DTOLFP(sys_residual, &fp_sys); 5474eea345dSchristos DTOLFP(step, &fp_ofs); 5484eea345dSchristos L_ADD(&fp_ofs, &fp_sys); 5494eea345dSchristos 5504eea345dSchristos /* ---> time-critical path starts ---> */ 5514eea345dSchristos 5524eea345dSchristos /* get the current time as l_fp (without fuzz) and as struct timeval */ 5534eea345dSchristos get_ostime(&timets); 5544eea345dSchristos fp_sys = tspec_stamp_to_lfp(timets); 5554eea345dSchristos tvlast.tv_sec = timets.tv_sec; 5564eea345dSchristos tvlast.tv_usec = (timets.tv_nsec + 500) / 1000; 5574eea345dSchristos 5584eea345dSchristos /* get the target time as l_fp */ 5594eea345dSchristos L_ADD(&fp_sys, &fp_ofs); 5604eea345dSchristos 5614eea345dSchristos /* unfold the new system time */ 5624eea345dSchristos timetv = lfp_stamp_to_tval(fp_sys, &pivot); 5634eea345dSchristos 5644eea345dSchristos /* now set new system time */ 5654eea345dSchristos if (ntp_set_tod(&timetv, NULL) != 0) { 5664eea345dSchristos msyslog(LOG_ERR, "step-systime: %m"); 5674eea345dSchristos if (enable_panic_check && allow_panic) { 5684eea345dSchristos msyslog(LOG_ERR, "step_systime: allow_panic is TRUE!"); 5694eea345dSchristos } 5704eea345dSchristos return FALSE; 5714eea345dSchristos } 5724eea345dSchristos 5734eea345dSchristos /* <--- time-critical path ended with 'ntp_set_tod()' <--- */ 5744eea345dSchristos 5754eea345dSchristos sys_residual = 0; 5764eea345dSchristos lamport_violated = (step < 0); 5774eea345dSchristos if (step_callback) 5784eea345dSchristos (*step_callback)(); 5794eea345dSchristos 5804eea345dSchristos #ifdef NEED_HPUX_ADJTIME 5814eea345dSchristos /* 5824eea345dSchristos * CHECKME: is this correct when called by ntpdate????? 5834eea345dSchristos */ 5844eea345dSchristos _clear_adjtime(); 5854eea345dSchristos #endif 5864eea345dSchristos 5874eea345dSchristos update_uwtmp(timetv, tvlast); 5888b8da087Schristos if (enable_panic_check && allow_panic) { 5898b8da087Schristos msyslog(LOG_ERR, "step_systime: allow_panic is TRUE!"); 5908b8da087Schristos INSIST(!allow_panic); 5918b8da087Schristos } 5928585484eSchristos return TRUE; 593abb0f93cSkardel } 594abb0f93cSkardel 595*eabc0478Schristos 596*eabc0478Schristos #if SIZEOF_TIME_T > 4 5974eea345dSchristos static const char * 5984eea345dSchristos tv_fmt_libbuf( 5994eea345dSchristos const struct timeval * ptv 6004eea345dSchristos ) 6014eea345dSchristos { 6024eea345dSchristos char * retv; 6034eea345dSchristos vint64 secs; 6044eea345dSchristos ntpcal_split dds; 6054eea345dSchristos struct calendar jd; 6064eea345dSchristos 6074eea345dSchristos secs = time_to_vint64(&ptv->tv_sec); 6084eea345dSchristos dds = ntpcal_daysplit(&secs); 6094eea345dSchristos ntpcal_daysplit_to_date(&jd, &dds, DAY_UNIX_STARTS); 6104eea345dSchristos LIB_GETBUF(retv); 6114eea345dSchristos snprintf(retv, LIB_BUFLENGTH, 6124eea345dSchristos "%04hu-%02hu-%02hu/%02hu:%02hu:%02hu.%06u", 6134eea345dSchristos jd.year, (u_short)jd.month, (u_short)jd.monthday, 6144eea345dSchristos (u_short)jd.hour, (u_short)jd.minute, (u_short)jd.second, 6154eea345dSchristos (u_int)ptv->tv_usec); 6164eea345dSchristos return retv; 6174eea345dSchristos } 618*eabc0478Schristos #endif /* SIZEOF_TIME_T > 4 */ 6194eea345dSchristos 6204eea345dSchristos 6214eea345dSchristos int /*BOOL*/ 6224eea345dSchristos clamp_systime(void) 6234eea345dSchristos { 6244eea345dSchristos #if SIZEOF_TIME_T > 4 6254eea345dSchristos 626cdfa2a7eSchristos struct timeval tvbase, tvlast; 6274eea345dSchristos struct timespec timets; 6284eea345dSchristos 629cdfa2a7eSchristos tvbase.tv_sec = basedate_get_erabase(); 630cdfa2a7eSchristos tvbase.tv_usec = 0; 6314eea345dSchristos 6324eea345dSchristos /* ---> time-critical path starts ---> */ 6334eea345dSchristos 6344eea345dSchristos /* get the current time as l_fp (without fuzz) and as struct timeval */ 6354eea345dSchristos get_ostime(&timets); 6364eea345dSchristos tvlast.tv_sec = timets.tv_sec; 6374eea345dSchristos tvlast.tv_usec = (timets.tv_nsec + 500) / 1000; 6384eea345dSchristos if (tvlast.tv_usec >= 1000000) { 6394eea345dSchristos tvlast.tv_usec -= 1000000; 6404eea345dSchristos tvlast.tv_sec += 1; 6414eea345dSchristos } 6424eea345dSchristos 643cdfa2a7eSchristos if (tvbase.tv_sec > tvlast.tv_sec) { 6444eea345dSchristos /* now set new system time */ 645cdfa2a7eSchristos if (ntp_set_tod(&tvbase, NULL) != 0) { 6464eea345dSchristos msyslog(LOG_ERR, "clamp-systime: %m"); 6474eea345dSchristos return FALSE; 6484eea345dSchristos } 6494eea345dSchristos } else { 6504eea345dSchristos msyslog(LOG_INFO, 6514eea345dSchristos "clamp-systime: clock (%s) in allowed range", 652cdfa2a7eSchristos tv_fmt_libbuf(&tvlast)); 6534eea345dSchristos return FALSE; 6544eea345dSchristos } 6554eea345dSchristos 6564eea345dSchristos /* <--- time-critical path ended with 'ntp_set_tod()' <--- */ 6574eea345dSchristos 6584eea345dSchristos sys_residual = 0; 659cdfa2a7eSchristos lamport_violated = (tvbase.tv_sec < tvlast.tv_sec); 6604eea345dSchristos if (step_callback) 6614eea345dSchristos (*step_callback)(); 6624eea345dSchristos 6634eea345dSchristos # ifdef NEED_HPUX_ADJTIME 6644eea345dSchristos /* 6654eea345dSchristos * CHECKME: is this correct when called by ntpdate????? 6664eea345dSchristos */ 6674eea345dSchristos _clear_adjtime(); 6684eea345dSchristos # endif 6694eea345dSchristos 670cdfa2a7eSchristos update_uwtmp(tvbase, tvlast); 6714eea345dSchristos msyslog(LOG_WARNING, 6724eea345dSchristos "clamp-systime: clock stepped from %s to %s!", 673cdfa2a7eSchristos tv_fmt_libbuf(&tvlast), tv_fmt_libbuf(&tvbase)); 6744eea345dSchristos return TRUE; 6754eea345dSchristos 6764eea345dSchristos #else 6774eea345dSchristos 678cdfa2a7eSchristos return FALSE; 679cdfa2a7eSchristos 6804eea345dSchristos #endif 6814eea345dSchristos } 6824eea345dSchristos 6838585484eSchristos #endif /* !SIM */ 684