diff options
Diffstat (limited to 'usr.sbin/xntpd/util/ntptime.c')
-rw-r--r-- | usr.sbin/xntpd/util/ntptime.c | 220 |
1 files changed, 220 insertions, 0 deletions
diff --git a/usr.sbin/xntpd/util/ntptime.c b/usr.sbin/xntpd/util/ntptime.c new file mode 100644 index 0000000..e528802 --- /dev/null +++ b/usr.sbin/xntpd/util/ntptime.c @@ -0,0 +1,220 @@ +/* + * NTP test program + * + * This program tests to see if the NTP user interface routines + * ntp_gettime() and ntp_adjtime() have been implemented in the kernel. + * If so, each of these routines is called to display current timekeeping + * data. + * + * For more information, see the README.kern file in the doc directory + * of the xntp3 distribution. + */ +#include <stdio.h> +#include <ctype.h> +#include <sys/time.h> +#include <signal.h> +#include <errno.h> + +#include <sys/syscall.h> + +#include "ntp_fp.h" +#include "ntp_unixtime.h" +#include "ntp_stdlib.h" + +#ifndef SYS_DECOSF1 +#define BADCALL -1 /* this is supposed to be a bad syscall */ +#endif +#include "ntp_timex.h" + +#ifdef KERNEL_PLL +#ifndef SYS_ntp_adjtime +#define SYS_ntp_adjtime NTP_SYSCALL_ADJ +#endif +#ifndef SYS_ntp_gettime +#define SYS_ntp_gettime NTP_SYSCALL_GET +#endif +#endif /* KERNEL_PLL */ + +extern int sigvec P((int, struct sigvec *, struct sigvec *)); +void pll_trap P((void)); +extern int getopt_l P((int, char **, char *)); + +static struct sigvec newsigsys; /* new sigvec status */ +static struct sigvec sigsys; /* current sigvec status */ +static int pll_control; /* (0) daemon, (1) kernel loop */ + +static char* progname; +static char optargs[] = "ce:f:hm:o:rs:t:"; + +void +main(argc, argv) + int argc; + char *argv[]; +{ + extern int optind; + extern char *optarg; + int status; + struct ntptimeval ntv; + struct timex ntx, _ntx; + int times[20]; + double ftemp; + l_fp ts; + int c; + int errflg = 0; + int cost = 0; + int rawtime = 0; + + ntx.mode = 0; + progname = argv[0]; + while ((c = getopt_l(argc, argv, optargs)) != EOF) switch (c) { + case 'c': + cost++; + break; + case 'e': + ntx.mode |= ADJ_ESTERROR; + ntx.esterror = atoi(optarg); + break; + case 'f': + ntx.mode |= ADJ_FREQUENCY; + ntx.frequency = (int) (atof(optarg) * (1 << SHIFT_USEC)); + if (ntx.frequency < (-100 << SHIFT_USEC) + || ntx.frequency > ( 100 << SHIFT_USEC)) errflg++; + break; + case 'm': + ntx.mode |= ADJ_MAXERROR; + ntx.maxerror = atoi(optarg); + break; + case 'o': + ntx.mode |= ADJ_OFFSET; + ntx.offset = atoi(optarg); + break; + case 'r': + rawtime++; + break; + case 's': + ntx.mode |= ADJ_STATUS; + ntx.status = atoi(optarg); + if (ntx.status < 0 || ntx.status > 4) errflg++; + break; + case 't': + ntx.mode |= ADJ_TIMECONST; + ntx.time_constant = atoi(optarg); + if (ntx.time_constant < 0 || ntx.time_constant > MAXTC) + errflg++; + break; + default: + errflg++; + } + if (errflg || (optind != argc)) { + (void) fprintf(stderr, + "usage: %s [-%s]\n\n\ + -c display the time taken to call ntp_gettime (us)\n\ + -e esterror estimate of the error (us)\n\ + -f frequency Frequency error (-100 .. 100) (ppm)\n\ + -h display this help info\n\ + -m maxerror max possible error (us)\n\ + -o offset current offset (ms)\n\ + -r print the unix and NTP time raw\n\ + -s status Set the status (0 .. 4)\n\ + -t timeconstant log2 of PLL time constant (0 .. %d)\n", + progname, optargs, MAXTC); + exit(2); + } + + + /* + * Test to make sure the sigvec() works in case of invalid + * syscall codes. + */ + newsigsys.sv_handler = pll_trap; + newsigsys.sv_mask = 0; + newsigsys.sv_flags = 0; + if (sigvec(SIGSYS, &newsigsys, &sigsys)) { + perror("sigvec() fails to save SIGSYS trap"); + exit(1); + } + +#ifdef BADCALL + /* + * Make sure the trapcatcher works. + */ + pll_control = 1; + (void)syscall(BADCALL, &ntv); /* dummy parameter f. ANSI compilers */ + if (pll_control) + printf("sigvec() failed to catch an invalid syscall\n"); +#endif + + if (cost) { + for (c=0; c< sizeof times / sizeof times[0]; c++) { + (void)ntp_gettime(&ntv); + if (pll_control < 0) break; + times[c] = ntv.time.tv_usec; + } + if (pll_control >= 0) { + printf("[ usec %06d:", times[0]); + for (c=1; c< sizeof times / sizeof times[0]; c++) printf(" %d", times[c] - times[c-1]); + printf(" ]\n"); + } + } + (void)ntp_gettime(&ntv); + ntx.mode = 0; /* Ensure nothing is set */ + (void)ntp_adjtime(&_ntx); + if (pll_control < 0) { + printf("NTP user interface routines are not configured in this kernel.\n"); + goto lexit; + } + + /* + * Fetch timekeeping data and display. + */ + if ((status = ntp_gettime(&ntv)) < 0) + perror("ntp_gettime() call fails"); + else { + printf("ntp_gettime() returns code %d\n", status); + TVTOTS(&ntv.time, &ts); + ts.l_uf += TS_ROUNDBIT; /* guaranteed not to overflow */ + ts.l_ui += JAN_1970; + ts.l_uf &= TS_MASK; + printf(" time: %s, (.%06d)\n", + prettydate(&ts), ntv.time.tv_usec); + printf(" confidence interval: %ld usec, estimated error: %ld usec\n", + ntv.maxerror, ntv.esterror); + if (rawtime) printf(" ntptime=%x.%x unixtime=%x.%06d %s", + ts.l_ui, ts.l_uf, + ntv.time.tv_sec, ntv.time.tv_usec, + ctime(&ntv.time.tv_sec)); + } + if ((status = ntp_adjtime(&ntx)) < 0) perror((errno == EPERM) ? + ">> Must be root to set kernel values\n>> ntp_adjtime() call fails" : + ">> ntp_adjtime() call fails"); + else { + printf("ntp_adjtime() returns code %d\n", status); + ftemp = ntx.frequency; + ftemp /= (1 << SHIFT_USEC); + printf(" mode: %02x, offset: %ld usec, frequency: %6.3f ppm,\n", + ntx.mode, ntx.offset, ftemp); + printf(" confidence interval: %ld usec, estimated error: %ld usec,\n", + ntx.maxerror, ntx.esterror); + printf(" status: %d, time constant: %ld, precision: %ld usec, tolerance: %ld usec\n", + ntx.status, ntx.time_constant, ntx.precision, + ntx.tolerance); + } + + /* + * Put things back together the way we found them. + */ +lexit: if (sigvec(SIGSYS, &sigsys, (struct sigvec *)NULL)) { + perror("sigvec() fails to restore SIGSYS trap"); + exit(1); + } + exit(0); +} + +/* + * pll1_trap - trap processor for undefined syscalls + */ +void +pll_trap() +{ + pll_control--; +} |