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 (u_int
, const char *);
58 const char *timex_state (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 volatile int debug
; /* for libntp */
73 static char optargs
[] = "MNT:cde:f:hm:o:rs:t:";
81 extern int ntp_optind
;
82 extern char *ntp_optarg
;
86 struct ntptimeval ntv
;
89 struct timex ntx
, _ntx
;
91 double ftemp
, gtemp
, htemp
;
92 long time_frac
; /* ntv.time.tv_frac_sec (us/ns) */
94 volatile unsigned ts_mask
= TS_MASK
; /* defaults to 20 bits (us) */
95 volatile unsigned ts_roundbit
= TS_ROUNDBIT
; /* defaults to 20 bits (us) */
96 volatile int fdigits
= 6; /* fractional digits for us */
100 volatile int rawtime
= 0;
102 memset((char *)&ntx
, 0, sizeof(ntx
));
104 while ((c
= ntp_getopt(argc
, argv
, optargs
)) != EOF
) switch (c
) {
107 ntx
.modes
|= MOD_MICRO
;
112 ntx
.modes
|= MOD_NANO
;
119 ntx
.constant
= atoi(ntp_optarg
);
127 ntx
.modes
|= MOD_ESTERROR
;
128 ntx
.esterror
= atoi(ntp_optarg
);
131 ntx
.modes
|= MOD_FREQUENCY
;
132 ntx
.freq
= (long)(atof(ntp_optarg
) * SCALE_FREQ
);
135 ntx
.modes
|= MOD_MAXERROR
;
136 ntx
.maxerror
= atoi(ntp_optarg
);
139 ntx
.modes
|= MOD_OFFSET
;
140 ntx
.offset
= atoi(ntp_optarg
);
146 ntx
.modes
|= MOD_STATUS
;
147 ntx
.status
= atoi(ntp_optarg
);
148 if (ntx
.status
< 0 || ntx
.status
>= 0x100) errflg
++;
151 ntx
.modes
|= MOD_TIMECONST
;
152 ntx
.constant
= atoi(ntp_optarg
);
157 if (errflg
|| (ntp_optind
!= argc
)) {
158 (void) fprintf(stderr
,
159 "usage: %s [-%s]\n\n\
161 -c display the time taken to call ntp_gettime (us)\n\
162 -e esterror estimate of the error (us)\n\
163 -f frequency Frequency error (-500 .. 500) (ppm)\n\
164 -h display this help info\n\
165 -m maxerror max possible error (us)\n\
166 -o offset current offset (ms)\n\
167 -r print the unix and NTP time raw\n\
168 -s status Set the status bits\n\
169 -t timeconstant log2 of PLL time constant (0 .. %d)\n",
172 "-M switch to microsecond mode\n",
177 "-N switch to nanosecond mode\n",
183 "-T tai_offset set TAI offset\n",
196 * Test to make sure the sigaction() works in case of invalid
199 newsigsys
.sa_handler
= pll_trap
;
200 newsigsys
.sa_flags
= 0;
201 if (sigaction(SIGSYS
, &newsigsys
, &sigsys
)) {
202 perror("sigaction() fails to save SIGSYS trap");
209 * Make sure the trapcatcher works.
213 if (sigsetjmp(env
, 1) == 0)
216 status
= syscall(BADCALL
, &ntv
); /* dummy parameter */
217 if ((status
< 0) && (errno
== ENOSYS
))
223 printf("sigaction() failed to catch an invalid syscall\n");
228 if (sigsetjmp(env
, 1) == 0) {
230 for (c
= 0; c
< sizeof times
/ sizeof times
[0]; c
++) {
231 status
= ntp_gettime(&ntv
);
232 if ((status
< 0) && (errno
== ENOSYS
))
236 times
[c
] = ntv
.time
.tv_frac_sec
;
241 if (pll_control
>= 0) {
242 printf("[ us %06d:", times
[0]);
243 for (c
= 1; c
< sizeof times
/ sizeof times
[0]; c
++)
244 printf(" %d", times
[c
] - times
[c
- 1]);
249 if (sigsetjmp(env
, 1) == 0) {
251 status
= ntp_gettime(&ntv
);
252 if ((status
< 0) && (errno
== ENOSYS
))
257 _ntx
.modes
= 0; /* Ensure nothing is set */
259 if (sigsetjmp(env
, 1) == 0) {
261 status
= ntp_adjtime(&_ntx
);
262 if ((status
< 0) && (errno
== ENOSYS
))
268 if (pll_control
< 0) {
269 printf("NTP user interface routines are not configured in this kernel.\n");
274 * Fetch timekeeping data and display.
276 status
= ntp_gettime(&ntv
);
278 perror("ntp_gettime() call fails");
280 printf("ntp_gettime() returns code %d (%s)\n",
281 status
, timex_state(status
));
282 time_frac
= ntv
.time
.tv_frac_sec
;
284 if (flash
& STA_NANO
) {
285 ntv
.time
.tv_frac_sec
/= 1000;
286 ts_mask
= 0xfffffffc; /* 1/2^30 */
287 ts_roundbit
= 0x00000002;
291 tv
.tv_sec
= ntv
.time
.tv_sec
;
292 tv
.tv_usec
= ntv
.time
.tv_frac_sec
;
295 ts
.l_uf
+= ts_roundbit
;
297 printf(" time %s, (.%0*d),\n",
298 prettydate(&ts
), fdigits
, (int) time_frac
);
299 printf(" maximum error %lu us, estimated error %lu us",
300 (u_long
)ntv
.maxerror
, (u_long
)ntv
.esterror
);
302 printf(" ntptime=%x.%x unixtime=%x.%0*d %s",
303 (unsigned int) ts
.l_ui
, (unsigned int) ts
.l_uf
,
304 (int) ntv
.time
.tv_sec
, fdigits
, (int) time_frac
,
305 ctime((const time_t *) &ntv
.time
.tv_sec
));
307 printf(", TAI offset %ld\n", (long)ntv
.tai
);
312 status
= ntp_adjtime(&ntx
);
314 perror((errno
== EPERM
) ?
315 "Must be root to set kernel values\nntp_adjtime() call fails" :
316 "ntp_adjtime() call fails");
319 printf("ntp_adjtime() returns code %d (%s)\n",
320 status
, timex_state(status
));
321 printf(" modes %s,\n", sprintb(ntx
.modes
, TIMEX_MOD_BITS
));
322 ftemp
= (double)ntx
.offset
;
324 if (flash
& STA_NANO
)
327 printf(" offset %.3f", ftemp
);
328 ftemp
= (double)ntx
.freq
/ SCALE_FREQ
;
329 printf(" us, frequency %.3f ppm, interval %d s,\n",
330 ftemp
, 1 << ntx
.shift
);
331 printf(" maximum error %lu us, estimated error %lu us,\n",
332 (u_long
)ntx
.maxerror
, (u_long
)ntx
.esterror
);
333 printf(" status %s,\n", sprintb((u_int
)ntx
.status
, TIMEX_STA_BITS
));
334 ftemp
= (double)ntx
.tolerance
/ SCALE_FREQ
;
335 gtemp
= (double)ntx
.precision
;
337 if (flash
& STA_NANO
)
341 " time constant %lu, precision %.3f us, tolerance %.0f ppm,\n",
342 (u_long
)ntx
.constant
, gtemp
, ftemp
);
345 ftemp
= (double)ntx
.ppsfreq
/ SCALE_FREQ
;
346 gtemp
= (double)ntx
.stabil
/ SCALE_FREQ
;
347 htemp
= (double)ntx
.jitter
;
349 if (flash
& STA_NANO
)
353 " pps frequency %.3f ppm, stability %.3f ppm, jitter %.3f us,\n",
354 ftemp
, gtemp
, htemp
);
355 printf(" intervals %lu, jitter exceeded %lu, stability exceeded %lu, errors %lu.\n",
356 (u_long
)ntx
.calcnt
, (u_long
)ntx
.jitcnt
,
357 (u_long
)ntx
.stbcnt
, (u_long
)ntx
.errcnt
);
362 * Put things back together the way we found them.
366 if (sigaction(SIGSYS
, &sigsys
, (struct sigaction
*)NULL
)) {
367 perror("sigaction() fails to restore SIGSYS trap");
376 * pll_trap - trap processor for undefined syscalls
389 * Print a value a la the %b format of the kernel's printf
394 register const char *bits
398 register int i
, any
= 0;
400 static char buf
[132];
402 if (bits
&& *bits
== 8)
403 (void)sprintf(buf
, "0%o", v
);
405 (void)sprintf(buf
, "0x%x", v
);
406 cp
= buf
+ strlen(buf
);
411 while ((i
= *bits
++) != 0) {
412 if (v
& (1 << (i
-1))) {
416 for (; (c
= *bits
) > 32; bits
++)
419 for (; *bits
> 32; bits
++)
428 const char *timex_states
[] = {
429 "OK", "INS", "DEL", "OOP", "WAIT", "ERROR"
439 if (s
>= 0 && s
< sizeof(timex_states
) / sizeof(timex_states
[0]))
440 return (timex_states
[s
]);
441 sprintf(buf
, "TIME-#%d", s
);