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