1 /* 2 * NTP test program 3 * 4 * This program tests to see if the NTP user interface routines 5 * ntp_gettime() and ntp_adjtime() have been implemented in the kernel. 6 * If so, each of these routines is called to display current timekeeping 7 * data. 8 * 9 * For more information, see the README.kern file in the doc directory 10 * of the xntp3 distribution. 11 */ 12 13 #ifdef HAVE_CONFIG_H 14 # include <config.h> 15 #endif /* HAVE_CONFIG_H */ 16 17 #include "ntp_fp.h" 18 #include "ntp_unixtime.h" 19 #include "ntp_syscall.h" 20 #include "ntp_stdlib.h" 21 22 #include <stdio.h> 23 #include <ctype.h> 24 #include <signal.h> 25 #include <setjmp.h> 26 27 #ifdef NTP_SYSCALLS_STD 28 # ifndef SYS_DECOSF1 29 # define BADCALL -1 /* this is supposed to be a bad syscall */ 30 # endif /* SYS_DECOSF1 */ 31 #endif 32 33 #ifdef HAVE_STRUCT_NTPTIMEVAL_TIME_TV_NSEC 34 #define tv_frac_sec tv_nsec 35 #else 36 #define tv_frac_sec tv_usec 37 #endif 38 39 40 #define TIMEX_MOD_BITS \ 41 "\20\1OFFSET\2FREQUENCY\3MAXERROR\4ESTERROR\5STATUS\6TIMECONST\ 42 \13PLL\14FLL\15MICRO\16NANO\17CLKB\20CLKA" 43 44 #define TIMEX_STA_BITS \ 45 "\20\1PLL\2PPSFREQ\3PPSTIME\4FLL\5INS\6DEL\7UNSYNC\10FREQHOLD\ 46 \11PPSSIGNAL\12PPSJITTER\13PPSWANDER\14PPSERROR\15CLOCKERR\ 47 \16NANO\17MODE\20CLK" 48 49 #define SCALE_FREQ 65536 /* frequency scale */ 50 51 52 /* 53 * Function prototypes 54 */ 55 char *sprintb P((u_int, const char *)); 56 const char *timex_state P((int)); 57 volatile int debug = 0; 58 59 #ifdef SIGSYS 60 void pll_trap P((int)); 61 62 static struct sigaction newsigsys; /* new sigaction status */ 63 static struct sigaction sigsys; /* current sigaction status */ 64 static sigjmp_buf env; /* environment var. for pll_trap() */ 65 #endif 66 67 static volatile int pll_control; /* (0) daemon, (1) kernel loop */ 68 static volatile int status; /* most recent status bits */ 69 static volatile int flash; /* most recent ntp_adjtime() bits */ 70 char* progname; 71 static char optargs[] = "MNT:cde:f:hm:o:rs:t:"; 72 73 int 74 main( 75 int argc, 76 char *argv[] 77 ) 78 { 79 extern int ntp_optind; 80 extern char *ntp_optarg; 81 #ifdef SUBST_ADJTIMEX 82 struct timex ntv; 83 #else 84 struct ntptimeval ntv; 85 #endif 86 struct timeval tv; 87 struct timex ntx, _ntx; 88 int times[20]; 89 double ftemp, gtemp, htemp; 90 long time_frac; /* ntv.time.tv_frac_sec (us/ns) */ 91 l_fp ts; 92 unsigned ts_mask = TS_MASK; /* defaults to 20 bits (us) */ 93 unsigned ts_roundbit = TS_ROUNDBIT; /* defaults to 20 bits (us) */ 94 int fdigits = 6; /* fractional digits for us */ 95 int c; 96 int errflg = 0; 97 int cost = 0; 98 int rawtime = 0; 99 100 memset((char *)&ntx, 0, sizeof(ntx)); 101 progname = argv[0]; 102 while ((c = ntp_getopt(argc, argv, optargs)) != EOF) switch (c) { 103 #ifdef MOD_MICRO 104 case 'M': 105 ntx.modes |= MOD_MICRO; 106 break; 107 #endif 108 #ifdef MOD_NANO 109 case 'N': 110 ntx.modes |= MOD_NANO; 111 break; 112 #endif 113 #ifdef NTP_API 114 # if NTP_API > 3 115 case 'T': 116 ntx.modes = MOD_TAI; 117 ntx.constant = atoi(ntp_optarg); 118 break; 119 # endif 120 #endif 121 case 'c': 122 cost++; 123 break; 124 case 'd': 125 debug++; 126 break; 127 case 'e': 128 ntx.modes |= MOD_ESTERROR; 129 ntx.esterror = atoi(ntp_optarg); 130 break; 131 case 'f': 132 ntx.modes |= MOD_FREQUENCY; 133 ntx.freq = (long)(atof(ntp_optarg) * SCALE_FREQ); 134 break; 135 case 'm': 136 ntx.modes |= MOD_MAXERROR; 137 ntx.maxerror = atoi(ntp_optarg); 138 break; 139 case 'o': 140 ntx.modes |= MOD_OFFSET; 141 ntx.offset = atoi(ntp_optarg); 142 break; 143 case 'r': 144 rawtime++; 145 break; 146 case 's': 147 ntx.modes |= MOD_STATUS; 148 ntx.status = atoi(ntp_optarg); 149 if (ntx.status < 0 || ntx.status >= 0x100) errflg++; 150 break; 151 case 't': 152 ntx.modes |= MOD_TIMECONST; 153 ntx.constant = atoi(ntp_optarg); 154 break; 155 default: 156 errflg++; 157 } 158 if (errflg || (ntp_optind != argc)) { 159 (void) fprintf(stderr, 160 "usage: %s [-%s]\n\n\ 161 %s%s%s\ 162 -c display the time taken to call ntp_gettime (us)\n\ 163 -e esterror estimate of the error (us)\n\ 164 -f frequency Frequency error (-500 .. 500) (ppm)\n\ 165 -h display this help info\n\ 166 -m maxerror max possible error (us)\n\ 167 -o offset current offset (ms)\n\ 168 -r print the unix and NTP time raw\n\ 169 -l leap Set the leap bits\n\ 170 -t timeconstant log2 of PLL time constant (0 .. %d)\n", 171 progname, optargs, 172 #ifdef MOD_MICRO 173 "-M switch to microsecond mode\n", 174 #else 175 "", 176 #endif 177 #ifdef MOD_NANO 178 "-N switch to nanosecond mode\n", 179 #else 180 "", 181 #endif 182 #ifdef NTP_API 183 # if NTP_API > 3 184 "-T tai_offset set TAI offset\n", 185 # else 186 "", 187 # endif 188 #else 189 "", 190 #endif 191 MAXTC); 192 exit(2); 193 } 194 195 #ifdef SIGSYS 196 /* 197 * Test to make sure the sigaction() works in case of invalid 198 * syscall codes. 199 */ 200 newsigsys.sa_handler = pll_trap; 201 newsigsys.sa_flags = 0; 202 if (sigaction(SIGSYS, &newsigsys, &sigsys)) { 203 perror("sigaction() fails to save SIGSYS trap"); 204 exit(1); 205 } 206 #endif /* SIGSYS */ 207 208 #ifdef BADCALL 209 /* 210 * Make sure the trapcatcher works. 211 */ 212 pll_control = 1; 213 #ifdef SIGSYS 214 if (sigsetjmp(env, 1) == 0) 215 { 216 #endif 217 status = syscall(BADCALL, &ntv); /* dummy parameter */ 218 if ((status < 0) && (errno == ENOSYS)) 219 --pll_control; 220 #ifdef SIGSYS 221 } 222 #endif 223 if (pll_control) 224 printf("sigaction() failed to catch an invalid syscall\n"); 225 #endif /* BADCALL */ 226 227 if (cost) { 228 #ifdef SIGSYS 229 if (sigsetjmp(env, 1) == 0) { 230 #endif 231 for (c = 0; c < sizeof times / sizeof times[0]; c++) { 232 status = ntp_gettime(&ntv); 233 if ((status < 0) && (errno == ENOSYS)) 234 --pll_control; 235 if (pll_control < 0) 236 break; 237 times[c] = ntv.time.tv_frac_sec; 238 } 239 #ifdef SIGSYS 240 } 241 #endif 242 if (pll_control >= 0) { 243 printf("[ us %06d:", times[0]); 244 for (c = 1; c < sizeof times / sizeof times[0]; c++) 245 printf(" %d", times[c] - times[c - 1]); 246 printf(" ]\n"); 247 } 248 } 249 #ifdef SIGSYS 250 if (sigsetjmp(env, 1) == 0) { 251 #endif 252 status = ntp_gettime(&ntv); 253 if ((status < 0) && (errno == ENOSYS)) 254 --pll_control; 255 #ifdef SIGSYS 256 } 257 #endif 258 _ntx.modes = 0; /* Ensure nothing is set */ 259 #ifdef SIGSYS 260 if (sigsetjmp(env, 1) == 0) { 261 #endif 262 status = ntp_adjtime(&_ntx); 263 if ((status < 0) && (errno == ENOSYS)) 264 --pll_control; 265 flash = _ntx.status; 266 #ifdef SIGSYS 267 } 268 #endif 269 if (pll_control < 0) { 270 printf("NTP user interface routines are not configured in this kernel.\n"); 271 goto lexit; 272 } 273 274 /* 275 * Fetch timekeeping data and display. 276 */ 277 status = ntp_gettime(&ntv); 278 if (status < 0) 279 perror("ntp_gettime() call fails"); 280 else { 281 printf("ntp_gettime() returns code %d (%s)\n", 282 status, timex_state(status)); 283 time_frac = ntv.time.tv_frac_sec; 284 #ifdef STA_NANO 285 if (flash & STA_NANO) { 286 ntv.time.tv_frac_sec /= 1000; 287 ts_mask = 0xfffffffc; /* 1/2^30 */ 288 ts_roundbit = 0x00000002; 289 fdigits = 9; 290 } 291 #endif 292 tv.tv_sec = ntv.time.tv_sec; 293 tv.tv_usec = ntv.time.tv_frac_sec; 294 TVTOTS(&tv, &ts); 295 ts.l_ui += JAN_1970; 296 ts.l_uf += ts_roundbit; 297 ts.l_uf &= ts_mask; 298 printf(" time %s, (.%0*d),\n", 299 prettydate(&ts), fdigits, (int) time_frac); 300 printf(" maximum error %lu us, estimated error %lu us", 301 (u_long)ntv.maxerror, (u_long)ntv.esterror); 302 if (rawtime) 303 printf(" ntptime=%x.%x unixtime=%x.%0*d %s", 304 (unsigned int) ts.l_ui, (unsigned int) ts.l_uf, 305 (int) ntv.time.tv_sec, fdigits, (int) time_frac, 306 ctime((const time_t *) &ntv.time.tv_sec)); 307 #if NTP_API > 3 308 printf(", TAI offset %d\n", ntv.tai); 309 #else 310 printf("\n"); 311 #endif /* NTP_API */ 312 } 313 status = ntp_adjtime(&ntx); 314 if (status < 0) 315 perror((errno == EPERM) ? 316 "Must be root to set kernel values\nntp_adjtime() call fails" : 317 "ntp_adjtime() call fails"); 318 else { 319 flash = ntx.status; 320 printf("ntp_adjtime() returns code %d (%s)\n", 321 status, timex_state(status)); 322 printf(" modes %s,\n", sprintb(ntx.modes, TIMEX_MOD_BITS)); 323 ftemp = (double)ntx.offset; 324 #ifdef STA_NANO 325 if (flash & STA_NANO) 326 ftemp /= 1000.0; 327 #endif 328 printf(" offset %.3f", ftemp); 329 ftemp = (double)ntx.freq / SCALE_FREQ; 330 printf(" us, frequency %.3f ppm, interval %d s,\n", 331 ftemp, 1 << ntx.shift); 332 printf(" maximum error %lu us, estimated error %lu us,\n", 333 (u_long)ntx.maxerror, (u_long)ntx.esterror); 334 printf(" status %s,\n", sprintb((u_int)ntx.status, TIMEX_STA_BITS)); 335 ftemp = (double)ntx.tolerance / SCALE_FREQ; 336 gtemp = (double)ntx.precision; 337 #ifdef STA_NANO 338 if (flash & STA_NANO) 339 gtemp /= 1000.0; 340 #endif 341 printf( 342 " time constant %lu, precision %.3f us, tolerance %.0f ppm,\n", 343 (u_long)ntx.constant, gtemp, ftemp); 344 if (ntx.shift == 0) 345 exit (0); 346 ftemp = (double)ntx.ppsfreq / SCALE_FREQ; 347 gtemp = (double)ntx.stabil / SCALE_FREQ; 348 htemp = (double)ntx.jitter; 349 #ifdef STA_NANO 350 if (flash & STA_NANO) 351 htemp /= 1000.0; 352 #endif 353 printf( 354 " pps frequency %.3f ppm, stability %.3f ppm, jitter %.3f us,\n", 355 ftemp, gtemp, htemp); 356 printf(" intervals %lu, jitter exceeded %lu, stability exceeded %lu, errors %lu.\n", 357 (u_long)ntx.calcnt, (u_long)ntx.jitcnt, 358 (u_long)ntx.stbcnt, (u_long)ntx.errcnt); 359 return (0); 360 } 361 362 /* 363 * Put things back together the way we found them. 364 */ 365 lexit: 366 #ifdef SIGSYS 367 if (sigaction(SIGSYS, &sigsys, (struct sigaction *)NULL)) { 368 perror("sigaction() fails to restore SIGSYS trap"); 369 exit(1); 370 } 371 #endif 372 exit(0); 373 } 374 375 #ifdef SIGSYS 376 /* 377 * pll_trap - trap processor for undefined syscalls 378 */ 379 void 380 pll_trap( 381 int arg 382 ) 383 { 384 pll_control--; 385 siglongjmp(env, 1); 386 } 387 #endif 388 389 /* 390 * Print a value a la the %b format of the kernel's printf 391 */ 392 char * 393 sprintb( 394 register u_int v, 395 register const char *bits 396 ) 397 { 398 register char *cp; 399 register int i, any = 0; 400 register char c; 401 static char buf[132]; 402 403 if (bits && *bits == 8) 404 (void)sprintf(buf, "0%o", v); 405 else 406 (void)sprintf(buf, "0x%x", v); 407 cp = buf + strlen(buf); 408 bits++; 409 if (bits) { 410 *cp++ = ' '; 411 *cp++ = '('; 412 while ((i = *bits++) != 0) { 413 if (v & (1 << (i-1))) { 414 if (any) 415 *cp++ = ','; 416 any = 1; 417 for (; (c = *bits) > 32; bits++) 418 *cp++ = c; 419 } else 420 for (; *bits > 32; bits++) 421 continue; 422 } 423 *cp++ = ')'; 424 } 425 *cp = '\0'; 426 return (buf); 427 } 428 429 const char *timex_states[] = { 430 "OK", "INS", "DEL", "OOP", "WAIT", "ERROR" 431 }; 432 433 const char * 434 timex_state( 435 register int s 436 ) 437 { 438 static char buf[32]; 439 440 if (s >= 0 && s <= sizeof(timex_states) / sizeof(timex_states[0])) 441 return (timex_states[s]); 442 sprintf(buf, "TIME-#%d", s); 443 return (buf); 444 } 445