xref: /netbsd-src/external/bsd/ntp/dist/libntp/systime.c (revision f8cf1a9151c7af1cb0bd8b09c13c66bca599c027)
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
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
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
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
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 */
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
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
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 *
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*/
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