summaryrefslogtreecommitdiffstats
path: root/usr.sbin/xntpd/util
diff options
context:
space:
mode:
authorwollman <wollman@FreeBSD.org>1993-12-21 18:36:48 +0000
committerwollman <wollman@FreeBSD.org>1993-12-21 18:36:48 +0000
commit8e51e9f1429efc498f923bce8b25b20f47d7c075 (patch)
tree9db10264d45dc397a38276190303093a450d769e /usr.sbin/xntpd/util
downloadFreeBSD-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.tmpl62
-rw-r--r--usr.sbin/xntpd/util/README67
-rw-r--r--usr.sbin/xntpd/util/byteorder.c52
-rw-r--r--usr.sbin/xntpd/util/jitter.c73
-rw-r--r--usr.sbin/xntpd/util/kern.c210
-rw-r--r--usr.sbin/xntpd/util/longsize.c11
-rw-r--r--usr.sbin/xntpd/util/ntptime.c220
-rw-r--r--usr.sbin/xntpd/util/precision.c81
-rw-r--r--usr.sbin/xntpd/util/testrs6000.c44
-rw-r--r--usr.sbin/xntpd/util/tickadj.c518
-rw-r--r--usr.sbin/xntpd/util/timetrim.c85
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);
+ }
+ }
+}
OpenPOWER on IntegriCloud