File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / ntp / util / ntptime.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue May 29 12:08:38 2012 UTC (12 years, 7 months ago) by misho
Branches: ntp, MAIN
CVS tags: v4_2_6p5p0, v4_2_6p5, HEAD
ntp 4.2.6p5

    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>