1: /*
2: * systime -- routines to fiddle a UNIX clock.
3: *
4: * ATTENTION: Get approval from Dave Mills on all changes to this file!
5: *
6: */
7: #include "ntp_machine.h"
8: #include "ntp_fp.h"
9: #include "ntp_syslog.h"
10: #include "ntp_unixtime.h"
11: #include "ntp_stdlib.h"
12: #include "ntp_random.h"
13: #include "ntpd.h" /* for sys_precision */
14:
15: #ifdef HAVE_SYS_PARAM_H
16: # include <sys/param.h>
17: #endif
18: #ifdef HAVE_UTMP_H
19: # include <utmp.h>
20: #endif /* HAVE_UTMP_H */
21: #ifdef HAVE_UTMPX_H
22: # include <utmpx.h>
23: #endif /* HAVE_UTMPX_H */
24:
25:
26: #define FUZZ 500e-6 /* fuzz pivot */
27:
28: /*
29: * These routines (get_systime, step_systime, adj_systime) implement an
30: * interface between the system independent NTP clock and the Unix
31: * system clock in various architectures and operating systems. Time is
32: * a precious quantity in these routines and every effort is made to
33: * minimize errors by unbiased rounding and amortizing adjustment
34: * residues.
35: *
36: * In order to improve the apparent resolution, provide unbiased
37: * rounding and insure that the readings cannot be predicted, the low-
38: * order unused portion of the time below the resolution limit is filled
39: * with an unbiased random fuzz.
40: *
41: * The sys_tick variable secifies the system clock tick interval in
42: * seconds. For systems that can interpolate between timer interrupts,
43: * the resolution is presumed much less than the time to read the system
44: * clock, which is the value of sys_tick after the precision has been
45: * determined. For those systems that cannot interpolate between timer
46: * interrupts, sys_tick will be much larger in the order of 10 ms, so the
47: * fuzz should be that value. For Sunses the tick is not interpolated, but
48: * the system clock is derived from a 2-MHz oscillator, so the resolution
49: * is 500 ns and sys_tick is 500 ns.
50: */
51: double sys_tick = 0; /* precision (time to read the clock) */
52: double sys_residual = 0; /* adjustment residue (s) */
53:
54: #ifndef SIM
55:
56: /*
57: * get_systime - return system time in NTP timestamp format.
58: */
59: void
60: get_systime(
61: l_fp *now /* system time */
62: )
63: {
64: double dtemp;
65:
66: #if defined(HAVE_CLOCK_GETTIME) || defined(HAVE_GETCLOCK)
67: struct timespec ts; /* seconds and nanoseconds */
68:
69: /*
70: * Convert Unix timespec from seconds and nanoseconds to NTP
71: * seconds and fraction.
72: */
73: # ifdef HAVE_CLOCK_GETTIME
74: clock_gettime(CLOCK_REALTIME, &ts);
75: # else
76: getclock(TIMEOFDAY, &ts);
77: # endif
78: now->l_i = (int32)ts.tv_sec + JAN_1970;
79: dtemp = 0;
80: if (sys_tick > FUZZ)
81: dtemp = ntp_random() * 2. / FRAC * sys_tick * 1e9;
82: else if (sys_tick > 0)
83: dtemp = ntp_random() * 2. / FRAC;
84: dtemp = (ts.tv_nsec + dtemp) * 1e-9;
85: if (dtemp >= 1.) {
86: dtemp -= 1.;
87: now->l_i++;
88: } else if (dtemp < 0) {
89: dtemp += 1.;
90: now->l_i--;
91: }
92: now->l_uf = (u_int32)(dtemp * FRAC);
93:
94: #else /* HAVE_CLOCK_GETTIME || HAVE_GETCLOCK */
95: struct timeval tv; /* seconds and microseconds */
96:
97: /*
98: * Convert Unix timeval from seconds and microseconds to NTP
99: * seconds and fraction.
100: */
101: GETTIMEOFDAY(&tv, NULL);
102: now->l_i = tv.tv_sec + JAN_1970;
103: dtemp = 0;
104: if (sys_tick > FUZZ)
105: dtemp = ntp_random() * 2. / FRAC * sys_tick * 1e6;
106: else if (sys_tick > 0)
107: dtemp = ntp_random() * 2. / FRAC;
108: dtemp = (tv.tv_usec + dtemp) * 1e-6;
109: if (dtemp >= 1.) {
110: dtemp -= 1.;
111: now->l_i++;
112: } else if (dtemp < 0) {
113: dtemp += 1.;
114: now->l_i--;
115: }
116: now->l_uf = (u_int32)(dtemp * FRAC);
117:
118: #endif /* HAVE_CLOCK_GETTIME || HAVE_GETCLOCK */
119: }
120:
121:
122: /*
123: * adj_systime - adjust system time by the argument.
124: */
125: #if !defined SYS_WINNT
126: int /* 0 okay, 1 error */
127: adj_systime(
128: double now /* adjustment (s) */
129: )
130: {
131: struct timeval adjtv; /* new adjustment */
132: struct timeval oadjtv; /* residual adjustment */
133: double dtemp;
134: long ticks;
135: int isneg = 0;
136:
137: /*
138: * Most Unix adjtime() implementations adjust the system clock
139: * in microsecond quanta, but some adjust in 10-ms quanta. We
140: * carefully round the adjustment to the nearest quantum, then
141: * adjust in quanta and keep the residue for later.
142: */
143: dtemp = now + sys_residual;
144: if (dtemp < 0) {
145: isneg = 1;
146: dtemp = -dtemp;
147: }
148: adjtv.tv_sec = (long)dtemp;
149: dtemp -= adjtv.tv_sec;
150: ticks = (long)(dtemp / sys_tick + .5);
151: adjtv.tv_usec = (long)(ticks * sys_tick * 1e6);
152: dtemp -= adjtv.tv_usec / 1e6;
153: sys_residual = dtemp;
154:
155: /*
156: * Convert to signed seconds and microseconds for the Unix
157: * adjtime() system call. Note we purposely lose the adjtime()
158: * leftover.
159: */
160: if (isneg) {
161: adjtv.tv_sec = -adjtv.tv_sec;
162: adjtv.tv_usec = -adjtv.tv_usec;
163: sys_residual = -sys_residual;
164: }
165: if (adjtv.tv_sec != 0 || adjtv.tv_usec != 0) {
166: if (adjtime(&adjtv, &oadjtv) < 0) {
167: msyslog(LOG_ERR, "adj_systime: %m");
168: return (0);
169: }
170: }
171: return (1);
172: }
173: #endif
174:
175:
176: /*
177: * step_systime - step the system clock.
178: */
179: int
180: step_systime(
181: double now
182: )
183: {
184: struct timeval timetv, adjtv, oldtimetv;
185: int isneg = 0;
186: double dtemp;
187: #if defined(HAVE_CLOCK_GETTIME) || defined(HAVE_GETCLOCK)
188: struct timespec ts;
189: #endif
190:
191: dtemp = sys_residual + now;
192: if (dtemp < 0) {
193: isneg = 1;
194: dtemp = - dtemp;
195: adjtv.tv_sec = (int32)dtemp;
196: adjtv.tv_usec = (u_int32)((dtemp -
197: (double)adjtv.tv_sec) * 1e6 + .5);
198: } else {
199: adjtv.tv_sec = (int32)dtemp;
200: adjtv.tv_usec = (u_int32)((dtemp -
201: (double)adjtv.tv_sec) * 1e6 + .5);
202: }
203: #if defined(HAVE_CLOCK_GETTIME) || defined(HAVE_GETCLOCK)
204: # ifdef HAVE_CLOCK_GETTIME
205: (void) clock_gettime(CLOCK_REALTIME, &ts);
206: # else
207: (void) getclock(TIMEOFDAY, &ts);
208: # endif
209: timetv.tv_sec = ts.tv_sec;
210: timetv.tv_usec = ts.tv_nsec / 1000;
211: #else /* not HAVE_GETCLOCK */
212: (void) GETTIMEOFDAY(&timetv, (struct timezone *)0);
213: #endif /* not HAVE_GETCLOCK */
214:
215: oldtimetv = timetv;
216:
217: #ifdef DEBUG
218: if (debug)
219: printf("step_systime: step %.6f residual %.6f\n", now, sys_residual);
220: #endif
221: if (isneg) {
222: timetv.tv_sec -= adjtv.tv_sec;
223: timetv.tv_usec -= adjtv.tv_usec;
224: if (timetv.tv_usec < 0) {
225: timetv.tv_sec--;
226: timetv.tv_usec += 1000000;
227: }
228: } else {
229: timetv.tv_sec += adjtv.tv_sec;
230: timetv.tv_usec += adjtv.tv_usec;
231: if (timetv.tv_usec >= 1000000) {
232: timetv.tv_sec++;
233: timetv.tv_usec -= 1000000;
234: }
235: }
236: if (ntp_set_tod(&timetv, NULL) != 0) {
237: msyslog(LOG_ERR, "step-systime: %m");
238: return (0);
239: }
240: sys_residual = 0;
241:
242: #ifdef NEED_HPUX_ADJTIME
243: /*
244: * CHECKME: is this correct when called by ntpdate?????
245: */
246: _clear_adjtime();
247: #endif
248:
249: /*
250: * FreeBSD, for example, has:
251: * struct utmp {
252: * char ut_line[UT_LINESIZE];
253: * char ut_name[UT_NAMESIZE];
254: * char ut_host[UT_HOSTSIZE];
255: * long ut_time;
256: * };
257: * and appends line="|", name="date", host="", time for the OLD
258: * and appends line="{", name="date", host="", time for the NEW
259: * to _PATH_WTMP .
260: *
261: * Some OSes have utmp, some have utmpx.
262: */
263:
264: /*
265: * Write old and new time entries in utmp and wtmp if step
266: * adjustment is greater than one second.
267: *
268: * This might become even Uglier...
269: */
270: if (oldtimetv.tv_sec != timetv.tv_sec)
271: {
272: #ifdef HAVE_UTMP_H
273: struct utmp ut;
274: #endif
275: #ifdef HAVE_UTMPX_H
276: struct utmpx utx;
277: #endif
278:
279: #ifdef HAVE_UTMP_H
280: memset((char *)&ut, 0, sizeof(ut));
281: #endif
282: #ifdef HAVE_UTMPX_H
283: memset((char *)&utx, 0, sizeof(utx));
284: #endif
285:
286: /* UTMP */
287:
288: #ifdef UPDATE_UTMP
289: # ifdef HAVE_PUTUTLINE
290: ut.ut_type = OLD_TIME;
291: (void)strcpy(ut.ut_line, OTIME_MSG);
292: ut.ut_time = oldtimetv.tv_sec;
293: pututline(&ut);
294: setutent();
295: ut.ut_type = NEW_TIME;
296: (void)strcpy(ut.ut_line, NTIME_MSG);
297: ut.ut_time = timetv.tv_sec;
298: pututline(&ut);
299: endutent();
300: # else /* not HAVE_PUTUTLINE */
301: # endif /* not HAVE_PUTUTLINE */
302: #endif /* UPDATE_UTMP */
303:
304: /* UTMPX */
305:
306: #ifdef UPDATE_UTMPX
307: # ifdef HAVE_PUTUTXLINE
308: utx.ut_type = OLD_TIME;
309: (void)strcpy(utx.ut_line, OTIME_MSG);
310: utx.ut_tv = oldtimetv;
311: pututxline(&utx);
312: setutxent();
313: utx.ut_type = NEW_TIME;
314: (void)strcpy(utx.ut_line, NTIME_MSG);
315: utx.ut_tv = timetv;
316: pututxline(&utx);
317: endutxent();
318: # else /* not HAVE_PUTUTXLINE */
319: # endif /* not HAVE_PUTUTXLINE */
320: #endif /* UPDATE_UTMPX */
321:
322: /* WTMP */
323:
324: #ifdef UPDATE_WTMP
325: # ifdef HAVE_PUTUTLINE
326: utmpname(WTMP_FILE);
327: ut.ut_type = OLD_TIME;
328: (void)strcpy(ut.ut_line, OTIME_MSG);
329: ut.ut_time = oldtimetv.tv_sec;
330: pututline(&ut);
331: ut.ut_type = NEW_TIME;
332: (void)strcpy(ut.ut_line, NTIME_MSG);
333: ut.ut_time = timetv.tv_sec;
334: pututline(&ut);
335: endutent();
336: # else /* not HAVE_PUTUTLINE */
337: # endif /* not HAVE_PUTUTLINE */
338: #endif /* UPDATE_WTMP */
339:
340: /* WTMPX */
341:
342: #ifdef UPDATE_WTMPX
343: # ifdef HAVE_PUTUTXLINE
344: utx.ut_type = OLD_TIME;
345: utx.ut_tv = oldtimetv;
346: (void)strcpy(utx.ut_line, OTIME_MSG);
347: # ifdef HAVE_UPDWTMPX
348: updwtmpx(WTMPX_FILE, &utx);
349: # else /* not HAVE_UPDWTMPX */
350: # endif /* not HAVE_UPDWTMPX */
351: # else /* not HAVE_PUTUTXLINE */
352: # endif /* not HAVE_PUTUTXLINE */
353: # ifdef HAVE_PUTUTXLINE
354: utx.ut_type = NEW_TIME;
355: utx.ut_tv = timetv;
356: (void)strcpy(utx.ut_line, NTIME_MSG);
357: # ifdef HAVE_UPDWTMPX
358: updwtmpx(WTMPX_FILE, &utx);
359: # else /* not HAVE_UPDWTMPX */
360: # endif /* not HAVE_UPDWTMPX */
361: # else /* not HAVE_PUTUTXLINE */
362: # endif /* not HAVE_PUTUTXLINE */
363: #endif /* UPDATE_WTMPX */
364:
365: }
366: return (1);
367: }
368:
369: #else /* SIM */
370: /*
371: * Clock routines for the simulator - Harish Nair, with help
372: */
373:
374:
375: /* SK:
376: * The code that used to be here has been moved to ntpsim.c,
377: * where, IMHO, it rightfully belonged.
378: */
379:
380: #endif
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>