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