1 /* $NetBSD: ntptime.c,v 1.3 2006/03/18 02:35:47 elad Exp $ */
6 * This program tests to see if the NTP user interface routines
7 * ntp_gettime() and ntp_adjtime() have been implemented in the kernel.
8 * If so, each of these routines is called to display current timekeeping
11 * For more information, see the README.kern file in the doc directory
12 * of the xntp3 distribution.
17 #endif /* HAVE_CONFIG_H */
20 #include "ntp_unixtime.h"
21 #include "ntp_syscall.h"
22 #include "ntp_stdlib.h"
29 #ifdef NTP_SYSCALLS_STD
31 # define BADCALL -1 /* this is supposed to be a bad syscall */
32 # endif /* SYS_DECOSF1 */
35 #ifdef HAVE_STRUCT_NTPTIMEVAL_TIME_TV_NSEC
36 #define tv_frac_sec tv_nsec
38 #define tv_frac_sec tv_usec
42 #define TIMEX_MOD_BITS \
43 "\20\1OFFSET\2FREQUENCY\3MAXERROR\4ESTERROR\5STATUS\6TIMECONST\
44 \13PLL\14FLL\15MICRO\16NANO\17CLKB\20CLKA"
46 #define TIMEX_STA_BITS \
47 "\20\1PLL\2PPSFREQ\3PPSTIME\4FLL\5INS\6DEL\7UNSYNC\10FREQHOLD\
48 \11PPSSIGNAL\12PPSJITTER\13PPSWANDER\14PPSERROR\15CLOCKERR\
51 #define SCALE_FREQ 65536 /* frequency scale */
57 char *sprintb
P((u_int
, const char *));
58 const char *timex_state
P((int));
61 void pll_trap
P((int));
63 static struct sigaction newsigsys
; /* new sigaction status */
64 static struct sigaction sigsys
; /* current sigaction status */
65 static sigjmp_buf env
; /* environment var. for pll_trap() */
68 static volatile int pll_control
; /* (0) daemon, (1) kernel loop */
69 static volatile int status
; /* most recent status bits */
70 static volatile int flash
; /* most recent ntp_adjtime() bits */
72 static char optargs
[] = "MNT:cde:f:hm:o:rs:t:";
80 extern int ntp_optind
;
81 extern char *ntp_optarg
;
85 struct ntptimeval ntv
;
88 struct timex ntx
, _ntx
;
90 double ftemp
, gtemp
, htemp
;
91 long time_frac
; /* ntv.time.tv_frac_sec (us/ns) */
93 volatile unsigned ts_mask
= TS_MASK
; /* defaults to 20 bits (us) */
94 volatile unsigned ts_roundbit
= TS_ROUNDBIT
; /* defaults to 20 bits (us) */
95 volatile int fdigits
= 6; /* fractional digits for us */
99 volatile int rawtime
= 0;
101 memset((char *)&ntx
, 0, sizeof(ntx
));
103 while ((c
= ntp_getopt(argc
, argv
, optargs
)) != EOF
) switch (c
) {
106 ntx
.modes
|= MOD_MICRO
;
111 ntx
.modes
|= MOD_NANO
;
118 ntx
.constant
= atoi(ntp_optarg
);
126 ntx
.modes
|= MOD_ESTERROR
;
127 ntx
.esterror
= atoi(ntp_optarg
);
130 ntx
.modes
|= MOD_FREQUENCY
;
131 ntx
.freq
= (long)(atof(ntp_optarg
) * SCALE_FREQ
);
134 ntx
.modes
|= MOD_MAXERROR
;
135 ntx
.maxerror
= atoi(ntp_optarg
);
138 ntx
.modes
|= MOD_OFFSET
;
139 ntx
.offset
= atoi(ntp_optarg
);
145 ntx
.modes
|= MOD_STATUS
;
146 ntx
.status
= atoi(ntp_optarg
);
147 if (ntx
.status
< 0 || ntx
.status
>= 0x100) errflg
++;
150 ntx
.modes
|= MOD_TIMECONST
;
151 ntx
.constant
= atoi(ntp_optarg
);
156 if (errflg
|| (ntp_optind
!= argc
)) {
157 (void) fprintf(stderr
,
158 "usage: %s [-%s]\n\n\
160 -c display the time taken to call ntp_gettime (us)\n\
161 -e esterror estimate of the error (us)\n\
162 -f frequency Frequency error (-500 .. 500) (ppm)\n\
163 -h display this help info\n\
164 -m maxerror max possible error (us)\n\
165 -o offset current offset (ms)\n\
166 -r print the unix and NTP time raw\n\
167 -s status Set the status bits\n\
168 -t timeconstant log2 of PLL time constant (0 .. %d)\n",
171 "-M switch to microsecond mode\n",
176 "-N switch to nanosecond mode\n",
182 "-T tai_offset set TAI offset\n",
195 * Test to make sure the sigaction() works in case of invalid
198 newsigsys
.sa_handler
= pll_trap
;
199 newsigsys
.sa_flags
= 0;
200 if (sigaction(SIGSYS
, &newsigsys
, &sigsys
)) {
201 perror("sigaction() fails to save SIGSYS trap");
208 * Make sure the trapcatcher works.
212 if (sigsetjmp(env
, 1) == 0)
215 status
= syscall(BADCALL
, &ntv
); /* dummy parameter */
216 if ((status
< 0) && (errno
== ENOSYS
))
222 printf("sigaction() failed to catch an invalid syscall\n");
227 if (sigsetjmp(env
, 1) == 0) {
229 for (c
= 0; c
< sizeof times
/ sizeof times
[0]; c
++) {
230 status
= ntp_gettime(&ntv
);
231 if ((status
< 0) && (errno
== ENOSYS
))
235 times
[c
] = ntv
.time
.tv_frac_sec
;
240 if (pll_control
>= 0) {
241 printf("[ us %06d:", times
[0]);
242 for (c
= 1; c
< sizeof times
/ sizeof times
[0]; c
++)
243 printf(" %d", times
[c
] - times
[c
- 1]);
248 if (sigsetjmp(env
, 1) == 0) {
250 status
= ntp_gettime(&ntv
);
251 if ((status
< 0) && (errno
== ENOSYS
))
256 _ntx
.modes
= 0; /* Ensure nothing is set */
258 if (sigsetjmp(env
, 1) == 0) {
260 status
= ntp_adjtime(&_ntx
);
261 if ((status
< 0) && (errno
== ENOSYS
))
267 if (pll_control
< 0) {
268 printf("NTP user interface routines are not configured in this kernel.\n");
273 * Fetch timekeeping data and display.
275 status
= ntp_gettime(&ntv
);
277 perror("ntp_gettime() call fails");
279 printf("ntp_gettime() returns code %d (%s)\n",
280 status
, timex_state(status
));
281 time_frac
= ntv
.time
.tv_frac_sec
;
283 if (flash
& STA_NANO
) {
284 ntv
.time
.tv_frac_sec
/= 1000;
285 ts_mask
= 0xfffffffc; /* 1/2^30 */
286 ts_roundbit
= 0x00000002;
290 tv
.tv_sec
= ntv
.time
.tv_sec
;
291 tv
.tv_usec
= ntv
.time
.tv_frac_sec
;
294 ts
.l_uf
+= ts_roundbit
;
296 printf(" time %s, (.%0*d),\n",
297 prettydate(&ts
), fdigits
, (int) time_frac
);
298 printf(" maximum error %lu us, estimated error %lu us",
299 (u_long
)ntv
.maxerror
, (u_long
)ntv
.esterror
);
301 printf(" ntptime=%x.%x unixtime=%x.%0*d %s",
302 (unsigned int) ts
.l_ui
, (unsigned int) ts
.l_uf
,
303 (int) ntv
.time
.tv_sec
, fdigits
, (int) time_frac
,
304 ctime((const time_t *) &ntv
.time
.tv_sec
));
306 printf(", TAI offset %ld\n", (long)ntv
.tai
);
311 status
= ntp_adjtime(&ntx
);
313 perror((errno
== EPERM
) ?
314 "Must be root to set kernel values\nntp_adjtime() call fails" :
315 "ntp_adjtime() call fails");
318 printf("ntp_adjtime() returns code %d (%s)\n",
319 status
, timex_state(status
));
320 printf(" modes %s,\n", sprintb(ntx
.modes
, TIMEX_MOD_BITS
));
321 ftemp
= (double)ntx
.offset
;
323 if (flash
& STA_NANO
)
326 printf(" offset %.3f", ftemp
);
327 ftemp
= (double)ntx
.freq
/ SCALE_FREQ
;
328 printf(" us, frequency %.3f ppm, interval %d s,\n",
329 ftemp
, 1 << ntx
.shift
);
330 printf(" maximum error %lu us, estimated error %lu us,\n",
331 (u_long
)ntx
.maxerror
, (u_long
)ntx
.esterror
);
332 printf(" status %s,\n", sprintb((u_int
)ntx
.status
, TIMEX_STA_BITS
));
333 ftemp
= (double)ntx
.tolerance
/ SCALE_FREQ
;
334 gtemp
= (double)ntx
.precision
;
336 if (flash
& STA_NANO
)
340 " time constant %lu, precision %.3f us, tolerance %.0f ppm,\n",
341 (u_long
)ntx
.constant
, gtemp
, ftemp
);
344 ftemp
= (double)ntx
.ppsfreq
/ SCALE_FREQ
;
345 gtemp
= (double)ntx
.stabil
/ SCALE_FREQ
;
346 htemp
= (double)ntx
.jitter
;
348 if (flash
& STA_NANO
)
352 " pps frequency %.3f ppm, stability %.3f ppm, jitter %.3f us,\n",
353 ftemp
, gtemp
, htemp
);
354 printf(" intervals %lu, jitter exceeded %lu, stability exceeded %lu, errors %lu.\n",
355 (u_long
)ntx
.calcnt
, (u_long
)ntx
.jitcnt
,
356 (u_long
)ntx
.stbcnt
, (u_long
)ntx
.errcnt
);
361 * Put things back together the way we found them.
365 if (sigaction(SIGSYS
, &sigsys
, (struct sigaction
*)NULL
)) {
366 perror("sigaction() fails to restore SIGSYS trap");
375 * pll_trap - trap processor for undefined syscalls
388 * Print a value a la the %b format of the kernel's printf
393 register const char *bits
397 register int i
, any
= 0;
399 static char buf
[132];
401 if (bits
&& *bits
== 8)
402 (void)sprintf(buf
, "0%o", v
);
404 (void)sprintf(buf
, "0x%x", v
);
405 cp
= buf
+ strlen(buf
);
410 while ((i
= *bits
++) != 0) {
411 if (v
& (1 << (i
-1))) {
415 for (; (c
= *bits
) > 32; bits
++)
418 for (; *bits
> 32; bits
++)
427 const char *timex_states
[] = {
428 "OK", "INS", "DEL", "OOP", "WAIT", "ERROR"
438 if (s
>= 0 && s
< sizeof(timex_states
) / sizeof(timex_states
[0]))
439 return (timex_states
[s
]);
440 sprintf(buf
, "TIME-#%d", s
);