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