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