2 * systime -- routines to fiddle a UNIX clock.
10 #include <sys/types.h>
12 #ifdef HAVE_SYS_PARAM_H
13 # include <sys/param.h>
17 #endif /* HAVE_UTMP_H */
20 #endif /* HAVE_UTMPX_H */
22 #include "ntp_machine.h"
24 #include "ntp_syslog.h"
25 #include "ntp_unixtime.h"
26 #include "ntp_stdlib.h"
28 int systime_10ms_ticks = 0; /* adj sysclock in 10ms increments */
30 #define MAXFREQ 500e-6
33 * These routines (init_systime, get_systime, step_systime, adj_systime)
34 * implement an interface between the (more or less) system independent
35 * bits of NTP and the peculiarities of dealing with the Unix system
38 double sys_residual = 0; /* residual from previous adjustment */
39 double sys_maxfreq = MAXFREQ; /* max frequency correction */
43 * get_systime - return the system time in timestamp format biased by
44 * the current time offset.
51 #if defined(HAVE_CLOCK_GETTIME) || defined(HAVE_GETCLOCK)
59 * We use nanosecond time if we can get it. Watch out for
60 * rounding wiggles, which may overflow the fraction.
62 #if defined(HAVE_CLOCK_GETTIME) || defined(HAVE_GETCLOCK)
63 # ifdef HAVE_CLOCK_GETTIME
64 (void) clock_gettime(CLOCK_REALTIME, &ts);
66 (void) getclock(TIMEOFDAY, &ts);
68 now->l_i = ts.tv_sec + JAN_1970;
69 dtemp = ts.tv_nsec * FRAC / 1e9;
72 now->l_uf = (u_int32)dtemp;
73 #else /* HAVE_CLOCK_GETTIME */
74 (void) GETTIMEOFDAY(&tv, (struct timezone *)0);
75 now->l_i = tv.tv_sec + JAN_1970;
77 #if defined RELIANTUNIX_CLOCK || defined SCO5_CLOCK
78 if (systime_10ms_ticks) {
79 /* fake better than 10ms resolution by interpolating
80 accumulated residual (in adj_systime(), see below) */
81 dtemp = tv.tv_usec / 1e6;
82 if (sys_residual < 5000e-6 && sys_residual > -5000e-6) {
83 dtemp += sys_residual;
93 dtemp = tv.tv_usec * FRAC / 1e6;
97 now->l_uf = (u_int32)dtemp;
98 #endif /* HAVE_CLOCK_GETTIME */
104 * adj_systime - called once every second to make system time adjustments.
105 * Returns 1 if okay, 0 if trouble.
107 #if !defined SYS_WINNT
114 struct timeval adjtv;
116 struct timeval oadjtv;
119 * Add the residual from the previous adjustment to the new
120 * adjustment, bound and round.
122 dtemp = sys_residual + now;
129 #if defined RELIANTUNIX_CLOCK || defined SCO5_CLOCK
130 if (systime_10ms_ticks) {
131 /* accumulate changes until we have enough to adjust a tick */
132 if (dtemp < 5000e-6) {
133 if (isneg) sys_residual = -dtemp;
134 else sys_residual = dtemp;
137 if (isneg) sys_residual = 10000e-6 - dtemp;
138 else sys_residual = dtemp - 10000e-6;
143 if (dtemp > sys_maxfreq)
146 dtemp = dtemp * 1e6 + .5;
151 adjtv.tv_usec = (int32)dtemp;
154 * Here we do the actual adjustment. If for some reason the adjtime()
155 * call fails, like it is not implemented or something like that,
156 * we honk to the log. If the previous adjustment did not complete,
157 * we correct the residual offset.
159 /* casey - we need a posix type thang here */
160 if (adjtime(&adjtv, &oadjtv) < 0)
162 msyslog(LOG_ERR, "Can't adjust time: %m");
166 sys_residual += oadjtv.tv_usec / 1e6;
170 printf("adj_systime: adj %.9f -> remaining residual %.9f\n", now, sys_residual);
178 * step_systime - step the system clock.
185 struct timeval timetv, adjtv, oldtimetv;
188 #if defined(HAVE_CLOCK_GETTIME) || defined(HAVE_GETCLOCK)
192 dtemp = sys_residual + now;
196 adjtv.tv_sec = (int32)dtemp;
197 adjtv.tv_usec = (u_int32)((dtemp - (double)adjtv.tv_sec) *
200 adjtv.tv_sec = (int32)dtemp;
201 adjtv.tv_usec = (u_int32)((dtemp - (double)adjtv.tv_sec) *
204 #if defined(HAVE_CLOCK_GETTIME) || defined(HAVE_GETCLOCK)
205 #ifdef HAVE_CLOCK_GETTIME
206 (void) clock_gettime(CLOCK_REALTIME, &ts);
208 (void) getclock(TIMEOFDAY, &ts);
210 timetv.tv_sec = ts.tv_sec;
211 timetv.tv_usec = ts.tv_nsec / 1000;
212 #else /* not HAVE_GETCLOCK */
213 (void) GETTIMEOFDAY(&timetv, (struct timezone *)0);
214 #endif /* not HAVE_GETCLOCK */
220 printf("step_systime: step %.6f residual %.6f\n", now, sys_residual);
223 timetv.tv_sec -= adjtv.tv_sec;
224 timetv.tv_usec -= adjtv.tv_usec;
225 if (timetv.tv_usec < 0) {
227 timetv.tv_usec += 1000000;
230 timetv.tv_sec += adjtv.tv_sec;
231 timetv.tv_usec += adjtv.tv_usec;
232 if (timetv.tv_usec >= 1000000) {
234 timetv.tv_usec -= 1000000;
237 if (ntp_set_tod(&timetv, (struct timezone *)0) != 0) {
238 msyslog(LOG_ERR, "Can't set time of day: %m");
243 #ifdef NEED_HPUX_ADJTIME
245 * CHECKME: is this correct when called by ntpdate?????
251 * FreeBSD, for example, has:
253 * char ut_line[UT_LINESIZE];
254 * char ut_name[UT_NAMESIZE];
255 * char ut_host[UT_HOSTSIZE];
258 * and appends line="|", name="date", host="", time for the OLD
259 * and appends line="{", name="date", host="", time for the NEW
262 * Some OSes have utmp, some have utmpx.
266 * Write old and new time entries in utmp and wtmp if step adjustment
267 * is greater than one second.
269 * This might become even Uglier...
271 if (oldtimetv.tv_sec != timetv.tv_sec)
281 memset((char *)&ut, 0, sizeof(ut));
284 memset((char *)&utx, 0, sizeof(utx));
290 # ifdef HAVE_PUTUTLINE
291 ut.ut_type = OLD_TIME;
292 (void)strcpy(ut.ut_line, OTIME_MSG);
293 ut.ut_time = oldtimetv.tv_sec;
296 ut.ut_type = NEW_TIME;
297 (void)strcpy(ut.ut_line, NTIME_MSG);
298 ut.ut_time = timetv.tv_sec;
301 # else /* not HAVE_PUTUTLINE */
302 # endif /* not HAVE_PUTUTLINE */
303 #endif /* UPDATE_UTMP */
308 # ifdef HAVE_PUTUTXLINE
309 utx.ut_type = OLD_TIME;
310 (void)strcpy(utx.ut_line, OTIME_MSG);
311 utx.ut_tv = oldtimetv;
314 utx.ut_type = NEW_TIME;
315 (void)strcpy(utx.ut_line, NTIME_MSG);
319 # else /* not HAVE_PUTUTXLINE */
320 # endif /* not HAVE_PUTUTXLINE */
321 #endif /* UPDATE_UTMPX */
326 # ifdef HAVE_PUTUTLINE
328 ut.ut_type = OLD_TIME;
329 (void)strcpy(ut.ut_line, OTIME_MSG);
330 ut.ut_time = oldtimetv.tv_sec;
332 ut.ut_type = NEW_TIME;
333 (void)strcpy(ut.ut_line, NTIME_MSG);
334 ut.ut_time = timetv.tv_sec;
337 # else /* not HAVE_PUTUTLINE */
338 # endif /* not HAVE_PUTUTLINE */
339 #endif /* UPDATE_WTMP */
344 # ifdef HAVE_PUTUTXLINE
345 utx.ut_type = OLD_TIME;
346 utx.ut_tv = oldtimetv;
347 (void)strcpy(utx.ut_line, OTIME_MSG);
348 # ifdef HAVE_UPDWTMPX
349 updwtmpx(WTMPX_FILE, &utx);
350 # else /* not HAVE_UPDWTMPX */
351 # endif /* not HAVE_UPDWTMPX */
352 # else /* not HAVE_PUTUTXLINE */
353 # endif /* not HAVE_PUTUTXLINE */
354 # ifdef HAVE_PUTUTXLINE
355 utx.ut_type = NEW_TIME;
357 (void)strcpy(utx.ut_line, NTIME_MSG);
358 # ifdef HAVE_UPDWTMPX
359 updwtmpx(WTMPX_FILE, &utx);
360 # else /* not HAVE_UPDWTMPX */
361 # endif /* not HAVE_UPDWTMPX */
362 # else /* not HAVE_PUTUTXLINE */
363 # endif /* not HAVE_PUTUTXLINE */
364 #endif /* UPDATE_WTMPX */