diff options
author | wollman <wollman@FreeBSD.org> | 1993-12-21 18:36:48 +0000 |
---|---|---|
committer | wollman <wollman@FreeBSD.org> | 1993-12-21 18:36:48 +0000 |
commit | 8e51e9f1429efc498f923bce8b25b20f47d7c075 (patch) | |
tree | 9db10264d45dc397a38276190303093a450d769e /usr.sbin/xntpd/util | |
download | FreeBSD-src-8e51e9f1429efc498f923bce8b25b20f47d7c075.zip FreeBSD-src-8e51e9f1429efc498f923bce8b25b20f47d7c075.tar.gz |
xntpd 3.3b from UDel
Diffstat (limited to 'usr.sbin/xntpd/util')
-rw-r--r-- | usr.sbin/xntpd/util/Makefile.tmpl | 62 | ||||
-rw-r--r-- | usr.sbin/xntpd/util/README | 67 | ||||
-rw-r--r-- | usr.sbin/xntpd/util/byteorder.c | 52 | ||||
-rw-r--r-- | usr.sbin/xntpd/util/jitter.c | 73 | ||||
-rw-r--r-- | usr.sbin/xntpd/util/kern.c | 210 | ||||
-rw-r--r-- | usr.sbin/xntpd/util/longsize.c | 11 | ||||
-rw-r--r-- | usr.sbin/xntpd/util/ntptime.c | 220 | ||||
-rw-r--r-- | usr.sbin/xntpd/util/precision.c | 81 | ||||
-rw-r--r-- | usr.sbin/xntpd/util/testrs6000.c | 44 | ||||
-rw-r--r-- | usr.sbin/xntpd/util/tickadj.c | 518 | ||||
-rw-r--r-- | usr.sbin/xntpd/util/timetrim.c | 85 |
11 files changed, 1423 insertions, 0 deletions
diff --git a/usr.sbin/xntpd/util/Makefile.tmpl b/usr.sbin/xntpd/util/Makefile.tmpl new file mode 100644 index 0000000..1115ef8 --- /dev/null +++ b/usr.sbin/xntpd/util/Makefile.tmpl @@ -0,0 +1,62 @@ +# +# Makefile.tmpl,v 3.1 1993/07/06 01:10:58 jbj Exp +# +PROGRAM= tickadj +# +# Makefile for utilities +# +COMPILER= cc +COPTS= -O +BINDIR= /usr/local +INSTALL= install +DEFS= +DEFS_OPT= +DEFS_LOCAL= +DAEMONLIBS= +RESLIB= +COMPAT= +# +INCL= -I../include +CFLAGS= $(COPTS) $(DEFS) $(DEFS_LOCAL) $(INCL) +CC= $(COMPILER) +LIB= ../lib/libntp.a +LINTLIB= ../lib/llib-llibntp.ln +MAKE= make +TOP=../ +# +SOURCE= tickadj.c ntptime.c +TKOBJS= tickadj.o +NTOBJS= ntptime.o +EXECS= ntptime jitter timetrim kern byteorder longsize precision + +all: $(PROGRAM) + +tickadj: $(TKOBJS) + $(CC) $(COPTS) -o $@ $(TKOBJS) $(DAEMONLIBS) $(RESLIB) $(COMPAT) + +ntptime: $(NTOBJS) + $(CC) $(COPTS) -o $@ $(NTOBJS) $(LIB) + +precision: precision.o + $(CC) $(COPTS) -o $@ $@.o + +install: $(BINDIR)/$(PROGRAM) + +$(BINDIR)/$(PROGRAM): $(PROGRAM) + $(INSTALL) -c -m 0755 $(PROGRAM) $(BINDIR) + +tags: + ctags *.c *.h + +depend: + mkdep $(CFLAGS) $(SOURCE) + +clean: + -@rm -f $(PROGRAM) $(EXECS) *.o *.out tags make.log Makefile.bak lint.errs + +distclean: clean + -@rm -f *.orig *.rej .version Makefile + +../lib/libntp.a: + cd ../lib && $(MAKE) $(MFLAGS) $(MFLAGS) MFLAGS="$(MFLAGS)" + diff --git a/usr.sbin/xntpd/util/README b/usr.sbin/xntpd/util/README new file mode 100644 index 0000000..2aedb00 --- /dev/null +++ b/usr.sbin/xntpd/util/README @@ -0,0 +1,67 @@ +README file for directory ./util of the NTP Version 3 distribution + +This directory contains the sources for the various utility programs. See +the README and RELNOTES files in the parent directory for directions on +how to make and install these programs. + +The ntptime.c program checks the kernel configuration for the NTP user +interface syscalls ntp_gettime() and ntp_adjtime(). If present, the +current timekeeping data are displayed. If not, a dissapointment is +displayed. Do "make ntptime" in this directory to make the thing, +but be advised that, unless you have installed the kernel support, +there will probably be missing vital header files. See the README.kern +file in the doc directory of this distribution for further details. + +The jitter.c program can be used to determine the timing jitter due to +the operating system in a gettimeofday() call. For most systems the +dominant contribution to the jitter budget is the period of the hardware +interrupt, usually in the range 1-10 ms. For those systems with microsecond +counters, such as recent Sun and certain Ultrix systems, the jitter is +dominated only by the operating system. + +The timetrim.c program can be used with SGI machines to implement a +scheme to discipline the hardware clock frequency. See the source code +for further information. + +The byteorder.c and longsize.c programs are used during the configuration +process to determine the byte order (little or big endian) and longword +size (32 or 64 bits). See the ../scripts/makefile.sh script for further +details. + +The testrs6000.c program is used for testing purposes with the IBM +RS/6000 AIX machines. Bill Jones <jones@chpc.utexas.edu> reports: +"I could not get a tickadj of less then 40 us to work on a RS6000. +If you set it less then 40 us do so at your own risk!" + +The tickadj.c program can be used to read and set various kernel +parameters affecting NTP operations. Comes now the rationale for its use. + +Then daemon's clock adjustment algorithms depend (too) strongly +on the internals of the kernel adjtime() call, and expect it to +match that which comes with Berkeley-flavour operating systems. +The daemon actually reads a couple of values from your kernel +using /dev/kmem (ugh!), the value of `tick' and the value of `tickadj'. +`tick' is expected to be the number of microseconds which are +added to the system time on timer interrupts when the clock isn't +being slewed. `tickadj' is the number of microseconds which are +added or subtracted from tick when the clock is being slewed. + +The program tickadj mimics the daemon's handling of these variables. +If you run it (as root) and it fails or produces bizarre looking +values you may have to torque ntp_unixclock.c in the daemon code. + +You can also use tickadj -a to set tickadj in the running kernel. +In addition, tickadj -A will compute the value to set based on the +kernel's value of tick, while the -t flag allows one to set the +value of tick and the -s flag will set the value of dosynctodr +to zero. This is an alternative for people who can't change the +values in the kernel's disk image. + +In addition, the -p flag will set the noprintf variable. This will +suppress any kernel messages. Kernel message can then only be seen via +syslog(3). This inhibits clockhopping due to kernel printf's. + +The target "ntptime" can only be compiled on systems with kernel PLL +support. This is currently only possible for SunOS4, Ultrix and DECOSF1. +You need the propriatary header files for that. So there is no need to +attempt to compile ntptime unless you have the above configuration. diff --git a/usr.sbin/xntpd/util/byteorder.c b/usr.sbin/xntpd/util/byteorder.c new file mode 100644 index 0000000..665c146 --- /dev/null +++ b/usr.sbin/xntpd/util/byteorder.c @@ -0,0 +1,52 @@ +/* + * This works on: + * Crays + * Conven + * sparc's + * Dec mip machines + * Dec alpha machines + * RS6000 + * SGI's + */ + +#include <stdio.h> +main() +{ + int i; + int big; + union { + unsigned long l; + char c[sizeof(long)]; + } u; + +#if defined(LONG8) + u.l = (((long)0x08070605) << 32) | (long)0x04030201; +#else + u.l = 0x04030201; +#endif + if (sizeof(long) > 4) { + if (u.c[0] == 0x08) big = 1; + else big = 0; + } else { + if (u.c[0] == 0x04) big = 1; + else big = 0; + } + for (i=0; i< sizeof(long); i++) { + if (big == 1 && (u.c[i] == (sizeof(long) - i))) { + continue; + } else if (big == 0 && (u.c[i] == (i+1))) { + continue; + } else { + big = -1; + break; + } + } + + if (big == 1) { + printf("XNTP_BIG_ENDIAN\n"); + } else if (big == 0) { + printf("XNTP_LITTLE_ENDIAN\n"); + } + exit(0); +} + diff --git a/usr.sbin/xntpd/util/jitter.c b/usr.sbin/xntpd/util/jitter.c new file mode 100644 index 0000000..7201e87 --- /dev/null +++ b/usr.sbin/xntpd/util/jitter.c @@ -0,0 +1,73 @@ +/* + * This program can be used to calibrate the clock reading jitter of a + * particular CPU and operating system. It first tickles every element + * of an array, in order to force pages into memory, then repeatedly calls + * gettimeofday() and, finally, writes out the time values for later + * analysis. From this you can determine the jitter and if the clock ever + * runs backwards. + */ +#include <sys/time.h> +#include <stdio.h> + +#define NBUF 10001 + +main() +{ + struct timeval tp, ts, tr; + struct timezone tzp; + long temp, j, i, gtod[NBUF]; + + gettimeofday(&ts, &tzp); + ts.tv_usec = 0; + + /* + * Force pages into memory + */ + for (i = 0; i < NBUF; i ++) + gtod[i] = 0; + + /* + * Construct gtod array + */ + for (i = 0; i < NBUF; i ++) { + gettimeofday(&tp, &tzp); + tr = tp; + tr.tv_sec -= ts.tv_sec; + tr.tv_usec -= ts.tv_usec; + if (tr.tv_usec < 0) { + tr.tv_usec += 1000000; + tr.tv_sec--; + } + gtod[i] = tr.tv_sec * 1000000 + tr.tv_usec; + } + + /* + * Write out gtod array for later processing with S + */ + for (i = 0; i < NBUF - 1; i++) { +/* + printf("%lu\n", gtod[i]); +*/ + gtod[i] = gtod[i + 1] - gtod[i]; + printf("%lu\n", gtod[i]); + } + + /* + * Sort the gtod array and display deciles + */ + for (i = 0; i < NBUF - 1; i++) { + for (j = 0; j <= i; j++) { + if (gtod[j] > gtod[i]) { + temp = gtod[j]; + gtod[j] = gtod[i]; + gtod[i] = temp; + } + } + } + fprintf(stderr, "First rank\n"); + for (i = 0; i < 10; i++) + fprintf(stderr, "%10ld%10ld\n", i, gtod[i]); + fprintf(stderr, "Last rank\n"); + for (i = NBUF - 11; i < NBUF - 1; i++) + fprintf(stderr, "%10ld%10ld\n", i, gtod[i]); +} diff --git a/usr.sbin/xntpd/util/kern.c b/usr.sbin/xntpd/util/kern.c new file mode 100644 index 0000000..a2a6672 --- /dev/null +++ b/usr.sbin/xntpd/util/kern.c @@ -0,0 +1,210 @@ +/* + * This program simulates a first-order, type-II phase-lock loop using + * actual code segments from modified kernel distributions for SunOS, + * Ultrix and OSF/1 kernels. These segments do not use any licensed code. + */ +#include <stdio.h> +#include <ctype.h> +#include <math.h> +#include <sys/time.h> + +#include "timex.h" + +/* + * Phase-lock loop definitions + */ +#define HZ 100 /* timer interrupt frequency (Hz) */ +#define MAXPHASE 512000 /* max phase error (us) */ +#define MAXFREQ 200 /* max frequency error (ppm) */ +#define TAU 2 /* time constant (shift 0 - 6) */ +#define POLL 16 /* interval between updates (s) */ +#define MAXSEC 1200 /* max interval between updates (s) */ + +/* + * Function declarations + */ +void hardupdate(); +void hardclock(); +void second_overflow(); + +/* + * Kernel variables + */ +int tick; /* timer interrupt period (us) */ +int fixtick; /* amortization constant (ppm) */ +struct timeval timex; /* ripoff of kernel time variable */ + +/* + * Phase-lock loop variables + */ +int time_status = TIME_BAD; /* clock synchronization status */ +long time_offset = 0; /* time adjustment (us) */ +long time_constant = 0; /* pll time constant */ +long time_tolerance = MAXFREQ; /* frequency tolerance (ppm) */ +long time_precision = 1000000 / HZ; /* clock precision (us) */ +long time_maxerror = MAXPHASE; /* maximum error (us) */ +long time_esterror = MAXPHASE; /* estimated error (us) */ +long time_phase = 0; /* phase offset (scaled us) */ +long time_freq = 0; /* frequency offset (scaled ppm) */ +long time_adj = 0; /* tick adjust (scaled 1 / HZ) */ +long time_reftime = 0; /* time at last adjustment (s) */ + +/* + * Simulation variables + */ +double timey = 0; /* simulation time (us) */ +long timez = 0; /* current error (us) */ +long poll_interval = 0; /* poll counter */ + +/* + * Simulation test program + */ +void main() +{ + tick = 1000000 / HZ; + fixtick = 1000000 % HZ; + timex.tv_sec = 0; + timex.tv_usec = MAXPHASE; + time_freq = 0; + time_constant = TAU; + printf("tick %d us, fixtick %d us\n", tick, fixtick); + printf(" time offset freq _offset _freq _adj\n"); + + /* + * Grind the loop until ^C + */ + while (1) { + timey += (double)(1000000) / HZ; + if (timey >= 1000000) + timey -= 1000000; + hardclock(); + if (timex.tv_usec >= 1000000) { + timex.tv_usec -= 1000000; + timex.tv_sec++; + second_overflow(); + poll_interval++; + if (!(poll_interval % POLL)) { + timez = (long)timey - timex.tv_usec; + if (timez > 500000) + timez -= 1000000; + if (timez < -500000) + timez += 1000000; + hardupdate(timez); + printf("%10li%10li%10.2f %08lx %08lx %08lx\n", + timex.tv_sec, timez, + (double)time_freq / (1 << SHIFT_KF), + time_offset, time_freq, time_adj); + } + } + } +} + +/* + * This routine simulates the ntp_adjtime() call + * + * For default SHIFT_UPDATE = 12, offset is limited to +-512 ms, the + * maximum interval between updates is 4096 s and the maximum frequency + * offset is +-31.25 ms/s. + */ +void hardupdate(offset) +long offset; +{ + long ltemp, mtemp; + + time_offset = offset << SHIFT_UPDATE; + mtemp = timex.tv_sec - time_reftime; + time_reftime = timex.tv_sec; + if (mtemp > MAXSEC) + mtemp = 0; + + /* ugly multiply should be replaced */ + if (offset < 0) + time_freq -= (-offset * mtemp) >> + (time_constant + time_constant); + else + time_freq += (offset * mtemp) >> + (time_constant + time_constant); + ltemp = time_tolerance << SHIFT_KF; + if (time_freq > ltemp) + time_freq = ltemp; + else if (time_freq < -ltemp) + time_freq = -ltemp; + if (time_status == TIME_BAD) + time_status = TIME_OK; +} + +/* + * This routine simulates the timer interrupt + */ +void hardclock() +{ + int ltemp, time_update; + + time_update = tick; /* computed by adjtime() */ + time_phase += time_adj; + if (time_phase < -FINEUSEC) { + ltemp = -time_phase >> SHIFT_SCALE; + time_phase += ltemp << SHIFT_SCALE; + time_update -= ltemp; + } + else if (time_phase > FINEUSEC) { + ltemp = time_phase >> SHIFT_SCALE; + time_phase -= ltemp << SHIFT_SCALE; + time_update += ltemp; + } + timex.tv_usec += time_update; +} + +/* + * This routine simulates the overflow of the microsecond field + * + * With SHIFT_SCALE = 23, the maximum frequency adjustment is +-256 us + * per tick, or 25.6 ms/s at a clock frequency of 100 Hz. The time + * contribution is shifted right a minimum of two bits, while the frequency + * contribution is a right shift. Thus, overflow is prevented if the + * frequency contribution is limited to half the maximum or 15.625 ms/s. + */ +void second_overflow() +{ + int ltemp; + + time_maxerror += time_tolerance; + if (time_offset < 0) { + ltemp = -time_offset >> + (SHIFT_KG + time_constant); + time_offset += ltemp; + time_adj = -(ltemp << + (SHIFT_SCALE - SHIFT_HZ - SHIFT_UPDATE)); + } else { + ltemp = time_offset >> + (SHIFT_KG + time_constant); + time_offset -= ltemp; + time_adj = ltemp << + (SHIFT_SCALE - SHIFT_HZ - SHIFT_UPDATE); + } + if (time_freq < 0) + time_adj -= -time_freq >> (SHIFT_KF + SHIFT_HZ - SHIFT_SCALE); + else + time_adj += time_freq >> (SHIFT_KF + SHIFT_HZ - SHIFT_SCALE); + time_adj += fixtick << (SHIFT_SCALE - SHIFT_HZ); + + /* ugly divide should be replaced */ + if (timex.tv_sec % 86400 == 0) { + switch (time_status) { + + case TIME_INS: + timex.tv_sec--; /* !! */ + time_status = TIME_OOP; + break; + + case TIME_DEL: + timex.tv_sec++; + time_status = TIME_OK; + break; + + case TIME_OOP: + time_status = TIME_OK; + break; + } + } +} diff --git a/usr.sbin/xntpd/util/longsize.c b/usr.sbin/xntpd/util/longsize.c new file mode 100644 index 0000000..6bdbdfe --- /dev/null +++ b/usr.sbin/xntpd/util/longsize.c @@ -0,0 +1,11 @@ +#include <stdio.h> + +main() +{ + if (sizeof(long) == 8) { + printf("-DLONG8\n"); + } else if (sizeof(long) == 4) { + printf("-DLONG4\n"); + } + exit(0); +} 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--; +} diff --git a/usr.sbin/xntpd/util/precision.c b/usr.sbin/xntpd/util/precision.c new file mode 100644 index 0000000..69af19f --- /dev/null +++ b/usr.sbin/xntpd/util/precision.c @@ -0,0 +1,81 @@ +#include <sys/types.h> +#include <sys/time.h> + +#define DEFAULT_SYS_PRECISION -99 + +int default_get_precision(); + +int +main() { + printf("log2(precision) = %d\n", default_get_precision()); + return 0; +} + +/* Find the precision of the system clock by watching how the current time + * changes as we read it repeatedly. + * + * struct timeval is only good to 1us, which may cause problems as machines + * get faster, but until then the logic goes: + * + * If a machine has precision (i.e. accurate timing info) > 1us, then it will + * probably use the "unused" low order bits as a counter (to force time to be + * a strictly increaing variable), incrementing it each time any process + * requests the time [[ or maybe time will stand still ? ]]. + * + * SO: the logic goes: + * + * IF the difference from the last time is "small" (< MINSTEP) + * THEN this machine is "counting" with the low order bits + * ELIF this is not the first time round the loop + * THEN this machine *WAS* counting, and has now stepped + * ELSE this machine has precision < time to read clock + * + * SO: if it exits on the first loop, assume "full accuracy" (1us) + * otherwise, take the log2(observered difference, rounded UP) + * + * MINLOOPS > 1 ensures that even if there is a STEP between the initial call + * and the first loop, it doesn't stop too early. + * Making it even greater allows MINSTEP to be reduced, assuming that the + * chance of MINSTEP-1 other processes getting in and calling gettimeofday + * between this processes's calls. + * Reducing MINSTEP may be necessary as this sets an upper bound for the time + * to actually call gettimeofday. + */ + +#define DUSECS 1000000 +#define HUSECS (1024 * 1024) +#define MINSTEP 5 /* some systems increment uS on each call */ + /* Don't use "1" as some *other* process may read too*/ + /*We assume no system actually *ANSWERS* in this time*/ +#define MAXLOOPS HUSECS /* Assume precision < .1s ! */ + +int default_get_precision() +{ + struct timeval tp; + struct timezone tzp; + long last; + int i; + long diff; + long val; + int minsteps = 2; /* need at least this many steps */ + + gettimeofday(&tp, &tzp); + last = tp.tv_usec; + for (i = - --minsteps; i< MAXLOOPS; i++) { + gettimeofday(&tp, &tzp); + diff = tp.tv_usec - last; + if (diff < 0) diff += DUSECS; + if (diff > MINSTEP) if (minsteps-- <= 0) break; + last = tp.tv_usec; + } + + printf("precision calculation given %dus after %d loop%s\n", + diff, i, (i==1) ? "" : "s"); + + diff = (diff *3)/2; + if (i >= MAXLOOPS) diff = 1; /* No STEP, so FAST machine */ + if (i == 0) diff = 1; /* time to read clock >= precision */ + for (i=0, val=HUSECS; val>0; i--, val >>= 1) if (diff >= val) return i; + return DEFAULT_SYS_PRECISION /* Something's BUST, so lie ! */; +} + diff --git a/usr.sbin/xntpd/util/testrs6000.c b/usr.sbin/xntpd/util/testrs6000.c new file mode 100644 index 0000000..9a5e0cd --- /dev/null +++ b/usr.sbin/xntpd/util/testrs6000.c @@ -0,0 +1,44 @@ +/* Checks for the RS/6000 AIX adjtime() bug, in which if a negative + * offset is given, the system gets messed up and never completes the + * adjustment. If the problem is fixed, this program will print the + * time, sit there for 10 seconds, and exit. If the problem isn't fixed, + * the program will print an occasional "result=nnnnnn" (the residual + * slew from adjtime()). + * + * Compile this with bsdcc and run it as root! + */ +#include <signal.h> +#include <sys/time.h> +#include <time.h> +#include <stdio.h> +int timeout(); +struct timeval adjustment, result; +main () { + struct itimerval value, oldvalue; + int i; + time_t curtime; + curtime = time(0); + printf("Starting: %s", ctime(&curtime)); + value.it_interval.tv_sec = value.it_value.tv_sec = 1; + value.it_interval.tv_usec = value.it_value.tv_usec = 0; + adjustment.tv_sec = 0; + adjustment.tv_usec = -2000; + signal(SIGALRM, timeout); + setitimer(ITIMER_REAL, &value, &oldvalue); + for (i=0; i<10; i++) { + pause(); + } +} + +int timeout(sig, code, scp) +int sig,code; +struct sigcontext *scp; +{ + signal (SIGALRM, timeout); + if (adjtime(&adjustment, &result)) + printf("adjtime call failed\n"); + if (result.tv_sec != 0 || result.tv_usec != 0) { + printf("result.u = %d.%06.6d ", (int) result.tv_sec, + (int) result.tv_usec); + } +} diff --git a/usr.sbin/xntpd/util/tickadj.c b/usr.sbin/xntpd/util/tickadj.c new file mode 100644 index 0000000..da18e06 --- /dev/null +++ b/usr.sbin/xntpd/util/tickadj.c @@ -0,0 +1,518 @@ +/* tickadj.c,v 3.1 1993/07/06 01:11:05 jbj Exp + * tickadj - read, and possibly modify, the kernel `tick' and + * `tickadj' variables, as well as `dosynctodr'. Note that + * this operates on the running kernel only. I'd like to be + * able to read and write the binary as well, but haven't + * mastered this yet. + */ +#include <stdio.h> +#include <sys/types.h> +#include <sys/file.h> +#include <sys/stat.h> + +#if defined(SYS_AUX3) || defined(SYS_AUX2) +#include <sys/param.h> +#include <sys/time.h> +#include <sys/resource.h> +#include <sys/file.h> +#include <a.out.h> +#include <sys/var.h> +#else +#include <nlist.h> +#endif + +#include "ntp_io.h" +#include "ntp_stdlib.h" + +#ifdef RS6000 +#undef hz +#endif /* RS6000 */ + +#if defined(SOLARIS)||defined(RS6000)||defined(SYS_SINIXM) +#if !defined(_SC_CLK_TCK) +#include <unistd.h> +#endif +#endif + +#ifdef SYS_PTX +#define L_SET SEEK_SET +#endif + +#define KMEM "/dev/kmem" +#define STREQ(a, b) (*(a) == *(b) && strcmp((a), (b)) == 0) + +char *progname; +int debug; + +int dokmem = 1; +int writetickadj = 0; +int writeopttickadj = 0; +int unsetdosync = 0; +int writetick = 0; +int quiet = 0; +int setnoprintf = 0; + +char *kmem = KMEM; +char *kernel = NULL; +char *file = NULL; +int fd = -1; + +static char * getoffsets P((char *, unsigned long *, unsigned long *, unsigned long *, unsigned long *)); +static int openfile P((char *, int)); +static void writevar P((int, unsigned long, int)); +static void readvar P((int, unsigned long, int *)); +#ifndef NTP_POSIX_SOURCE +extern int getopt P((int, char **, char *)); +#endif + +/* + * main - parse arguments and handle options + */ +void +main(argc, argv) +int argc; +char *argv[]; +{ + int c; + int errflg = 0; + extern int optind; + extern char *optarg; + unsigned long tickadj_offset; + unsigned long tick_offset; + unsigned long dosync_offset; + unsigned long noprintf_offset; + int tickadj; + int tick; + int dosynctodr; + int noprintf; + int hz, hz_hundredths; + int recommend_tickadj; + long tmp; + int openfile(); + char *getoffsets(); + void readvar(); + void writevar(); + + progname = argv[0]; + while ((c = getopt(argc, argv, "a:Adkqpst:")) != EOF) + switch (c) { + case 'd': + ++debug; + break; + case 'k': + dokmem = 1; + break; + case 'p': + setnoprintf = 1; + break; + case 'q': + quiet = 1; + break; + case 'a': + writetickadj = atoi(optarg); + if (writetickadj <= 0) { + (void) fprintf(stderr, + "%s: unlikely value for tickadj: %s\n", + progname, optarg); + errflg++; + } + break; + case 'A': + writeopttickadj = 1; + break; + case 's': + unsetdosync = 1; + break; + case 't': + writetick = atoi(optarg); + if (writetick <= 0) { + (void) fprintf(stderr, + "%s: unlikely value for tick: %s\n", + progname, optarg); + errflg++; + } + break; + default: + errflg++; + break; + } + if (errflg || optind != argc) { + (void) fprintf(stderr, + "usage: %s [-Aqsp] [-a newadj] [-t newtick]\n", progname); + exit(2); + } + kernel = getoffsets(kernel, &tick_offset, + &tickadj_offset, &dosync_offset, &noprintf_offset); + + if (debug) { + (void) printf("tick offset = %lu\n", tick_offset); + (void) printf("tickadj offset = %lu\n", tickadj_offset); + (void) printf("dosynctodr offset = %lu\n", dosync_offset); + (void) printf("noprintf offset = %lu\n", noprintf_offset); + } + + if (setnoprintf && (noprintf_offset == 0)) { + (void) fprintf(stderr, + "No noprintf kernal variable\n"); + exit(1); + } + + if (unsetdosync && (dosync_offset == 0)) { + (void) fprintf(stderr, + "No dosynctodr kernal variable\n"); + exit(1); + } + + if (writeopttickadj && (tickadj_offset == 0)) { + (void) fprintf(stderr, + "No tickadj kernal variable\n"); + exit(1); + } + + if (writetick && (tick_offset == 0)) { + (void) fprintf(stderr, + "No tick kernal variable\n"); + exit(1); + } + + + if (tickadj_offset != 0) + readvar(fd, tickadj_offset, &tickadj); + +#if defined(SOLARIS)||defined(RS6000)||defined(SYS_SINIXM) + tick = 1000000/sysconf(_SC_CLK_TCK); +#else + readvar(fd, tick_offset, &tick); +#endif + + if (dosync_offset != 0) + readvar(fd, dosync_offset, &dosynctodr); + if (noprintf_offset != 0) + readvar(fd, noprintf_offset, &noprintf); + (void) close(fd); + + if (unsetdosync && dosync_offset == 0) { + (void) fprintf(stderr, + "%s: can't find dosynctodr in namelist\n", progname); + exit(1); + } + + if (!quiet) { + (void) printf("tick = %d us",tick); + if (tickadj_offset != 0) + (void) printf(", tickadj = %d us", tickadj); + if (dosync_offset != 0) + (void) printf(", dosynctodr is %s", dosynctodr ? "on" : "off"); + (void) printf("\n"); + if (noprintf_offset != 0) + (void) printf("kernel level printf's: %s\n", noprintf ? "off" : "on"); + } + + if (tick <= 0) { + (void) fprintf(stderr, "%s: the value of tick is silly!\n", + progname); + exit(1); + } + + hz = (int)(1000000L / (long)tick); + hz_hundredths = (int)((100000000L / (long)tick) - ((long)hz * 100L)); + if (!quiet) + (void) printf("calculated hz = %d.%02d Hz\n", hz, + hz_hundredths); + tmp = (long) tick * 500L; + recommend_tickadj = (int)(tmp / 1000000L); + if (tmp % 1000000L > 0) + recommend_tickadj++; + +#if defined(RS6000) + if (recommend_tickadj < 40) recommend_tickadj = 40; +#endif + + if ((!quiet) && (tickadj_offset != 0)) + (void) printf("recommended value of tickadj = %d us\n", + recommend_tickadj); + + if (writetickadj == 0 && !writeopttickadj && + !unsetdosync && writetick == 0 && !setnoprintf) + exit(0); + + if (writetickadj == 0 && writeopttickadj) + writetickadj = recommend_tickadj; + + fd = openfile(file, O_WRONLY); + + if (setnoprintf && (dosync_offset != 0)) { + if (!quiet) { + (void) fprintf(stderr, "setting noprintf: "); + (void) fflush(stderr); + } + writevar(fd, noprintf_offset, 1); + if (!quiet) + (void) fprintf(stderr, "done!\n"); + } + + if ((writetick > 0) && (tick_offset != 0)) { + if (!quiet) { + (void) fprintf(stderr, "writing tick, value %d: ", + writetick); + (void) fflush(stderr); + } + writevar(fd, tick_offset, writetick); + if (!quiet) + (void) fprintf(stderr, "done!\n"); + } + + if ((writetickadj > 0) && (tickadj_offset != 0)) { + if (!quiet) { + (void) fprintf(stderr, "writing tickadj, value %d: ", + writetickadj); + (void) fflush(stderr); + } + writevar(fd, tickadj_offset, writetickadj); + if (!quiet) + (void) fprintf(stderr, "done!\n"); + } + + if (unsetdosync && (dosync_offset != 0)) { + if (!quiet) { + (void) fprintf(stderr, "zeroing dosynctodr: "); + (void) fflush(stderr); + } + writevar(fd, dosync_offset, 0); + if (!quiet) + (void) fprintf(stderr, "done!\n"); + } + (void) close(fd); + exit(0); +} + +/* + * getoffsets - read the magic offsets from the specified file + */ +static char * +getoffsets(filex, tick_off, tickadj_off, dosync_off, noprintf_off) + char *filex; + unsigned long *tick_off; + unsigned long *tickadj_off; + unsigned long *dosync_off; + unsigned long *noprintf_off; +{ + char **kname; + +#if defined(SYS_AUX3) || defined(SYS_AUX2) +#define X_TICKADJ 0 +#define X_V 1 +#define X_TICK 2 +#define X_DEF + static struct nlist nl[4]; +#endif + +#ifdef NeXT +#define X_TICKADJ 0 +#define X_TICK 1 +#define X_DOSYNC 2 +#define X_NOPRINTF 3 +#define X_DEF + static struct nlist nl[] = + { {{"_tickadj"}}, + {{"_tick"}}, + {{"_dosynctodr"}}, + {{"_noprintf"}}, + {{""}}, + }; +#endif + +#if defined(SYS_SVR4) || defined(SYS_PTX) +#define X_TICKADJ 0 +#define X_TICK 1 +#define X_DOSYNC 2 +#define X_NOPRINTF 3 +#define X_DEF + static struct nlist nl[] = + { {{"tickadj"}}, + {{"tick"}}, + {{"doresettodr"}}, + {{"noprintf"}}, + {{""}}, + }; +#endif /* SYS_SVR4 */ + +#if defined(SOLARIS)||defined(RS6000)||defined(SYS_SINIXM) +#ifndef SOLARIS_HRTIME +#define X_TICKADJ 0 +#endif +#define X_DOSYNC 1 +#define X_NOPRINTF 2 +#define X_DEF + static struct nlist nl[] = + { {"tickadj"}, + {"dosynctodr"}, + {"noprintf"}, + {""}, + }; + +#if defined(RS6000) + int i; +#endif +#endif + +#if !defined(X_DEF) +#define X_TICKADJ 0 +#define X_TICK 1 +#define X_DOSYNC 2 +#define X_NOPRINTF 3 + static struct nlist nl[] = + { {"_tickadj"}, + {"_tick"}, + {"_dosynctodr"}, + {"_noprintf"}, + {""}, + }; +#endif + static char *kernels[] = { + "/vmunix", + "/unix", + "/mach", + "/kernel/unix", + "/386bsd", + "/netbsd", + NULL + }; + struct stat stbuf; + +#if defined(SYS_AUX3) || defined(SYS_AUX2) + strcpy (nl[X_TICKADJ].n_name, "tickadj"); + strcpy (nl[X_V].n_name, "v"); + strcpy (nl[X_TICK].n_name, "tick"); + nl[3].n_name[0] = '\0'; +#endif + + for (kname = kernels; *kname != NULL; kname++) { + if (stat(*kname, &stbuf) == -1) + continue; + if (nlist(*kname, nl) >= 0) + break; + } + if (*kname == NULL) { + (void) fprintf(stderr, + "%s: nlist fails: can't find/read /vmunix or /unix\n", + progname); + exit(1); + } + + if (dokmem) + file = kmem; + else + file = kernel; + + fd = openfile(file, O_RDONLY); +#if defined(RS6000) + /* + * Go one more round of indirection. + */ + for (i=0; i<(sizeof(nl)/sizeof(struct nlist)); i++) { + if (nl[i].n_value) { + readvar(fd, nl[i].n_value, &nl[i].n_value); + } + } +#endif + *tickadj_off = 0; + *tick_off = 0; + *dosync_off = 0; + *noprintf_off = 0; + +#if defined(X_TICKADJ) + *tickadj_off = nl[X_TICKADJ].n_value; +#endif + +#if defined(X_TICK) + *tick_off = nl[X_TICK].n_value; +#endif + +#if defined(X_DOSYNC) + *dosync_off = nl[X_DOSYNC].n_value; +#endif + +#if defined(X_NOPRINTF) + *noprintf_off = nl[X_NOPRINTF].n_value; +#endif + return *kname; +} + +#undef X_TICKADJ +#undef X_TICK +#undef X_DOSYNC +#undef X_NOPRINTF + + +/* + * openfile - open the file, check for errors + */ +static int +openfile(name, mode) + char *name; + int mode; +{ + int fd; + + fd = open(name, mode); + if (fd < 0) { + (void) fprintf(stderr, "%s: open %s: ", progname, name); + perror(""); + exit(1); + } + return fd; +} + + +/* + * writevar - write a variable into the file + */ +static void +writevar(fd, off, var) + int fd; + unsigned long off; + int var; +{ + + if (lseek(fd, off, L_SET) == -1) { + (void) fprintf(stderr, "%s: lseek fails: ", progname); + perror(""); + exit(1); + } + if (write(fd, (char *)&var, sizeof(int)) != sizeof(int)) { + (void) fprintf(stderr, "%s: write fails: ", progname); + perror(""); + exit(1); + } +} + + +/* + * readvar - read a variable from the file + */ +static void +readvar(fd, off, var) + int fd; + unsigned long off; + int *var; +{ + int i; + + if (lseek(fd, off, L_SET) == -1) { + (void) fprintf(stderr, "%s: lseek fails: ", progname); + perror(""); + exit(1); + } + i = read(fd, (char *)var, sizeof(int)); + if (i < 0) { + (void) fprintf(stderr, "%s: read fails: ", progname); + perror(""); + exit(1); + } + if (i != sizeof(int)) { + (void) fprintf(stderr, "%s: read expected %d, got %d\n", + progname, sizeof(int), i); + exit(1); + } +} diff --git a/usr.sbin/xntpd/util/timetrim.c b/usr.sbin/xntpd/util/timetrim.c new file mode 100644 index 0000000..052a587 --- /dev/null +++ b/usr.sbin/xntpd/util/timetrim.c @@ -0,0 +1,85 @@ +/* + * timetrim.c,v 3.1 1993/07/06 01:11:06 jbj Exp + * + * "timetrim" allows setting and adjustment of the system clock frequency + * trim parameter on Silicon Graphics machines. The trim value native + * units are nanoseconds per second (10**-9), so a trim value of 1 makes + * the system clock step ahead 1 nanosecond more per second than a value + * of zero. Xntpd currently uses units of 2**-20 secs for its frequency + * offset (drift) values; to convert to a timetrim value, multiply by + * 1E9 / 2**20 (about 954). + * + * "timetrim" with no arguments just prints out the current kernel value. + * With a numeric argument, the kernel value is set to the supplied value. + * The "-i" flag causes the supplied value to be added to the kernel value. + * The "-n" option causes all input and output to be in xntpd units rather + * than timetrim native units. + * + * Note that there is a limit of +-3000000 (0.3%) on the timetrim value + * which is (silently?) enforced by the kernel. + * + */ + +#include <stdio.h> +#include <ctype.h> +#include <sys/syssgi.h> + +#define abs(X) (((X) < 0) ? -(X) : (X)) +#define USAGE "usage: timetrim [-n] [[-i] value]\n" +#define SGITONTP(X) ((double)(X) * 1048576.0/1.0e9) +#define NTPTOSGI(X) ((LONG)((X) * 1.0e9/1048576.0)) + +main(argc, argv) +int argc; +char **argv; +{ + char *rem; + int c, incremental = 0, ntpunits = 0; + LONG timetrim; + double value, strtod(); + + while (--argc && **++argv == '-' && isalpha(argv[0][1])) { + switch (argv[0][1]) { + case 'i': + incremental++; + break; + case 'n': + ntpunits++; + break; + default: + fprintf(stderr, USAGE); + exit(1); + } + } + + if (syssgi(SGI_GETTIMETRIM, &timetrim) < 0) { + perror("syssgi"); + exit(2); + } + + if (argc == 0) { + if (ntpunits) + fprintf(stdout, "%0.5lf\n", SGITONTP(timetrim)); + else + fprintf(stdout, "%ld\n", timetrim); + } else if (argc != 1) { + fprintf(stderr, USAGE); + exit(1); + } else { + value = strtod(argv[0], &rem); + if (*rem != '\0') { + fprintf(stderr, USAGE); + exit(1); + } + if (ntpunits) + value = NTPTOSGI(value); + if (incremental) + timetrim += value; + else + timetrim = value; + if (syssgi(SGI_SETTIMETRIM, timetrim) < 0) { + perror("syssgi"); + exit(2); + } + } +} |