]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/ntp/libntp/systime.c
unfinished sblive driver, playback/mixer only for now - not enabled in
[FreeBSD/FreeBSD.git] / contrib / ntp / libntp / systime.c
1 /*
2  * systime -- routines to fiddle a UNIX clock.
3  */
4
5 #ifdef HAVE_CONFIG_H
6 # include <config.h>
7 #endif
8
9 #include <stdio.h>
10 #include <sys/types.h>
11 #include <sys/time.h>
12 #ifdef HAVE_SYS_PARAM_H
13 # include <sys/param.h>
14 #endif
15 #ifdef HAVE_UTMP_H
16 # include <utmp.h>
17 #endif /* HAVE_UTMP_H */
18 #ifdef HAVE_UTMPX_H
19 # include <utmpx.h>
20 #endif /* HAVE_UTMPX_H */
21
22 #include "ntp_machine.h"
23 #include "ntp_fp.h"
24 #include "ntp_syslog.h"
25 #include "ntp_unixtime.h"
26 #include "ntp_stdlib.h"
27
28 int     systime_10ms_ticks = 0; /* adj sysclock in 10ms increments */
29
30 #define MAXFREQ 500e-6
31
32 /*
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
36  * clock.
37  */
38 double sys_residual = 0;        /* residual from previous adjustment */
39 double sys_maxfreq = MAXFREQ;   /* max frequency correction */
40
41
42 /*
43  * get_systime - return the system time in timestamp format biased by
44  * the current time offset.
45  */
46 void
47 get_systime(
48         l_fp *now
49         )
50 {
51 #if defined(HAVE_CLOCK_GETTIME) || defined(HAVE_GETCLOCK)
52         struct timespec ts;
53 #else
54         struct timeval tv;
55 #endif
56         double dtemp;
57
58         /*
59          * We use nanosecond time if we can get it. Watch out for
60          * rounding wiggles, which may overflow the fraction.
61          */
62 #if defined(HAVE_CLOCK_GETTIME) || defined(HAVE_GETCLOCK)
63 # ifdef HAVE_CLOCK_GETTIME
64         (void) clock_gettime(CLOCK_REALTIME, &ts);
65 # else
66         (void) getclock(TIMEOFDAY, &ts);
67 # endif
68         now->l_i = ts.tv_sec + JAN_1970;
69         dtemp = ts.tv_nsec * FRAC / 1e9;
70         if (dtemp >= FRAC)
71                 now->l_i++;
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;
76
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;
84                         if (dtemp < 0) {
85                                 now->l_i--;
86                                 dtemp++;
87                         }
88                 }
89                 dtemp *= FRAC;
90         } else
91 #endif
92
93         dtemp = tv.tv_usec * FRAC / 1e6;
94
95         if (dtemp >= FRAC)
96                 now->l_i++;
97         now->l_uf = (u_int32)dtemp;
98 #endif /* HAVE_CLOCK_GETTIME */
99
100 }
101
102
103 /*
104  * adj_systime - called once every second to make system time adjustments.
105  * Returns 1 if okay, 0 if trouble.
106  */
107 #if !defined SYS_WINNT
108 int
109 adj_systime(
110         double now
111         )
112 {
113         double dtemp;
114         struct timeval adjtv;
115         u_char isneg = 0;
116         struct timeval oadjtv;
117
118         /*
119          * Add the residual from the previous adjustment to the new
120          * adjustment, bound and round.
121          */
122         dtemp = sys_residual + now;
123         sys_residual = 0;
124         if (dtemp < 0) {
125                 isneg = 1;
126                 dtemp = -dtemp;
127         }
128
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;
135                         dtemp = 0;
136                 } else {
137                         if (isneg) sys_residual = 10000e-6 - dtemp;
138                         else sys_residual = dtemp - 10000e-6;
139                         dtemp = 10000e-6;
140                 }
141         } else 
142 #endif
143                 if (dtemp > sys_maxfreq)
144                         dtemp = sys_maxfreq;
145
146         dtemp = dtemp * 1e6 + .5;
147
148         if (isneg)
149                 dtemp = -dtemp;
150         adjtv.tv_sec = 0;
151         adjtv.tv_usec = (int32)dtemp;
152
153         /*
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.
158          */
159         /* casey - we need a posix type thang here */
160         if (adjtime(&adjtv, &oadjtv) < 0)
161         {
162                 msyslog(LOG_ERR, "Can't adjust time: %m");
163                 return 0;
164         } 
165         else {
166         sys_residual += oadjtv.tv_usec / 1e6;
167         }
168 #ifdef DEBUG
169         if (debug > 6)
170                 printf("adj_systime: adj %.9f -> remaining residual %.9f\n", now, sys_residual);
171 #endif
172         return 1;
173 }
174 #endif
175
176
177 /*
178  * step_systime - step the system clock.
179  */
180 int
181 step_systime(
182         double now
183         )
184 {
185         struct timeval timetv, adjtv, oldtimetv;
186         int isneg = 0;
187         double dtemp;
188 #if defined(HAVE_CLOCK_GETTIME) || defined(HAVE_GETCLOCK)
189         struct timespec ts;
190 #endif
191
192         dtemp = sys_residual + now;
193         if (dtemp < 0) {
194                 isneg = 1;
195                 dtemp = - dtemp;
196                 adjtv.tv_sec = (int32)dtemp;
197                 adjtv.tv_usec = (u_int32)((dtemp - (double)adjtv.tv_sec) *
198                                           1e6 + .5);
199         } else {
200                 adjtv.tv_sec = (int32)dtemp;
201                 adjtv.tv_usec = (u_int32)((dtemp - (double)adjtv.tv_sec) *
202                                           1e6 + .5);
203         }
204 #if defined(HAVE_CLOCK_GETTIME) || defined(HAVE_GETCLOCK)
205 #ifdef HAVE_CLOCK_GETTIME
206         (void) clock_gettime(CLOCK_REALTIME, &ts);
207 #else
208         (void) getclock(TIMEOFDAY, &ts);
209 #endif
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 */
215
216         oldtimetv = timetv;
217
218 #ifdef DEBUG
219         if (debug)
220                 printf("step_systime: step %.6f residual %.6f\n", now, sys_residual);
221 #endif
222         if (isneg) {
223                 timetv.tv_sec -= adjtv.tv_sec;
224                 timetv.tv_usec -= adjtv.tv_usec;
225                 if (timetv.tv_usec < 0) {
226                         timetv.tv_sec--;
227                         timetv.tv_usec += 1000000;
228                 }
229         } else {
230                 timetv.tv_sec += adjtv.tv_sec;
231                 timetv.tv_usec += adjtv.tv_usec;
232                 if (timetv.tv_usec >= 1000000) {
233                         timetv.tv_sec++;
234                         timetv.tv_usec -= 1000000;
235                 }
236         }
237         if (ntp_set_tod(&timetv, (struct timezone *)0) != 0) {
238                 msyslog(LOG_ERR, "Can't set time of day: %m");
239                 return (0);
240         }
241         sys_residual = 0;
242
243 #ifdef NEED_HPUX_ADJTIME
244         /*
245          * CHECKME: is this correct when called by ntpdate?????
246          */
247         _clear_adjtime();
248 #endif
249
250         /*
251          * FreeBSD, for example, has:
252          * struct utmp {
253          *         char    ut_line[UT_LINESIZE];
254          *         char    ut_name[UT_NAMESIZE];
255          *         char    ut_host[UT_HOSTSIZE];
256          *         long    ut_time;
257          * };
258          * and appends line="|", name="date", host="", time for the OLD
259          * and appends line="{", name="date", host="", time for the NEW
260          * to _PATH_WTMP .
261          *
262          * Some OSes have utmp, some have utmpx.
263          */
264
265         /*
266          * Write old and new time entries in utmp and wtmp if step adjustment
267          * is greater than one second.
268          *
269          * This might become even Uglier...
270          */
271         if (oldtimetv.tv_sec != timetv.tv_sec)
272         {
273 #ifdef HAVE_UTMP_H
274                 struct utmp ut;
275 #endif
276 #ifdef HAVE_UTMPX_H
277                 struct utmpx utx;
278 #endif
279
280 #ifdef HAVE_UTMP_H
281                 memset((char *)&ut, 0, sizeof(ut));
282 #endif
283 #ifdef HAVE_UTMPX_H
284                 memset((char *)&utx, 0, sizeof(utx));
285 #endif
286
287                 /* UTMP */
288
289 #ifdef UPDATE_UTMP
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;
294                 pututline(&ut);
295                 setutent();
296                 ut.ut_type = NEW_TIME;
297                 (void)strcpy(ut.ut_line, NTIME_MSG);
298                 ut.ut_time = timetv.tv_sec;
299                 pututline(&ut);
300                 endutent();
301 # else /* not HAVE_PUTUTLINE */
302 # endif /* not HAVE_PUTUTLINE */
303 #endif /* UPDATE_UTMP */
304
305                 /* UTMPX */
306
307 #ifdef UPDATE_UTMPX
308 # ifdef HAVE_PUTUTXLINE
309                 utx.ut_type = OLD_TIME;
310                 (void)strcpy(utx.ut_line, OTIME_MSG);
311                 utx.ut_tv = oldtimetv;
312                 pututxline(&utx);
313                 setutxent();
314                 utx.ut_type = NEW_TIME;
315                 (void)strcpy(utx.ut_line, NTIME_MSG);
316                 utx.ut_tv = timetv;
317                 pututxline(&utx);
318                 endutxent();
319 # else /* not HAVE_PUTUTXLINE */
320 # endif /* not HAVE_PUTUTXLINE */
321 #endif /* UPDATE_UTMPX */
322
323                 /* WTMP */
324
325 #ifdef UPDATE_WTMP
326 # ifdef HAVE_PUTUTLINE
327                 utmpname(WTMP_FILE);
328                 ut.ut_type = OLD_TIME;
329                 (void)strcpy(ut.ut_line, OTIME_MSG);
330                 ut.ut_time = oldtimetv.tv_sec;
331                 pututline(&ut);
332                 ut.ut_type = NEW_TIME;
333                 (void)strcpy(ut.ut_line, NTIME_MSG);
334                 ut.ut_time = timetv.tv_sec;
335                 pututline(&ut);
336                 endutent();
337 # else /* not HAVE_PUTUTLINE */
338 # endif /* not HAVE_PUTUTLINE */
339 #endif /* UPDATE_WTMP */
340
341                 /* WTMPX */
342
343 #ifdef UPDATE_WTMPX
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;
356                 utx.ut_tv = timetv;
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 */
365
366         }
367         return (1);
368 }