xref: /freebsd/contrib/ntp/libntp/systime.c (revision ea906c4152774dff300bb26fbfc1e4188351c89a)
1c0b746e5SOllivier Robert /*
2c0b746e5SOllivier Robert  * systime -- routines to fiddle a UNIX clock.
39c2daa00SOllivier Robert  *
49c2daa00SOllivier Robert  * ATTENTION: Get approval from Dave Mills on all changes to this file!
59c2daa00SOllivier Robert  *
6c0b746e5SOllivier Robert  */
7224ba2bdSOllivier Robert #include "ntp_machine.h"
8224ba2bdSOllivier Robert #include "ntp_fp.h"
9224ba2bdSOllivier Robert #include "ntp_syslog.h"
10224ba2bdSOllivier Robert #include "ntp_unixtime.h"
11224ba2bdSOllivier Robert #include "ntp_stdlib.h"
12ea906c41SOllivier Robert #include "ntp_random.h"
13ea906c41SOllivier Robert #include "ntpd.h"		/* for sys_precision */
14c0b746e5SOllivier Robert 
159c2daa00SOllivier Robert #ifdef SIM
169c2daa00SOllivier Robert # include "ntpsim.h"
179c2daa00SOllivier Robert #endif /*SIM */
189c2daa00SOllivier Robert 
19c0b746e5SOllivier Robert #ifdef HAVE_SYS_PARAM_H
20c0b746e5SOllivier Robert # include <sys/param.h>
21c0b746e5SOllivier Robert #endif
22c0b746e5SOllivier Robert #ifdef HAVE_UTMP_H
23c0b746e5SOllivier Robert # include <utmp.h>
24c0b746e5SOllivier Robert #endif /* HAVE_UTMP_H */
25c0b746e5SOllivier Robert #ifdef HAVE_UTMPX_H
26c0b746e5SOllivier Robert # include <utmpx.h>
27c0b746e5SOllivier Robert #endif /* HAVE_UTMPX_H */
28c0b746e5SOllivier Robert 
29c0b746e5SOllivier Robert /*
309c2daa00SOllivier Robert  * These routines (get_systime, step_systime, adj_systime) implement an
319c2daa00SOllivier Robert  * interface between the system independent NTP clock and the Unix
329c2daa00SOllivier Robert  * system clock in various architectures and operating systems.
339c2daa00SOllivier Robert  *
349c2daa00SOllivier Robert  * Time is a precious quantity in these routines and every effort is
359c2daa00SOllivier Robert  * made to minimize errors by always rounding toward zero and amortizing
369c2daa00SOllivier Robert  * adjustment residues. By default the adjustment quantum is 1 us for
379c2daa00SOllivier Robert  * the usual Unix tickadj() system call, but this can be increased if
38ea906c41SOllivier Robert  * necessary by the tick configuration command. For instance, when the
399c2daa00SOllivier Robert  * adjtime() quantum is a clock tick for a 100-Hz clock, the quantum
409c2daa00SOllivier Robert  * should be 10 ms.
41c0b746e5SOllivier Robert  */
42ea906c41SOllivier Robert #if defined RELIANTUNIX_CLOCK || defined SCO5_CLOCK
43ea906c41SOllivier Robert double	sys_tick = 10e-3;	/* 10 ms tickadj() */
44ea906c41SOllivier Robert #else
45ea906c41SOllivier Robert double	sys_tick = 1e-6;	/* 1 us tickadj() */
46ea906c41SOllivier Robert #endif
479c2daa00SOllivier Robert double	sys_residual = 0;	/* adjustment residue (s) */
48c0b746e5SOllivier Robert 
499c2daa00SOllivier Robert #ifndef SIM
50c0b746e5SOllivier Robert 
51c0b746e5SOllivier Robert /*
529c2daa00SOllivier Robert  * get_systime - return system time in NTP timestamp format.
53c0b746e5SOllivier Robert  */
54c0b746e5SOllivier Robert void
55c0b746e5SOllivier Robert get_systime(
569c2daa00SOllivier Robert 	l_fp *now		/* system time */
57c0b746e5SOllivier Robert 	)
58c0b746e5SOllivier Robert {
59c0b746e5SOllivier Robert 	double dtemp;
60c0b746e5SOllivier Robert 
61c0b746e5SOllivier Robert #if defined(HAVE_CLOCK_GETTIME) || defined(HAVE_GETCLOCK)
629c2daa00SOllivier Robert 	struct timespec ts;	/* seconds and nanoseconds */
639c2daa00SOllivier Robert 
649c2daa00SOllivier Robert 	/*
659c2daa00SOllivier Robert 	 * Convert Unix clock from seconds and nanoseconds to seconds.
66ea906c41SOllivier Robert 	 * The bottom is only two bits down, so no need for fuzz.
67ea906c41SOllivier Robert 	 * Some systems don't have that level of precision, however...
689c2daa00SOllivier Robert 	 */
69c0b746e5SOllivier Robert # ifdef HAVE_CLOCK_GETTIME
709c2daa00SOllivier Robert 	clock_gettime(CLOCK_REALTIME, &ts);
71c0b746e5SOllivier Robert # else
729c2daa00SOllivier Robert 	getclock(TIMEOFDAY, &ts);
73c0b746e5SOllivier Robert # endif
74c0b746e5SOllivier Robert 	now->l_i = ts.tv_sec + JAN_1970;
759c2daa00SOllivier Robert 	dtemp = ts.tv_nsec / 1e9;
76c0b746e5SOllivier Robert 
779c2daa00SOllivier Robert #else /* HAVE_CLOCK_GETTIME || HAVE_GETCLOCK */
789c2daa00SOllivier Robert 	struct timeval tv;	/* seconds and microseconds */
799c2daa00SOllivier Robert 
809c2daa00SOllivier Robert 	/*
819c2daa00SOllivier Robert 	 * Convert Unix clock from seconds and microseconds to seconds.
82ea906c41SOllivier Robert 	 * Add in unbiased random fuzz beneath the microsecond.
839c2daa00SOllivier Robert 	 */
849c2daa00SOllivier Robert 	GETTIMEOFDAY(&tv, NULL);
859c2daa00SOllivier Robert 	now->l_i = tv.tv_sec + JAN_1970;
86c0b746e5SOllivier Robert 	dtemp = tv.tv_usec / 1e6;
879c2daa00SOllivier Robert 
889c2daa00SOllivier Robert #endif /* HAVE_CLOCK_GETTIME || HAVE_GETCLOCK */
899c2daa00SOllivier Robert 
909c2daa00SOllivier Robert 	/*
91ea906c41SOllivier Robert 	 * ntp_random() produces 31 bits (always nonnegative).
92ea906c41SOllivier Robert 	 * This bit is done only after the precision has been
93ea906c41SOllivier Robert 	 * determined.
94ea906c41SOllivier Robert 	 */
95ea906c41SOllivier Robert 	if (sys_precision != 0)
96ea906c41SOllivier Robert 		dtemp += (ntp_random() / FRAC - .5) / (1 <<
97ea906c41SOllivier Robert 		    -sys_precision);
98ea906c41SOllivier Robert 
99ea906c41SOllivier Robert 	/*
1009c2daa00SOllivier Robert 	 * Renormalize to seconds past 1900 and fraction.
1019c2daa00SOllivier Robert 	 */
102c0b746e5SOllivier Robert 	dtemp += sys_residual;
1039c2daa00SOllivier Robert 	if (dtemp >= 1) {
1049c2daa00SOllivier Robert 		dtemp -= 1;
1059c2daa00SOllivier Robert 		now->l_i++;
106ea906c41SOllivier Robert 	} else if (dtemp < 0) {
1079c2daa00SOllivier Robert 		dtemp += 1;
108c0b746e5SOllivier Robert 		now->l_i--;
109c0b746e5SOllivier Robert 	}
110c0b746e5SOllivier Robert 	dtemp *= FRAC;
111c0b746e5SOllivier Robert 	now->l_uf = (u_int32)dtemp;
112c0b746e5SOllivier Robert }
113c0b746e5SOllivier Robert 
114c0b746e5SOllivier Robert 
115c0b746e5SOllivier Robert /*
1169c2daa00SOllivier Robert  * adj_systime - adjust system time by the argument.
117c0b746e5SOllivier Robert  */
118a151a66cSOllivier Robert #if !defined SYS_WINNT
1199c2daa00SOllivier Robert int				/* 0 okay, 1 error */
120c0b746e5SOllivier Robert adj_systime(
1219c2daa00SOllivier Robert 	double now		/* adjustment (s) */
122c0b746e5SOllivier Robert 	)
123c0b746e5SOllivier Robert {
1249c2daa00SOllivier Robert 	struct timeval adjtv;	/* new adjustment */
1259c2daa00SOllivier Robert 	struct timeval oadjtv;	/* residual adjustment */
126c0b746e5SOllivier Robert 	double	dtemp;
1279c2daa00SOllivier Robert 	long	ticks;
1289c2daa00SOllivier Robert 	int	isneg = 0;
129c0b746e5SOllivier Robert 
130c0b746e5SOllivier Robert 	/*
1319c2daa00SOllivier Robert 	 * Most Unix adjtime() implementations adjust the system clock
1329c2daa00SOllivier Robert 	 * in microsecond quanta, but some adjust in 10-ms quanta. We
1339c2daa00SOllivier Robert 	 * carefully round the adjustment to the nearest quantum, then
1349c2daa00SOllivier Robert 	 * adjust in quanta and keep the residue for later.
135c0b746e5SOllivier Robert 	 */
1369c2daa00SOllivier Robert 	dtemp = now + sys_residual;
137c0b746e5SOllivier Robert 	if (dtemp < 0) {
138c0b746e5SOllivier Robert 		isneg = 1;
139c0b746e5SOllivier Robert 		dtemp = -dtemp;
140c0b746e5SOllivier Robert 	}
1419c2daa00SOllivier Robert 	adjtv.tv_sec = (long)dtemp;
1429c2daa00SOllivier Robert 	dtemp -= adjtv.tv_sec;
1439c2daa00SOllivier Robert 	ticks = (long)(dtemp / sys_tick + .5);
1449c2daa00SOllivier Robert 	adjtv.tv_usec = (long)(ticks * sys_tick * 1e6);
1459c2daa00SOllivier Robert 	dtemp -= adjtv.tv_usec / 1e6;
1469c2daa00SOllivier Robert 	sys_residual = dtemp;
147c0b746e5SOllivier Robert 
148c0b746e5SOllivier Robert 	/*
1499c2daa00SOllivier Robert 	 * Convert to signed seconds and microseconds for the Unix
1509c2daa00SOllivier Robert 	 * adjtime() system call. Note we purposely lose the adjtime()
1519c2daa00SOllivier Robert 	 * leftover.
152c0b746e5SOllivier Robert 	 */
1539c2daa00SOllivier Robert 	if (isneg) {
1549c2daa00SOllivier Robert 		adjtv.tv_sec = -adjtv.tv_sec;
1559c2daa00SOllivier Robert 		adjtv.tv_usec = -adjtv.tv_usec;
156ea906c41SOllivier Robert 		sys_residual = -sys_residual;
157c0b746e5SOllivier Robert 	}
158ea906c41SOllivier Robert 	if (adjtv.tv_sec != 0 || adjtv.tv_usec != 0) {
1599c2daa00SOllivier Robert 		if (adjtime(&adjtv, &oadjtv) < 0) {
1609c2daa00SOllivier Robert 			msyslog(LOG_ERR, "adj_systime: %m");
1619c2daa00SOllivier Robert 			return (0);
162c0b746e5SOllivier Robert 		}
163ea906c41SOllivier Robert 	}
1649c2daa00SOllivier Robert 	return (1);
165c0b746e5SOllivier Robert }
166a151a66cSOllivier Robert #endif
167c0b746e5SOllivier Robert 
168c0b746e5SOllivier Robert 
169c0b746e5SOllivier Robert /*
170c0b746e5SOllivier Robert  * step_systime - step the system clock.
171c0b746e5SOllivier Robert  */
172c0b746e5SOllivier Robert int
173c0b746e5SOllivier Robert step_systime(
174c0b746e5SOllivier Robert 	double now
175c0b746e5SOllivier Robert 	)
176c0b746e5SOllivier Robert {
177c0b746e5SOllivier Robert 	struct timeval timetv, adjtv, oldtimetv;
178c0b746e5SOllivier Robert 	int isneg = 0;
179c0b746e5SOllivier Robert 	double dtemp;
180c0b746e5SOllivier Robert #if defined(HAVE_CLOCK_GETTIME) || defined(HAVE_GETCLOCK)
181c0b746e5SOllivier Robert 	struct timespec ts;
182c0b746e5SOllivier Robert #endif
183c0b746e5SOllivier Robert 
184c0b746e5SOllivier Robert 	dtemp = sys_residual + now;
185c0b746e5SOllivier Robert 	if (dtemp < 0) {
186c0b746e5SOllivier Robert 		isneg = 1;
187c0b746e5SOllivier Robert 		dtemp = - dtemp;
188c0b746e5SOllivier Robert 		adjtv.tv_sec = (int32)dtemp;
1899c2daa00SOllivier Robert 		adjtv.tv_usec = (u_int32)((dtemp -
1909c2daa00SOllivier Robert 		    (double)adjtv.tv_sec) * 1e6 + .5);
191c0b746e5SOllivier Robert 	} else {
192c0b746e5SOllivier Robert 		adjtv.tv_sec = (int32)dtemp;
1939c2daa00SOllivier Robert 		adjtv.tv_usec = (u_int32)((dtemp -
1949c2daa00SOllivier Robert 		    (double)adjtv.tv_sec) * 1e6 + .5);
195c0b746e5SOllivier Robert 	}
196c0b746e5SOllivier Robert #if defined(HAVE_CLOCK_GETTIME) || defined(HAVE_GETCLOCK)
197c0b746e5SOllivier Robert # ifdef HAVE_CLOCK_GETTIME
198c0b746e5SOllivier Robert 	(void) clock_gettime(CLOCK_REALTIME, &ts);
199c0b746e5SOllivier Robert # else
200c0b746e5SOllivier Robert 	(void) getclock(TIMEOFDAY, &ts);
201c0b746e5SOllivier Robert # endif
202c0b746e5SOllivier Robert 	timetv.tv_sec = ts.tv_sec;
203c0b746e5SOllivier Robert 	timetv.tv_usec = ts.tv_nsec / 1000;
204c0b746e5SOllivier Robert #else /*  not HAVE_GETCLOCK */
205c0b746e5SOllivier Robert 	(void) GETTIMEOFDAY(&timetv, (struct timezone *)0);
206c0b746e5SOllivier Robert #endif /* not HAVE_GETCLOCK */
207c0b746e5SOllivier Robert 
208c0b746e5SOllivier Robert 	oldtimetv = timetv;
209c0b746e5SOllivier Robert 
210c0b746e5SOllivier Robert #ifdef DEBUG
211c0b746e5SOllivier Robert 	if (debug)
212c0b746e5SOllivier Robert 		printf("step_systime: step %.6f residual %.6f\n", now, sys_residual);
213c0b746e5SOllivier Robert #endif
214c0b746e5SOllivier Robert 	if (isneg) {
215c0b746e5SOllivier Robert 		timetv.tv_sec -= adjtv.tv_sec;
216c0b746e5SOllivier Robert 		timetv.tv_usec -= adjtv.tv_usec;
217c0b746e5SOllivier Robert 		if (timetv.tv_usec < 0) {
218c0b746e5SOllivier Robert 			timetv.tv_sec--;
219c0b746e5SOllivier Robert 			timetv.tv_usec += 1000000;
220c0b746e5SOllivier Robert 		}
221c0b746e5SOllivier Robert 	} else {
222c0b746e5SOllivier Robert 		timetv.tv_sec += adjtv.tv_sec;
223c0b746e5SOllivier Robert 		timetv.tv_usec += adjtv.tv_usec;
224c0b746e5SOllivier Robert 		if (timetv.tv_usec >= 1000000) {
225c0b746e5SOllivier Robert 			timetv.tv_sec++;
226c0b746e5SOllivier Robert 			timetv.tv_usec -= 1000000;
227c0b746e5SOllivier Robert 		}
228c0b746e5SOllivier Robert 	}
2299c2daa00SOllivier Robert 	if (ntp_set_tod(&timetv, NULL) != 0) {
2309c2daa00SOllivier Robert 		msyslog(LOG_ERR, "step-systime: %m");
231c0b746e5SOllivier Robert 		return (0);
232c0b746e5SOllivier Robert 	}
233c0b746e5SOllivier Robert 	sys_residual = 0;
234c0b746e5SOllivier Robert 
235c0b746e5SOllivier Robert #ifdef NEED_HPUX_ADJTIME
236c0b746e5SOllivier Robert 	/*
237c0b746e5SOllivier Robert 	 * CHECKME: is this correct when called by ntpdate?????
238c0b746e5SOllivier Robert 	 */
239c0b746e5SOllivier Robert 	_clear_adjtime();
240c0b746e5SOllivier Robert #endif
241c0b746e5SOllivier Robert 
242c0b746e5SOllivier Robert 	/*
243c0b746e5SOllivier Robert 	 * FreeBSD, for example, has:
244c0b746e5SOllivier Robert 	 * struct utmp {
245c0b746e5SOllivier Robert 	 *	   char    ut_line[UT_LINESIZE];
246c0b746e5SOllivier Robert 	 *	   char    ut_name[UT_NAMESIZE];
247c0b746e5SOllivier Robert 	 *	   char    ut_host[UT_HOSTSIZE];
248c0b746e5SOllivier Robert 	 *	   long    ut_time;
249c0b746e5SOllivier Robert 	 * };
250c0b746e5SOllivier Robert 	 * and appends line="|", name="date", host="", time for the OLD
251c0b746e5SOllivier Robert 	 * and appends line="{", name="date", host="", time for the NEW
252c0b746e5SOllivier Robert 	 * to _PATH_WTMP .
253c0b746e5SOllivier Robert 	 *
254c0b746e5SOllivier Robert 	 * Some OSes have utmp, some have utmpx.
255c0b746e5SOllivier Robert 	 */
256c0b746e5SOllivier Robert 
257c0b746e5SOllivier Robert 	/*
2589c2daa00SOllivier Robert 	 * Write old and new time entries in utmp and wtmp if step
2599c2daa00SOllivier Robert 	 * adjustment is greater than one second.
260c0b746e5SOllivier Robert 	 *
261c0b746e5SOllivier Robert 	 * This might become even Uglier...
262c0b746e5SOllivier Robert 	 */
263c0b746e5SOllivier Robert 	if (oldtimetv.tv_sec != timetv.tv_sec)
264c0b746e5SOllivier Robert 	{
265c0b746e5SOllivier Robert #ifdef HAVE_UTMP_H
266c0b746e5SOllivier Robert 		struct utmp ut;
267c0b746e5SOllivier Robert #endif
268c0b746e5SOllivier Robert #ifdef HAVE_UTMPX_H
269c0b746e5SOllivier Robert 		struct utmpx utx;
270c0b746e5SOllivier Robert #endif
271c0b746e5SOllivier Robert 
272c0b746e5SOllivier Robert #ifdef HAVE_UTMP_H
273c0b746e5SOllivier Robert 		memset((char *)&ut, 0, sizeof(ut));
274c0b746e5SOllivier Robert #endif
275c0b746e5SOllivier Robert #ifdef HAVE_UTMPX_H
276c0b746e5SOllivier Robert 		memset((char *)&utx, 0, sizeof(utx));
277c0b746e5SOllivier Robert #endif
278c0b746e5SOllivier Robert 
279c0b746e5SOllivier Robert 		/* UTMP */
280c0b746e5SOllivier Robert 
281c0b746e5SOllivier Robert #ifdef UPDATE_UTMP
282c0b746e5SOllivier Robert # ifdef HAVE_PUTUTLINE
283c0b746e5SOllivier Robert 		ut.ut_type = OLD_TIME;
284c0b746e5SOllivier Robert 		(void)strcpy(ut.ut_line, OTIME_MSG);
285c0b746e5SOllivier Robert 		ut.ut_time = oldtimetv.tv_sec;
286c0b746e5SOllivier Robert 		pututline(&ut);
287c0b746e5SOllivier Robert 		setutent();
288c0b746e5SOllivier Robert 		ut.ut_type = NEW_TIME;
289c0b746e5SOllivier Robert 		(void)strcpy(ut.ut_line, NTIME_MSG);
290c0b746e5SOllivier Robert 		ut.ut_time = timetv.tv_sec;
291c0b746e5SOllivier Robert 		pututline(&ut);
292c0b746e5SOllivier Robert 		endutent();
293c0b746e5SOllivier Robert # else /* not HAVE_PUTUTLINE */
294c0b746e5SOllivier Robert # endif /* not HAVE_PUTUTLINE */
295c0b746e5SOllivier Robert #endif /* UPDATE_UTMP */
296c0b746e5SOllivier Robert 
297c0b746e5SOllivier Robert 		/* UTMPX */
298c0b746e5SOllivier Robert 
299c0b746e5SOllivier Robert #ifdef UPDATE_UTMPX
300c0b746e5SOllivier Robert # ifdef HAVE_PUTUTXLINE
301c0b746e5SOllivier Robert 		utx.ut_type = OLD_TIME;
302c0b746e5SOllivier Robert 		(void)strcpy(utx.ut_line, OTIME_MSG);
303c0b746e5SOllivier Robert 		utx.ut_tv = oldtimetv;
304c0b746e5SOllivier Robert 		pututxline(&utx);
305c0b746e5SOllivier Robert 		setutxent();
306c0b746e5SOllivier Robert 		utx.ut_type = NEW_TIME;
307c0b746e5SOllivier Robert 		(void)strcpy(utx.ut_line, NTIME_MSG);
308c0b746e5SOllivier Robert 		utx.ut_tv = timetv;
309c0b746e5SOllivier Robert 		pututxline(&utx);
310c0b746e5SOllivier Robert 		endutxent();
311c0b746e5SOllivier Robert # else /* not HAVE_PUTUTXLINE */
312c0b746e5SOllivier Robert # endif /* not HAVE_PUTUTXLINE */
313c0b746e5SOllivier Robert #endif /* UPDATE_UTMPX */
314c0b746e5SOllivier Robert 
315c0b746e5SOllivier Robert 		/* WTMP */
316c0b746e5SOllivier Robert 
317c0b746e5SOllivier Robert #ifdef UPDATE_WTMP
318c0b746e5SOllivier Robert # ifdef HAVE_PUTUTLINE
319c0b746e5SOllivier Robert 		utmpname(WTMP_FILE);
320c0b746e5SOllivier Robert 		ut.ut_type = OLD_TIME;
321c0b746e5SOllivier Robert 		(void)strcpy(ut.ut_line, OTIME_MSG);
322c0b746e5SOllivier Robert 		ut.ut_time = oldtimetv.tv_sec;
323c0b746e5SOllivier Robert 		pututline(&ut);
324c0b746e5SOllivier Robert 		ut.ut_type = NEW_TIME;
325c0b746e5SOllivier Robert 		(void)strcpy(ut.ut_line, NTIME_MSG);
326c0b746e5SOllivier Robert 		ut.ut_time = timetv.tv_sec;
327c0b746e5SOllivier Robert 		pututline(&ut);
328c0b746e5SOllivier Robert 		endutent();
329c0b746e5SOllivier Robert # else /* not HAVE_PUTUTLINE */
330c0b746e5SOllivier Robert # endif /* not HAVE_PUTUTLINE */
331c0b746e5SOllivier Robert #endif /* UPDATE_WTMP */
332c0b746e5SOllivier Robert 
333c0b746e5SOllivier Robert 		/* WTMPX */
334c0b746e5SOllivier Robert 
335c0b746e5SOllivier Robert #ifdef UPDATE_WTMPX
336c0b746e5SOllivier Robert # ifdef HAVE_PUTUTXLINE
337c0b746e5SOllivier Robert 		utx.ut_type = OLD_TIME;
338c0b746e5SOllivier Robert 		utx.ut_tv = oldtimetv;
339c0b746e5SOllivier Robert 		(void)strcpy(utx.ut_line, OTIME_MSG);
340c0b746e5SOllivier Robert #  ifdef HAVE_UPDWTMPX
341c0b746e5SOllivier Robert 		updwtmpx(WTMPX_FILE, &utx);
342c0b746e5SOllivier Robert #  else /* not HAVE_UPDWTMPX */
343c0b746e5SOllivier Robert #  endif /* not HAVE_UPDWTMPX */
344c0b746e5SOllivier Robert # else /* not HAVE_PUTUTXLINE */
345c0b746e5SOllivier Robert # endif /* not HAVE_PUTUTXLINE */
346c0b746e5SOllivier Robert # ifdef HAVE_PUTUTXLINE
347c0b746e5SOllivier Robert 		utx.ut_type = NEW_TIME;
348c0b746e5SOllivier Robert 		utx.ut_tv = timetv;
349c0b746e5SOllivier Robert 		(void)strcpy(utx.ut_line, NTIME_MSG);
350c0b746e5SOllivier Robert #  ifdef HAVE_UPDWTMPX
351c0b746e5SOllivier Robert 		updwtmpx(WTMPX_FILE, &utx);
352c0b746e5SOllivier Robert #  else /* not HAVE_UPDWTMPX */
353c0b746e5SOllivier Robert #  endif /* not HAVE_UPDWTMPX */
354c0b746e5SOllivier Robert # else /* not HAVE_PUTUTXLINE */
355c0b746e5SOllivier Robert # endif /* not HAVE_PUTUTXLINE */
356c0b746e5SOllivier Robert #endif /* UPDATE_WTMPX */
357c0b746e5SOllivier Robert 
358c0b746e5SOllivier Robert 	}
359c0b746e5SOllivier Robert 	return (1);
360c0b746e5SOllivier Robert }
3619c2daa00SOllivier Robert 
3629c2daa00SOllivier Robert #else /* SIM */
3639c2daa00SOllivier Robert /*
3649c2daa00SOllivier Robert  * Clock routines for the simulator - Harish Nair, with help
3659c2daa00SOllivier Robert  */
3669c2daa00SOllivier Robert /*
3679c2daa00SOllivier Robert  * get_systime - return the system time in NTP timestamp format
3689c2daa00SOllivier Robert  */
3699c2daa00SOllivier Robert void
3709c2daa00SOllivier Robert get_systime(
3719c2daa00SOllivier Robert         l_fp *now		/* current system time in l_fp */        )
3729c2daa00SOllivier Robert {
3739c2daa00SOllivier Robert 	/*
3749c2daa00SOllivier Robert 	 * To fool the code that determines the local clock precision,
3759c2daa00SOllivier Robert 	 * we advance the clock a minimum of 200 nanoseconds on every
3769c2daa00SOllivier Robert 	 * clock read. This is appropriate for a typical modern machine
3779c2daa00SOllivier Robert 	 * with nanosecond clocks. Note we make no attempt here to
3789c2daa00SOllivier Robert 	 * simulate reading error, since the error is so small. This may
3799c2daa00SOllivier Robert 	 * change when the need comes to implement picosecond clocks.
3809c2daa00SOllivier Robert 	 */
3819c2daa00SOllivier Robert 	if (ntp_node.ntp_time == ntp_node.last_time)
3829c2daa00SOllivier Robert 		ntp_node.ntp_time += 200e-9;
3839c2daa00SOllivier Robert 	ntp_node.last_time = ntp_node.ntp_time;
3849c2daa00SOllivier Robert 	DTOLFP(ntp_node.ntp_time, now);
3859c2daa00SOllivier Robert }
3869c2daa00SOllivier Robert 
3879c2daa00SOllivier Robert 
3889c2daa00SOllivier Robert /*
3899c2daa00SOllivier Robert  * adj_systime - advance or retard the system clock exactly like the
3909c2daa00SOllivier Robert  * real thng.
3919c2daa00SOllivier Robert  */
3929c2daa00SOllivier Robert int				/* always succeeds */
3939c2daa00SOllivier Robert adj_systime(
3949c2daa00SOllivier Robert         double now		/* time adjustment (s) */
3959c2daa00SOllivier Robert         )
3969c2daa00SOllivier Robert {
3979c2daa00SOllivier Robert 	struct timeval adjtv;	/* new adjustment */
3989c2daa00SOllivier Robert 	double	dtemp;
3999c2daa00SOllivier Robert 	long	ticks;
4009c2daa00SOllivier Robert 	int	isneg = 0;
4019c2daa00SOllivier Robert 
4029c2daa00SOllivier Robert 	/*
4039c2daa00SOllivier Robert 	 * Most Unix adjtime() implementations adjust the system clock
4049c2daa00SOllivier Robert 	 * in microsecond quanta, but some adjust in 10-ms quanta. We
4059c2daa00SOllivier Robert 	 * carefully round the adjustment to the nearest quantum, then
4069c2daa00SOllivier Robert 	 * adjust in quanta and keep the residue for later.
4079c2daa00SOllivier Robert 	 */
4089c2daa00SOllivier Robert 	dtemp = now + sys_residual;
4099c2daa00SOllivier Robert 	if (dtemp < 0) {
4109c2daa00SOllivier Robert 		isneg = 1;
4119c2daa00SOllivier Robert 		dtemp = -dtemp;
4129c2daa00SOllivier Robert 	}
4139c2daa00SOllivier Robert 	adjtv.tv_sec = (long)dtemp;
4149c2daa00SOllivier Robert 	dtemp -= adjtv.tv_sec;
4159c2daa00SOllivier Robert 	ticks = (long)(dtemp / sys_tick + .5);
4169c2daa00SOllivier Robert 	adjtv.tv_usec = (long)(ticks * sys_tick * 1e6);
4179c2daa00SOllivier Robert 	dtemp -= adjtv.tv_usec / 1e6;
4189c2daa00SOllivier Robert 	sys_residual = dtemp;
4199c2daa00SOllivier Robert 
4209c2daa00SOllivier Robert 	/*
4219c2daa00SOllivier Robert 	 * Convert to signed seconds and microseconds for the Unix
4229c2daa00SOllivier Robert 	 * adjtime() system call. Note we purposely lose the adjtime()
4239c2daa00SOllivier Robert 	 * leftover.
4249c2daa00SOllivier Robert 	 */
4259c2daa00SOllivier Robert 	if (isneg) {
4269c2daa00SOllivier Robert 		adjtv.tv_sec = -adjtv.tv_sec;
4279c2daa00SOllivier Robert 		adjtv.tv_usec = -adjtv.tv_usec;
4289c2daa00SOllivier Robert 		sys_residual = -sys_residual;
4299c2daa00SOllivier Robert 	}
430ea906c41SOllivier Robert 	ntp_node.adj = now;
4319c2daa00SOllivier Robert 	return (1);
4329c2daa00SOllivier Robert }
4339c2daa00SOllivier Robert 
4349c2daa00SOllivier Robert 
4359c2daa00SOllivier Robert /*
4369c2daa00SOllivier Robert  * step_systime - step the system clock. We are religious here.
4379c2daa00SOllivier Robert  */
4389c2daa00SOllivier Robert int				/* always succeeds */
4399c2daa00SOllivier Robert step_systime(
4409c2daa00SOllivier Robert         double now		/* step adjustment (s) */
4419c2daa00SOllivier Robert         )
4429c2daa00SOllivier Robert {
443ea906c41SOllivier Robert #ifdef DEBUG
444ea906c41SOllivier Robert 	if (debug)
445ea906c41SOllivier Robert 		printf("step_systime: time %.6f adj %.6f\n",
446ea906c41SOllivier Robert 		   ntp_node.ntp_time, now);
447ea906c41SOllivier Robert #endif
448ea906c41SOllivier Robert 	ntp_node.ntp_time += now;
4499c2daa00SOllivier Robert 	return (1);
4509c2daa00SOllivier Robert }
4519c2daa00SOllivier Robert 
4529c2daa00SOllivier Robert /*
4539c2daa00SOllivier Robert  * node_clock - update the clocks
4549c2daa00SOllivier Robert  */
4559c2daa00SOllivier Robert int				/* always succeeds */
4569c2daa00SOllivier Robert node_clock(
4579c2daa00SOllivier Robert 	Node *n,		/* global node pointer */
4589c2daa00SOllivier Robert 	double t		/* node time */
4599c2daa00SOllivier Robert 	)
4609c2daa00SOllivier Robert {
4619c2daa00SOllivier Robert 	double	dtemp;
4629c2daa00SOllivier Robert 
4639c2daa00SOllivier Robert 	/*
4649c2daa00SOllivier Robert 	 * Advance client clock (ntp_time). Advance server clock
4659c2daa00SOllivier Robert 	 * (clk_time) adjusted for systematic and random frequency
4669c2daa00SOllivier Robert 	 * errors. The random error is a random walk computed as the
4679c2daa00SOllivier Robert 	 * integral of samples from a Gaussian distribution.
4689c2daa00SOllivier Robert 	 */
4699c2daa00SOllivier Robert 	dtemp = t - n->ntp_time;
4709c2daa00SOllivier Robert 	n->time = t;
4719c2daa00SOllivier Robert 	n->ntp_time += dtemp;
4729c2daa00SOllivier Robert 	n->ferr += gauss(0, dtemp * n->fnse);
4739c2daa00SOllivier Robert 	n->clk_time += dtemp * (1 + n->ferr);
4749c2daa00SOllivier Robert 
4759c2daa00SOllivier Robert 	/*
4769c2daa00SOllivier Robert 	 * Perform the adjtime() function. If the adjustment completed
4779c2daa00SOllivier Robert 	 * in the previous interval, amortize the entire amount; if not,
4789c2daa00SOllivier Robert 	 * carry the leftover to the next interval.
4799c2daa00SOllivier Robert 	 */
4809c2daa00SOllivier Robert 	dtemp *= n->slew;
4819c2daa00SOllivier Robert 	if (dtemp < fabs(n->adj)) {
4829c2daa00SOllivier Robert 		if (n->adj < 0) {
4839c2daa00SOllivier Robert 			n->adj += dtemp;
4849c2daa00SOllivier Robert 			n->ntp_time -= dtemp;
4859c2daa00SOllivier Robert 		} else {
4869c2daa00SOllivier Robert 			n->adj -= dtemp;
4879c2daa00SOllivier Robert 			n->ntp_time += dtemp;
4889c2daa00SOllivier Robert 		}
4899c2daa00SOllivier Robert 	} else {
4909c2daa00SOllivier Robert 		n->ntp_time += n->adj;
4919c2daa00SOllivier Robert 		n->adj = 0;
4929c2daa00SOllivier Robert 	}
4939c2daa00SOllivier Robert         return (0);
4949c2daa00SOllivier Robert }
4959c2daa00SOllivier Robert 
4969c2daa00SOllivier Robert 
4979c2daa00SOllivier Robert /*
4989c2daa00SOllivier Robert  * gauss() - returns samples from a gaussion distribution
4999c2daa00SOllivier Robert  */
5009c2daa00SOllivier Robert double				/* Gaussian sample */
5019c2daa00SOllivier Robert gauss(
5029c2daa00SOllivier Robert 	double m,		/* sample mean */
5039c2daa00SOllivier Robert 	double s		/* sample standard deviation (sigma) */
5049c2daa00SOllivier Robert 	)
5059c2daa00SOllivier Robert {
5069c2daa00SOllivier Robert         double q1, q2;
5079c2daa00SOllivier Robert 
5089c2daa00SOllivier Robert 	/*
5099c2daa00SOllivier Robert 	 * Roll a sample from a Gaussian distribution with mean m and
5109c2daa00SOllivier Robert 	 * standard deviation s. For m = 0, s = 1, mean(y) = 0,
5119c2daa00SOllivier Robert 	 * std(y) = 1.
5129c2daa00SOllivier Robert 	 */
5139c2daa00SOllivier Robert 	if (s == 0)
5149c2daa00SOllivier Robert 		return (m);
5159c2daa00SOllivier Robert         while ((q1 = drand48()) == 0);
5169c2daa00SOllivier Robert         q2 = drand48();
5179c2daa00SOllivier Robert         return (m + s * sqrt(-2. * log(q1)) * cos(2. * PI * q2));
5189c2daa00SOllivier Robert }
5199c2daa00SOllivier Robert 
5209c2daa00SOllivier Robert 
5219c2daa00SOllivier Robert /*
5229c2daa00SOllivier Robert  * poisson() - returns samples from a network delay distribution
5239c2daa00SOllivier Robert  */
5249c2daa00SOllivier Robert double				/* delay sample (s) */
5259c2daa00SOllivier Robert poisson(
5269c2daa00SOllivier Robert 	double m,		/* fixed propagation delay (s) */
5279c2daa00SOllivier Robert 	double s		/* exponential parameter (mu) */
5289c2daa00SOllivier Robert 	)
5299c2daa00SOllivier Robert {
5309c2daa00SOllivier Robert         double q1;
5319c2daa00SOllivier Robert 
5329c2daa00SOllivier Robert 	/*
5339c2daa00SOllivier Robert 	 * Roll a sample from a composite distribution with propagation
5349c2daa00SOllivier Robert 	 * delay m and exponential distribution time with parameter s.
5359c2daa00SOllivier Robert 	 * For m = 0, s = 1, mean(y) = std(y) = 1.
5369c2daa00SOllivier Robert 	 */
5379c2daa00SOllivier Robert 	if (s == 0)
5389c2daa00SOllivier Robert 		return (m);
5399c2daa00SOllivier Robert         while ((q1 = drand48()) == 0);
5409c2daa00SOllivier Robert         return (m - s * log(q1 * s));
5419c2daa00SOllivier Robert }
5429c2daa00SOllivier Robert #endif /* SIM */
543