summaryrefslogtreecommitdiffstats
path: root/contrib/ntp/ntpq
diff options
context:
space:
mode:
authorroberto <roberto@FreeBSD.org>1999-12-09 13:01:21 +0000
committerroberto <roberto@FreeBSD.org>1999-12-09 13:01:21 +0000
commitef64b99e8412f2273dd2e8b3291c2f78ffc4667f (patch)
treefc0cfa1aab0ff6b228f511b410733ef4f35d1ead /contrib/ntp/ntpq
downloadFreeBSD-src-ef64b99e8412f2273dd2e8b3291c2f78ffc4667f.zip
FreeBSD-src-ef64b99e8412f2273dd2e8b3291c2f78ffc4667f.tar.gz
Virgin import of ntpd 4.0.98f
Diffstat (limited to 'contrib/ntp/ntpq')
-rw-r--r--contrib/ntp/ntpq/Makefile.am21
-rw-r--r--contrib/ntp/ntpq/Makefile.in360
-rw-r--r--contrib/ntp/ntpq/README6
-rw-r--r--contrib/ntp/ntpq/ntpq.c3095
-rw-r--r--contrib/ntp/ntpq/ntpq.h89
-rw-r--r--contrib/ntp/ntpq/ntpq_ops.c1651
6 files changed, 5222 insertions, 0 deletions
diff --git a/contrib/ntp/ntpq/Makefile.am b/contrib/ntp/ntpq/Makefile.am
new file mode 100644
index 0000000..aced169
--- /dev/null
+++ b/contrib/ntp/ntpq/Makefile.am
@@ -0,0 +1,21 @@
+#AUTOMAKE_OPTIONS = ../util/ansi2knr no-dependencies
+AUTOMAKE_OPTIONS = ../util/ansi2knr
+bin_PROGRAMS = ntpq
+INCLUDES = -I$(top_srcdir)/include
+# LDADD might need RESLIB and ADJLIB
+LDADD = version.o ../libntp/libntp.a @LIBRSAREF@
+DISTCLEANFILES = .version
+noinst_HEADERS = ntpq.h
+#EXTRA_DIST = ntpq.mak
+ETAGS_ARGS = Makefile.am
+
+ntpq_SOURCES = ntpq.c ntpq_ops.c
+
+$(PROGRAMS): $(LDADD)
+
+../libntp/libntp.a:
+ cd ../libntp && $(MAKE)
+
+version.o: $(ntpq_OBJECTS) ../libntp/libntp.a @LIBRSAREF@ Makefile
+ $(top_builddir)/scripts/mkver ntpq
+ $(COMPILE) -c version.c
diff --git a/contrib/ntp/ntpq/Makefile.in b/contrib/ntp/ntpq/Makefile.in
new file mode 100644
index 0000000..549840a
--- /dev/null
+++ b/contrib/ntp/ntpq/Makefile.in
@@ -0,0 +1,360 @@
+# Makefile.in generated automatically by automake 1.4a from Makefile.am
+
+# Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+SHELL = @SHELL@
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+
+bindir = @bindir@
+sbindir = @sbindir@
+libexecdir = @libexecdir@
+datadir = @datadir@
+sysconfdir = @sysconfdir@
+sharedstatedir = @sharedstatedir@
+localstatedir = @localstatedir@
+libdir = @libdir@
+infodir = @infodir@
+mandir = @mandir@
+includedir = @includedir@
+oldincludedir = /usr/include
+
+DESTDIR =
+
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+
+top_builddir = ..
+
+ACLOCAL = @ACLOCAL@
+AUTOCONF = @AUTOCONF@
+AUTOMAKE = @AUTOMAKE@
+AUTOHEADER = @AUTOHEADER@
+
+INSTALL = @INSTALL@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_FLAG =
+transform = @program_transform_name@
+
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_alias = @build_alias@
+build_triplet = @build@
+host_alias = @host_alias@
+host_triplet = @host@
+target_alias = @target_alias@
+target_triplet = @target@
+AMTAR = @AMTAR@
+AMTARFLAGS = @AMTARFLAGS@
+AWK = @AWK@
+CC = @CC@
+CFLAGS = @CFLAGS@
+CHUTEST = @CHUTEST@
+CLKTEST = @CLKTEST@
+CPP = @CPP@
+DCFD = @DCFD@
+LDFLAGS = @LDFLAGS@
+LIBPARSE = @LIBPARSE@
+LIBRSAREF = @LIBRSAREF@
+LN_S = @LN_S@
+MAKEINFO = @MAKEINFO@
+MAKE_ADJTIMED = @MAKE_ADJTIMED@
+MAKE_CHECK_Y2K = @MAKE_CHECK_Y2K@
+MAKE_LIBPARSE = @MAKE_LIBPARSE@
+MAKE_LIBPARSE_KERNEL = @MAKE_LIBPARSE_KERNEL@
+MAKE_LIBRSAREF = @MAKE_LIBRSAREF@
+MAKE_NTPTIME = @MAKE_NTPTIME@
+MAKE_PARSEKMODULE = @MAKE_PARSEKMODULE@
+MAKE_TICKADJ = @MAKE_TICKADJ@
+PACKAGE = @PACKAGE@
+PATH_SH = @PATH_SH@
+PROPDELAY = @PROPDELAY@
+RANLIB = @RANLIB@
+RSAREF = @RSAREF@
+TESTDCF = @TESTDCF@
+U = @U@
+VERSION = @VERSION@
+
+#AUTOMAKE_OPTIONS = ../util/ansi2knr no-dependencies
+
+
+AUTOMAKE_OPTIONS = ../util/ansi2knr
+bin_PROGRAMS = ntpq
+INCLUDES = -I$(top_srcdir)/include
+# LDADD might need RESLIB and ADJLIB
+LDADD = version.o ../libntp/libntp.a @LIBRSAREF@
+DISTCLEANFILES = .version
+noinst_HEADERS = ntpq.h
+#EXTRA_DIST = ntpq.mak
+ETAGS_ARGS = Makefile.am
+
+ntpq_SOURCES = ntpq.c ntpq_ops.c
+subdir = ntpq
+mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
+CONFIG_HEADER = ../config.h
+CONFIG_CLEAN_FILES =
+PROGRAMS = $(bin_PROGRAMS)
+
+
+DEFS = @DEFS@ -I. -I$(srcdir) -I..
+CPPFLAGS = @CPPFLAGS@
+LIBS = @LIBS@
+ANSI2KNR = ../util/ansi2knr
+am_ntpq_OBJECTS = ntpq$U.o ntpq_ops$U.o
+ntpq_OBJECTS = $(am_ntpq_OBJECTS)
+ntpq_LDADD = $(LDADD)
+ntpq_DEPENDENCIES = version.o ../libntp/libntp.a
+ntpq_LDFLAGS =
+COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
+DIST_SOURCES = $(ntpq_SOURCES)
+HEADERS = $(noinst_HEADERS)
+
+DIST_COMMON = README $(noinst_HEADERS) Makefile.am Makefile.in
+
+
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+
+GZIP_ENV = --best
+SOURCES = $(ntpq_SOURCES)
+OBJECTS = $(am_ntpq_OBJECTS)
+
+all: all-redirect
+.SUFFIXES:
+.SUFFIXES: .c .o
+$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4)
+ cd $(top_srcdir) && $(AUTOMAKE) --gnu --include-deps ntpq/Makefile
+
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ cd $(top_builddir) \
+ && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status
+
+
+mostlyclean-binPROGRAMS:
+
+clean-binPROGRAMS:
+ -test -z "$(bin_PROGRAMS)" || rm -f $(bin_PROGRAMS)
+
+distclean-binPROGRAMS:
+
+maintainer-clean-binPROGRAMS:
+
+install-binPROGRAMS: $(bin_PROGRAMS)
+ @$(NORMAL_INSTALL)
+ $(mkinstalldirs) $(DESTDIR)$(bindir)
+ @list='$(bin_PROGRAMS)'; for p in $$list; do \
+ if test -f $$p; then \
+ f="`echo $$p|sed -e 's/$(EXEEXT)$$//' -e '$(transform)' -e 's/$$/$(EXEEXT)/'`"; \
+ echo " $(INSTALL_PROGRAM) $(INSTALL_STRIP_FLAG) $$p $(DESTDIR)$(bindir)/$$f"; \
+ $(INSTALL_PROGRAM) $(INSTALL_STRIP_FLAG) $$p $(DESTDIR)$(bindir)/$$f; \
+ else :; fi; \
+ done
+
+uninstall-binPROGRAMS:
+ @$(NORMAL_UNINSTALL)
+ @list='$(bin_PROGRAMS)'; for p in $$list; do \
+ f="`echo $$p|sed -e 's/$(EXEEXT)$$//' -e '$(transform)' -e 's/$$/$(EXEEXT)/'`"; \
+ echo " rm -f $(DESTDIR)$(bindir)/$$f"; \
+ rm -f $(DESTDIR)$(bindir)/$$f; \
+ done
+
+.c.o:
+ $(COMPILE) -c $<
+
+mostlyclean-compile:
+ -rm -f *.o core *.core
+
+clean-compile:
+
+distclean-compile:
+ -rm -f *.tab.c
+
+maintainer-clean-compile:
+../util/ansi2knr: ../util/ansi2knr.o
+ cd ../util && $(MAKE) $(AM_MAKEFLAGS) ansi2knr
+
+../util/ansi2knr.o:
+ cd ../util && $(MAKE) $(AM_MAKEFLAGS) ansi2knr.o
+
+
+mostlyclean-kr:
+ -rm -f *_.c
+
+clean-kr:
+
+distclean-kr:
+
+maintainer-clean-kr:
+ntpq$U.o:
+ntpq_ops$U.o:
+
+ntpq: $(ntpq_OBJECTS) $(ntpq_DEPENDENCIES)
+ @rm -f ntpq
+ $(LINK) $(ntpq_LDFLAGS) $(ntpq_OBJECTS) $(ntpq_LDADD) $(LIBS)
+ntpq_.c: ntpq.c $(ANSI2KNR)
+ $(CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/ntpq.c; then echo $(srcdir)/ntpq.c; else echo ntpq.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > ntpq_.c
+ntpq_ops_.c: ntpq_ops.c $(ANSI2KNR)
+ $(CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/ntpq_ops.c; then echo $(srcdir)/ntpq_ops.c; else echo ntpq_ops.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > ntpq_ops_.c
+ntpq_.o ntpq_ops_.o : $(ANSI2KNR)
+
+tags: TAGS
+
+ID: $(HEADERS) $(SOURCES) $(LISP)
+ list='$(SOURCES) $(HEADERS)'; \
+ unique=`for i in $$list; do echo $$i; done | \
+ ${AWK:-awk} ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ here=`pwd` && cd $(srcdir) \
+ && mkid -f$$here/ID $$unique $(LISP)
+
+TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS)'; \
+ unique=`for i in $$list; do echo $$i; done | \
+ ${AWK:-awk} ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ test -z "$(ETAGS_ARGS)$$unique$(LISP)$$tags" \
+ || (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags $$unique $(LISP) -o $$here/TAGS)
+
+mostlyclean-tags:
+
+clean-tags:
+
+distclean-tags:
+ -rm -f TAGS ID
+
+maintainer-clean-tags:
+
+distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir)
+
+distdir: $(DISTFILES)
+ @for file in $(DISTFILES); do \
+ d=$(srcdir); \
+ if test -d $$d/$$file; then \
+ cp -pr $$d/$$file $(distdir)/$$file; \
+ else \
+ test -f $(distdir)/$$file \
+ || ln $$d/$$file $(distdir)/$$file 2> /dev/null \
+ || cp -p $$d/$$file $(distdir)/$$file || :; \
+ fi; \
+ done
+ntpq.o: ntpq.c ntpq.h ../include/ntp_fp.h ../include/ntp_types.h \
+ ../include/ntp_machine.h ../config.h ../include/ntp_proto.h \
+ ../include/ntp.h ../include/ntp_control.h \
+ ../include/ntp_string.h ../include/ntp_malloc.h \
+ ../include/ntp_unixtime.h ../include/ntp_calendar.h \
+ ../include/ntp_io.h ../include/ntp_select.h \
+ ../include/ntp_stdlib.h ../include/l_stdlib.h
+ntpq_ops.o: ntpq_ops.c ntpq.h ../include/ntp_fp.h ../include/ntp_types.h \
+ ../include/ntp_machine.h ../config.h ../include/ntp_proto.h \
+ ../include/ntp.h ../include/ntp_control.h \
+ ../include/ntp_string.h ../include/ntp_malloc.h \
+ ../include/ntp_stdlib.h ../include/l_stdlib.h
+
+info-am:
+info: info-am
+dvi-am:
+dvi: dvi-am
+check-am: all-am
+check: check-am
+installcheck-am:
+installcheck: installcheck-am
+install-exec-am: install-binPROGRAMS
+install-exec: install-exec-am
+
+install-data-am:
+install-data: install-data-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+install: install-am
+uninstall-am: uninstall-binPROGRAMS
+uninstall: uninstall-am
+all-am: Makefile $(PROGRAMS) $(HEADERS)
+all-redirect: all-am
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_STRIP_FLAG=-s install
+installdirs:
+ $(mkinstalldirs) $(DESTDIR)$(bindir)
+
+
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -rm -f Makefile $(CONFIG_CLEAN_FILES)
+ -rm -f config.cache config.log stamp-h stamp-h[0-9]*
+ -test -z "$(DISTCLEANFILES)" || rm -f $(DISTCLEANFILES)
+
+maintainer-clean-generic:
+mostlyclean-am: mostlyclean-binPROGRAMS mostlyclean-compile \
+ mostlyclean-kr mostlyclean-tags mostlyclean-generic
+
+mostlyclean: mostlyclean-am
+
+clean-am: clean-binPROGRAMS clean-compile clean-kr clean-tags \
+ clean-generic mostlyclean-am
+
+clean: clean-am
+
+distclean-am: distclean-binPROGRAMS distclean-compile distclean-kr \
+ distclean-tags distclean-generic clean-am
+
+distclean: distclean-am
+
+maintainer-clean-am: maintainer-clean-binPROGRAMS \
+ maintainer-clean-compile maintainer-clean-kr \
+ maintainer-clean-tags maintainer-clean-generic \
+ distclean-am
+ @echo "This command is intended for maintainers to use;"
+ @echo "it deletes files that may require special tools to rebuild."
+
+maintainer-clean: maintainer-clean-am
+
+.PHONY: mostlyclean-binPROGRAMS distclean-binPROGRAMS clean-binPROGRAMS \
+maintainer-clean-binPROGRAMS uninstall-binPROGRAMS install-binPROGRAMS \
+mostlyclean-compile distclean-compile clean-compile \
+maintainer-clean-compile mostlyclean-kr distclean-kr clean-kr \
+maintainer-clean-kr tags mostlyclean-tags distclean-tags clean-tags \
+maintainer-clean-tags distdir info-am info dvi-am dvi check check-am \
+installcheck-am installcheck install-exec-am install-exec \
+install-data-am install-data install-am install uninstall-am uninstall \
+all-redirect all-am all install-strip installdirs mostlyclean-generic \
+distclean-generic clean-generic maintainer-clean-generic clean \
+mostlyclean distclean maintainer-clean
+
+
+$(PROGRAMS): $(LDADD)
+
+../libntp/libntp.a:
+ cd ../libntp && $(MAKE)
+
+version.o: $(ntpq_OBJECTS) ../libntp/libntp.a @LIBRSAREF@ Makefile
+ $(top_builddir)/scripts/mkver ntpq
+ $(COMPILE) -c version.c
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/contrib/ntp/ntpq/README b/contrib/ntp/ntpq/README
new file mode 100644
index 0000000..d280f74
--- /dev/null
+++ b/contrib/ntp/ntpq/README
@@ -0,0 +1,6 @@
+README file for directory ./ntpq of the NTP Version 4 distribution
+
+This directory contains the sources for the ntpq utility program. See
+the README and RELNOTES files in the parent directory for directions on
+how to make and install this program. The current version number of this
+program is in the version.c file.
diff --git a/contrib/ntp/ntpq/ntpq.c b/contrib/ntp/ntpq/ntpq.c
new file mode 100644
index 0000000..3361e2b
--- /dev/null
+++ b/contrib/ntp/ntpq/ntpq.c
@@ -0,0 +1,3095 @@
+/*
+ * ntpq - query an NTP server using mode 6 commands
+ */
+#include <stdio.h>
+#include <ctype.h>
+#include <signal.h>
+#include <setjmp.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <netdb.h>
+#ifdef SYS_WINNT
+# include <io.h>
+#else
+#define closesocket close
+#endif /* SYS_WINNT */
+
+#include "ntpq.h"
+#include "ntp_unixtime.h"
+#include "ntp_calendar.h"
+#include "ntp_io.h"
+#include "ntp_select.h"
+#include "ntp_stdlib.h"
+
+#ifdef SYS_VXWORKS
+/* vxWorks needs mode flag -casey*/
+#define open(name, flags) open(name, flags, 0777)
+#define SERVER_PORT_NUM 123
+#endif
+
+/*
+ * Because we potentially understand a lot of commands we will run
+ * interactive if connected to a terminal.
+ */
+int interactive = 0; /* set to 1 when we should prompt */
+const char *prompt = "ntpq> "; /* prompt to ask him about */
+
+
+/*
+ * Keyid used for authenticated requests. Obtained on the fly.
+ */
+u_long info_auth_keyid = NTP_MAXKEY;
+
+/*
+ * Type of key md5 or des
+ */
+#define KEY_TYPE_DES 3
+#define KEY_TYPE_MD5 4
+
+static int info_auth_keytype = KEY_TYPE_MD5; /* MD5 */
+u_long current_time; /* needed by authkeys; not used */
+
+/*
+ * Flag which indicates we should always send authenticated requests
+ */
+int always_auth = 0;
+
+/*
+ * Flag which indicates raw mode output.
+ */
+int rawmode = 0;
+
+/*
+ * Packet version number we use
+ */
+u_char pktversion = NTP_OLDVERSION + 1;
+
+/*
+ * Don't jump if no set jmp.
+ */
+volatile int jump = 0;
+
+/*
+ * Format values
+ */
+#define PADDING 0
+#define TS 1 /* time stamp */
+#define FL 2 /* l_fp type value */
+#define FU 3 /* u_fp type value */
+#define FS 4 /* s_fp type value */
+#define UI 5 /* unsigned integer value */
+#define SI 6 /* signed integer value */
+#define HA 7 /* host address */
+#define NA 8 /* network address */
+#define ST 9 /* string value */
+#define RF 10 /* refid (sometimes string, sometimes not) */
+#define LP 11 /* leap (print in binary) */
+#define OC 12 /* integer, print in octal */
+#define MD 13 /* mode */
+#define AR 14 /* array of times */
+#define FX 15 /* test flags */
+#define EOV 255 /* end of table */
+
+
+/*
+ * System variable values. The array can be indexed by
+ * the variable index to find the textual name.
+ */
+struct ctl_var sys_var[] = {
+ { 0, PADDING, "" }, /* 0 */
+ { CS_LEAP, LP, "leap" }, /* 1 */
+ { CS_STRATUM, UI, "stratum" }, /* 2 */
+ { CS_PRECISION, SI, "precision" }, /* 3 */
+ { CS_ROOTDELAY, FS, "rootdelay" }, /* 4 */
+ { CS_ROOTDISPERSION, FU, "rootdispersion" }, /* 5 */
+ { CS_REFID, RF, "refid" }, /* 6 */
+ { CS_REFTIME, TS, "reftime" }, /* 7 */
+ { CS_POLL, UI, "poll" }, /* 8 */
+ { CS_PEERID, UI, "peer" }, /* 9 */
+ { CS_STATE, UI, "state" }, /* 10 */
+ { CS_OFFSET, FL, "phase" }, /* 11 */
+ { CS_DRIFT, FS, "frequency" }, /* 12 */
+ { CS_COMPLIANCE, FU, "jitter" }, /* 13 */
+ { CS_CLOCK, TS, "clock" }, /* 14 */
+ { CS_PROCESSOR, ST, "processor" }, /* 15 */
+ { CS_SYSTEM, ST, "system" }, /* 16 */
+ { CS_STABIL, FS, "stability" }, /* 17 */
+ { 0, EOV, "" }
+};
+
+
+/*
+ * Peer variable list
+ */
+struct ctl_var peer_var[] = {
+ { 0, PADDING, "" }, /* 0 */
+ { CP_CONFIG, UI, "config" }, /* 1 */
+ { CP_AUTHENABLE, UI, "authenable" }, /* 2 */
+ { CP_AUTHENTIC, UI, "authentic" }, /* 3 */
+ { CP_SRCADR, HA, "srcadr" }, /* 4 */
+ { CP_SRCPORT, UI, "srcport" }, /* 5 */
+ { CP_DSTADR, NA, "dstadr" }, /* 6 */
+ { CP_DSTPORT, UI, "dstport" }, /* 7 */
+ { CP_LEAP, LP, "leap" }, /* 8 */
+ { CP_HMODE, MD, "hmode" }, /* 9 */
+ { CP_STRATUM, UI, "stratum" }, /* 10 */
+ { CP_PPOLL, UI, "ppoll" }, /* 11 */
+ { CP_HPOLL, UI, "hpoll" }, /* 12 */
+ { CP_PRECISION, SI, "precision" }, /* 13 */
+ { CP_ROOTDELAY, FS, "rootdelay" }, /* 14 */
+ { CP_ROOTDISPERSION, FU, "rootdispersion" }, /* 15 */
+ { CP_REFID, RF, "refid" }, /* 16 */
+ { CP_REFTIME, TS, "reftime" }, /* 17 */
+ { CP_ORG, TS, "org" }, /* 18 */
+ { CP_REC, TS, "rec" }, /* 19 */
+ { CP_XMT, TS, "xmt" }, /* 20 */
+ { CP_REACH, OC, "reach" }, /* 21 */
+ { CP_VALID, UI, "valid" }, /* 22 */
+ { CP_TIMER, UI, "timer" }, /* 23 */
+ { CP_DELAY, FS, "delay" }, /* 24 */
+ { CP_OFFSET, FL, "offset" }, /* 25 */
+ { CP_JITTER, FU, "jitter" }, /* 26 */
+ { CP_DISPERSION, FU, "dispersion" }, /* 27 */
+ { CP_KEYID, UI, "keyid" }, /* 28 */
+ { CP_FILTDELAY, AR, "filtdelay" }, /* 29 */
+ { CP_FILTOFFSET, AR, "filtoffset" }, /* 30 */
+ { CP_PMODE, ST, "pmode" }, /* 31 */
+ { CP_RECEIVED, UI, "received" }, /* 32 */
+ { CP_SENT, UI, "sent" }, /* 33 */
+ { CP_FILTERROR, AR, "filtdisp" }, /* 34 */
+ { CP_FLASH, FX, "flash" }, /* 35 */
+ { CP_DISP, FU, "disp" }, /* 36 */
+ /*
+ * These are duplicate entries so that we can
+ * process deviant version of the ntp protocol.
+ */
+ { CP_SRCADR, HA, "peeraddr" }, /* 4 */
+ { CP_SRCPORT, UI, "peerport" }, /* 5 */
+ { CP_PPOLL, UI, "peerpoll" }, /* 11 */
+ { CP_HPOLL, UI, "hostpoll" }, /* 12 */
+ { CP_FILTERROR, AR, "filterror" }, /* 34 */
+ { 0, EOV, "" }
+};
+
+
+/*
+ * Clock variable list
+ */
+struct ctl_var clock_var[] = {
+ { 0, PADDING, "" }, /* 0 */
+ { CC_TYPE, UI, "type" }, /* 1 */
+ { CC_TIMECODE, ST, "timecode" }, /* 2 */
+ { CC_POLL, UI, "poll" }, /* 3 */
+ { CC_NOREPLY, UI, "noreply" }, /* 4 */
+ { CC_BADFORMAT, UI, "badformat" }, /* 5 */
+ { CC_BADDATA, UI, "baddata" }, /* 6 */
+ { CC_FUDGETIME1, FL, "fudgetime1" }, /* 7 */
+ { CC_FUDGETIME2, FL, "fudgetime2" }, /* 8 */
+ { CC_FUDGEVAL1, UI, "stratum" }, /* 9 */
+ { CC_FUDGEVAL2, RF, "refid" }, /* 10 */
+ { CC_FLAGS, UI, "flags" }, /* 11 */
+ { CC_DEVICE, ST, "device" }, /* 12 */
+ { 0, EOV, "" }
+};
+
+
+/*
+ * flasher bits
+ */
+static const char *tstflagnames[] = {
+ "dup_pkt", /* TEST1 */
+ "bogus_pkt", /* TEST2 */
+ "proto_sync", /* TEST3 */
+ "peer_bounds", /* TEST4 */
+ "auth", /* TEST5 */
+ "peer_sync", /* TEST6 */
+ "peer_stratum", /* TEST7 */
+ "root_bounds", /* TEST8 */
+ "peer_auth", /* TEST9 */
+ "access" /* TEST10 */
+};
+
+
+int ntpqmain P((int, char **));
+/*
+ * Built in command handler declarations
+ */
+static int openhost P((const char *));
+static int sendpkt P((char *, int));
+static int getresponse P((int, int, u_short *, int *, char **, int));
+static int sendrequest P((int, int, int, int, char *));
+static char * tstflags P((u_long));
+static void getcmds P((void));
+static RETSIGTYPE abortcmd P((int));
+static void docmd P((const char *));
+static void tokenize P((const char *, char **, int *));
+static int findcmd P((char *, struct xcmd *, struct xcmd *, struct xcmd **));
+static int getarg P((char *, int, arg_v *));
+static int rtdatetolfp P((char *, l_fp *));
+static int decodearr P((char *, int *, l_fp *));
+static void help P((struct parse *, FILE *));
+#ifdef QSORT_USES_VOID_P
+static int helpsort P((const void *, const void *));
+#else
+static int helpsort P((char **, char **));
+#endif
+static void printusage P((struct xcmd *, FILE *));
+static void timeout P((struct parse *, FILE *));
+static void auth_delay P((struct parse *, FILE *));
+static void host P((struct parse *, FILE *));
+static void ntp_poll P((struct parse *, FILE *));
+static void keyid P((struct parse *, FILE *));
+static void keytype P((struct parse *, FILE *));
+static void passwd P((struct parse *, FILE *));
+static void hostnames P((struct parse *, FILE *));
+static void setdebug P((struct parse *, FILE *));
+static void quit P((struct parse *, FILE *));
+static void version P((struct parse *, FILE *));
+static void raw P((struct parse *, FILE *));
+static void cooked P((struct parse *, FILE *));
+static void authenticate P((struct parse *, FILE *));
+static void ntpversion P((struct parse *, FILE *));
+static void warning P((const char *, const char *, const char *));
+static void error P((const char *, const char *, const char *));
+static u_long getkeyid P((const char *));
+static void atoascii P((int, char *, char *));
+static void makeascii P((int, char *, FILE *));
+static void rawprint P((int, int, char *, int, FILE *));
+static void startoutput P((void));
+static void output P((FILE *, char *, char *));
+static void endoutput P((FILE *));
+static void outputarr P((FILE *, char *, int, l_fp *));
+static void cookedprint P((int, int, char *, int, FILE *));
+#ifdef QSORT_USES_VOID_P
+static int assoccmp P((const void *, const void *));
+#else
+static int assoccmp P((struct association *, struct association *));
+#endif /* sgi || bsdi */
+
+
+/*
+ * Built-in commands we understand
+ */
+struct xcmd builtins[] = {
+ { "?", help, { OPT|STR, NO, NO, NO },
+ { "command", "", "", "" },
+ "tell the use and syntax of commands" },
+ { "help", help, { OPT|STR, NO, NO, NO },
+ { "command", "", "", "" },
+ "tell the use and syntax of commands" },
+ { "timeout", timeout, { OPT|UINT, NO, NO, NO },
+ { "msec", "", "", "" },
+ "set the primary receive time out" },
+ { "delay", auth_delay, { OPT|INT, NO, NO, NO },
+ { "msec", "", "", "" },
+ "set the delay added to encryption time stamps" },
+ { "host", host, { OPT|STR, NO, NO, NO },
+ { "hostname", "", "", "" },
+ "specify the host whose NTP server we talk to" },
+ { "poll", ntp_poll, { OPT|UINT, OPT|STR, NO, NO },
+ { "n", "verbose", "", "" },
+ "poll an NTP server in client mode `n' times" },
+ { "passwd", passwd, { NO, NO, NO, NO },
+ { "", "", "", "" },
+ "specify a password to use for authenticated requests"},
+ { "hostnames", hostnames, { OPT|STR, NO, NO, NO },
+ { "yes|no", "", "", "" },
+ "specify whether hostnames or net numbers are printed"},
+ { "debug", setdebug, { OPT|STR, NO, NO, NO },
+ { "no|more|less", "", "", "" },
+ "set/change debugging level" },
+ { "quit", quit, { NO, NO, NO, NO },
+ { "", "", "", "" },
+ "exit ntpq" },
+ { "exit", quit, { NO, NO, NO, NO },
+ { "", "", "", "" },
+ "exit ntpq" },
+ { "keyid", keyid, { OPT|UINT, NO, NO, NO },
+ { "key#", "", "", "" },
+ "set keyid to use for authenticated requests" },
+ { "version", version, { NO, NO, NO, NO },
+ { "", "", "", "" },
+ "print version number" },
+ { "raw", raw, { NO, NO, NO, NO },
+ { "", "", "", "" },
+ "do raw mode variable output" },
+ { "cooked", cooked, { NO, NO, NO, NO },
+ { "", "", "", "" },
+ "do cooked mode variable output" },
+ { "authenticate", authenticate, { OPT|STR, NO, NO, NO },
+ { "yes|no", "", "", "" },
+ "always authenticate requests to this server" },
+ { "ntpversion", ntpversion, { OPT|UINT, NO, NO, NO },
+ { "version number", "", "", "" },
+ "set the NTP version number to use for requests" },
+ { "keytype", keytype, { OPT|STR, NO, NO, NO },
+ { "key type (md5|des)", "", "", "" },
+ "set key type to use for authenticated requests (des|md5)" },
+ { 0, 0, { NO, NO, NO, NO },
+ { "", "", "", "" }, "" }
+};
+
+
+/*
+ * Default values we use.
+ */
+#define DEFTIMEOUT (5) /* 5 second time out */
+#define DEFSTIMEOUT (2) /* 2 second time out after first */
+#define DEFDELAY 0x51EB852 /* 20 milliseconds, l_fp fraction */
+#define DEFHOST "localhost" /* default host name */
+#define LENHOSTNAME 256 /* host name is 256 characters long */
+#define MAXCMDS 100 /* maximum commands on cmd line */
+#define MAXHOSTS 200 /* maximum hosts on cmd line */
+#define MAXLINE 512 /* maximum line length */
+#define MAXTOKENS (1+MAXARGS+2) /* maximum number of usable tokens */
+#define MAXVARLEN 256 /* maximum length of a variable name */
+#define MAXVALLEN 400 /* maximum length of a variable value */
+#define MAXOUTLINE 72 /* maximum length of an output line */
+
+/*
+ * Some variables used and manipulated locally
+ */
+struct timeval tvout = { DEFTIMEOUT, 0 }; /* time out for reads */
+struct timeval tvsout = { DEFSTIMEOUT, 0 }; /* secondary time out */
+l_fp delay_time; /* delay time */
+char currenthost[LENHOSTNAME]; /* current host name */
+struct sockaddr_in hostaddr = { 0 }; /* host address */
+int showhostnames = 1; /* show host names by default */
+
+int sockfd; /* fd socket is opened on */
+int havehost = 0; /* set to 1 when host open */
+struct servent *server_entry = NULL; /* server entry for ntp */
+
+#ifdef SYS_WINNT
+WORD wVersionRequested;
+WSADATA wsaData;
+DWORD NumberOfBytesWritten;
+
+HANDLE TimerThreadHandle = NULL; /* 1998/06/03 - Used in ntplib/machines.c */
+void timer(void) { ; }; /* 1998/06/03 - Used in ntplib/machines.c */
+
+#endif /* SYS_WINNT */
+
+/*
+ * Sequence number used for requests. It is incremented before
+ * it is used.
+ */
+u_short sequence;
+
+/*
+ * Holds data returned from queries. Declare buffer long to be sure of
+ * alignment.
+ */
+#define MAXFRAGS 24 /* maximum number of fragments */
+#define DATASIZE (MAXFRAGS*480) /* maximum amount of data */
+long pktdata[DATASIZE/sizeof(long)];
+
+/*
+ * Holds association data for use with the &n operator.
+ */
+struct association assoc_cache[MAXASSOC];
+int numassoc = 0; /* number of cached associations */
+
+/*
+ * For commands typed on the command line (with the -c option)
+ */
+int numcmds = 0;
+const char *ccmds[MAXCMDS];
+#define ADDCMD(cp) if (numcmds < MAXCMDS) ccmds[numcmds++] = (cp)
+
+/*
+ * When multiple hosts are specified.
+ */
+int numhosts = 0;
+const char *chosts[MAXHOSTS];
+#define ADDHOST(cp) if (numhosts < MAXHOSTS) chosts[numhosts++] = (cp)
+
+/*
+ * Error codes for internal use
+ */
+#define ERR_UNSPEC 256
+#define ERR_INCOMPLETE 257
+#define ERR_TIMEOUT 258
+#define ERR_TOOMUCH 259
+
+/*
+ * Macro definitions we use
+ */
+#define ISSPACE(c) ((c) == ' ' || (c) == '\t')
+#define ISEOL(c) ((c) == '\n' || (c) == '\r' || (c) == '\0')
+#define STREQ(a, b) (*(a) == *(b) && strcmp((a), (b)) == 0)
+
+/*
+ * Jump buffer for longjumping back to the command level
+ */
+jmp_buf interrupt_buf;
+
+/*
+ * Points at file being currently printed into
+ */
+FILE *current_output;
+
+/*
+ * Command table imported from ntpdc_ops.c
+ */
+extern struct xcmd opcmds[];
+
+char *progname;
+volatile int debug;
+
+#ifdef NO_MAIN_ALLOWED
+CALL(ntpq,"ntpq",ntpqmain);
+
+void clear_globals(void)
+{
+ extern int ntp_optind;
+ extern char *ntp_optarg;
+ showhostnames = 0; /* don'tshow host names by default */
+ ntp_optind = 0;
+ ntp_optarg = 0;
+ server_entry = NULL; /* server entry for ntp */
+ havehost = 0; /* set to 1 when host open */
+ numassoc = 0; /* number of cached associations */
+ numcmds = 0;
+ numhosts = 0;
+}
+#endif
+
+/*
+ * main - parse arguments and handle options
+ */
+#ifndef NO_MAIN_ALLOWED
+int
+main(
+ int argc,
+ char *argv[]
+ )
+{
+ return ntpqmain(argc, argv);
+}
+#endif
+
+int
+ntpqmain(
+ int argc,
+ char *argv[]
+ )
+{
+ int c;
+ int errflg = 0;
+ extern int ntp_optind;
+ extern char *ntp_optarg;
+
+#ifdef NO_MAIN_ALLOWED
+ clear_globals();
+ taskPrioritySet(taskIdSelf(), 100 );
+#endif
+ delay_time.l_ui = 0;
+ delay_time.l_uf = DEFDELAY;
+
+ progname = argv[0];
+ while ((c = ntp_getopt(argc, argv, "c:dinp")) != EOF)
+ switch (c) {
+ case 'c':
+ ADDCMD(ntp_optarg);
+ break;
+ case 'd':
+ ++debug;
+ break;
+ case 'i':
+ interactive = 1;
+ break;
+ case 'n':
+ showhostnames = 0;
+ break;
+ case 'p':
+ ADDCMD("peers");
+ break;
+ default:
+ errflg++;
+ break;
+ }
+ if (errflg) {
+ (void) fprintf(stderr,
+ "usage: %s [-dinp] [-c cmd] host ...\n",
+ progname);
+ exit(2);
+ }
+ if (ntp_optind == argc) {
+ ADDHOST(DEFHOST);
+ } else {
+ for (; ntp_optind < argc; ntp_optind++)
+ ADDHOST(argv[ntp_optind]);
+ }
+
+ if (numcmds == 0 && interactive == 0
+ && isatty(fileno(stdin)) && isatty(fileno(stderr))) {
+ interactive = 1;
+ }
+
+#ifndef SYS_WINNT /* Under NT cannot handle SIGINT, WIN32 spawns a handler */
+ if (interactive)
+ (void) signal_no_reset(SIGINT, abortcmd);
+#endif /* SYS_WINNT */
+
+#ifdef SYS_WINNT
+ wVersionRequested = MAKEWORD(1,1);
+ if (WSAStartup(wVersionRequested, &wsaData)) {
+ fprintf(stderr, "No useable winsock.dll");
+ exit(1);
+ }
+#endif /* SYS_WINNT */
+
+ if (numcmds == 0) {
+ (void) openhost(chosts[0]);
+ getcmds();
+ } else {
+ int ihost;
+ int icmd;
+
+ for (ihost = 0; ihost < numhosts; ihost++) {
+ if (openhost(chosts[ihost]))
+ for (icmd = 0; icmd < numcmds; icmd++)
+ docmd(ccmds[icmd]);
+ }
+ }
+#ifdef SYS_WINNT
+ WSACleanup();
+#endif /* SYS_WINNT */
+ return 0;
+}
+
+
+/*
+ * openhost - open a socket to a host
+ */
+static int
+openhost(
+ const char *hname
+ )
+{
+ u_int32 netnum;
+ char temphost[LENHOSTNAME];
+
+ if (server_entry == NULL) {
+ server_entry = getservbyname("ntp", "udp");
+ if (server_entry == NULL) {
+#ifdef VMS /* UCX getservbyname() doesn't work [yet], but we do know better */
+ server_entry = (struct servent *)
+ malloc(sizeof(struct servent));
+ server_entry->s_port = htons(NTP_PORT);
+#else
+ (void) fprintf(stderr, "%s: ntp/udp: unknown service\n",
+ progname);
+ exit(1);
+#endif /* VMS & UCX */
+ }
+ if (debug > 2)
+ printf("Got ntp/udp service entry\n");
+ }
+
+ if (!getnetnum(hname, &netnum, temphost))
+ return 0;
+
+ if (debug > 2)
+ printf("Opening host %s\n", temphost);
+
+ if (havehost == 1) {
+ if (debug > 2)
+ printf("Closing old host %s\n", currenthost);
+ (void) closesocket(sockfd);
+ havehost = 0;
+ }
+ (void) strcpy(currenthost, temphost);
+
+ hostaddr.sin_family = AF_INET;
+#ifndef SYS_VXWORKS
+ hostaddr.sin_port = server_entry->s_port;
+#else
+ hostaddr.sin_port = htons(SERVER_PORT_NUM);
+#endif
+ hostaddr.sin_addr.s_addr = netnum;
+
+#ifdef SYS_WINNT
+ {
+ int optionValue = SO_SYNCHRONOUS_NONALERT;
+ int err;
+ err = setsockopt(INVALID_SOCKET, SOL_SOCKET, SO_OPENTYPE, (char *)&optionValue, sizeof(optionValue));
+ if (err != NO_ERROR) {
+ (void) fprintf(stderr, "cannot open nonoverlapped sockets\n");
+ exit(1);
+ }
+ }
+
+
+ sockfd = socket(AF_INET, SOCK_DGRAM, 0);
+ if (sockfd == INVALID_SOCKET) {
+ error("socket", "", "");
+ exit(-1);
+ }
+#else
+ sockfd = socket(AF_INET, SOCK_DGRAM, 0);
+ if (sockfd == -1)
+ error("socket", "", "");
+#endif /* SYS_WINNT */
+
+
+#ifdef NEED_RCVBUF_SLOP
+# ifdef SO_RCVBUF
+ { int rbufsize = DATASIZE + 2048; /* 2K for slop */
+ if (setsockopt(sockfd, SOL_SOCKET, SO_RCVBUF,
+ &rbufsize, sizeof(int)) == -1)
+ error("setsockopt", "", "");
+ }
+# endif
+#endif
+
+ if (connect(sockfd, (struct sockaddr *)&hostaddr,
+ sizeof(hostaddr)) == -1)
+ error("connect", "", "");
+
+ havehost = 1;
+ return 1;
+}
+
+
+/* XXX ELIMINATE sendpkt similar in ntpq.c, ntpdc.c, ntp_io.c, ntptrace.c */
+/*
+ * sendpkt - send a packet to the remote host
+ */
+static int
+sendpkt(
+ char *xdata,
+ int xdatalen
+ )
+{
+ if (debug >= 3)
+ printf("Sending %d octets\n", xdatalen);
+
+
+ if (send(sockfd, xdata, xdatalen, 0) == -1) {
+ warning("write to %s failed", currenthost, "");
+ return -1;
+ }
+
+ if (debug >= 4) {
+ int first = 8;
+ printf("Packet data:\n");
+ while (xdatalen-- > 0) {
+ if (first-- == 0) {
+ printf("\n");
+ first = 7;
+ }
+ printf(" %02x", *xdata++ & 0xff);
+ }
+ printf("\n");
+ }
+ return 0;
+}
+
+
+
+/*
+ * getresponse - get a (series of) response packet(s) and return the data
+ */
+static int
+getresponse(
+ int opcode,
+ int associd,
+ u_short *rstatus,
+ int *rsize,
+ char **rdata,
+ int timeo
+ )
+{
+ struct ntp_control rpkt;
+ struct timeval tvo;
+ u_short offsets[MAXFRAGS+1];
+ u_short counts[MAXFRAGS+1];
+ u_short offset;
+ u_short count;
+ int numfrags;
+ int seenlastfrag;
+ fd_set fds;
+ int n;
+
+ /*
+ * This is pretty tricky. We may get between 1 and MAXFRAG packets
+ * back in response to the request. We peel the data out of
+ * each packet and collect it in one long block. When the last
+ * packet in the sequence is received we'll know how much data we
+ * should have had. Note we use one long time out, should reconsider.
+ */
+ *rsize = 0;
+ if (rstatus)
+ *rstatus = 0;
+ *rdata = (char *)pktdata;
+
+ numfrags = 0;
+ seenlastfrag = 0;
+
+ FD_ZERO(&fds);
+
+ again:
+ if (numfrags == 0)
+ tvo = tvout;
+ else
+ tvo = tvsout;
+
+ FD_SET(sockfd, &fds);
+ n = select(sockfd+1, &fds, (fd_set *)0, (fd_set *)0, &tvo);
+
+#if 0
+ if (debug >= 1)
+ printf("select() returns %d\n", n);
+#endif
+
+ if (n == -1) {
+ warning("select fails", "", "");
+ return -1;
+ }
+ if (n == 0) {
+ /*
+ * Timed out. Return what we have
+ */
+ if (numfrags == 0) {
+ if (timeo)
+ (void) fprintf(stderr,
+ "%s: timed out, nothing received\n",
+ currenthost);
+ return ERR_TIMEOUT;
+ } else {
+ if (timeo)
+ (void) fprintf(stderr,
+ "%s: timed out with incomplete data\n",
+ currenthost);
+ if (debug) {
+ printf("Received fragments:\n");
+ for (n = 0; n < numfrags; n++)
+ printf("%4d %d\n", offsets[n],
+ counts[n]);
+ if (seenlastfrag)
+ printf("last fragment received\n");
+ else
+ printf("last fragment not received\n");
+ }
+ return ERR_INCOMPLETE;
+ }
+ }
+
+ n = recv(sockfd, (char *)&rpkt, sizeof(rpkt), 0);
+ if (n == -1) {
+ warning("read", "", "");
+ return -1;
+ }
+
+ if (debug >= 4) {
+ int len = n, first = 8;
+ char *data = (char *)&rpkt;
+
+ printf("Packet data:\n");
+ while (len-- > 0) {
+ if (first-- == 0) {
+ printf("\n");
+ first = 7;
+ }
+ printf(" %02x", *data++ & 0xff);
+ }
+ printf("\n");
+ }
+
+ /*
+ * Check for format errors. Bug proofing.
+ */
+ if (n < CTL_HEADER_LEN) {
+ if (debug)
+ printf("Short (%d byte) packet received\n", n);
+ goto again;
+ }
+ if (PKT_VERSION(rpkt.li_vn_mode) > NTP_VERSION
+ || PKT_VERSION(rpkt.li_vn_mode) < NTP_OLDVERSION) {
+ if (debug)
+ printf("Packet received with version %d\n",
+ PKT_VERSION(rpkt.li_vn_mode));
+ goto again;
+ }
+ if (PKT_MODE(rpkt.li_vn_mode) != MODE_CONTROL) {
+ if (debug)
+ printf("Packet received with mode %d\n",
+ PKT_MODE(rpkt.li_vn_mode));
+ goto again;
+ }
+ if (!CTL_ISRESPONSE(rpkt.r_m_e_op)) {
+ if (debug)
+ printf("Received request packet, wanted response\n");
+ goto again;
+ }
+
+ /*
+ * Check opcode and sequence number for a match.
+ * Could be old data getting to us.
+ */
+ if (ntohs(rpkt.sequence) != sequence) {
+ if (debug)
+ printf(
+ "Received sequnce number %d, wanted %d\n",
+ ntohs(rpkt.sequence), sequence);
+ goto again;
+ }
+ if (CTL_OP(rpkt.r_m_e_op) != opcode) {
+ if (debug)
+ printf(
+ "Received opcode %d, wanted %d (sequence number okay)\n",
+ CTL_OP(rpkt.r_m_e_op), opcode);
+ goto again;
+ }
+
+ /*
+ * Check the error code. If non-zero, return it.
+ */
+ if (CTL_ISERROR(rpkt.r_m_e_op)) {
+ int errcode;
+
+ errcode = (ntohs(rpkt.status) >> 8) & 0xff;
+ if (debug && CTL_ISMORE(rpkt.r_m_e_op)) {
+ printf("Error code %d received on not-final packet\n",
+ errcode);
+ }
+ if (errcode == CERR_UNSPEC)
+ return ERR_UNSPEC;
+ return errcode;
+ }
+
+ /*
+ * Check the association ID to make sure it matches what
+ * we sent.
+ */
+ if (ntohs(rpkt.associd) != associd) {
+ if (debug)
+ printf("Association ID %d doesn't match expected %d\n",
+ ntohs(rpkt.associd), associd);
+ /*
+ * Hack for silly fuzzballs which, at the time of writing,
+ * return an assID of sys.peer when queried for system variables.
+ */
+#ifdef notdef
+ goto again;
+#endif
+ }
+
+ /*
+ * Collect offset and count. Make sure they make sense.
+ */
+ offset = ntohs(rpkt.offset);
+ count = ntohs(rpkt.count);
+
+ if (debug >= 3) {
+ int shouldbesize;
+ u_long key;
+ u_long *lpkt;
+ int maclen;
+
+ /*
+ * Usually we ignore authentication, but for debugging purposes
+ * we watch it here.
+ */
+ shouldbesize = CTL_HEADER_LEN + count;
+
+ /* round to 8 octet boundary */
+ shouldbesize = (shouldbesize + 7) & ~7;
+
+ if (n & 0x3) {
+ printf("Packet not padded, size = %d\n", n);
+ } if ((maclen = n - shouldbesize) >= MIN_MAC_LEN) {
+ printf(
+ "Packet shows signs of authentication (total %d, data %d, mac %d)\n",
+ n, shouldbesize, maclen);
+ lpkt = (u_long *)&rpkt;
+ printf("%08lx %08lx %08lx %08lx %08lx %08lx\n",
+ (u_long)ntohl(lpkt[(n - maclen)/sizeof(u_long) - 3]),
+ (u_long)ntohl(lpkt[(n - maclen)/sizeof(u_long) - 2]),
+ (u_long)ntohl(lpkt[(n - maclen)/sizeof(u_long) - 1]),
+ (u_long)ntohl(lpkt[(n - maclen)/sizeof(u_long)]),
+ (u_long)ntohl(lpkt[(n - maclen)/sizeof(u_long) + 1]),
+ (u_long)ntohl(lpkt[(n - maclen)/sizeof(u_long) + 2]));
+ key = ntohl(lpkt[(n - maclen) / sizeof(u_long)]);
+ printf("Authenticated with keyid %lu\n", (u_long)key);
+ if (key != 0 && key != info_auth_keyid) {
+ printf("We don't know that key\n");
+ } else {
+ if (authdecrypt(key, (u_int32 *)&rpkt,
+ n - maclen, maclen)) {
+ printf("Auth okay!\n");
+ } else {
+ printf("Auth failed!\n");
+ }
+ }
+ }
+ }
+
+ if (debug >= 2)
+ printf("Got packet, size = %d\n", n);
+ if (count > (u_short)(n-CTL_HEADER_LEN)) {
+ if (debug)
+ printf(
+ "Received count of %d octets, data in packet is %d\n",
+ count, n-CTL_HEADER_LEN);
+ goto again;
+ }
+ if (count == 0 && CTL_ISMORE(rpkt.r_m_e_op)) {
+ if (debug)
+ printf("Received count of 0 in non-final fragment\n");
+ goto again;
+ }
+ if (offset + count > sizeof(pktdata)) {
+ if (debug)
+ printf("Offset %d, count %d, too big for buffer\n",
+ offset, count);
+ return ERR_TOOMUCH;
+ }
+ if (seenlastfrag && !CTL_ISMORE(rpkt.r_m_e_op)) {
+ if (debug)
+ printf("Received second last fragment packet\n");
+ goto again;
+ }
+
+ /*
+ * So far, so good. Record this fragment, making sure it doesn't
+ * overlap anything.
+ */
+ if (debug >= 2)
+ printf("Packet okay\n");;
+
+ if (numfrags == MAXFRAGS) {
+ if (debug)
+ printf("Number of fragments exceeds maximum\n");
+ return ERR_TOOMUCH;
+ }
+
+ for (n = 0; n < numfrags; n++) {
+ if (offset == offsets[n])
+ goto again; /* duplicate */
+ if (offset < offsets[n])
+ break;
+ }
+
+ if ((u_short)(n > 0 && offsets[n-1] + counts[n-1]) > offset)
+ goto overlap;
+ if (n < numfrags && (u_short)(offset + count) > offsets[n])
+ goto overlap;
+
+ {
+ register int i;
+
+ for (i = numfrags; i > n; i--) {
+ offsets[i] = offsets[i-1];
+ counts[i] = counts[i-1];
+ }
+ }
+ offsets[n] = offset;
+ counts[n] = count;
+ numfrags++;
+
+ /*
+ * Got that stuffed in right. Figure out if this was the last.
+ * Record status info out of the last packet.
+ */
+ if (!CTL_ISMORE(rpkt.r_m_e_op)) {
+ seenlastfrag = 1;
+ if (rstatus != 0)
+ *rstatus = ntohs(rpkt.status);
+ }
+
+ /*
+ * Copy the data into the data buffer.
+ */
+ memmove((char *)pktdata + offset, (char *)rpkt.data, count);
+
+ /*
+ * If we've seen the last fragment, look for holes in the sequence.
+ * If there aren't any, we're done.
+ */
+ if (seenlastfrag && offsets[0] == 0) {
+ for (n = 1; n < numfrags; n++) {
+ if (offsets[n-1] + counts[n-1] != offsets[n])
+ break;
+ }
+ if (n == numfrags) {
+ *rsize = offsets[numfrags-1] + counts[numfrags-1];
+ return 0;
+ }
+ }
+ goto again;
+
+ overlap:
+ /*
+ * Print debugging message about overlapping fragments
+ */
+ if (debug)
+ printf("Overlapping fragments returned in response\n");
+ goto again;
+}
+
+
+/*
+ * sendrequest - format and send a request packet
+ */
+static int
+sendrequest(
+ int opcode,
+ int associd,
+ int auth,
+ int qsize,
+ char *qdata
+ )
+{
+ struct ntp_control qpkt;
+ int pktsize;
+
+ /*
+ * Check to make sure the data will fit in one packet
+ */
+ if (qsize > CTL_MAX_DATA_LEN) {
+ (void) fprintf(stderr,
+ "***Internal error! qsize (%d) too large\n",
+ qsize);
+ return 1;
+ }
+
+ /*
+ * Fill in the packet
+ */
+ qpkt.li_vn_mode = PKT_LI_VN_MODE(0, pktversion, MODE_CONTROL);
+ qpkt.r_m_e_op = (u_char)opcode & CTL_OP_MASK;
+ qpkt.sequence = htons(sequence);
+ qpkt.status = 0;
+ qpkt.associd = htons((u_short)associd);
+ qpkt.offset = 0;
+ qpkt.count = htons((u_short)qsize);
+
+ /*
+ * If we have data, copy it in and pad it out to a 64
+ * bit boundary.
+ */
+ if (qsize > 0) {
+ memmove((char *)qpkt.data, qdata, (unsigned)qsize);
+ pktsize = qsize + CTL_HEADER_LEN;
+ while (pktsize & (sizeof(u_long) - 1)) {
+ qpkt.data[qsize++] = 0;
+ pktsize++;
+ }
+ } else {
+ pktsize = CTL_HEADER_LEN;
+ }
+
+ /*
+ * If it isn't authenticated we can just send it. Otherwise
+ * we're going to have to think about it a little.
+ */
+ if (!auth && !always_auth) {
+ return sendpkt((char *)&qpkt, pktsize);
+ } else {
+ const char *pass = "\0";
+ int maclen = 0;
+ u_long my_keyid;
+
+ /*
+ * Pad out packet to a multiple of 8 octets to be sure
+ * receiver can handle it.
+ */
+ while (pktsize & 7) {
+ qpkt.data[qsize++] = 0;
+ pktsize++;
+ }
+
+ /*
+ * Get the keyid and the password if we don't have one.
+ */
+ if (info_auth_keyid == 0) {
+ maclen = getkeyid("Keyid: ");
+ if (maclen == 0) {
+ (void) fprintf(stderr,
+ "Invalid key identifier\n");
+ return 1;
+ }
+ }
+ if (!authistrusted(info_auth_keyid)) {
+ pass = getpass((info_auth_keytype == KEY_TYPE_DES)
+ ? "DES Password: " : "MD5 Password: ");
+ if (*pass == '\0') {
+ (void) fprintf(stderr,
+ "Invalid password\n");
+ return (1);
+ }
+ }
+ info_auth_keyid = maclen;
+ authusekey(info_auth_keyid, info_auth_keytype, (const u_char *)pass);
+ authtrust(info_auth_keyid, 1);
+
+ /*
+ * Stick the keyid in the packet where
+ * cp currently points. Cp should be aligned
+ * properly. Then do the encryptions.
+ */
+ my_keyid = htonl(info_auth_keyid);
+ memcpy(&qpkt.data[qsize], &my_keyid, sizeof my_keyid);
+ maclen = authencrypt(info_auth_keyid, (u_int32 *)&qpkt,
+ pktsize);
+ if (maclen == 0) {
+ (void) fprintf(stderr, "Key not found\n");
+ return (1);
+ }
+ return sendpkt((char *)&qpkt, pktsize + maclen);
+ }
+ /*NOTREACHED*/
+}
+
+
+/*
+ * doquery - send a request and process the response
+ */
+int
+doquery(
+ int opcode,
+ int associd,
+ int auth,
+ int qsize,
+ char *qdata,
+ u_short *rstatus,
+ int *rsize,
+ char **rdata
+ )
+{
+ int res;
+ int done;
+
+ /*
+ * Check to make sure host is open
+ */
+ if (!havehost) {
+ (void) fprintf(stderr, "***No host open, use `host' command\n");
+ return -1;
+ }
+
+ done = 0;
+ sequence++;
+
+ again:
+ /*
+ * send a request
+ */
+ res = sendrequest(opcode, associd, auth, qsize, qdata);
+ if (res != 0)
+ return res;
+
+ /*
+ * Get the response. If we got a standard error, print a message
+ */
+ res = getresponse(opcode, associd, rstatus, rsize, rdata, done);
+
+ if (res > 0) {
+ if (!done && (res == ERR_TIMEOUT || res == ERR_INCOMPLETE)) {
+ if (res == ERR_INCOMPLETE) {
+ /*
+ * better bump the sequence so we don't
+ * get confused about differing fragments.
+ */
+ sequence++;
+ }
+ done = 1;
+ goto again;
+ }
+ switch(res) {
+ case CERR_BADFMT:
+ (void) fprintf(stderr,
+ "***Server reports a bad format request packet\n");
+ break;
+ case CERR_PERMISSION:
+ (void) fprintf(stderr,
+ "***Server disallowed request (authentication?)\n");
+ break;
+ case CERR_BADOP:
+ (void) fprintf(stderr,
+ "***Server reports a bad opcode in request\n");
+ break;
+ case CERR_BADASSOC:
+ (void) fprintf(stderr,
+ "***Association ID %d unknown to server\n",associd);
+ break;
+ case CERR_UNKNOWNVAR:
+ (void) fprintf(stderr,
+ "***A request variable unknown to the server\n");
+ break;
+ case CERR_BADVALUE:
+ (void) fprintf(stderr,
+ "***Server indicates a request variable was bad\n");
+ break;
+ case ERR_UNSPEC:
+ (void) fprintf(stderr,
+ "***Server returned an unspecified error\n");
+ break;
+ case ERR_TIMEOUT:
+ (void) fprintf(stderr, "***Request timed out\n");
+ break;
+ case ERR_INCOMPLETE:
+ (void) fprintf(stderr,
+ "***Response from server was incomplete\n");
+ break;
+ case ERR_TOOMUCH:
+ (void) fprintf(stderr,
+ "***Buffer size exceeded for returned data\n");
+ break;
+ default:
+ (void) fprintf(stderr,
+ "***Server returns unknown error code %d\n", res);
+ break;
+ }
+ }
+ return res;
+}
+
+
+/*
+ * getcmds - read commands from the standard input and execute them
+ */
+static void
+getcmds(void)
+{
+ char line[MAXLINE];
+
+ for (;;) {
+ if (interactive) {
+#ifdef VMS /* work around a problem with mixing stdout & stderr */
+ fputs("",stdout);
+#endif
+ (void) fputs(prompt, stderr);
+ (void) fflush(stderr);
+ }
+
+ if (fgets(line, sizeof line, stdin) == NULL)
+ return;
+
+ docmd(line);
+ }
+}
+
+
+/*
+ * abortcmd - catch interrupts and abort the current command
+ */
+static RETSIGTYPE
+abortcmd(
+ int sig
+ )
+{
+ if (current_output == stdout)
+ (void) fflush(stdout);
+ putc('\n', stderr);
+ (void) fflush(stderr);
+ if (jump) longjmp(interrupt_buf, 1);
+}
+
+
+/*
+ * docmd - decode the command line and execute a command
+ */
+static void
+docmd(
+ const char *cmdline
+ )
+{
+ char *tokens[1+MAXARGS+2];
+ struct parse pcmd;
+ int ntok;
+ static int i;
+ struct xcmd *xcmd;
+
+ /*
+ * Tokenize the command line. If nothing on it, return.
+ */
+ tokenize(cmdline, tokens, &ntok);
+ if (ntok == 0)
+ return;
+
+ /*
+ * Find the appropriate command description.
+ */
+ i = findcmd(tokens[0], builtins, opcmds, &xcmd);
+ if (i == 0) {
+ (void) fprintf(stderr, "***Command `%s' unknown\n",
+ tokens[0]);
+ return;
+ } else if (i >= 2) {
+ (void) fprintf(stderr, "***Command `%s' ambiguous\n",
+ tokens[0]);
+ return;
+ }
+
+ /*
+ * Save the keyword, then walk through the arguments, interpreting
+ * as we go.
+ */
+ pcmd.keyword = tokens[0];
+ pcmd.nargs = 0;
+ for (i = 0; i < MAXARGS && xcmd->arg[i] != NO; i++) {
+ if ((i+1) >= ntok) {
+ if (!(xcmd->arg[i] & OPT)) {
+ printusage(xcmd, stderr);
+ return;
+ }
+ break;
+ }
+ if ((xcmd->arg[i] & OPT) && (*tokens[i+1] == '>'))
+ break;
+ if (!getarg(tokens[i+1], (int)xcmd->arg[i], &pcmd.argval[i]))
+ return;
+ pcmd.nargs++;
+ }
+
+ i++;
+ if (i < ntok && *tokens[i] == '>') {
+ char *fname;
+
+ if (*(tokens[i]+1) != '\0')
+ fname = tokens[i]+1;
+ else if ((i+1) < ntok)
+ fname = tokens[i+1];
+ else {
+ (void) fprintf(stderr, "***No file for redirect\n");
+ return;
+ }
+
+ current_output = fopen(fname, "w");
+ if (current_output == NULL) {
+ (void) fprintf(stderr, "***Error opening %s: ", fname);
+ perror("");
+ return;
+ }
+ i = 1; /* flag we need a close */
+ } else {
+ current_output = stdout;
+ i = 0; /* flag no close */
+ }
+
+ if (interactive && setjmp(interrupt_buf)) {
+ jump = 0;
+ return;
+ } else {
+ jump++;
+ (xcmd->handler)(&pcmd, current_output);
+ jump = 0; /* HMS: 961106: was after fclose() */
+ if (i) (void) fclose(current_output);
+ }
+}
+
+
+/*
+ * tokenize - turn a command line into tokens
+ */
+static void
+tokenize(
+ const char *line,
+ char **tokens,
+ int *ntok
+ )
+{
+ register const char *cp;
+ register char *sp;
+ static char tspace[MAXLINE];
+
+ sp = tspace;
+ cp = line;
+ for (*ntok = 0; *ntok < MAXTOKENS; (*ntok)++) {
+ tokens[*ntok] = sp;
+ while (ISSPACE(*cp))
+ cp++;
+ if (ISEOL(*cp))
+ break;
+ do {
+ *sp++ = *cp++;
+ } while (!ISSPACE(*cp) && !ISEOL(*cp));
+
+ *sp++ = '\0';
+ }
+}
+
+
+
+/*
+ * findcmd - find a command in a command description table
+ */
+static int
+findcmd(
+ register char *str,
+ struct xcmd *clist1,
+ struct xcmd *clist2,
+ struct xcmd **cmd
+ )
+{
+ register struct xcmd *cl;
+ register int clen;
+ int nmatch;
+ struct xcmd *nearmatch = NULL;
+ struct xcmd *clist;
+
+ clen = strlen(str);
+ nmatch = 0;
+ if (clist1 != 0)
+ clist = clist1;
+ else if (clist2 != 0)
+ clist = clist2;
+ else
+ return 0;
+
+ again:
+ for (cl = clist; cl->keyword != 0; cl++) {
+ /* do a first character check, for efficiency */
+ if (*str != *(cl->keyword))
+ continue;
+ if (strncmp(str, cl->keyword, (unsigned)clen) == 0) {
+ /*
+ * Could be extact match, could be approximate.
+ * Is exact if the length of the keyword is the
+ * same as the str.
+ */
+ if (*((cl->keyword) + clen) == '\0') {
+ *cmd = cl;
+ return 1;
+ }
+ nmatch++;
+ nearmatch = cl;
+ }
+ }
+
+ /*
+ * See if there is more to do. If so, go again. Sorry about the
+ * goto, too much looking at BSD sources...
+ */
+ if (clist == clist1 && clist2 != 0) {
+ clist = clist2;
+ goto again;
+ }
+
+ /*
+ * If we got extactly 1 near match, use it, else return number
+ * of matches.
+ */
+ if (nmatch == 1) {
+ *cmd = nearmatch;
+ return 1;
+ }
+ return nmatch;
+}
+
+
+/*
+ * getarg - interpret an argument token
+ */
+static int
+getarg(
+ char *str,
+ int code,
+ arg_v *argp
+ )
+{
+ int isneg;
+ char *cp, *np;
+ static const char *digits = "0123456789";
+
+ switch (code & ~OPT) {
+ case STR:
+ argp->string = str;
+ break;
+ case ADD:
+ if (!getnetnum(str, &(argp->netnum), (char *)0)) {
+ return 0;
+ }
+ break;
+ case INT:
+ case UINT:
+ isneg = 0;
+ np = str;
+ if (*np == '&') {
+ np++;
+ isneg = atoi(np);
+ if (isneg <= 0) {
+ (void) fprintf(stderr,
+ "***Association value `%s' invalid/undecodable\n", str);
+ return 0;
+ }
+ if (isneg > numassoc) {
+ (void) fprintf(stderr,
+ "***Association for `%s' unknown (max &%d)\n",
+ str, numassoc);
+ return 0;
+ }
+ argp->uval = assoc_cache[isneg-1].assid;
+ break;
+ }
+
+ if (*np == '-') {
+ np++;
+ isneg = 1;
+ }
+
+ argp->uval = 0;
+ do {
+ cp = strchr(digits, *np);
+ if (cp == NULL) {
+ (void) fprintf(stderr,
+ "***Illegal integer value %s\n", str);
+ return 0;
+ }
+ argp->uval *= 10;
+ argp->uval += (cp - digits);
+ } while (*(++np) != '\0');
+
+ if (isneg) {
+ if ((code & ~OPT) == UINT) {
+ (void) fprintf(stderr,
+ "***Value %s should be unsigned\n", str);
+ return 0;
+ }
+ argp->ival = -argp->ival;
+ }
+ break;
+ }
+
+ return 1;
+}
+
+
+/*
+ * getnetnum - given a host name, return its net number
+ * and (optional) full name
+ */
+int
+getnetnum(
+ const char *hname,
+ u_int32 *num,
+ char *fullhost
+ )
+{
+ struct hostent *hp;
+
+ if (decodenetnum(hname, num)) {
+ if (fullhost != 0) {
+ (void) sprintf(fullhost, "%lu.%lu.%lu.%lu",
+ (u_long)((htonl(*num) >> 24) & 0xff),
+ (u_long)((htonl(*num) >> 16) & 0xff),
+ (u_long)((htonl(*num) >> 8) & 0xff),
+ (u_long)(htonl(*num) & 0xff));
+ }
+ return 1;
+ } else if ((hp = gethostbyname(hname)) != 0) {
+ memmove((char *)num, hp->h_addr, sizeof(u_int32));
+ if (fullhost != 0)
+ (void) strcpy(fullhost, hp->h_name);
+ return 1;
+ } else {
+ (void) fprintf(stderr, "***Can't find host %s\n", hname);
+ return 0;
+ }
+ /*NOTREACHED*/
+}
+
+/*
+ * nntohost - convert network number to host name. This routine enforces
+ * the showhostnames setting.
+ */
+char *
+nntohost(
+ u_int32 netnum
+ )
+{
+ if (!showhostnames)
+ return numtoa(netnum);
+ if ((ntohl(netnum) & REFCLOCK_MASK) == REFCLOCK_ADDR)
+ return refnumtoa(netnum);
+ return numtohost(netnum);
+}
+
+
+/*
+ * rtdatetolfp - decode an RT-11 date into an l_fp
+ */
+static int
+rtdatetolfp(
+ char *str,
+ l_fp *lfp
+ )
+{
+ register char *cp;
+ register int i;
+ struct calendar cal;
+ char buf[4];
+ static const char *months[12] = {
+ "Jan", "Feb", "Mar", "Apr", "May", "Jun",
+ "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
+ };
+
+ cal.yearday = 0;
+
+ /*
+ * An RT-11 date looks like:
+ *
+ * d[d]-Mth-y[y] hh:mm:ss
+ *
+ * (No docs, but assume 4-digit years are also legal...)
+ *
+ * d[d]-Mth-y[y[y[y]]] hh:mm:ss
+ */
+ cp = str;
+ if (!isdigit((int)*cp)) {
+ if (*cp == '-') {
+ /*
+ * Catch special case
+ */
+ L_CLR(lfp);
+ return 1;
+ }
+ return 0;
+ }
+
+ cal.monthday = *cp++ - '0'; /* ascii dependent */
+ if (isdigit((int)*cp)) {
+ cal.monthday = (cal.monthday << 3) + (cal.monthday << 1);
+ cal.monthday += *cp++ - '0';
+ }
+
+ if (*cp++ != '-')
+ return 0;
+
+ for (i = 0; i < 3; i++)
+ buf[i] = *cp++;
+ buf[3] = '\0';
+
+ for (i = 0; i < 12; i++)
+ if (STREQ(buf, months[i]))
+ break;
+ if (i == 12)
+ return 0;
+ cal.month = i + 1;
+
+ if (*cp++ != '-')
+ return 0;
+
+ if (!isdigit((int)*cp))
+ return 0;
+ cal.year = *cp++ - '0';
+ if (isdigit((int)*cp)) {
+ cal.year = (cal.year << 3) + (cal.year << 1);
+ cal.year += *cp++ - '0';
+ }
+ if (isdigit((int)*cp)) {
+ cal.year = (cal.year << 3) + (cal.year << 1);
+ cal.year += *cp++ - '0';
+ }
+ if (isdigit((int)*cp)) {
+ cal.year = (cal.year << 3) + (cal.year << 1);
+ cal.year += *cp++ - '0';
+ }
+
+ /*
+ * Catch special case. If cal.year == 0 this is a zero timestamp.
+ */
+ if (cal.year == 0) {
+ L_CLR(lfp);
+ return 1;
+ }
+
+ if (*cp++ != ' ' || !isdigit((int)*cp))
+ return 0;
+ cal.hour = *cp++ - '0';
+ if (isdigit((int)*cp)) {
+ cal.hour = (cal.hour << 3) + (cal.hour << 1);
+ cal.hour += *cp++ - '0';
+ }
+
+ if (*cp++ != ':' || !isdigit((int)*cp))
+ return 0;
+ cal.minute = *cp++ - '0';
+ if (isdigit((int)*cp)) {
+ cal.minute = (cal.minute << 3) + (cal.minute << 1);
+ cal.minute += *cp++ - '0';
+ }
+
+ if (*cp++ != ':' || !isdigit((int)*cp))
+ return 0;
+ cal.second = *cp++ - '0';
+ if (isdigit((int)*cp)) {
+ cal.second = (cal.second << 3) + (cal.second << 1);
+ cal.second += *cp++ - '0';
+ }
+
+ /*
+ * For RT-11, 1972 seems to be the pivot year
+ */
+ if (cal.year < 72)
+ cal.year += 2000;
+ if (cal.year < 100)
+ cal.year += 1900;
+
+ lfp->l_ui = caltontp(&cal);
+ lfp->l_uf = 0;
+ return 1;
+}
+
+
+/*
+ * decodets - decode a timestamp into an l_fp format number, with
+ * consideration of fuzzball formats.
+ */
+int
+decodets(
+ char *str,
+ l_fp *lfp
+ )
+{
+ /*
+ * If it starts with a 0x, decode as hex.
+ */
+ if (*str == '0' && (*(str+1) == 'x' || *(str+1) == 'X'))
+ return hextolfp(str+2, lfp);
+
+ /*
+ * If it starts with a '"', try it as an RT-11 date.
+ */
+ if (*str == '"') {
+ register char *cp = str+1;
+ register char *bp;
+ char buf[30];
+
+ bp = buf;
+ while (*cp != '"' && *cp != '\0' && bp < &buf[29])
+ *bp++ = *cp++;
+ *bp = '\0';
+ return rtdatetolfp(buf, lfp);
+ }
+
+ /*
+ * Might still be hex. Check out the first character. Talk
+ * about heuristics!
+ */
+ if ((*str >= 'A' && *str <= 'F') || (*str >= 'a' && *str <= 'f'))
+ return hextolfp(str, lfp);
+
+ /*
+ * Try it as a decimal. If this fails, try as an unquoted
+ * RT-11 date. This code should go away eventually.
+ */
+ if (atolfp(str, lfp))
+ return 1;
+ return rtdatetolfp(str, lfp);
+}
+
+
+/*
+ * decodetime - decode a time value. It should be in milliseconds
+ */
+int
+decodetime(
+ char *str,
+ l_fp *lfp
+ )
+{
+ return mstolfp(str, lfp);
+}
+
+
+/*
+ * decodeint - decode an integer
+ */
+int
+decodeint(
+ char *str,
+ long *val
+ )
+{
+ if (*str == '0') {
+ if (*(str+1) == 'x' || *(str+1) == 'X')
+ return hextoint(str+2, (u_long *)&val);
+ return octtoint(str, (u_long *)&val);
+ }
+ return atoint(str, val);
+}
+
+
+/*
+ * decodeuint - decode an unsigned integer
+ */
+int
+decodeuint(
+ char *str,
+ u_long *val
+ )
+{
+ if (*str == '0') {
+ if (*(str + 1) == 'x' || *(str + 1) == 'X')
+ return (hextoint(str + 2, val));
+ return (octtoint(str, val));
+ }
+ return (atouint(str, val));
+}
+
+
+/*
+ * decodearr - decode an array of time values
+ */
+static int
+decodearr(
+ char *str,
+ int *narr,
+ l_fp *lfparr
+ )
+{
+ register char *cp, *bp;
+ register l_fp *lfp;
+ char buf[60];
+
+ lfp = lfparr;
+ cp = str;
+ *narr = 0;
+
+ while (*narr < 8) {
+ while (isspace((int)*cp))
+ cp++;
+ if (*cp == '\0')
+ break;
+
+ bp = buf;
+ while (!isspace((int)*cp) && *cp != '\0')
+ *bp++ = *cp++;
+ *bp++ = '\0';
+
+ if (!decodetime(buf, lfp))
+ return 0;
+ (*narr)++;
+ lfp++;
+ }
+ return 1;
+}
+
+
+/*
+ * Finally, the built in command handlers
+ */
+
+/*
+ * help - tell about commands, or details of a particular command
+ */
+static void
+help(
+ struct parse *pcmd,
+ FILE *fp
+ )
+{
+ int i;
+ int n;
+ struct xcmd *xcp;
+ char *cmd;
+ const char *cmdsort[100];
+ int length[100];
+ int maxlength;
+ int numperline;
+ static const char *spaces = " "; /* 20 spaces */
+
+ if (pcmd->nargs == 0) {
+ n = 0;
+ for (xcp = builtins; xcp->keyword != 0; xcp++) {
+ if (*(xcp->keyword) != '?')
+ cmdsort[n++] = xcp->keyword;
+ }
+ for (xcp = opcmds; xcp->keyword != 0; xcp++)
+ cmdsort[n++] = xcp->keyword;
+
+#ifdef QSORT_USES_VOID_P
+ qsort(cmdsort, (unsigned)n, sizeof(char *), helpsort);
+#else
+ qsort((char *)cmdsort, n, sizeof(char *), helpsort);
+#endif
+
+ maxlength = 0;
+ for (i = 0; i < n; i++) {
+ length[i] = strlen(cmdsort[i]);
+ if (length[i] > maxlength)
+ maxlength = length[i];
+ }
+ maxlength++;
+ numperline = 76 / maxlength;
+
+ (void) fprintf(fp, "Commands available:\n");
+ for (i = 0; i < n; i++) {
+ if ((i % numperline) == (numperline-1)
+ || i == (n-1))
+ (void) fprintf(fp, "%s\n", cmdsort[i]);
+ else
+ (void) fprintf(fp, "%s%s", cmdsort[i],
+ spaces+20-maxlength+length[i]);
+ }
+ } else {
+ cmd = pcmd->argval[0].string;
+ n = findcmd(cmd, builtins, opcmds, &xcp);
+ if (n == 0) {
+ (void) fprintf(stderr,
+ "Command `%s' is unknown\n", cmd);
+ return;
+ } else if (n >= 2) {
+ (void) fprintf(stderr,
+ "Command `%s' is ambiguous\n", cmd);
+ return;
+ }
+ (void) fprintf(fp, "function: %s\n", xcp->comment);
+ printusage(xcp, fp);
+ }
+}
+
+
+/*
+ * helpsort - do hostname qsort comparisons
+ */
+#ifdef QSORT_USES_VOID_P
+static int
+helpsort(
+ const void *t1,
+ const void *t2
+ )
+{
+ const char **name1 = (const char **)t1;
+ const char **name2 = (const char **)t2;
+
+ return strcmp(*name1, *name2);
+}
+
+#else
+static int
+helpsort(
+ char **name1,
+ char **name2
+ )
+{
+ return strcmp(*name1, *name2);
+}
+#endif
+
+/*
+ * printusage - print usage information for a command
+ */
+static void
+printusage(
+ struct xcmd *xcp,
+ FILE *fp
+ )
+{
+ register int i;
+
+ (void) fprintf(fp, "usage: %s", xcp->keyword);
+ for (i = 0; i < MAXARGS && xcp->arg[i] != NO; i++) {
+ if (xcp->arg[i] & OPT)
+ (void) fprintf(fp, " [ %s ]", xcp->desc[i]);
+ else
+ (void) fprintf(fp, " %s", xcp->desc[i]);
+ }
+ (void) fprintf(fp, "\n");
+}
+
+
+/*
+ * timeout - set time out time
+ */
+static void
+timeout(
+ struct parse *pcmd,
+ FILE *fp
+ )
+{
+ int val;
+
+ if (pcmd->nargs == 0) {
+ val = tvout.tv_sec * 1000 + tvout.tv_usec / 1000;
+ (void) fprintf(fp, "primary timeout %d ms\n", val);
+ } else {
+ tvout.tv_sec = pcmd->argval[0].uval / 1000;
+ tvout.tv_usec = (pcmd->argval[0].uval - (tvout.tv_sec * 1000))
+ * 1000;
+ }
+}
+
+
+/*
+ * auth_delay - set delay for auth requests
+ */
+static void
+auth_delay(
+ struct parse *pcmd,
+ FILE *fp
+ )
+{
+ int isneg;
+ u_long val;
+
+ if (pcmd->nargs == 0) {
+ val = delay_time.l_ui * 1000 + delay_time.l_uf / 4294967;
+ (void) fprintf(fp, "delay %lu ms\n", val);
+ } else {
+ if (pcmd->argval[0].ival < 0) {
+ isneg = 1;
+ val = (u_long)(-pcmd->argval[0].ival);
+ } else {
+ isneg = 0;
+ val = (u_long)pcmd->argval[0].ival;
+ }
+
+ delay_time.l_ui = val / 1000;
+ val %= 1000;
+ delay_time.l_uf = val * 4294967; /* 2**32/1000 */
+
+ if (isneg)
+ L_NEG(&delay_time);
+ }
+}
+
+
+/*
+ * host - set the host we are dealing with.
+ */
+static void
+host(
+ struct parse *pcmd,
+ FILE *fp
+ )
+{
+ if (pcmd->nargs == 0) {
+ if (havehost)
+ (void) fprintf(fp, "current host is %s\n", currenthost);
+ else
+ (void) fprintf(fp, "no current host\n");
+ } else if (openhost(pcmd->argval[0].string)) {
+ (void) fprintf(fp, "current host set to %s\n", currenthost);
+ numassoc = 0;
+ } else {
+ if (havehost)
+ (void) fprintf(fp,
+ "current host remains %s\n", currenthost);
+ else
+ (void) fprintf(fp, "still no current host\n");
+ }
+}
+
+
+/*
+ * poll - do one (or more) polls of the host via NTP
+ */
+/*ARGSUSED*/
+static void
+ntp_poll(
+ struct parse *pcmd,
+ FILE *fp
+ )
+{
+ (void) fprintf(fp, "poll not implemented yet\n");
+}
+
+
+/*
+ * keyid - get a keyid to use for authenticating requests
+ */
+static void
+keyid(
+ struct parse *pcmd,
+ FILE *fp
+ )
+{
+ if (pcmd->nargs == 0) {
+ if (info_auth_keyid > NTP_MAXKEY)
+ (void) fprintf(fp, "no keyid defined\n");
+ else
+ (void) fprintf(fp, "keyid is %lu\n", (u_long)info_auth_keyid);
+ } else {
+ info_auth_keyid = pcmd->argval[0].uval;
+ }
+}
+
+/*
+ * keytype - get type of key to use for authenticating requests
+ */
+static void
+keytype(
+ struct parse *pcmd,
+ FILE *fp
+ )
+{
+ if (pcmd->nargs == 0)
+ fprintf(fp, "keytype is %s\n",
+ (info_auth_keytype == KEY_TYPE_MD5) ? "MD5" : "DES");
+ else
+ switch (*(pcmd->argval[0].string)) {
+ case 'm':
+ case 'M':
+ info_auth_keytype = KEY_TYPE_MD5;
+ break;
+
+ case 'd':
+ case 'D':
+ info_auth_keytype = KEY_TYPE_DES;
+ break;
+
+ default:
+ fprintf(fp, "keytype must be 'md5' or 'des'\n");
+ }
+}
+
+
+
+/*
+ * passwd - get an authentication key
+ */
+/*ARGSUSED*/
+static void
+passwd(
+ struct parse *pcmd,
+ FILE *fp
+ )
+{
+ char *pass;
+
+ if (info_auth_keyid > NTP_MAXKEY) {
+ info_auth_keyid = getkeyid("Keyid: ");
+ if (info_auth_keyid > NTP_MAXKEY) {
+ (void)fprintf(fp, "Keyid must be defined\n");
+ return;
+ }
+ }
+ pass = getpass((info_auth_keytype == KEY_TYPE_DES)
+ ? "DES Password: "
+ : "MD5 Password: "
+ );
+ if (*pass == '\0')
+ (void) fprintf(fp, "Password unchanged\n");
+ else
+ authusekey(info_auth_keyid, info_auth_keytype, (u_char *)pass);
+}
+
+
+/*
+ * hostnames - set the showhostnames flag
+ */
+static void
+hostnames(
+ struct parse *pcmd,
+ FILE *fp
+ )
+{
+ if (pcmd->nargs == 0) {
+ if (showhostnames)
+ (void) fprintf(fp, "hostnames being shown\n");
+ else
+ (void) fprintf(fp, "hostnames not being shown\n");
+ } else {
+ if (STREQ(pcmd->argval[0].string, "yes"))
+ showhostnames = 1;
+ else if (STREQ(pcmd->argval[0].string, "no"))
+ showhostnames = 0;
+ else
+ (void)fprintf(stderr, "What?\n");
+ }
+}
+
+
+
+/*
+ * setdebug - set/change debugging level
+ */
+static void
+setdebug(
+ struct parse *pcmd,
+ FILE *fp
+ )
+{
+ if (pcmd->nargs == 0) {
+ (void) fprintf(fp, "debug level is %d\n", debug);
+ return;
+ } else if (STREQ(pcmd->argval[0].string, "no")) {
+ debug = 0;
+ } else if (STREQ(pcmd->argval[0].string, "more")) {
+ debug++;
+ } else if (STREQ(pcmd->argval[0].string, "less")) {
+ debug--;
+ } else {
+ (void) fprintf(fp, "What?\n");
+ return;
+ }
+ (void) fprintf(fp, "debug level set to %d\n", debug);
+}
+
+
+/*
+ * quit - stop this nonsense
+ */
+/*ARGSUSED*/
+static void
+quit(
+ struct parse *pcmd,
+ FILE *fp
+ )
+{
+ if (havehost)
+ closesocket(sockfd); /* cleanliness next to godliness */
+ exit(0);
+}
+
+
+/*
+ * version - print the current version number
+ */
+/*ARGSUSED*/
+static void
+version(
+ struct parse *pcmd,
+ FILE *fp
+ )
+{
+
+ (void) fprintf(fp, "%s\n", Version);
+ return;
+}
+
+
+/*
+ * raw - set raw mode output
+ */
+/*ARGSUSED*/
+static void
+raw(
+ struct parse *pcmd,
+ FILE *fp
+ )
+{
+ rawmode = 1;
+ (void) fprintf(fp, "Output set to raw\n");
+}
+
+
+/*
+ * cooked - set cooked mode output
+ */
+/*ARGSUSED*/
+static void
+cooked(
+ struct parse *pcmd,
+ FILE *fp
+ )
+{
+ rawmode = 0;
+ (void) fprintf(fp, "Output set to cooked\n");
+ return;
+}
+
+
+/*
+ * authenticate - always authenticate requests to this host
+ */
+static void
+authenticate(
+ struct parse *pcmd,
+ FILE *fp
+ )
+{
+ if (pcmd->nargs == 0) {
+ if (always_auth) {
+ (void) fprintf(fp,
+ "authenticated requests being sent\n");
+ } else
+ (void) fprintf(fp,
+ "unauthenticated requests being sent\n");
+ } else {
+ if (STREQ(pcmd->argval[0].string, "yes")) {
+ always_auth = 1;
+ } else if (STREQ(pcmd->argval[0].string, "no")) {
+ always_auth = 0;
+ } else
+ (void)fprintf(stderr, "What?\n");
+ }
+}
+
+
+/*
+ * ntpversion - choose the NTP version to use
+ */
+static void
+ntpversion(
+ struct parse *pcmd,
+ FILE *fp
+ )
+{
+ if (pcmd->nargs == 0) {
+ (void) fprintf(fp,
+ "NTP version being claimed is %d\n", pktversion);
+ } else {
+ if (pcmd->argval[0].uval < NTP_OLDVERSION
+ || pcmd->argval[0].uval > NTP_VERSION) {
+ (void) fprintf(stderr, "versions %d to %d, please\n",
+ NTP_OLDVERSION, NTP_VERSION);
+ } else {
+ pktversion = (u_char) pcmd->argval[0].uval;
+ }
+ }
+}
+
+
+/*
+ * warning - print a warning message
+ */
+static void
+warning(
+ const char *fmt,
+ const char *st1,
+ const char *st2
+ )
+{
+ (void) fprintf(stderr, "%s: ", progname);
+ (void) fprintf(stderr, fmt, st1, st2);
+ (void) fprintf(stderr, ": ");
+ perror("");
+}
+
+
+/*
+ * error - print a message and exit
+ */
+static void
+error(
+ const char *fmt,
+ const char *st1,
+ const char *st2
+ )
+{
+ warning(fmt, st1, st2);
+ exit(1);
+}
+
+/*
+ * getkeyid - prompt the user for a keyid to use
+ */
+static u_long
+getkeyid(
+ const char *keyprompt
+ )
+{
+ register char *p;
+ register int c;
+ FILE *fi;
+ char pbuf[20];
+
+#ifndef SYS_WINNT
+ if ((fi = fdopen(open("/dev/tty", 2), "r")) == NULL)
+#else
+ if ((fi = _fdopen((int)GetStdHandle(STD_INPUT_HANDLE), "r")) == NULL)
+#endif /* SYS_WINNT */
+ fi = stdin;
+ else
+ setbuf(fi, (char *)NULL);
+ fprintf(stderr, "%s", keyprompt); fflush(stderr);
+ for (p=pbuf; (c = getc(fi))!='\n' && c!=EOF;) {
+ if (p < &pbuf[18])
+ *p++ = c;
+ }
+ *p = '\0';
+ if (fi != stdin)
+ fclose(fi);
+ if (strcmp(pbuf, "0") == 0)
+ return 0;
+
+ return (u_long) atoi(pbuf);
+}
+
+
+/*
+ * atoascii - printable-ize possibly ascii data using the character
+ * transformations cat -v uses.
+ */
+static void
+atoascii(
+ int length,
+ char *data,
+ char *outdata
+ )
+{
+ register u_char *cp;
+ register u_char *ocp;
+ register u_char c;
+
+ if (!data)
+ {
+ *outdata = '\0';
+ return;
+ }
+
+ ocp = (u_char *)outdata;
+ for (cp = (u_char *)data; cp < (u_char *)data + length; cp++) {
+ c = *cp;
+ if (c == '\0')
+ break;
+ if (c == '\0')
+ break;
+ if (c > 0177) {
+ *ocp++ = 'M';
+ *ocp++ = '-';
+ c &= 0177;
+ }
+
+ if (c < ' ') {
+ *ocp++ = '^';
+ *ocp++ = c + '@';
+ } else if (c == 0177) {
+ *ocp++ = '^';
+ *ocp++ = '?';
+ } else {
+ *ocp++ = c;
+ }
+ if (ocp >= ((u_char *)outdata + length - 4))
+ break;
+ }
+ *ocp++ = '\0';
+}
+
+
+
+/*
+ * makeascii - print possibly ascii data using the character
+ * transformations that cat -v uses.
+ */
+static void
+makeascii(
+ int length,
+ char *data,
+ FILE *fp
+ )
+{
+ register u_char *cp;
+ register int c;
+
+ for (cp = (u_char *)data; cp < (u_char *)data + length; cp++) {
+ c = (int)*cp;
+ if (c > 0177) {
+ putc('M', fp);
+ putc('-', fp);
+ c &= 0177;
+ }
+
+ if (c < ' ') {
+ putc('^', fp);
+ putc(c+'@', fp);
+ } else if (c == 0177) {
+ putc('^', fp);
+ putc('?', fp);
+ } else {
+ putc(c, fp);
+ }
+ }
+}
+
+
+/*
+ * asciize - same thing as makeascii except add a newline
+ */
+void
+asciize(
+ int length,
+ char *data,
+ FILE *fp
+ )
+{
+ makeascii(length, data, fp);
+ putc('\n', fp);
+}
+
+
+/*
+ * Some circular buffer space
+ */
+#define CBLEN 80
+#define NUMCB 6
+
+char circ_buf[NUMCB][CBLEN];
+int nextcb = 0;
+
+/*
+ * nextvar - find the next variable in the buffer
+ */
+int
+nextvar(
+ int *datalen,
+ char **datap,
+ char **vname,
+ char **vvalue
+ )
+{
+ register char *cp;
+ register char *np;
+ register char *cpend;
+ register char *npend; /* character after last */
+ int quoted = 0;
+ static char name[MAXVARLEN];
+ static char value[MAXVALLEN];
+
+ cp = *datap;
+ cpend = cp + *datalen;
+
+ /*
+ * Space past commas and white space
+ */
+ while (cp < cpend && (*cp == ',' || isspace((int)*cp)))
+ cp++;
+ if (cp == cpend)
+ return 0;
+
+ /*
+ * Copy name until we hit a ',', an '=', a '\r' or a '\n'. Backspace
+ * over any white space and terminate it.
+ */
+ np = name;
+ npend = &name[MAXVARLEN];
+ while (cp < cpend && np < npend && *cp != ',' && *cp != '='
+ && *cp != '\r' && *cp != '\n')
+ *np++ = *cp++;
+ /*
+ * Check if we ran out of name space, without reaching the end or a
+ * terminating character
+ */
+ if (np == npend && !(cp == cpend || *cp == ',' || *cp == '=' ||
+ *cp == '\r' || *cp == '\n'))
+ return 0;
+ while (isspace((int)(*(np-1))))
+ np--;
+ *np = '\0';
+ *vname = name;
+
+ /*
+ * Check if we hit the end of the buffer or a ','. If so we are done.
+ */
+ if (cp == cpend || *cp == ',' || *cp == '\r' || *cp == '\n') {
+ if (cp != cpend)
+ cp++;
+ *datap = cp;
+ *datalen = cpend - cp;
+ *vvalue = (char *)0;
+ return 1;
+ }
+
+ /*
+ * So far, so good. Copy out the value
+ */
+ cp++; /* past '=' */
+ while (cp < cpend && (isspace((int)*cp) && *cp != '\r' && *cp != '\n'))
+ cp++;
+ np = value;
+ npend = &value[MAXVALLEN];
+ while (cp < cpend && np < npend && ((*cp != ',') || quoted))
+ {
+ quoted ^= ((*np++ = *cp++) == '"');
+ }
+
+ /*
+ * Check if we overran the value buffer while still in a quoted string
+ * or without finding a comma
+ */
+ if (np == npend && (quoted || *cp != ','))
+ return 0;
+ /*
+ * Trim off any trailing whitespace
+ */
+ while (np > value && isspace((int)(*(np-1))))
+ np--;
+ *np = '\0';
+
+ /*
+ * Return this. All done.
+ */
+ if (cp != cpend)
+ cp++;
+ *datap = cp;
+ *datalen = cpend - cp;
+ *vvalue = value;
+ return 1;
+}
+
+
+/*
+ * findvar - see if this variable is known to us
+ */
+int
+findvar(
+ char *varname,
+ struct ctl_var *varlist
+ )
+{
+ register char *np;
+ register struct ctl_var *vl;
+
+ vl = varlist;
+ np = varname;
+ while (vl->fmt != EOV) {
+ if (vl->fmt != PADDING && STREQ(np, vl->text))
+ return vl->code;
+ vl++;
+ }
+ return 0;
+}
+
+
+
+/*
+ * printvars - print variables returned in response packet
+ */
+void
+printvars(
+ int length,
+ char *data,
+ int status,
+ int sttype,
+ FILE *fp
+ )
+{
+ if (rawmode)
+ rawprint(sttype, length, data, status, fp);
+ else
+ cookedprint(sttype, length, data, status, fp);
+}
+
+
+/*
+ * rawprint - do a printout of the data in raw mode
+ */
+static void
+rawprint(
+ int datatype,
+ int length,
+ char *data,
+ int status,
+ FILE *fp
+ )
+{
+ register char *cp;
+ register char *cpend;
+
+ /*
+ * Essentially print the data as is. We reformat unprintables, though.
+ */
+ cp = data;
+ cpend = data + length;
+
+ (void) fprintf(fp, "status=0x%04x,\n", status);
+
+ while (cp < cpend) {
+ if (*cp == '\r') {
+ /*
+ * If this is a \r and the next character is a
+ * \n, supress this, else pretty print it. Otherwise
+ * just output the character.
+ */
+ if (cp == (cpend-1) || *(cp+1) != '\n')
+ makeascii(1, cp, fp);
+ } else if (isspace((int)*cp) || isprint((int)*cp)) {
+ putc(*cp, fp);
+ } else {
+ makeascii(1, cp, fp);
+ }
+ cp++;
+ }
+}
+
+
+/*
+ * Global data used by the cooked output routines
+ */
+int out_chars; /* number of characters output */
+int out_linecount; /* number of characters output on this line */
+
+
+/*
+ * startoutput - get ready to do cooked output
+ */
+static void
+startoutput(void)
+{
+ out_chars = 0;
+ out_linecount = 0;
+}
+
+
+/*
+ * output - output a variable=value combination
+ */
+static void
+output(
+ FILE *fp,
+ char *name,
+ char *value
+ )
+{
+ int lenname;
+ int lenvalue;
+
+ lenname = strlen(name);
+ lenvalue = strlen(value);
+
+ if (out_chars != 0) {
+ putc(',', fp);
+ out_chars++;
+ out_linecount++;
+ if ((out_linecount + lenname + lenvalue + 3) > MAXOUTLINE) {
+ putc('\n', fp);
+ out_chars++;
+ out_linecount = 0;
+ } else {
+ putc(' ', fp);
+ out_chars++;
+ out_linecount++;
+ }
+ }
+
+ fputs(name, fp);
+ putc('=', fp);
+ fputs(value, fp);
+ out_chars += lenname + 1 + lenvalue;
+ out_linecount += lenname + 1 + lenvalue;
+}
+
+
+/*
+ * endoutput - terminate a block of cooked output
+ */
+static void
+endoutput(
+ FILE *fp
+ )
+{
+ if (out_chars != 0)
+ putc('\n', fp);
+}
+
+
+/*
+ * outputarr - output an array of values
+ */
+static void
+outputarr(
+ FILE *fp,
+ char *name,
+ int narr,
+ l_fp *lfp
+ )
+{
+ register char *bp;
+ register char *cp;
+ register int i;
+ register int len;
+ char buf[256];
+
+ bp = buf;
+ /*
+ * Hack to align delay and offset values
+ */
+ for (i = (int)strlen(name); i < 11; i++)
+ *bp++ = ' ';
+
+ for (i = narr; i > 0; i--) {
+ if (i != narr)
+ *bp++ = ' ';
+ cp = lfptoms(lfp, 2);
+ len = strlen(cp);
+ if (len > 7) {
+ cp[7] = '\0';
+ len = 7;
+ }
+ while (len < 7) {
+ *bp++ = ' ';
+ len++;
+ }
+ while (*cp != '\0')
+ *bp++ = *cp++;
+ lfp++;
+ }
+ *bp = '\0';
+ output(fp, name, buf);
+}
+
+static char *
+tstflags(
+ u_long val
+ )
+{
+ register char *cb, *s;
+ register int i;
+ register const char *sep;
+
+ sep = "";
+ i = 0;
+ s = cb = &circ_buf[nextcb][0];
+ if (++nextcb >= NUMCB)
+ nextcb = 0;
+
+ sprintf(cb, "%02lx", val);
+ cb += strlen(cb);
+ if (!val) {
+ strcat(cb, " ok");
+ cb += strlen(cb);
+ } else {
+ *cb++ = ' ';
+ for (i = 0; i < 10; i++) {
+ if (val & 0x1) {
+ sprintf(cb, "%s%s", sep, tstflagnames[i]);
+ sep = ", ";
+ cb += strlen(cb);
+ }
+ val >>= 1;
+ }
+ }
+ *cb = '\0';
+ return s;
+}
+
+/*
+ * cookedprint - output variables in cooked mode
+ */
+static void
+cookedprint(
+ int datatype,
+ int length,
+ char *data,
+ int status,
+ FILE *fp
+ )
+{
+ register int varid;
+ char *name;
+ char *value;
+ int output_raw;
+ int fmt;
+ struct ctl_var *varlist;
+ l_fp lfp;
+ long ival;
+ u_int32 hval;
+ u_long uval;
+ l_fp lfparr[8];
+ int narr;
+
+ switch (datatype) {
+ case TYPE_PEER:
+ varlist = peer_var;
+ break;
+ case TYPE_SYS:
+ varlist = sys_var;
+ break;
+ case TYPE_CLOCK:
+ varlist = clock_var;
+ break;
+ default:
+ (void) fprintf(stderr, "Unknown datatype(0x%x) in cookedprint\n", datatype);
+ return;
+ }
+
+ (void) fprintf(fp, "status=%04x %s,\n", status,
+ statustoa(datatype, status));
+
+ startoutput();
+ while (nextvar(&length, &data, &name, &value)) {
+ varid = findvar(name, varlist);
+ if (varid == 0) {
+ output_raw = '*';
+ } else {
+ output_raw = 0;
+ fmt = varlist[varid].fmt;
+ switch(fmt) {
+ case TS:
+ if (!decodets(value, &lfp))
+ output_raw = '?';
+ else
+ output(fp, name, prettydate(&lfp));
+ break;
+ case FL:
+ case FU:
+ case FS:
+ if (!decodetime(value, &lfp))
+ output_raw = '?';
+ else {
+ switch (fmt) {
+ case FL:
+ output(fp, name,
+ lfptoms(&lfp, 3));
+ break;
+ case FU:
+ output(fp, name,
+ ulfptoms(&lfp, 3));
+ break;
+ case FS:
+ output(fp, name,
+ lfptoms(&lfp, 3));
+ break;
+ }
+ }
+ break;
+
+ case UI:
+ if (!decodeuint(value, &uval))
+ output_raw = '?';
+ else
+ output(fp, name, uinttoa(uval));
+ break;
+
+ case SI:
+ if (!decodeint(value, &ival))
+ output_raw = '?';
+ else
+ output(fp, name, inttoa(ival));
+ break;
+
+ case HA:
+ case NA:
+ if (!decodenetnum(value, &hval))
+ output_raw = '?';
+ else if (fmt == HA)
+ output(fp, name, nntohost(hval));
+ else
+ output(fp, name, numtoa(hval));
+ break;
+
+ case ST:
+ output_raw = '*';
+ break;
+
+ case RF:
+ if (decodenetnum(value, &hval))
+ output(fp, name, nntohost(hval));
+ else if ((int)strlen(value) <= 4)
+ output(fp, name, value);
+ else
+ output_raw = '?';
+ break;
+
+ case LP:
+ if (!decodeuint(value, &uval) || uval > 3)
+ output_raw = '?';
+ else {
+ char b[3];
+ b[0] = b[1] = '0';
+ if (uval & 0x2)
+ b[0] = '1';
+ if (uval & 0x1)
+ b[1] = '1';
+ b[2] = '\0';
+ output(fp, name, b);
+ }
+ break;
+
+ case OC:
+ if (!decodeuint(value, &uval))
+ output_raw = '?';
+ else {
+ char b[10];
+
+ (void) sprintf(b, "%03lo", uval);
+ output(fp, name, b);
+ }
+ break;
+
+ case MD:
+ if (!decodeuint(value, &uval))
+ output_raw = '?';
+ else
+ output(fp, name, uinttoa(uval));
+ break;
+
+ case AR:
+ if (!decodearr(value, &narr, lfparr))
+ output_raw = '?';
+ else
+ outputarr(fp, name, narr, lfparr);
+ break;
+
+ case FX:
+ if (!decodeuint(value, &uval))
+ output_raw = '?';
+ else
+ output(fp, name, tstflags(uval));
+ break;
+
+ default:
+ (void) fprintf(stderr,
+ "Internal error in cookedprint, %s=%s, fmt %d\n",
+ name, value, fmt);
+ break;
+ }
+
+ }
+ if (output_raw != 0) {
+ char bn[401];
+ char bv[401];
+ int len;
+
+ atoascii(400, name, bn);
+ atoascii(400, value, bv);
+ if (output_raw != '*') {
+ len = strlen(bv);
+ bv[len] = output_raw;
+ bv[len+1] = '\0';
+ }
+ output(fp, bn, bv);
+ }
+ }
+ endoutput(fp);
+}
+
+
+/*
+ * sortassoc - sort associations in the cache into ascending order
+ */
+void
+sortassoc(void)
+{
+ if (numassoc > 1)
+ qsort(
+#ifdef QSORT_USES_VOID_P
+ (void *)
+#else
+ (char *)
+#endif
+ assoc_cache, (unsigned)numassoc,
+ sizeof(struct association), assoccmp);
+}
+
+
+/*
+ * assoccmp - compare two associations
+ */
+#ifdef QSORT_USES_VOID_P
+static int
+assoccmp(
+ const void *t1,
+ const void *t2
+ )
+{
+ const struct association *ass1 = (const struct association *)t1;
+ const struct association *ass2 = (const struct association *)t2;
+
+ if (ass1->assid < ass2->assid)
+ return -1;
+ if (ass1->assid > ass2->assid)
+ return 1;
+ return 0;
+}
+#else
+static int
+assoccmp(
+ struct association *ass1,
+ struct association *ass2
+ )
+{
+ if (ass1->assid < ass2->assid)
+ return -1;
+ if (ass1->assid > ass2->assid)
+ return 1;
+ return 0;
+}
+#endif /* not QSORT_USES_VOID_P */
diff --git a/contrib/ntp/ntpq/ntpq.h b/contrib/ntp/ntpq/ntpq.h
new file mode 100644
index 0000000..8739cd4
--- /dev/null
+++ b/contrib/ntp/ntpq/ntpq.h
@@ -0,0 +1,89 @@
+/*
+ * ntpq.h - definitions of interest to ntpq
+ */
+#include "ntp_fp.h"
+#include "ntp.h"
+#include "ntp_control.h"
+#include "ntp_string.h"
+#include "ntp_malloc.h"
+
+/*
+ * Maximum number of arguments
+ */
+#define MAXARGS 4
+
+/*
+ * Flags for forming descriptors.
+ */
+#define OPT 0x80 /* this argument is optional, or'd with type */
+
+#define NO 0x0
+#define STR 0x1 /* string argument */
+#define UINT 0x2 /* unsigned integer */
+#define INT 0x3 /* signed integer */
+#define ADD 0x4 /* IP network address */
+
+/*
+ * Arguments are returned in a union
+ */
+typedef union {
+ char *string;
+ long ival;
+ u_long uval;
+ u_int32 netnum;
+} arg_v;
+
+/*
+ * Structure for passing parsed command line
+ */
+struct parse {
+ const char *keyword;
+ arg_v argval[MAXARGS];
+ int nargs;
+};
+
+/*
+ * ntpdc includes a command parser which could charitably be called
+ * crude. The following structure is used to define the command
+ * syntax.
+ */
+struct xcmd {
+ const char *keyword; /* command key word */
+ void (*handler) P((struct parse *, FILE *)); /* command handler */
+ u_char arg[MAXARGS]; /* descriptors for arguments */
+ const char *desc[MAXARGS]; /* descriptions for arguments */
+ const char *comment;
+};
+
+/*
+ * Structure to hold association data
+ */
+struct association {
+ u_short assid;
+ u_short status;
+};
+
+#define MAXASSOC 1024
+
+/*
+ * Structure for translation tables between text format
+ * variable indices and text format.
+ */
+struct ctl_var {
+ u_short code;
+ u_short fmt;
+ const char *text;
+};
+
+extern void asciize P((int, char *, FILE *));
+extern int getnetnum P((const char *, u_int32 *, char *));
+extern void sortassoc P((void));
+extern int doquery P((int, int, int, int, char *, u_short *, int *, char **));
+extern char * nntohost P((u_int32));
+extern int decodets P((char *, l_fp *));
+extern int decodeuint P((char *, u_long *));
+extern int nextvar P((int *, char **, char **, char **));
+extern int decodetime P((char *, l_fp *));
+extern void printvars P((int, char *, int, int, FILE *));
+extern int decodeint P((char *, long *));
+extern int findvar P((char *, struct ctl_var *));
diff --git a/contrib/ntp/ntpq/ntpq_ops.c b/contrib/ntp/ntpq/ntpq_ops.c
new file mode 100644
index 0000000..d43d228
--- /dev/null
+++ b/contrib/ntp/ntpq/ntpq_ops.c
@@ -0,0 +1,1651 @@
+/*
+ * ntpdc_ops.c - subroutines which are called to perform operations by ntpdc
+ */
+#include <stdio.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <netdb.h>
+
+#include "ntpq.h"
+#include "ntp_stdlib.h"
+
+extern char * chosts[];
+extern char currenthost[];
+extern int numhosts;
+int maxhostlen;
+
+/*
+ * Declarations for command handlers in here
+ */
+static int checkassocid P((u_int32));
+static char * strsave P((char *));
+static struct varlist *findlistvar P((struct varlist *, char *));
+static void doaddvlist P((struct varlist *, char *));
+static void dormvlist P((struct varlist *, char *));
+static void doclearvlist P((struct varlist *));
+static void makequerydata P((struct varlist *, int *, char *));
+static int doquerylist P((struct varlist *, int, int, int, u_short *, int *, char **));
+static void doprintvlist P((struct varlist *, FILE *));
+static void addvars P((struct parse *, FILE *));
+static void rmvars P((struct parse *, FILE *));
+static void clearvars P((struct parse *, FILE *));
+static void showvars P((struct parse *, FILE *));
+static int dolist P((struct varlist *, int, int, int, FILE *));
+static void readlist P((struct parse *, FILE *));
+static void writelist P((struct parse *, FILE *));
+static void readvar P((struct parse *, FILE *));
+static void writevar P((struct parse *, FILE *));
+static void clocklist P((struct parse *, FILE *));
+static void clockvar P((struct parse *, FILE *));
+static int findassidrange P((u_int32, u_int32, int *, int *));
+static void mreadlist P((struct parse *, FILE *));
+static void mreadvar P((struct parse *, FILE *));
+static int dogetassoc P((FILE *));
+static void printassoc P((int, FILE *));
+static void associations P((struct parse *, FILE *));
+static void lassociations P((struct parse *, FILE *));
+static void passociations P((struct parse *, FILE *));
+static void lpassociations P((struct parse *, FILE *));
+
+#ifdef UNUSED
+static void radiostatus P((struct parse *, FILE *));
+#endif /* UNUSED */
+
+static void pstatus P((struct parse *, FILE *));
+static long when P((l_fp *, l_fp *, l_fp *));
+static char * prettyinterval P((char *, long));
+static int doprintpeers P((struct varlist *, int, int, int, char *, FILE *));
+static int dogetpeers P((struct varlist *, int, FILE *));
+static void dopeers P((int, FILE *));
+static void peers P((struct parse *, FILE *));
+static void lpeers P((struct parse *, FILE *));
+static void doopeers P((int, FILE *));
+static void opeers P((struct parse *, FILE *));
+static void lopeers P((struct parse *, FILE *));
+
+
+/*
+ * Commands we understand. Ntpdc imports this.
+ */
+struct xcmd opcmds[] = {
+ { "associations", associations, { NO, NO, NO, NO },
+ { "", "", "", "" },
+ "print list of association ID's and statuses for the server's peers" },
+ { "passociations", passociations, { NO, NO, NO, NO },
+ { "", "", "", "" },
+ "print list of associations returned by last associations command" },
+ { "lassociations", lassociations, { NO, NO, NO, NO },
+ { "", "", "", "" },
+ "print list of associations including all client information" },
+ { "lpassociations", lpassociations, { NO, NO, NO, NO },
+ { "", "", "", "" },
+ "print last obtained list of associations, including client information" },
+ { "addvars", addvars, { STR, NO, NO, NO },
+ { "name[=value][,...]", "", "", "" },
+ "add variables to the variable list or change their values" },
+ { "rmvars", rmvars, { STR, NO, NO, NO },
+ { "name[,...]", "", "", "" },
+ "remove variables from the variable list" },
+ { "clearvars", clearvars, { NO, NO, NO, NO },
+ { "", "", "", "" },
+ "remove all variables from the variable list" },
+ { "showvars", showvars, { NO, NO, NO, NO },
+ { "", "", "", "" },
+ "print variables on the variable list" },
+ { "readlist", readlist, { OPT|UINT, NO, NO, NO },
+ { "assocID", "", "", "" },
+ "read the system or peer variables included in the variable list" },
+ { "rl", readlist, { OPT|UINT, NO, NO, NO },
+ { "assocID", "", "", "" },
+ "read the system or peer variables included in the variable list" },
+ { "writelist", writelist, { OPT|UINT, NO, NO, NO },
+ { "assocID", "", "", "" },
+ "write the system or peer variables included in the variable list" },
+ { "readvar", readvar, { OPT|UINT, OPT|STR, NO, NO },
+ { "assocID", "name=value[,...]", "", "" },
+ "read system or peer variables" },
+ { "rv", readvar, { OPT|UINT, OPT|STR, NO, NO },
+ { "assocID", "name=value[,...]", "", "" },
+ "read system or peer variables" },
+ { "writevar", writevar, { UINT, STR, NO, NO },
+ { "assocID", "name=value,[...]", "", "" },
+ "write system or peer variables" },
+ { "mreadlist", mreadlist, { UINT, UINT, NO, NO },
+ { "assocID", "assocID", "", "" },
+ "read the peer variables in the variable list for multiple peers" },
+ { "mrl", mreadlist, { UINT, UINT, NO, NO },
+ { "assocID", "assocID", "", "" },
+ "read the peer variables in the variable list for multiple peers" },
+ { "mreadvar", mreadvar, { UINT, UINT, OPT|STR, NO },
+ { "assocID", "assocID", "name=value[,...]", "" },
+ "read peer variables from multiple peers" },
+ { "mrv", mreadvar, { UINT, UINT, OPT|STR, NO },
+ { "assocID", "assocID", "name=value[,...]", "" },
+ "read peer variables from multiple peers" },
+ { "clocklist", clocklist, { OPT|UINT, NO, NO, NO },
+ { "assocID", "", "", "" },
+ "read the clock variables included in the variable list" },
+ { "cl", clocklist, { OPT|UINT, NO, NO, NO },
+ { "assocID", "", "", "" },
+ "read the clock variables included in the variable list" },
+ { "clockvar", clockvar, { OPT|UINT, OPT|STR, NO, NO },
+ { "assocID", "name=value[,...]", "", "" },
+ "read clock variables" },
+ { "cv", clockvar, { OPT|UINT, OPT|STR, NO, NO },
+ { "assocID", "name=value[,...]", "", "" },
+ "read clock variables" },
+ { "pstatus", pstatus, { UINT, NO, NO, NO },
+ { "assocID", "", "", "" },
+ "print status information returned for a peer" },
+ { "peers", peers, { NO, NO, NO, NO },
+ { "", "", "", "" },
+ "obtain and print a list of the server's peers" },
+ { "lpeers", lpeers, { NO, NO, NO, NO },
+ { "", "", "", "" },
+ "obtain and print a list of all peers and clients" },
+ { "opeers", opeers, { NO, NO, NO, NO },
+ { "", "", "", "" },
+ "print peer list the old way, with dstadr shown rather than refid" },
+ { "lopeers", lopeers, { NO, NO, NO, NO },
+ { "", "", "", "" },
+ "obtain and print a list of all peers and clients showing dstadr" },
+ { 0, 0, { NO, NO, NO, NO },
+ { "", "", "", "" }, "" }
+};
+
+
+/*
+ * Variable list data space
+ */
+#define MAXLIST 64 /* maximum number of variables in list */
+#define LENHOSTNAME 256 /* host name is 256 characters long */
+/*
+ * Old CTL_PST defines for version 2.
+ */
+#define OLD_CTL_PST_CONFIG 0x80
+#define OLD_CTL_PST_AUTHENABLE 0x40
+#define OLD_CTL_PST_AUTHENTIC 0x20
+#define OLD_CTL_PST_REACH 0x10
+#define OLD_CTL_PST_SANE 0x08
+#define OLD_CTL_PST_DISP 0x04
+#define OLD_CTL_PST_SEL_REJECT 0
+#define OLD_CTL_PST_SEL_SELCAND 1
+#define OLD_CTL_PST_SEL_SYNCCAND 2
+#define OLD_CTL_PST_SEL_SYSPEER 3
+
+
+char flash2[] = " .+* "; /* flash decode for version 2 */
+char flash3[] = " x.-+#*o"; /* flash decode for peer status version 3 */
+
+struct varlist {
+ char *name;
+ char *value;
+} varlist[MAXLIST] = { { 0, 0 } };
+
+/*
+ * Imported from ntpq.c
+ */
+extern int showhostnames;
+extern int rawmode;
+extern struct servent *server_entry;
+extern struct association assoc_cache[];
+extern int numassoc;
+extern u_char pktversion;
+extern struct ctl_var peer_var[];
+
+/*
+ * For quick string comparisons
+ */
+#define STREQ(a, b) (*(a) == *(b) && strcmp((a), (b)) == 0)
+
+
+/*
+ * checkassocid - return the association ID, checking to see if it is valid
+ */
+static int
+checkassocid(
+ u_int32 value
+ )
+{
+ if (value == 0 || value >= 65536) {
+ (void) fprintf(stderr, "***Invalid association ID specified\n");
+ return 0;
+ }
+ return (int)value;
+}
+
+
+/*
+ * strsave - save a string
+ * XXX - should be in libntp.a
+ */
+static char *
+strsave(
+ char *str
+ )
+{
+ char *cp;
+ u_int len;
+
+ len = strlen(str) + 1;
+ if ((cp = (char *)malloc(len)) == NULL) {
+ (void) fprintf(stderr, "Malloc failed!!\n");
+ exit(1);
+ }
+
+ memmove(cp, str, len);
+ return (cp);
+}
+
+
+/*
+ * findlistvar - look for the named variable in a list and return if found
+ */
+static struct varlist *
+findlistvar(
+ struct varlist *list,
+ char *name
+ )
+{
+ register struct varlist *vl;
+
+ for (vl = list; vl < list + MAXLIST && vl->name != 0; vl++)
+ if (STREQ(name, vl->name))
+ return vl;
+ if (vl < list + MAXLIST)
+ return vl;
+ return (struct varlist *)0;
+}
+
+
+/*
+ * doaddvlist - add variable(s) to the variable list
+ */
+static void
+doaddvlist(
+ struct varlist *vlist,
+ char *vars
+ )
+{
+ register struct varlist *vl;
+ int len;
+ char *name;
+ char *value;
+
+ len = strlen(vars);
+ while (nextvar(&len, &vars, &name, &value)) {
+ vl = findlistvar(vlist, name);
+ if (vl == 0) {
+ (void) fprintf(stderr, "Variable list full\n");
+ return;
+ }
+
+ if (vl->name == 0) {
+ vl->name = strsave(name);
+ } else if (vl->value != 0) {
+ free(vl->value);
+ vl->value = 0;
+ }
+
+ if (value != 0)
+ vl->value = strsave(value);
+ }
+}
+
+
+/*
+ * dormvlist - remove variable(s) from the variable list
+ */
+static void
+dormvlist(
+ struct varlist *vlist,
+ char *vars
+ )
+{
+ register struct varlist *vl;
+ int len;
+ char *name;
+ char *value;
+
+ len = strlen(vars);
+ while (nextvar(&len, &vars, &name, &value)) {
+ vl = findlistvar(vlist, name);
+ if (vl == 0 || vl->name == 0) {
+ (void) fprintf(stderr, "Variable `%s' not found\n",
+ name);
+ } else {
+ free((void *)vl->name);
+ if (vl->value != 0)
+ free(vl->value);
+ for ( ; (vl+1) < (varlist+MAXLIST)
+ && (vl+1)->name != 0; vl++) {
+ vl->name = (vl+1)->name;
+ vl->value = (vl+1)->value;
+ }
+ vl->name = vl->value = 0;
+ }
+ }
+}
+
+
+/*
+ * doclearvlist - clear a variable list
+ */
+static void
+doclearvlist(
+ struct varlist *vlist
+ )
+{
+ register struct varlist *vl;
+
+ for (vl = vlist; vl < vlist + MAXLIST && vl->name != 0; vl++) {
+ free((void *)vl->name);
+ vl->name = 0;
+ if (vl->value != 0) {
+ free(vl->value);
+ vl->value = 0;
+ }
+ }
+}
+
+
+/*
+ * makequerydata - form a data buffer to be included with a query
+ */
+static void
+makequerydata(
+ struct varlist *vlist,
+ int *datalen,
+ char *data
+ )
+{
+ register struct varlist *vl;
+ register char *cp, *cpend;
+ register int namelen, valuelen;
+ register int totallen;
+
+ cp = data;
+ cpend = data + *datalen;
+
+ for (vl = vlist; vl < vlist + MAXLIST && vl->name != 0; vl++) {
+ namelen = strlen(vl->name);
+ if (vl->value == 0)
+ valuelen = 0;
+ else
+ valuelen = strlen(vl->value);
+ totallen = namelen + valuelen + (valuelen != 0) + (cp != data);
+ if (cp + totallen > cpend)
+ break;
+
+ if (cp != data)
+ *cp++ = ',';
+ memmove(cp, vl->name, (unsigned)namelen);
+ cp += namelen;
+ if (valuelen != 0) {
+ *cp++ = '=';
+ memmove(cp, vl->value, (unsigned)valuelen);
+ cp += valuelen;
+ }
+ }
+ *datalen = cp - data;
+}
+
+
+/*
+ * doquerylist - send a message including variables in a list
+ */
+static int
+doquerylist(
+ struct varlist *vlist,
+ int op,
+ int associd,
+ int auth,
+ u_short *rstatus,
+ int *dsize,
+ char **datap
+ )
+{
+ char data[CTL_MAX_DATA_LEN];
+ int datalen;
+
+ datalen = sizeof(data);
+ makequerydata(vlist, &datalen, data);
+
+ return doquery(op, associd, auth, datalen, data, rstatus,
+ dsize, datap);
+}
+
+
+/*
+ * doprintvlist - print the variables on a list
+ */
+static void
+doprintvlist(
+ struct varlist *vlist,
+ FILE *fp
+ )
+{
+ register struct varlist *vl;
+
+ if (vlist->name == 0) {
+ (void) fprintf(fp, "No variables on list\n");
+ } else {
+ for (vl = vlist; vl < vlist + MAXLIST && vl->name != 0; vl++) {
+ if (vl->value == 0) {
+ (void) fprintf(fp, "%s\n", vl->name);
+ } else {
+ (void) fprintf(fp, "%s=%s\n",
+ vl->name, vl->value);
+ }
+ }
+ }
+}
+
+
+/*
+ * addvars - add variables to the variable list
+ */
+/*ARGSUSED*/
+static void
+addvars(
+ struct parse *pcmd,
+ FILE *fp
+ )
+{
+ doaddvlist(varlist, pcmd->argval[0].string);
+}
+
+
+/*
+ * rmvars - remove variables from the variable list
+ */
+/*ARGSUSED*/
+static void
+rmvars(
+ struct parse *pcmd,
+ FILE *fp
+ )
+{
+ dormvlist(varlist, pcmd->argval[0].string);
+}
+
+
+/*
+ * clearvars - clear the variable list
+ */
+/*ARGSUSED*/
+static void
+clearvars(
+ struct parse *pcmd,
+ FILE *fp
+ )
+{
+ doclearvlist(varlist);
+}
+
+
+/*
+ * showvars - show variables on the variable list
+ */
+/*ARGSUSED*/
+static void
+showvars(
+ struct parse *pcmd,
+ FILE *fp
+ )
+{
+ doprintvlist(varlist, fp);
+}
+
+
+/*
+ * dolist - send a request with the given list of variables
+ */
+static int
+dolist(
+ struct varlist *vlist,
+ int associd,
+ int op,
+ int type,
+ FILE *fp
+ )
+{
+ char *datap;
+ int res;
+ int dsize;
+ u_short rstatus;
+
+ res = doquerylist(vlist, op, associd, 0, &rstatus, &dsize, &datap);
+
+ if (res != 0)
+ return 0;
+
+ if (dsize == 0) {
+ if (associd == 0)
+ (void) fprintf(fp, "No system%s variables returned\n",
+ (type == TYPE_CLOCK) ? " clock" : "");
+ else
+ (void) fprintf(fp,
+ "No information returned for%s association %u\n",
+ (type == TYPE_CLOCK) ? " clock" : "", associd);
+ return 1;
+ }
+
+ printvars(dsize, datap, (int)rstatus, type, fp);
+ return 1;
+}
+
+
+/*
+ * readlist - send a read variables request with the variables on the list
+ */
+static void
+readlist(
+ struct parse *pcmd,
+ FILE *fp
+ )
+{
+ int associd;
+
+ if (pcmd->nargs == 0) {
+ associd = 0;
+ } else {
+ /* HMS: I think we want the u_int32 target here, not the u_long */
+ if (pcmd->argval[0].uval == 0)
+ associd = 0;
+ else if ((associd = checkassocid(pcmd->argval[0].uval)) == 0)
+ return;
+ }
+
+ (void) dolist(varlist, associd, CTL_OP_READVAR,
+ (associd == 0) ? TYPE_SYS : TYPE_PEER, fp);
+}
+
+
+/*
+ * writelist - send a write variables request with the variables on the list
+ */
+static void
+writelist(
+ struct parse *pcmd,
+ FILE *fp
+ )
+{
+ char *datap;
+ int res;
+ int associd;
+ int dsize;
+ u_short rstatus;
+
+ if (pcmd->nargs == 0) {
+ associd = 0;
+ } else {
+ /* HMS: Do we really want uval here? */
+ if (pcmd->argval[0].uval == 0)
+ associd = 0;
+ else if ((associd = checkassocid(pcmd->argval[0].uval)) == 0)
+ return;
+ }
+
+ res = doquerylist(varlist, CTL_OP_WRITEVAR, associd, 1, &rstatus,
+ &dsize, &datap);
+
+ if (res != 0)
+ return;
+
+ if (dsize == 0)
+ (void) fprintf(fp, "done! (no data returned)\n");
+ else
+ printvars(dsize, datap, (int)rstatus,
+ (associd != 0) ? TYPE_PEER : TYPE_SYS, fp);
+ return;
+}
+
+
+/*
+ * readvar - send a read variables request with the specified variables
+ */
+static void
+readvar(
+ struct parse *pcmd,
+ FILE *fp
+ )
+{
+ int associd;
+ struct varlist tmplist[MAXLIST];
+
+ /* HMS: uval? */
+ if (pcmd->nargs == 0 || pcmd->argval[0].uval == 0)
+ associd = 0;
+ else if ((associd = checkassocid(pcmd->argval[0].uval)) == 0)
+ return;
+
+ memset((char *)tmplist, 0, sizeof(tmplist));
+ if (pcmd->nargs >= 2)
+ doaddvlist(tmplist, pcmd->argval[1].string);
+
+ (void) dolist(tmplist, associd, CTL_OP_READVAR,
+ (associd == 0) ? TYPE_SYS : TYPE_PEER, fp);
+
+ doclearvlist(tmplist);
+}
+
+
+/*
+ * writevar - send a write variables request with the specified variables
+ */
+static void
+writevar(
+ struct parse *pcmd,
+ FILE *fp
+ )
+{
+ char *datap;
+ int res;
+ int associd;
+ int dsize;
+ u_short rstatus;
+ struct varlist tmplist[MAXLIST];
+
+ /* HMS: uval? */
+ if (pcmd->argval[0].uval == 0)
+ associd = 0;
+ else if ((associd = checkassocid(pcmd->argval[0].uval)) == 0)
+ return;
+
+ memset((char *)tmplist, 0, sizeof(tmplist));
+ doaddvlist(tmplist, pcmd->argval[1].string);
+
+ res = doquerylist(tmplist, CTL_OP_WRITEVAR, associd, 1, &rstatus,
+ &dsize, &datap);
+
+ doclearvlist(tmplist);
+
+ if (res != 0)
+ return;
+
+ if (dsize == 0)
+ (void) fprintf(fp, "done! (no data returned)\n");
+ else
+ printvars(dsize, datap, (int)rstatus,
+ (associd != 0) ? TYPE_PEER : TYPE_SYS, fp);
+ return;
+}
+
+
+/*
+ * clocklist - send a clock variables request with the variables on the list
+ */
+static void
+clocklist(
+ struct parse *pcmd,
+ FILE *fp
+ )
+{
+ int associd;
+
+ /* HMS: uval? */
+ if (pcmd->nargs == 0) {
+ associd = 0;
+ } else {
+ if (pcmd->argval[0].uval == 0)
+ associd = 0;
+ else if ((associd = checkassocid(pcmd->argval[0].uval)) == 0)
+ return;
+ }
+
+ (void) dolist(varlist, associd, CTL_OP_READCLOCK, TYPE_CLOCK, fp);
+}
+
+
+/*
+ * clockvar - send a clock variables request with the specified variables
+ */
+static void
+clockvar(
+ struct parse *pcmd,
+ FILE *fp
+ )
+{
+ int associd;
+ struct varlist tmplist[MAXLIST];
+
+ /* HMS: uval? */
+ if (pcmd->nargs == 0 || pcmd->argval[0].uval == 0)
+ associd = 0;
+ else if ((associd = checkassocid(pcmd->argval[0].uval)) == 0)
+ return;
+
+ memset((char *)tmplist, 0, sizeof(tmplist));
+ if (pcmd->nargs >= 2)
+ doaddvlist(tmplist, pcmd->argval[1].string);
+
+ (void) dolist(tmplist, associd, CTL_OP_READCLOCK, TYPE_CLOCK, fp);
+
+ doclearvlist(tmplist);
+}
+
+
+/*
+ * findassidrange - verify a range of association ID's
+ */
+static int
+findassidrange(
+ u_int32 assid1,
+ u_int32 assid2,
+ int *from,
+ int *to
+ )
+{
+ register int i;
+ int f, t;
+
+ if (assid1 == 0 || assid1 > 65535) {
+ (void) fprintf(stderr,
+ "***Invalid association ID %lu specified\n", (u_long)assid1);
+ return 0;
+ }
+
+ if (assid2 == 0 || assid2 > 65535) {
+ (void) fprintf(stderr,
+ "***Invalid association ID %lu specified\n", (u_long)assid2);
+ return 0;
+ }
+
+ f = t = -1;
+ for (i = 0; i < numassoc; i++) {
+ if (assoc_cache[i].assid == assid1) {
+ f = i;
+ if (t != -1)
+ break;
+ }
+ if (assoc_cache[i].assid == assid2) {
+ t = i;
+ if (f != -1)
+ break;
+ }
+ }
+
+ if (f == -1 || t == -1) {
+ (void) fprintf(stderr,
+ "***Association ID %lu not found in list\n",
+ (f == -1) ? (u_long)assid1 : (u_long)assid2);
+ return 0;
+ }
+
+ if (f < t) {
+ *from = f;
+ *to = t;
+ } else {
+ *from = t;
+ *to = f;
+ }
+ return 1;
+}
+
+
+
+/*
+ * mreadlist - send a read variables request for multiple associations
+ */
+static void
+mreadlist(
+ struct parse *pcmd,
+ FILE *fp
+ )
+{
+ int i;
+ int from;
+ int to;
+
+ /* HMS: uval? */
+ if (!findassidrange(pcmd->argval[0].uval, pcmd->argval[1].uval,
+ &from, &to))
+ return;
+
+ for (i = from; i <= to; i++) {
+ if (i != from)
+ (void) fprintf(fp, "\n");
+ if (!dolist(varlist, (int)assoc_cache[i].assid,
+ CTL_OP_READVAR, TYPE_PEER, fp))
+ return;
+ }
+ return;
+}
+
+
+/*
+ * mreadvar - send a read variables request for multiple associations
+ */
+static void
+mreadvar(
+ struct parse *pcmd,
+ FILE *fp
+ )
+{
+ int i;
+ int from;
+ int to;
+ struct varlist tmplist[MAXLIST];
+
+ /* HMS: uval? */
+ if (!findassidrange(pcmd->argval[0].uval, pcmd->argval[1].uval,
+ &from, &to))
+ return;
+
+ memset((char *)tmplist, 0, sizeof(tmplist));
+ if (pcmd->nargs >= 3)
+ doaddvlist(tmplist, pcmd->argval[2].string);
+
+ for (i = from; i <= to; i++) {
+ if (i != from)
+ (void) fprintf(fp, "\n");
+ if (!dolist(varlist, (int)assoc_cache[i].assid,
+ CTL_OP_READVAR, TYPE_PEER, fp))
+ break;
+ }
+ doclearvlist(tmplist);
+ return;
+}
+
+
+/*
+ * dogetassoc - query the host for its list of associations
+ */
+static int
+dogetassoc(
+ FILE *fp
+ )
+{
+ u_short *datap;
+ int res;
+ int dsize;
+ u_short rstatus;
+
+ res = doquery(CTL_OP_READSTAT, 0, 0, 0, (char *)0, &rstatus,
+ &dsize, (char **)&datap);
+
+ if (res != 0)
+ return 0;
+
+ if (dsize == 0) {
+ (void) fprintf(fp, "No association ID's returned\n");
+ return 0;
+ }
+
+ if (dsize & 0x3) {
+ (void) fprintf(stderr,
+ "***Server returned %d octets, should be multiple of 4\n",
+ dsize);
+ return 0;
+ }
+
+ numassoc = 0;
+ while (dsize > 0) {
+ assoc_cache[numassoc].assid = ntohs(*datap);
+ datap++;
+ assoc_cache[numassoc].status = ntohs(*datap);
+ datap++;
+ if (++numassoc >= MAXASSOC)
+ break;
+ dsize -= sizeof(u_short) + sizeof(u_short);
+ }
+ sortassoc();
+ return 1;
+}
+
+
+/*
+ * printassoc - print the current list of associations
+ */
+static void
+printassoc(
+ int showall,
+ FILE *fp
+ )
+{
+ register char *bp;
+ int i;
+ u_char statval;
+ int event;
+ u_long event_count;
+ const char *conf;
+ const char *reach;
+ const char *auth;
+ const char *condition = "";
+ const char *last_event;
+ const char *cnt;
+ char buf[128];
+
+ if (numassoc == 0) {
+ (void) fprintf(fp, "No association ID's in list\n");
+ return;
+ }
+
+ /*
+ * Output a header
+ */
+ (void) fprintf(fp,
+ "ind assID status conf reach auth condition last_event cnt\n");
+ (void) fprintf(fp,
+ "===========================================================\n");
+ for (i = 0; i < numassoc; i++) {
+ statval = CTL_PEER_STATVAL(assoc_cache[i].status);
+ if (!showall && !(statval & (CTL_PST_CONFIG|CTL_PST_REACH)))
+ continue;
+ event = CTL_PEER_EVENT(assoc_cache[i].status);
+ event_count = CTL_PEER_NEVNT(assoc_cache[i].status);
+ if (statval & CTL_PST_CONFIG)
+ conf = "yes";
+ else
+ conf = "no";
+ if (statval & CTL_PST_REACH) {
+ reach = "yes";
+ if (statval & CTL_PST_AUTHENABLE) {
+ if (statval & CTL_PST_AUTHENTIC)
+ auth = "ok ";
+ else
+ auth = "bad";
+ } else
+ auth = "none";
+
+ if (pktversion > NTP_OLDVERSION)
+ switch (statval & 0x7) {
+ case CTL_PST_SEL_REJECT:
+ condition = "reject";
+ break;
+ case CTL_PST_SEL_SANE:
+ condition = "falsetick";
+ break;
+ case CTL_PST_SEL_CORRECT:
+ condition = "excess";
+ break;
+ case CTL_PST_SEL_SELCAND:
+ condition = "outlyer";
+ break;
+ case CTL_PST_SEL_SYNCCAND:
+ condition = "candidat";
+ break;
+ case CTL_PST_SEL_DISTSYSPEER:
+ condition = "selected";
+ break;
+ case CTL_PST_SEL_SYSPEER:
+ condition = "sys.peer";
+ break;
+ case CTL_PST_SEL_PPS:
+ condition = "pps.peer";
+ break;
+ }
+ else
+ switch (statval & 0x3) {
+ case OLD_CTL_PST_SEL_REJECT:
+ if (!(statval & OLD_CTL_PST_SANE))
+ condition = "insane";
+ else if (!(statval & OLD_CTL_PST_DISP))
+ condition = "hi_disp";
+ else
+ condition = "";
+ break;
+ case OLD_CTL_PST_SEL_SELCAND:
+ condition = "sel_cand";
+ break;
+ case OLD_CTL_PST_SEL_SYNCCAND:
+ condition = "sync_cand";
+ break;
+ case OLD_CTL_PST_SEL_SYSPEER:
+ condition = "sys_peer";
+ break;
+ }
+
+ } else {
+ reach = "no";
+ auth = condition = "";
+ }
+
+ switch (PEER_EVENT|event) {
+ case EVNT_PEERIPERR:
+ last_event = "IP error";
+ break;
+ case EVNT_PEERAUTH:
+ last_event = "auth fail";
+ break;
+ case EVNT_UNREACH:
+ last_event = "lost reach";
+ break;
+ case EVNT_REACH:
+ last_event = "reachable";
+ break;
+ case EVNT_PEERCLOCK:
+ last_event = "clock expt";
+ break;
+#if 0
+ case EVNT_PEERSTRAT:
+ last_event = "stratum chg";
+ break;
+#endif
+ default:
+ last_event = "";
+ break;
+ }
+
+ if (event_count != 0)
+ cnt = uinttoa(event_count);
+ else
+ cnt = "";
+ (void) sprintf(buf,
+ "%3d %5u %04x %3.3s %4s %4.4s %9.9s %11s %2s",
+ i+1, assoc_cache[i].assid, assoc_cache[i].status,
+ conf, reach, auth, condition, last_event, cnt);
+ bp = &buf[strlen(buf)];
+ while (bp > buf && *(bp-1) == ' ')
+ *(--bp) = '\0';
+ (void) fprintf(fp, "%s\n", buf);
+ }
+}
+
+
+
+/*
+ * associations - get, record and print a list of associations
+ */
+/*ARGSUSED*/
+static void
+associations(
+ struct parse *pcmd,
+ FILE *fp
+ )
+{
+ if (dogetassoc(fp))
+ printassoc(0, fp);
+}
+
+
+/*
+ * lassociations - get, record and print a long list of associations
+ */
+/*ARGSUSED*/
+static void
+lassociations(
+ struct parse *pcmd,
+ FILE *fp
+ )
+{
+ if (dogetassoc(fp))
+ printassoc(1, fp);
+}
+
+
+/*
+ * passociations - print the association list
+ */
+/*ARGSUSED*/
+static void
+passociations(
+ struct parse *pcmd,
+ FILE *fp
+ )
+{
+ printassoc(0, fp);
+}
+
+
+/*
+ * lpassociations - print the long association list
+ */
+/*ARGSUSED*/
+static void
+lpassociations(
+ struct parse *pcmd,
+ FILE *fp
+ )
+{
+ printassoc(1, fp);
+}
+
+
+#ifdef UNUSED
+/*
+ * radiostatus - print the radio status returned by the server
+ */
+/*ARGSUSED*/
+static void
+radiostatus(
+ struct parse *pcmd,
+ FILE *fp
+ )
+{
+ char *datap;
+ int res;
+ int dsize;
+ u_short rstatus;
+
+ res = doquery(CTL_OP_READCLOCK, 0, 0, 0, (char *)0, &rstatus,
+ &dsize, &datap);
+
+ if (res != 0)
+ return;
+
+ if (dsize == 0) {
+ (void) fprintf(fp, "No radio status string returned\n");
+ return;
+ }
+
+ asciize(dsize, datap, fp);
+}
+#endif /* UNUSED */
+
+/*
+ * pstatus - print peer status returned by the server
+ */
+static void
+pstatus(
+ struct parse *pcmd,
+ FILE *fp
+ )
+{
+ char *datap;
+ int res;
+ int associd;
+ int dsize;
+ u_short rstatus;
+
+ /* HMS: uval? */
+ if ((associd = checkassocid(pcmd->argval[0].uval)) == 0)
+ return;
+
+ res = doquery(CTL_OP_READSTAT, associd, 0, 0, (char *)0, &rstatus,
+ &dsize, &datap);
+
+ if (res != 0)
+ return;
+
+ if (dsize == 0) {
+ (void) fprintf(fp,
+ "No information returned for association %u\n",
+ associd);
+ return;
+ }
+
+ printvars(dsize, datap, (int)rstatus, TYPE_PEER, fp);
+}
+
+
+/*
+ * when - print how long its been since his last packet arrived
+ */
+static long
+when(
+ l_fp *ts,
+ l_fp *rec,
+ l_fp *reftime
+ )
+{
+ l_fp *lasttime;
+
+ if (rec->l_ui != 0)
+ lasttime = rec;
+ else if (reftime->l_ui != 0)
+ lasttime = reftime;
+ else
+ return 0;
+
+ return (ts->l_ui - lasttime->l_ui);
+}
+
+
+/*
+ * Pretty-print an interval into the given buffer, in a human-friendly format.
+ */
+static char *
+prettyinterval(
+ char *buf,
+ long diff
+ )
+{
+ if (diff <= 0) {
+ buf[0] = '-';
+ buf[1] = 0;
+ return buf;
+ }
+
+ if (diff <= 2048) {
+ (void) sprintf(buf, "%ld", (long int)diff);
+ return buf;
+ }
+
+ diff = (diff + 29) / 60;
+ if (diff <= 300) {
+ (void) sprintf(buf, "%ldm", (long int)diff);
+ return buf;
+ }
+
+ diff = (diff + 29) / 60;
+ if (diff <= 96) {
+ (void) sprintf(buf, "%ldh", (long int)diff);
+ return buf;
+ }
+
+ diff = (diff + 11) / 24;
+ (void) sprintf(buf, "%ldd", (long int)diff);
+ return buf;
+}
+
+
+/*
+ * A list of variables required by the peers command
+ */
+struct varlist opeervarlist[] = {
+ { "srcadr", 0 }, /* 0 */
+ { "dstadr", 0 }, /* 1 */
+ { "stratum", 0 }, /* 2 */
+ { "hpoll", 0 }, /* 3 */
+ { "ppoll", 0 }, /* 4 */
+ { "reach", 0 }, /* 5 */
+ { "delay", 0 }, /* 6 */
+ { "offset", 0 }, /* 7 */
+ { "jitter", 0 }, /* 8 */
+ { "dispersion", 0 }, /* 9 */
+ { "rec", 0 }, /* 10 */
+ { "reftime", 0 }, /* 11 */
+ { "srcport", 0 }, /* 12 */
+ { 0, 0 }
+};
+
+struct varlist peervarlist[] = {
+ { "srcadr", 0 }, /* 0 */
+ { "refid", 0 }, /* 1 */
+ { "stratum", 0 }, /* 2 */
+ { "hpoll", 0 }, /* 3 */
+ { "ppoll", 0 }, /* 4 */
+ { "reach", 0 }, /* 5 */
+ { "delay", 0 }, /* 6 */
+ { "offset", 0 }, /* 7 */
+ { "jitter", 0 }, /* 8 */
+ { "dispersion", 0 }, /* 9 */
+ { "rec", 0 }, /* 10 */
+ { "reftime", 0 }, /* 11 */
+ { "srcport", 0 }, /* 12 */
+ { 0, 0 }
+};
+
+#define HAVE_SRCADR 0
+#define HAVE_DSTADR 1
+#define HAVE_REFID 1
+#define HAVE_STRATUM 2
+#define HAVE_HPOLL 3
+#define HAVE_PPOLL 4
+#define HAVE_REACH 5
+#define HAVE_DELAY 6
+#define HAVE_OFFSET 7
+#define HAVE_JITTER 8
+#define HAVE_DISPERSION 9
+#define HAVE_REC 10
+#define HAVE_REFTIME 11
+#define HAVE_SRCPORT 12
+#define MAXHAVE 13
+
+/*
+ * Decode an incoming data buffer and print a line in the peer list
+ */
+static int
+doprintpeers(
+ struct varlist *pvl,
+ int associd,
+ int rstatus,
+ int datalen,
+ char *data,
+ FILE *fp
+ )
+{
+ char *name;
+ char *value;
+ int i;
+ int c;
+
+ u_int32 srcadr;
+ u_int32 dstadr;
+ u_long srcport;
+ const char *dstadr_refid = "0.0.0.0";
+ u_long stratum;
+ long ppoll;
+ long hpoll;
+ u_long reach;
+ l_fp estoffset;
+ l_fp estdelay;
+ l_fp estjitter;
+ l_fp estdisp;
+ l_fp reftime;
+ l_fp rec;
+ l_fp ts;
+ u_char havevar[MAXHAVE];
+ u_long poll;
+ char type = '?';
+ char refid_string[10];
+ char whenbuf[8], pollbuf[8];
+
+ memset((char *)havevar, 0, sizeof(havevar));
+ get_systime(&ts);
+
+ while (nextvar(&datalen, &data, &name, &value)) {
+ u_int32 dummy;
+
+ i = findvar(name, peer_var);
+ if (i == 0)
+ continue; /* don't know this one */
+ switch (i) {
+ case CP_SRCADR:
+ if (decodenetnum(value, &srcadr))
+ havevar[HAVE_SRCADR] = 1;
+ break;
+ case CP_DSTADR:
+ if (decodenetnum(value, &dummy)) {
+ dummy = ntohl(dummy);
+ type = ((dummy&0xf0000000)==0xe0000000) ? 'm' :
+ ((dummy&0x000000ff)==0x000000ff) ? 'b' :
+ ((dummy&0xffffffff)==0x7f000001) ? 'l' :
+ ((dummy&0xffffffe0)==0x00000000) ? '-' :
+ 'u';
+ }
+ if (pvl == opeervarlist) {
+ if (decodenetnum(value, &dstadr)) {
+ havevar[HAVE_DSTADR] = 1;
+ dstadr_refid = numtoa(dstadr);
+ }
+ }
+ break;
+ case CP_REFID:
+ if (pvl == peervarlist) {
+ havevar[HAVE_REFID] = 1;
+ if (*value == '\0') {
+ dstadr_refid = "0.0.0.0";
+ } else if (decodenetnum(value, &dstadr)) {
+ if (dstadr == 0)
+ dstadr_refid = "0.0.0.0";
+ else
+ dstadr_refid = nntohost(dstadr);
+ } else if ((int)strlen(value) <= 4) {
+ refid_string[0] = '.';
+ (void) strcpy(&refid_string[1], value);
+ i = strlen(refid_string);
+ refid_string[i] = '.';
+ refid_string[i+1] = '\0';
+ dstadr_refid = refid_string;
+ } else {
+ havevar[HAVE_REFID] = 0;
+ }
+ }
+ break;
+ case CP_STRATUM:
+ if (decodeuint(value, &stratum))
+ havevar[HAVE_STRATUM] = 1;
+ break;
+ case CP_HPOLL:
+ if (decodeint(value, &hpoll)) {
+ havevar[HAVE_HPOLL] = 1;
+ if (hpoll < 0)
+ hpoll = NTP_MINPOLL;
+ }
+ break;
+ case CP_PPOLL:
+ if (decodeint(value, &ppoll)) {
+ havevar[HAVE_PPOLL] = 1;
+ if (ppoll < 0)
+ ppoll = NTP_MINPOLL;
+ }
+ break;
+ case CP_REACH:
+ if (decodeuint(value, &reach))
+ havevar[HAVE_REACH] = 1;
+ break;
+ case CP_DELAY:
+ if (decodetime(value, &estdelay))
+ havevar[HAVE_DELAY] = 1;
+ break;
+ case CP_OFFSET:
+ if (decodetime(value, &estoffset))
+ havevar[HAVE_OFFSET] = 1;
+ break;
+ case CP_JITTER:
+ if (decodetime(value, &estjitter))
+ havevar[HAVE_JITTER] = 1;
+ break;
+ case CP_DISPERSION:
+ if (decodetime(value, &estdisp))
+ havevar[HAVE_DISPERSION] = 1;
+ break;
+ case CP_REC:
+ if (decodets(value, &rec))
+ havevar[HAVE_REC] = 1;
+ break;
+ case CP_SRCPORT:
+ if (decodeuint(value, &srcport))
+ havevar[HAVE_SRCPORT] = 1;
+ break;
+ case CP_REFTIME:
+ havevar[HAVE_REFTIME] = 1;
+ if (!decodets(value, &reftime))
+ L_CLR(&reftime);
+ break;
+ default:
+ break;
+ }
+ }
+
+ /*
+ * Check to see if the srcport is NTP's port. If not this probably
+ * isn't a valid peer association.
+ */
+ if (havevar[HAVE_SRCPORT] && srcport != NTP_PORT)
+ return (1);
+
+ /*
+ * Got everything, format the line
+ */
+ poll = 1<<max(min3(ppoll, hpoll, NTP_MAXPOLL), NTP_MINPOLL);
+ if (pktversion > NTP_OLDVERSION)
+ c = flash3[CTL_PEER_STATVAL(rstatus) & 0x7];
+ else
+ c = flash2[CTL_PEER_STATVAL(rstatus) & 0x3];
+ if (numhosts > 1)
+ (void) fprintf(fp, "%-*s ", maxhostlen, currenthost);
+ (void) fprintf(fp,
+ "%c%-15.15s %-15.15s %2ld %c %4.4s %4.4s %3lo %7.7s %8.7s %7.7s\n",
+ c, nntohost(srcadr), dstadr_refid, stratum, type,
+ prettyinterval(whenbuf, when(&ts, &rec, &reftime)),
+ prettyinterval(pollbuf, (int)poll), reach,
+ lfptoms(&estdelay, 3), lfptoms(&estoffset, 3),
+ havevar[HAVE_JITTER] ? lfptoms(&estjitter, 3) :
+ lfptoms(&estdisp, 3));
+ return (1);
+}
+
+#undef HAVE_SRCADR
+#undef HAVE_DSTADR
+#undef HAVE_STRATUM
+#undef HAVE_PPOLL
+#undef HAVE_HPOLL
+#undef HAVE_REACH
+#undef HAVE_ESTDELAY
+#undef HAVE_ESTOFFSET
+#undef HAVE_JITTER
+#undef HAVE_ESTDISP
+#undef HAVE_REFID
+#undef HAVE_REC
+#undef HAVE_SRCPORT
+#undef HAVE_REFTIME
+#undef MAXHAVE
+
+
+/*
+ * dogetpeers - given an association ID, read and print the spreadsheet
+ * peer variables.
+ */
+static int
+dogetpeers(
+ struct varlist *pvl,
+ int associd,
+ FILE *fp
+ )
+{
+ char *datap;
+ int res;
+ int dsize;
+ u_short rstatus;
+
+#ifdef notdef
+ res = doquerylist(pvl, CTL_OP_READVAR, associd, 0, &rstatus,
+ &dsize, &datap);
+#else
+ /*
+ * Damn fuzzballs
+ */
+ res = doquery(CTL_OP_READVAR, associd, 0, 0, (char *)0, &rstatus,
+ &dsize, &datap);
+#endif
+
+ if (res != 0)
+ return 0;
+
+ if (dsize == 0) {
+ (void) fprintf(stderr,
+ "***No information returned for association %d\n",
+ associd);
+ return 0;
+ }
+
+
+ return doprintpeers(pvl, associd, (int)rstatus, dsize, datap, fp);
+}
+
+
+/*
+ * peers - print a peer spreadsheet
+ */
+static void
+dopeers(
+ int showall,
+ FILE *fp
+ )
+{
+ register int i;
+ char fullname[LENHOSTNAME];
+ u_int32 netnum;
+
+ if (!dogetassoc(fp))
+ return;
+
+ for (i = 0; i < numhosts; ++i)
+ { if(getnetnum(chosts[i],&netnum,fullname))
+ if ((int)strlen(fullname) > maxhostlen)
+ maxhostlen = strlen(fullname);
+ }
+ if (numhosts > 1)
+ (void) fprintf(fp, "%-*.*s ", maxhostlen, maxhostlen, "host");
+ (void) fprintf(fp,
+ " remote refid st t when poll reach delay offset jitter\n");
+ if (numhosts > 1)
+ for (i = 0; i <= maxhostlen; ++i)
+ (void) fprintf(fp, "=");
+ (void) fprintf(fp,
+ "==============================================================================\n");
+
+ for (i = 0; i < numassoc; i++) {
+ if (!showall &&
+ !(CTL_PEER_STATVAL(assoc_cache[i].status)
+ & (CTL_PST_CONFIG|CTL_PST_REACH)))
+ continue;
+ if (!dogetpeers(peervarlist, (int)assoc_cache[i].assid, fp)) {
+ return;
+ }
+ }
+ return;
+}
+
+
+/*
+ * peers - print a peer spreadsheet
+ */
+/*ARGSUSED*/
+static void
+peers(
+ struct parse *pcmd,
+ FILE *fp
+ )
+{
+ dopeers(0, fp);
+}
+
+
+/*
+ * lpeers - print a peer spreadsheet including all fuzzball peers
+ */
+/*ARGSUSED*/
+static void
+lpeers(
+ struct parse *pcmd,
+ FILE *fp
+ )
+{
+ dopeers(1, fp);
+}
+
+
+/*
+ * opeers - print a peer spreadsheet
+ */
+static void
+doopeers(
+ int showall,
+ FILE *fp
+ )
+{
+ register int i;
+
+ if (!dogetassoc(fp))
+ return;
+
+ (void) fprintf(fp,
+ " remote local st t when poll reach delay offset disp\n");
+ (void) fprintf(fp,
+ "==============================================================================\n");
+
+ for (i = 0; i < numassoc; i++) {
+ if (!showall &&
+ !(CTL_PEER_STATVAL(assoc_cache[i].status)
+ & (CTL_PST_CONFIG|CTL_PST_REACH)))
+ continue;
+ if (!dogetpeers(opeervarlist, (int)assoc_cache[i].assid, fp)) {
+ return;
+ }
+ }
+ return;
+}
+
+
+/*
+ * opeers - print a peer spreadsheet the old way
+ */
+/*ARGSUSED*/
+static void
+opeers(
+ struct parse *pcmd,
+ FILE *fp
+ )
+{
+ doopeers(0, fp);
+}
+
+
+/*
+ * lopeers - print a peer spreadsheet including all fuzzball peers
+ */
+/*ARGSUSED*/
+static void
+lopeers(
+ struct parse *pcmd,
+ FILE *fp
+ )
+{
+ doopeers(1, fp);
+}
OpenPOWER on IntegriCloud