1 /* $NetBSD: systime.c,v 1.6 2018/04/07 00:19:52 christos Exp $ */ 2 3 /* 4 * systime -- routines to fiddle a UNIX clock. 5 * 6 * ATTENTION: Get approval from Dave Mills on all changes to this file! 7 * 8 */ 9 #include <config.h> 10 #include <math.h> 11 12 #include "ntp.h" 13 #include "ntpd.h" 14 #include "ntp_syslog.h" 15 #include "ntp_stdlib.h" 16 #include "ntp_random.h" 17 #include "iosignal.h" 18 #include "timevalops.h" 19 #include "timespecops.h" 20 #include "ntp_calendar.h" 21 #include "lib_strbuf.h" 22 23 #ifdef HAVE_SYS_PARAM_H 24 # include <sys/param.h> 25 #endif 26 #ifdef HAVE_UTMP_H 27 # include <utmp.h> 28 #endif /* HAVE_UTMP_H */ 29 #ifdef HAVE_UTMPX_H 30 # include <utmpx.h> 31 #endif /* HAVE_UTMPX_H */ 32 33 int allow_panic = FALSE; /* allow panic correction (-g) */ 34 int enable_panic_check = TRUE; /* Can we check allow_panic's state? */ 35 36 u_long sys_lamport; /* Lamport violation */ 37 u_long sys_tsrounding; /* timestamp rounding errors */ 38 39 #ifndef USE_COMPILETIME_PIVOT 40 # define USE_COMPILETIME_PIVOT 1 41 #endif 42 43 /* 44 * These routines (get_systime, step_systime, adj_systime) implement an 45 * interface between the system independent NTP clock and the Unix 46 * system clock in various architectures and operating systems. Time is 47 * a precious quantity in these routines and every effort is made to 48 * minimize errors by unbiased rounding and amortizing adjustment 49 * residues. 50 * 51 * In order to improve the apparent resolution, provide unbiased 52 * rounding and most importantly ensure that the readings cannot be 53 * predicted, the low-order unused portion of the time below the minimum 54 * time to read the clock is filled with an unbiased random fuzz. 55 * 56 * The sys_tick variable specifies the system clock tick interval in 57 * seconds, for stepping clocks, defined as those which return times 58 * less than MINSTEP greater than the previous reading. For systems that 59 * use a high-resolution counter such that each clock reading is always 60 * at least MINSTEP greater than the prior, sys_tick is the time to read 61 * the system clock. 62 * 63 * The sys_fuzz variable measures the minimum time to read the system 64 * clock, regardless of its precision. When reading the system clock 65 * using get_systime() after sys_tick and sys_fuzz have been determined, 66 * ntpd ensures each unprocessed clock reading is no less than sys_fuzz 67 * later than the prior unprocessed reading, and then fuzzes the bits 68 * below sys_fuzz in the timestamp returned, ensuring each of its 69 * resulting readings is strictly later than the previous. 70 * 71 * When slewing the system clock using adj_systime() (with the kernel 72 * loop discipline unavailable or disabled), adjtime() offsets are 73 * quantized to sys_tick, if sys_tick is greater than sys_fuzz, which 74 * is to say if the OS presents a stepping clock. Otherwise, offsets 75 * are quantized to the microsecond resolution of adjtime()'s timeval 76 * input. The remaining correction sys_residual is carried into the 77 * next adjtime() and meanwhile is also factored into get_systime() 78 * readings. 79 */ 80 double sys_tick = 0; /* tick size or time to read (s) */ 81 double sys_fuzz = 0; /* min. time to read the clock (s) */ 82 long sys_fuzz_nsec = 0; /* min. time to read the clock (ns) */ 83 double measured_tick; /* non-overridable sys_tick (s) */ 84 double sys_residual = 0; /* adjustment residue (s) */ 85 int trunc_os_clock; /* sys_tick > measured_tick */ 86 time_stepped_callback step_callback; 87 88 #ifndef SIM 89 /* perlinger@ntp.org: As 'get_sysime()' does it's own check for clock 90 * backstepping, this could probably become a local variable in 91 * 'get_systime()' and the cruft associated with communicating via a 92 * static value could be removed after the v4.2.8 release. 93 */ 94 static int lamport_violated; /* clock was stepped back */ 95 #endif /* !SIM */ 96 97 #ifdef DEBUG 98 static int systime_init_done; 99 # define DONE_SYSTIME_INIT() systime_init_done = TRUE 100 #else 101 # define DONE_SYSTIME_INIT() do {} while (FALSE) 102 #endif 103 104 #ifdef HAVE_SIGNALED_IO 105 int using_sigio; 106 #endif 107 108 #ifdef SYS_WINNT 109 CRITICAL_SECTION get_systime_cs; 110 #endif 111 112 113 void 114 set_sys_fuzz( 115 double fuzz_val 116 ) 117 { 118 sys_fuzz = fuzz_val; 119 INSIST(sys_fuzz >= 0); 120 INSIST(sys_fuzz <= 1.0); 121 /* [Bug 3450] ensure nsec fuzz >= sys_fuzz to reduce chance of 122 * short-falling fuzz advance 123 */ 124 sys_fuzz_nsec = (long)ceil(sys_fuzz * 1e9); 125 } 126 127 128 void 129 init_systime(void) 130 { 131 INIT_GET_SYSTIME_CRITSEC(); 132 INIT_WIN_PRECISE_TIME(); 133 DONE_SYSTIME_INIT(); 134 } 135 136 137 #ifndef SIM /* ntpsim.c has get_systime() and friends for sim */ 138 139 static inline void 140 get_ostime( 141 struct timespec * tsp 142 ) 143 { 144 int rc; 145 long ticks; 146 147 #if defined(HAVE_CLOCK_GETTIME) 148 rc = clock_gettime(CLOCK_REALTIME, tsp); 149 #elif defined(HAVE_GETCLOCK) 150 rc = getclock(TIMEOFDAY, tsp); 151 #else 152 struct timeval tv; 153 154 rc = GETTIMEOFDAY(&tv, NULL); 155 tsp->tv_sec = tv.tv_sec; 156 tsp->tv_nsec = tv.tv_usec * 1000; 157 #endif 158 if (rc < 0) { 159 msyslog(LOG_ERR, "read system clock failed: %m (%d)", 160 errno); 161 exit(1); 162 } 163 164 if (trunc_os_clock) { 165 ticks = (long)((tsp->tv_nsec * 1e-9) / sys_tick); 166 tsp->tv_nsec = (long)(ticks * 1e9 * sys_tick); 167 } 168 } 169 170 171 /* 172 * get_systime - return system time in NTP timestamp format. 173 */ 174 void 175 get_systime( 176 l_fp *now /* system time */ 177 ) 178 { 179 static struct timespec ts_last; /* last sampled os time */ 180 static struct timespec ts_prev; /* prior os time */ 181 static l_fp lfp_prev; /* prior result */ 182 struct timespec ts; /* seconds and nanoseconds */ 183 struct timespec ts_min; /* earliest permissible */ 184 struct timespec ts_lam; /* lamport fictional increment */ 185 double dfuzz; 186 l_fp result; 187 l_fp lfpfuzz; 188 l_fp lfpdelta; 189 190 get_ostime(&ts); 191 DEBUG_REQUIRE(systime_init_done); 192 ENTER_GET_SYSTIME_CRITSEC(); 193 194 /* First check if here was a Lamport violation, that is, two 195 * successive calls to 'get_ostime()' resulted in negative 196 * time difference. Use a few milliseconds of permissible 197 * tolerance -- being too sharp can hurt here. (This is intented 198 * for the Win32 target, where the HPC interpolation might 199 * introduce small steps backward. It should not be an issue on 200 * systems where get_ostime() results in a true syscall.) 201 */ 202 if (cmp_tspec(add_tspec_ns(ts, 50000000), ts_last) < 0) { 203 lamport_violated = 1; 204 sys_lamport++; 205 } 206 ts_last = ts; 207 208 /* 209 * After default_get_precision() has set a nonzero sys_fuzz, 210 * ensure every reading of the OS clock advances by at least 211 * sys_fuzz over the prior reading, thereby assuring each 212 * fuzzed result is strictly later than the prior. Limit the 213 * necessary fiction to 1 second. 214 */ 215 if (!USING_SIGIO()) { 216 ts_min = add_tspec_ns(ts_prev, sys_fuzz_nsec); 217 if (cmp_tspec(ts, ts_min) < 0) { 218 ts_lam = sub_tspec(ts_min, ts); 219 if (ts_lam.tv_sec > 0 && !lamport_violated) { 220 msyslog(LOG_ERR, 221 "get_systime Lamport advance exceeds one second (%.9f)", 222 ts_lam.tv_sec + 223 1e-9 * ts_lam.tv_nsec); 224 exit(1); 225 } 226 if (!lamport_violated) 227 ts = ts_min; 228 } 229 ts_prev = ts; 230 } 231 232 /* convert from timespec to l_fp fixed-point */ 233 result = tspec_stamp_to_lfp(ts); 234 235 /* 236 * Add in the fuzz. 'ntp_random()' returns [0..2**31-1] so we 237 * must scale up the result by 2.0 to cover the full fractional 238 * range. 239 */ 240 dfuzz = ntp_random() * 2. / FRAC * sys_fuzz; 241 DTOLFP(dfuzz, &lfpfuzz); 242 L_ADD(&result, &lfpfuzz); 243 244 /* 245 * Ensure result is strictly greater than prior result (ignoring 246 * sys_residual's effect for now) once sys_fuzz has been 247 * determined. 248 * 249 * [Bug 3450] Rounding errors and time slew can lead to a 250 * violation of the expected postcondition. This is bound to 251 * happen from time to time (depending on state of the random 252 * generator, the current slew and the closeness of system time 253 * stamps drawn) and does not warrant a syslog entry. Instead it 254 * makes much more sense to ensure the postcondition and hop 255 * along silently. 256 */ 257 if (!USING_SIGIO()) { 258 if ( !L_ISZERO(&lfp_prev) 259 && !lamport_violated 260 && (sys_fuzz > 0.0) 261 ) { 262 lfpdelta = result; 263 L_SUB(&lfpdelta, &lfp_prev); 264 L_SUBUF(&lfpdelta, 1); 265 if (lfpdelta.l_i < 0) 266 { 267 L_NEG(&lfpdelta); 268 DPRINTF(1, ("get_systime: postcond failed by %s secs, fixed\n", 269 lfptoa(&lfpdelta, 9))); 270 result = lfp_prev; 271 L_ADDUF(&result, 1); 272 sys_tsrounding++; 273 } 274 } 275 lfp_prev = result; 276 if (lamport_violated) 277 lamport_violated = FALSE; 278 } 279 LEAVE_GET_SYSTIME_CRITSEC(); 280 *now = result; 281 } 282 283 284 /* 285 * adj_systime - adjust system time by the argument. 286 */ 287 #if !defined SYS_WINNT 288 int /* 0 okay, 1 error */ 289 adj_systime( 290 double now /* adjustment (s) */ 291 ) 292 { 293 struct timeval adjtv; /* new adjustment */ 294 struct timeval oadjtv; /* residual adjustment */ 295 double quant; /* quantize to multiples of */ 296 double dtemp; 297 long ticks; 298 int isneg = 0; 299 300 /* 301 * The Windows port adj_systime() depends on being called each 302 * second even when there's no additional correction, to allow 303 * emulation of adjtime() behavior on top of an API that simply 304 * sets the current rate. This POSIX implementation needs to 305 * ignore invocations with zero correction, otherwise ongoing 306 * EVNT_NSET adjtime() can be aborted by a tiny adjtime() 307 * triggered by sys_residual. 308 */ 309 if (0. == now) { 310 if (enable_panic_check && allow_panic) { 311 msyslog(LOG_ERR, "adj_systime: allow_panic is TRUE!"); 312 INSIST(!allow_panic); 313 } 314 return TRUE; 315 } 316 317 /* 318 * Most Unix adjtime() implementations adjust the system clock 319 * in microsecond quanta, but some adjust in 10-ms quanta. We 320 * carefully round the adjustment to the nearest quantum, then 321 * adjust in quanta and keep the residue for later. 322 */ 323 dtemp = now + sys_residual; 324 if (dtemp < 0) { 325 isneg = 1; 326 dtemp = -dtemp; 327 } 328 adjtv.tv_sec = (long)dtemp; 329 dtemp -= adjtv.tv_sec; 330 if (sys_tick > sys_fuzz) 331 quant = sys_tick; 332 else 333 quant = 1e-6; 334 ticks = (long)(dtemp / quant + .5); 335 adjtv.tv_usec = (long)(ticks * quant * 1.e6 + .5); 336 /* The rounding in the conversions could us push over the 337 * limits: make sure the result is properly normalised! 338 * note: sign comes later, all numbers non-negative here. 339 */ 340 if (adjtv.tv_usec >= 1000000) { 341 adjtv.tv_sec += 1; 342 adjtv.tv_usec -= 1000000; 343 dtemp -= 1.; 344 } 345 /* set the new residual with leftover from correction */ 346 sys_residual = dtemp - adjtv.tv_usec * 1.e-6; 347 348 /* 349 * Convert to signed seconds and microseconds for the Unix 350 * adjtime() system call. Note we purposely lose the adjtime() 351 * leftover. 352 */ 353 if (isneg) { 354 adjtv.tv_sec = -adjtv.tv_sec; 355 adjtv.tv_usec = -adjtv.tv_usec; 356 sys_residual = -sys_residual; 357 } 358 if (adjtv.tv_sec != 0 || adjtv.tv_usec != 0) { 359 if (adjtime(&adjtv, &oadjtv) < 0) { 360 msyslog(LOG_ERR, "adj_systime: %m"); 361 if (enable_panic_check && allow_panic) { 362 msyslog(LOG_ERR, "adj_systime: allow_panic is TRUE!"); 363 } 364 return FALSE; 365 } 366 } 367 if (enable_panic_check && allow_panic) { 368 msyslog(LOG_ERR, "adj_systime: allow_panic is TRUE!"); 369 } 370 return TRUE; 371 } 372 #endif 373 374 /* 375 * helper to keep utmp/wtmp up to date 376 */ 377 static void 378 update_uwtmp( 379 struct timeval timetv, 380 struct timeval tvlast 381 ) 382 { 383 struct timeval tvdiff; 384 /* 385 * FreeBSD, for example, has: 386 * struct utmp { 387 * char ut_line[UT_LINESIZE]; 388 * char ut_name[UT_NAMESIZE]; 389 * char ut_host[UT_HOSTSIZE]; 390 * long ut_time; 391 * }; 392 * and appends line="|", name="date", host="", time for the OLD 393 * and appends line="{", name="date", host="", time for the NEW // } 394 * to _PATH_WTMP . 395 * 396 * Some OSes have utmp, some have utmpx. 397 */ 398 399 /* 400 * Write old and new time entries in utmp and wtmp if step 401 * adjustment is greater than one second. 402 * 403 * This might become even Uglier... 404 */ 405 tvdiff = abs_tval(sub_tval(timetv, tvlast)); 406 if (tvdiff.tv_sec > 0) { 407 #ifdef HAVE_UTMP_H 408 struct utmp ut; 409 #endif 410 #ifdef HAVE_UTMPX_H 411 struct utmpx utx; 412 #endif 413 414 #ifdef HAVE_UTMP_H 415 ZERO(ut); 416 #endif 417 #ifdef HAVE_UTMPX_H 418 ZERO(utx); 419 #endif 420 421 /* UTMP */ 422 423 #ifdef UPDATE_UTMP 424 # ifdef HAVE_PUTUTLINE 425 # ifndef _PATH_UTMP 426 # define _PATH_UTMP UTMP_FILE 427 # endif 428 utmpname(_PATH_UTMP); 429 ut.ut_type = OLD_TIME; 430 strlcpy(ut.ut_line, OTIME_MSG, sizeof(ut.ut_line)); 431 ut.ut_time = tvlast.tv_sec; 432 setutent(); 433 pututline(&ut); 434 ut.ut_type = NEW_TIME; 435 strlcpy(ut.ut_line, NTIME_MSG, sizeof(ut.ut_line)); 436 ut.ut_time = timetv.tv_sec; 437 setutent(); 438 pututline(&ut); 439 endutent(); 440 # else /* not HAVE_PUTUTLINE */ 441 # endif /* not HAVE_PUTUTLINE */ 442 #endif /* UPDATE_UTMP */ 443 444 /* UTMPX */ 445 446 #ifdef UPDATE_UTMPX 447 # ifdef HAVE_PUTUTXLINE 448 utx.ut_type = OLD_TIME; 449 strlcpy(utx.ut_line, OTIME_MSG, sizeof(utx.ut_line)); 450 utx.ut_tv = tvlast; 451 setutxent(); 452 pututxline(&utx); 453 utx.ut_type = NEW_TIME; 454 strlcpy(utx.ut_line, NTIME_MSG, sizeof(utx.ut_line)); 455 utx.ut_tv = timetv; 456 setutxent(); 457 pututxline(&utx); 458 endutxent(); 459 # else /* not HAVE_PUTUTXLINE */ 460 # endif /* not HAVE_PUTUTXLINE */ 461 #endif /* UPDATE_UTMPX */ 462 463 /* WTMP */ 464 465 #ifdef UPDATE_WTMP 466 # ifdef HAVE_PUTUTLINE 467 # ifndef _PATH_WTMP 468 # define _PATH_WTMP WTMP_FILE 469 # endif 470 utmpname(_PATH_WTMP); 471 ut.ut_type = OLD_TIME; 472 strlcpy(ut.ut_line, OTIME_MSG, sizeof(ut.ut_line)); 473 ut.ut_time = tvlast.tv_sec; 474 setutent(); 475 pututline(&ut); 476 ut.ut_type = NEW_TIME; 477 strlcpy(ut.ut_line, NTIME_MSG, sizeof(ut.ut_line)); 478 ut.ut_time = timetv.tv_sec; 479 setutent(); 480 pututline(&ut); 481 endutent(); 482 # else /* not HAVE_PUTUTLINE */ 483 # endif /* not HAVE_PUTUTLINE */ 484 #endif /* UPDATE_WTMP */ 485 486 /* WTMPX */ 487 488 #ifdef UPDATE_WTMPX 489 # ifdef HAVE_PUTUTXLINE 490 utx.ut_type = OLD_TIME; 491 utx.ut_tv = tvlast; 492 strlcpy(utx.ut_line, OTIME_MSG, sizeof(utx.ut_line)); 493 # ifdef HAVE_UPDWTMPX 494 updwtmpx(WTMPX_FILE, &utx); 495 # else /* not HAVE_UPDWTMPX */ 496 # endif /* not HAVE_UPDWTMPX */ 497 # else /* not HAVE_PUTUTXLINE */ 498 # endif /* not HAVE_PUTUTXLINE */ 499 # ifdef HAVE_PUTUTXLINE 500 utx.ut_type = NEW_TIME; 501 utx.ut_tv = timetv; 502 strlcpy(utx.ut_line, NTIME_MSG, sizeof(utx.ut_line)); 503 # ifdef HAVE_UPDWTMPX 504 updwtmpx(WTMPX_FILE, &utx); 505 # else /* not HAVE_UPDWTMPX */ 506 # endif /* not HAVE_UPDWTMPX */ 507 # else /* not HAVE_PUTUTXLINE */ 508 # endif /* not HAVE_PUTUTXLINE */ 509 #endif /* UPDATE_WTMPX */ 510 511 } 512 } 513 514 /* 515 * step_systime - step the system clock. 516 */ 517 518 int 519 step_systime( 520 double step 521 ) 522 { 523 time_t pivot; /* for ntp era unfolding */ 524 struct timeval timetv, tvlast; 525 struct timespec timets; 526 l_fp fp_ofs, fp_sys; /* offset and target system time in FP */ 527 528 /* 529 * Get pivot time for NTP era unfolding. Since we don't step 530 * very often, we can afford to do the whole calculation from 531 * scratch. And we're not in the time-critical path yet. 532 */ 533 #if SIZEOF_TIME_T > 4 534 pivot = basedate_get_eracenter(); 535 #else 536 /* This makes sure the resulting time stamp is on or after 537 * 1969-12-31/23:59:59 UTC and gives us additional two years, 538 * from the change of NTP era in 2036 to the UNIX rollover in 539 * 2038. (Minus one second, but that won't hurt.) We *really* 540 * need a longer 'time_t' after that! Or a different baseline, 541 * but that would cause other serious trouble, too. 542 */ 543 pivot = 0x7FFFFFFF; 544 #endif 545 546 /* get the complete jump distance as l_fp */ 547 DTOLFP(sys_residual, &fp_sys); 548 DTOLFP(step, &fp_ofs); 549 L_ADD(&fp_ofs, &fp_sys); 550 551 /* ---> time-critical path starts ---> */ 552 553 /* get the current time as l_fp (without fuzz) and as struct timeval */ 554 get_ostime(&timets); 555 fp_sys = tspec_stamp_to_lfp(timets); 556 tvlast.tv_sec = timets.tv_sec; 557 tvlast.tv_usec = (timets.tv_nsec + 500) / 1000; 558 559 /* get the target time as l_fp */ 560 L_ADD(&fp_sys, &fp_ofs); 561 562 /* unfold the new system time */ 563 timetv = lfp_stamp_to_tval(fp_sys, &pivot); 564 565 /* now set new system time */ 566 if (ntp_set_tod(&timetv, NULL) != 0) { 567 msyslog(LOG_ERR, "step-systime: %m"); 568 if (enable_panic_check && allow_panic) { 569 msyslog(LOG_ERR, "step_systime: allow_panic is TRUE!"); 570 } 571 return FALSE; 572 } 573 574 /* <--- time-critical path ended with 'ntp_set_tod()' <--- */ 575 576 sys_residual = 0; 577 lamport_violated = (step < 0); 578 if (step_callback) 579 (*step_callback)(); 580 581 #ifdef NEED_HPUX_ADJTIME 582 /* 583 * CHECKME: is this correct when called by ntpdate????? 584 */ 585 _clear_adjtime(); 586 #endif 587 588 update_uwtmp(timetv, tvlast); 589 if (enable_panic_check && allow_panic) { 590 msyslog(LOG_ERR, "step_systime: allow_panic is TRUE!"); 591 INSIST(!allow_panic); 592 } 593 return TRUE; 594 } 595 596 static const char * 597 tv_fmt_libbuf( 598 const struct timeval * ptv 599 ) 600 { 601 char * retv; 602 vint64 secs; 603 ntpcal_split dds; 604 struct calendar jd; 605 606 secs = time_to_vint64(&ptv->tv_sec); 607 dds = ntpcal_daysplit(&secs); 608 ntpcal_daysplit_to_date(&jd, &dds, DAY_UNIX_STARTS); 609 LIB_GETBUF(retv); 610 snprintf(retv, LIB_BUFLENGTH, 611 "%04hu-%02hu-%02hu/%02hu:%02hu:%02hu.%06u", 612 jd.year, (u_short)jd.month, (u_short)jd.monthday, 613 (u_short)jd.hour, (u_short)jd.minute, (u_short)jd.second, 614 (u_int)ptv->tv_usec); 615 return retv; 616 } 617 618 619 int /*BOOL*/ 620 clamp_systime(void) 621 { 622 #if SIZEOF_TIME_T > 4 623 624 struct timeval timetv, tvlast; 625 struct timespec timets; 626 uint32_t tdiff; 627 628 629 timetv.tv_sec = basedate_get_erabase(); 630 631 /* ---> time-critical path starts ---> */ 632 633 /* get the current time as l_fp (without fuzz) and as struct timeval */ 634 get_ostime(&timets); 635 tvlast.tv_sec = timets.tv_sec; 636 tvlast.tv_usec = (timets.tv_nsec + 500) / 1000; 637 if (tvlast.tv_usec >= 1000000) { 638 tvlast.tv_usec -= 1000000; 639 tvlast.tv_sec += 1; 640 } 641 timetv.tv_usec = tvlast.tv_usec; 642 643 tdiff = (uint32_t)(tvlast.tv_sec & UINT32_MAX) - 644 (uint32_t)(timetv.tv_sec & UINT32_MAX); 645 timetv.tv_sec += tdiff; 646 if (timetv.tv_sec != tvlast.tv_sec) { 647 /* now set new system time */ 648 if (ntp_set_tod(&timetv, NULL) != 0) { 649 msyslog(LOG_ERR, "clamp-systime: %m"); 650 return FALSE; 651 } 652 } else { 653 msyslog(LOG_INFO, 654 "clamp-systime: clock (%s) in allowed range", 655 tv_fmt_libbuf(&timetv)); 656 return FALSE; 657 } 658 659 /* <--- time-critical path ended with 'ntp_set_tod()' <--- */ 660 661 sys_residual = 0; 662 lamport_violated = (timetv.tv_sec < tvlast.tv_sec); 663 if (step_callback) 664 (*step_callback)(); 665 666 # ifdef NEED_HPUX_ADJTIME 667 /* 668 * CHECKME: is this correct when called by ntpdate????? 669 */ 670 _clear_adjtime(); 671 # endif 672 673 update_uwtmp(timetv, tvlast); 674 msyslog(LOG_WARNING, 675 "clamp-systime: clock stepped from %s to %s!", 676 tv_fmt_libbuf(&tvlast), tv_fmt_libbuf(&timetv)); 677 return TRUE; 678 679 #else 680 681 return 0; 682 #endif 683 } 684 685 #endif /* !SIM */ 686