diff options
Diffstat (limited to 'contrib/ntp/scripts')
70 files changed, 7882 insertions, 0 deletions
diff --git a/contrib/ntp/scripts/Makefile.am b/contrib/ntp/scripts/Makefile.am new file mode 100644 index 0000000..c3bb684 --- /dev/null +++ b/contrib/ntp/scripts/Makefile.am @@ -0,0 +1 @@ +noinst_SCRIPTS = mkver ntpver diff --git a/contrib/ntp/scripts/Makefile.in b/contrib/ntp/scripts/Makefile.in new file mode 100644 index 0000000..008640b --- /dev/null +++ b/contrib/ntp/scripts/Makefile.in @@ -0,0 +1,210 @@ +# 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@ + + +noinst_SCRIPTS = mkver ntpver +subdir = scripts +mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs +CONFIG_HEADER = ../config.h +CONFIG_CLEAN_FILES = mkver ntpver +SCRIPTS = $(noinst_SCRIPTS) + +DIST_SOURCES = +DIST_COMMON = README Makefile.am Makefile.in mkver.in ntpver.in + + +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) + +GZIP_ENV = --best +all: all-redirect +.SUFFIXES: +$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) + cd $(top_srcdir) && $(AUTOMAKE) --gnu scripts/Makefile + +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status $(BUILT_SOURCES) + cd $(top_builddir) \ + && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status + +mkver: $(top_builddir)/config.status mkver.in + cd $(top_builddir) && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status +ntpver: $(top_builddir)/config.status ntpver.in + cd $(top_builddir) && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status +tags: TAGS +TAGS: + + +distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir) + +distdir: $(DISTFILES) + here=`cd $(top_builddir) && pwd`; \ + top_distdir=`cd $(top_distdir) && pwd`; \ + distdir=`cd $(distdir) && pwd`; \ + cd $(top_srcdir) \ + && $(AUTOMAKE) --include-deps --build-dir=$$here --srcdir-name=$(top_srcdir) --output-dir=$$top_distdir --gnu scripts/Makefile + @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 +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-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: uninstall-am +all-am: Makefile $(SCRIPTS) +all-redirect: all-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_STRIP_FLAG=-s install +installdirs: + + +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f Makefile $(CONFIG_CLEAN_FILES) + -rm -f config.cache config.log stamp-h stamp-h[0-9]* + +maintainer-clean-generic: +mostlyclean-am: mostlyclean-generic + +mostlyclean: mostlyclean-am + +clean-am: clean-generic mostlyclean-am + +clean: clean-am + +distclean-am: distclean-generic clean-am + +distclean: distclean-am + +maintainer-clean-am: 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: 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 + + +# 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/scripts/README b/contrib/ntp/scripts/README new file mode 100644 index 0000000..37442f1 --- /dev/null +++ b/contrib/ntp/scripts/README @@ -0,0 +1,30 @@ +README file for directory ./scripts of the NTP Version 4 distribution + +This directory contains shell and perl script files for the configuration, +monitoring and support of NTP installations. See the README and RELNOTES +files in the parent directory for directions on how to use these files. + +calc_tickadj Calculates "optimal" value for tick given ntp.drift file + +mkver.in script to create new version numbers for all sources + +monitoring directory containing perl scripts useful for monitoring + operations + +rc1 start/stop scripts for NTP + +rc2 start/stop script for NTP + +ntp-groper script useful for reaching out and rattling the cages of + NTP peers to see if animals are inside the bars + +ntp-restart script useful for killing and restarting the NTP daemon + +ntpver What version of the NTP daemon is running? + +stats directory containing awk and shell scripts useful for + maintaining statistics summaries of clockstats, loopstats + and peerstats files + +support directory containing shell and perl scripts useful for + configuration and monitoring of NTP subnets diff --git a/contrib/ntp/scripts/calc_tickadj b/contrib/ntp/scripts/calc_tickadj new file mode 100644 index 0000000..f7a9f9f --- /dev/null +++ b/contrib/ntp/scripts/calc_tickadj @@ -0,0 +1,38 @@ +#! /usr/local/bin/perl +# +# drift of 104.8576 -> +1 tick. Base of 10000 ticks. +# +# 970306 HMS Deal with nanoseconds. Fix sign of adjustments. + +$df="/etc/ntp.drift"; +# Assumes a 100Hz box with "tick" of 10000 +# Someday, we might call "tickadj" for better values... +$base=10000; # tick: 1,000,000 / HZ +$cvt=104.8576; # 2 ** 20 / $base +$v1=0.; +$v2=""; + +if (open(DF, $df)) + { + if ($_=<DF>) + { + ($v1, $v2) = split; + } + + while ($v1 < 0) + { + $v1 += $cvt; + $base--; + } + + while ($v1 > $cvt) + { + $v1 -= $cvt; + $base++; + } + } + +printf("%.3f (drift)\n", $v1); + +printf("%d usec; %d nsec\n", $base, ($base + ($v1/$cvt)) * 1000); + diff --git a/contrib/ntp/scripts/checktime b/contrib/ntp/scripts/checktime new file mode 100755 index 0000000..850e2ec --- /dev/null +++ b/contrib/ntp/scripts/checktime @@ -0,0 +1,79 @@ +#!/usr/local/bin/perl +#!/usr/local/bin/perl -d +# +# This script compares the time of several machines with the +# time on the local host. +# +# Use or modify it as you wish. +# +# As the original author is only expecting 14 minutes of fame, +# leaving his name attached would be appreciated. +# +# R. Gary Cutbill <rgary@chrysalis.com> +# 21 April 1999 +# +$tol=2.0; +$|=1; +print "Time Check"; + +open(HOSTS,"ypcat hosts.byaddr |"); # get a list of hosts from the yp server. + +while ($line=<HOSTS>) { # loop for each host getting the offset compared to localhost + ($addr,$host,$aliases)=split(/\s+/,$line,3); + $res=`/usr/local/bin/ntptrace -m 1 -r 1 -t 1 $host`; + print "."; + chop $res; + push (@results,$res); +} +print "\n"; + + +# +# Sort the list of hosts, and print out there offsets +# from the local host. +# +@list=sort appropriately @results; +foreach $i ( @list ) { + + @dargs=split(/\s+/,$i); + if ( $dargs[1] eq "\*Timeout\*" ) { + print "$i\n"; + chop $dargs[0]; + push(@down,$dargs[0]); + } else { + printf "%-25s %7s %3s %6s %10s %5s %8s %8s\n",@dargs; + if ( ( $dargs[4] > $tol ) || ( $dargs[4] < -$tol ) ) { + chop $dargs[0]; + push(@toofarout,$dargs[0]); } + } +} +# +# When the above list finishes, hosts that are different by +/- $tol (two seconds) +# are in @toofarout. Hosts that are down are in @down. They are treated the same +# way here, but you might want to do something different depending on your site. +# +# print a set of suggested rsh commands to run on the hosts that +# don't have "good" time. "restartntp" is left as an excersize to the reader. +# I usually use it to kill a running xntpd, ntpdate some server, and the start xntp +# again. +# +print "\nConsider:\n"; +foreach $i ( (@down,@toofarout) ) { + print " rsh $i sudo restartntp\n"; +} + + +# +# sort the results from the list. First by stratum, then by time deviation +# Put hosts that didn't respond (timed out) on the bottom. +# +sub appropriately { + @af=split(/\s+/,$a); + @bf=split(/\s+/,$b); + $aba= ($af[4]<0)?-$af[4]:$af[4]; + $abb= ($bf[4]<0)?-$bf[4]:$bf[4]; + + ( $af[1] ne $bf[1] ) ? $bf[1] cmp $af[1] : + ( ( $af[2] != $bf[2] ) ? ( $bf[2] <=> $af[2] ) : + ( ( $aba != $abb ) ? ( $abb <=> $aba ) : ($af[0] cmp $bf[0] ) ) ); +} diff --git a/contrib/ntp/scripts/fixautomakedepsmagic b/contrib/ntp/scripts/fixautomakedepsmagic new file mode 100644 index 0000000..ec82bba --- /dev/null +++ b/contrib/ntp/scripts/fixautomakedepsmagic @@ -0,0 +1,28 @@ +#!/bin/sh + +prog=`basename $0` + + +t=/tmp/$prog.$$ + +trap 'rm -f ${t} ; exit 1' 1 3 15 + +while [ $# -gt 0 ]; do + f=$1 + shift + sed -e '/^DEPS_MAGIC :=/,/^-include \$/s/^/#/' $f > $t + c="diff $f $t" + echo $c + $c + tstatus=$? + if [ $tstatus = 0 ]; then + echo "$prog":" $f not modified" + elif [ ! -w $f ]; then + echo "$prog":" $f not not writable" + else + c="cp $t $f" + echo $c + $c + fi + rm -f $t +done diff --git a/contrib/ntp/scripts/hpadjtime.sh b/contrib/ntp/scripts/hpadjtime.sh new file mode 100755 index 0000000..3de2a40 --- /dev/null +++ b/contrib/ntp/scripts/hpadjtime.sh @@ -0,0 +1,18 @@ +#! /bin/sh +val=1 +if [ -f /bin/uname -o -f /usr/bin/uname ]; then + set `uname -a | tr '[A-Z]' '[a-z]'` + case "$1" in + hp-ux) case "$3" in + *.10.*) val=1 ;; + *.09.03 | *.09.10) case "$5" in + 9000/3*) val=1 ;; + *) val=0 ;; + esac ;; + *) val=0 ;; + esac + ;; + *) + esac +fi +exit $val diff --git a/contrib/ntp/scripts/mkver.in b/contrib/ntp/scripts/mkver.in new file mode 100644 index 0000000..79d83f8 --- /dev/null +++ b/contrib/ntp/scripts/mkver.in @@ -0,0 +1,31 @@ +#!@PATH_SH@ +PROG=${1-UNKNOWN} + +ConfStr="$PROG" + +case "@LIBRSAREF@" in + '') ;; + *) ConfStr="$ConfStr RSAREF" ;; +esac + +ConfStr="$ConfStr @VERSION@ `date`" + +if [ ! -f .version ]; then + echo 0 > .version +fi +RUN="`cat .version`" +RUN="`expr $RUN + 1`" +echo $RUN > .version + +ConfStr="$ConfStr (${RUN})" + +echo "Version <${ConfStr}>"; + +rm -f version.c +cat > version.c << -EoF- +/* + * version file for $PROG + */ +#include <config.h> +const char * Version = "${ConfStr}"; +-EoF- diff --git a/contrib/ntp/scripts/monitoring/README b/contrib/ntp/scripts/monitoring/README new file mode 100644 index 0000000..fa8ad8b --- /dev/null +++ b/contrib/ntp/scripts/monitoring/README @@ -0,0 +1,154 @@ +This directory contains support for monitoring the local clock of xntp daemons. + +WARNING: The scripts and routines contained in this directory are bete realease! + Do not depend on their correct operation. They are, however, in regular + use at University of Erlangen-Nuernberg. No severe problems are known + for this code. + +!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +PLEASE THINK TWICE BEFORE STARTING MONITORING REMOTE XNTP DEAMONS !!!! +MONITORING MAY INCREASE THE LOAD OF THE DEAMON MONITORED AND MAY +INCREASE THE NETWORK LOAD SIGNIFICANTLY +!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + + +Files are: + +README: + This file + +ntptrap: + perl script to log ntp mode 6 trap messages. + + It sends a set_trap request to each server given and dumps the + trap messages received. It handles refresh of set_trap. + Currently it handles only NTP V2, however the NTP V3 servers + also accept v2 requests. It will not interpret v3 system and peer + stati correctly. + + usage: + ntptrap [-n] [-p <port>] [-l <debug-output>] servers... + + -n: do not send set_trap requests + + port: port to listen for responses + useful if you have a configured trap + + debug-output: file to write trace output to (for debugging) + + This script convinced me that ntp trap messages are only of + little use. + +ntploopstat: + perl script to gather loop info statistics from xntpd via mode 7 + LOOP_INFO requests. + + This script collects data to allow monitoring of remote xntp servers + where it is not possible to directly access the loopstats file + produced by xntpd itself. Of course, it can be used to sample + a local server if it is not configured to produce a loopstats file. + + Please note, this program poses a high load on the server as + a communication takes place every delay seconds ! USE WITH CARE ! + + usage: + ntploopstat [-d<delay>] [-t<timeout>] [-l <logfile>] [-v] [ntpserver] + + delay: number of seconds to wait between samples + default: 60 seconds + timeout: number of seconds to wait for reply + default 12 seconds + logfile: file to log samples to + default: loopstats:<ntpserver>: + (note the trailing colon) + This name actually is a prefix. + The file name is dynamically derived by appending + the name of the month the sample belongs to. + Thus all samples of a month end up in the same file. + + the format of the files generated is identical to the format used by + xntpd with the loopstats file: + MJD <seconds since midnight UTC> offset frequency compliance + + if a timeout occurs the next sample is tried after delay/2 seconds + + The script will terminate after MAX_FAIL (currently 60) consecutive errors. + Errors are counted for: + - error on send call + - error on select call + - error on recv call + - short packet received + - bad packet + - error on open for logfile + +ntploopwatch: + perl script to display loop filter statistics collected by ntploopstat + or dumped directly by xntpd. + + Gnuplot is used to produce a graphical representation of the sample + values, that have been preprocessed and analysed by this script. + + It can either be called to produce a printout of specific data set or + used to continously monitor the values. Monitoring is achieved by + periodically reprocessing the logfiles, which are updated regularly + either by a running ntploopstat process or by the running xntpd. + + usage: + to watch statistics permanently: + ntploopwatch [-v[<level>]] [-c <config-file>] [-d <working-dir>] + + to get a single print out specify also + -P<printer> [-s<samples>] + [-S <start-time>] [-E <end-time>] + [-O <MaxOffs>] [-o <MinOffs>] + + level: level of verbosity for debugging + config-file: file to read configurable settings from + On each iteration it is checked and reread + if it has been changed + default: loopwatch.config + working-dir: specify working directory for process, affects + interpretation of relative file names + + All other flags are only useful with printing plots, as otherwise + command line values would be replaced by settings from the config file. + + printer: specify printer to print plot + BSD print systems semantics apply; if printer is omitted + the name "ps" is used; plots are prepared using + PostScript, thus the printer should best accept + postscript input + + For the following see also the comments in loopwatch.config.SAMPLE + + samples: use last # samples from input data + start-time: ignore input samples before this date + end-time: ignore input samples after this date + if both start-time and end-time are specified + a given samples value is ignored + MaxOffs: + MinOffs: restrict value range + +loopwatch.config.SAMPLE: + sample config file for ntploopwatch + each configurable option is explained there + +lr.pl: + linear regression package used by ntploopwatch to compute + linear approximations for frequency and offset values + within display range + +timelocal.pl: + used during conversion of ISO_DATE_TIME values specified in loopwatch + config files to unix epoch values (seconds since 1970-01-01_00:00_00 UTC) + + A version of this file is distributed with perl-4.x, however, + it has a bug related to dates crossing 1970, causing endless loops.. + The version contained here has been fixed. + +ntp.pl: + perl support for ntp v2 mode 6 message handling + WARNING: This code is beta level - it triggers a memory leak; + as for now it is not quite clear, wether this is caused by a + bug in perl or by bad usage of perl within this script. + diff --git a/contrib/ntp/scripts/monitoring/loopwatch.config.SAMPLE b/contrib/ntp/scripts/monitoring/loopwatch.config.SAMPLE new file mode 100644 index 0000000..8cefea3 --- /dev/null +++ b/contrib/ntp/scripts/monitoring/loopwatch.config.SAMPLE @@ -0,0 +1,89 @@ +# sample configuration and control file for ntploowatch +# +# delay: sampling interval in seconds +delay=60 +# samples: use only last # samples +samples=600 +# DO NOT USE srcprefix in shared config files +# srcprefix: name of file to read samples from +# current time suffix (month name) is appended +# defaults to "./var@$STATHOST/loopstats." +# The string "$STATHOST"is replaced by the name of the host +# being monitored +#srcprefix=./var@$STATHOST/loopstats. +# +# showoffs: yes/no control display of offset values +showoffs=yes +# +# showfreq: yes/no control display of frequency values +showfreq=yes +# +# showcmpl: yes/no control display of compliance values +showcmpl=no +# +# showoreg: yes/no control display of linear regression of offset values +showoreg=no +# +# showfreg: yes/no control display of linear regression of frequency values +showfreg=no +# +# timebase: dynamic/ISO_DATE_TIME point of zero for linear regression +# ISO_DATE_TIME: yyyy-mm-dd_hh:mm:ss.ms +# values are interpreted using local time zone +# parts omitted from front default to current date/time +# parts omitted from end default to lowest permitted values +# to get aa:bb being interpreted as minutes:seconds use aa:bb.0 +# for dynamic '00:00:00.0 of current day' is used +timebase=dynamic +# +# freqbase: dynamic/<baseval> +# if a number is given, subtract this from sampling values for display +# if dynamic is selected, freqbase is adjusted to fit into the range of +# offset values +freqbase=dynamic +# +# cmplscale: dynamic/<scaling> +# if a number is given, the sampling values are divided by this number +# if dynamic is selected, cmplscale is adjusted to fit into the range of +# offset values +cmplscale=dynamic +# +# DumbScale: 0/1 +# 0 enables dynamic adjust of value ranges for freqbase and cmplscale +# timescale is labeled with human readable times +# 1 only uses explicit scaling for numbers +# timescale is labeled with hours relative to timebase +DumbScale=0 +# +# StartTime: none/ISO_DATE_TIME +# ignore any samples before the specified date +StartTime=none +# +# EndTime: none/ISO_DATE_TIME +# ignore any samples after the specified date +# +# if both StartTime and EndTime are specified +# the value specified for samples is ignored +EndTime=none +# +# MaxOffs: none/<number> +# limit display (y-axis) to values not larger than <number> +MaxOffset=none +# +# MinOffs: none/<number> +# limit display (y-axis) to values not smaller than <number> +MinOffset=none + +# +# verbose: <number> +# specify level for debugging +# default is 0 for printing and 1 for monitoring +# level 1 will just print a timestamp for any display update +# (this is every delay seconds) +verbose=1 +# +# deltaT: <seconds> +# mark `holes' in the sample data grater than <seconds> +# by a break in the plot +# default: 512 seconds +deltaT=512 diff --git a/contrib/ntp/scripts/monitoring/lr.pl b/contrib/ntp/scripts/monitoring/lr.pl new file mode 100644 index 0000000..02c7550 --- /dev/null +++ b/contrib/ntp/scripts/monitoring/lr.pl @@ -0,0 +1,145 @@ +;# +;# lr.pl,v 3.1 1993/07/06 01:09:08 jbj Exp +;# +;# +;# Linear Regression Package for perl +;# to be 'required' from perl +;# +;# Copyright (c) 1992 +;# Frank Kardel, Rainer Pruy +;# Friedrich-Alexander Universitaet Erlangen-Nuernberg +;# +;# +;############################################################# + +## +## y = A + Bx +## +## B = (n * Sum(xy) - Sum(x) * Sum(y)) / (n * Sum(x^2) - Sum(x)^2) +## +## A = (Sum(y) - B * Sum(x)) / n +## + +## +## interface +## +*lr_init = *lr'lr_init; #';# &lr_init(tag); initialize data set for tag +*lr_sample = *lr'lr_sample; #';# &lr_sample(x,y,tag); enter sample +*lr_Y = *lr'lr_Y; #';# &lr_Y(x,tag); compute y for given x +*lr_X = *lr'lr_X; #';# &lr_X(y,tag); compute x for given y +*lr_r = *lr'lr_r; #';# &lr_r(tag); regression coeffizient +*lr_cov = *lr'lr_cov; #';# &lr_cov(tag); covariance +*lr_A = *lr'lr_A; #';# &lr_A(tag); +*lr_B = *lr'lr_B; #';# &lr_B(tag); +*lr_sigma = *lr'lr_sigma; #';# &lr_sigma(tag); standard deviation +*lr_mean = *lr'lr_mean; #';# &lr_mean(tag); +######################### + +package lr; + +sub tagify +{ + local($tag) = @_; + if (defined($tag)) + { + *lr_n = eval "*${tag}_n"; + *lr_sx = eval "*${tag}_sx"; + *lr_sx2 = eval "*${tag}_sx2"; + *lr_sxy = eval "*${tag}_sxy"; + *lr_sy = eval "*${tag}_sy"; + *lr_sy2 = eval "*${tag}_sy2"; + } +} + +sub lr_init +{ + &tagify($_[$[]) if defined($_[$[]); + + $lr_n = 0; + $lr_sx = 0.0; + $lr_sx2 = 0.0; + $lr_sxy = 0.0; + $lr_sy = 0.0; + $lr_sy2 = 0.0; +} + +sub lr_sample +{ + local($_x, $_y) = @_; + + &tagify($_[$[+2]) if defined($_[$[+2]); + + $lr_n++; + $lr_sx += $_x; + $lr_sy += $_y; + $lr_sxy += $_x * $_y; + $lr_sx2 += $_x**2; + $lr_sy2 += $_y**2; +} + +sub lr_B +{ + &tagify($_[$[]) if defined($_[$[]); + + return 1 unless ($lr_n * $lr_sx2 - $lr_sx**2); + return ($lr_n * $lr_sxy - $lr_sx * $lr_sy) / ($lr_n * $lr_sx2 - $lr_sx**2); +} + +sub lr_A +{ + &tagify($_[$[]) if defined($_[$[]); + + return ($lr_sy - &lr_B * $lr_sx) / $lr_n; +} + +sub lr_Y +{ + &tagify($_[$[]) if defined($_[$[]); + + return &lr_A + &lr_B * $_[$[]; +} + +sub lr_X +{ + &tagify($_[$[]) if defined($_[$[]); + + return ($_[$[] - &lr_A) / &lr_B; +} + +sub lr_r +{ + &tagify($_[$[]) if defined($_[$[]); + + local($s) = ($lr_n * $lr_sx2 - $lr_sx**2) * ($lr_n * $lr_sy2 - $lr_sy**2); + + return 1 unless $s; + + return ($lr_n * $lr_sxy - $lr_sx * $lr_sy) / sqrt($s); +} + +sub lr_cov +{ + &tagify($_[$[]) if defined($_[$[]); + + return ($lr_sxy - $lr_sx * $lr_sy / $lr_n) / ($lr_n - 1); +} + +sub lr_sigma +{ + &tagify($_[$[]) if defined($_[$[]); + + return 0 if $lr_n <= 1; + return sqrt(($lr_sy2 - ($lr_sy * $lr_sy) / $lr_n) / ($lr_n)); +} + +sub lr_mean +{ + &tagify($_[$[]) if defined($_[$[]); + + return 0 if $lr_n <= 0; + return $lr_sy / $lr_n; +} + +&lr_init(); + +1; diff --git a/contrib/ntp/scripts/monitoring/ntp.pl b/contrib/ntp/scripts/monitoring/ntp.pl new file mode 100644 index 0000000..ea9e69c --- /dev/null +++ b/contrib/ntp/scripts/monitoring/ntp.pl @@ -0,0 +1,478 @@ +#!/local/bin/perl +;# +;# ntp.pl,v 3.1 1993/07/06 01:09:09 jbj Exp +;# +;# process loop filter statistics file and either +;# - show statistics periodically using gnuplot +;# - or print a single plot +;# +;# Copyright (c) 1992 +;# Rainer Pruy Friedrich-Alexander Universitaet Erlangen-Nuernberg +;# +;# +;############################################################# + +package ntp; + +$NTP_version = 2; +$ctrl_mode=6; + +$byte1 = (($NTP_version & 0x7)<< 3) & 0x34 | ($ctrl_mode & 0x7); +$MAX_DATA = 468; + +$sequence = 0; # initial sequence number incred before used +$pad=4; +$do_auth=0; # no possibility today +$keyid=0; +;#list if known keys (passwords) +%KEYS = ( 0, "\200\200\200\200\200\200\200\200", + ); + +;#----------------------------------------------------------------------------- +;# access routines for ntp control packet + ;# NTP control message format + ;# C LI|VN|MODE LI 2bit=00 VN 3bit=2(3) MODE 3bit=6 : $byte1 + ;# C R|E|M|Op R response E error M more Op opcode + ;# n sequence + ;# n status + ;# n associd + ;# n offset + ;# n count + ;# a+ data (+ padding) + ;# optional authentication data + ;# N key + ;# N2 checksum + +;# first bye of packet +sub pkt_LI { return ($_[$[] >> 6) & 0x3; } +sub pkt_VN { return ($_[$[] >> 3) & 0x7; } +sub pkt_MODE { return ($_[$[] ) & 0x7; } + +;# second byte of packet +sub pkt_R { return ($_[$[] & 0x80) == 0x80; } +sub pkt_E { return ($_[$[] & 0x40) == 0x40; } +sub pkt_M { return ($_[$[] & 0x20) == 0x20; } +sub pkt_OP { return $_[$[] & 0x1f; } + +;#----------------------------------------------------------------------------- + +sub setkey +{ + local($id,$key) = @_; + + $KEYS{$id} = $key if (defined($key)); + if (! defined($KEYS{$id})) + { + warn "Key $id not yet specified - key not changed\n"; + return undef; + } + return ($keyid,$keyid = $id)[$[]; +} + +;#----------------------------------------------------------------------------- +sub numerical { $a <=> $b; } + +;#----------------------------------------------------------------------------- + +sub send #' +{ + local($fh,$opcode, $associd, $data,$address) = @_; + $fh = caller(0)."'$fh"; + + local($junksize,$junk,$packet,$offset,$ret); + $offset = 0; + + $sequence++; + while(1) + { + $junksize = length($data); + $junksize = $MAX_DATA if $junksize > $MAX_DATA; + + ($junk,$data) = $data =~ /^(.{$junksize})(.*)$/; + $packet + = pack("C2n5a".(($junk eq "") ? 0 : &pad($junksize+12,$pad)-12), + $byte1, + ($opcode & 0x1f) | ($data ? 0x20 : 0), + $sequence, + 0, $associd, + $offset, $junksize, $junk); + if ($do_auth) + { + ;# not yet + } + $offset += $junksize; + + if (defined($address)) + { + $ret = send($fh, $packet, 0, $address); + } + else + { + $ret = send($fh, $packet, 0); + } + + if (! defined($ret)) + { + warn "send failed: $!\n"; + return undef; + } + elsif ($ret != length($packet)) + { + warn "send failed: sent only $ret from ".length($packet). "bytes\n"; + return undef; + } + return $sequence unless $data; + } +} + +;#----------------------------------------------------------------------------- +;# status interpretation +;# +sub getval +{ + local($val,*list) = @_; + + return $list{$val} if defined($list{$val}); + return sprintf("%s#%d",$list{"-"},$val) if defined($list{"-"}); + return "unknown-$val"; +} + +;#--------------------------------- +;# system status +;# +;# format: |LI|CS|SECnt|SECode| LI=2bit CS=6bit SECnt=4bit SECode=4bit +sub ssw_LI { return ($_[$[] >> 14) & 0x3; } +sub ssw_CS { return ($_[$[] >> 8) & 0x3f; } +sub ssw_SECnt { return ($_[$[] >> 4) & 0xf; } +sub ssw_SECode { return $_[$[] & 0xf; } + +%LI = ( 0, "leap_none", 1, "leap_add_sec", 2, "leap_del_sec", 3, "sync_alarm", "-", "leap"); +%ClockSource = (0, "sync_unspec", + 1, "sync_lf_clock", + 2, "sync_uhf_clock", + 3, "sync_hf_clock", + 4, "sync_local_proto", + 5, "sync_ntp", + 6, "sync_udp/time", + 7, "sync_wristwatch", + "-", "ClockSource", + ); + +%SystemEvent = (0, "event_unspec", + 1, "event_restart", + 2, "event_fault", + 3, "event_sync_chg", + 4, "event_sync/strat_chg", + 5, "event_clock_reset", + 6, "event_bad_date", + 7, "event_clock_excptn", + "-", "event", + ); +sub LI +{ + &getval(&ssw_LI($_[$[]),*LI); +} +sub ClockSource +{ + &getval(&ssw_CS($_[$[]),*ClockSource); +} + +sub SystemEvent +{ + &getval(&ssw_SECode($_[$[]),*SystemEvent); +} + +sub system_status +{ + return sprintf("%s, %s, %d event%s, %s", &LI($_[$[]), &ClockSource($_[$[]), + &ssw_SECnt($_[$[]), ((&ssw_SECnt($_[$[])==1) ? "" : "s"), + &SystemEvent($_[$[])); +} +;#--------------------------------- +;# peer status +;# +;# format: |PStat|PSel|PCnt|PCode| Pstat=6bit PSel=2bit PCnt=4bit PCode=4bit +sub psw_PStat_config { return ($_[$[] & 0x8000) == 0x8000; } +sub psw_PStat_authenable { return ($_[$[] & 0x4000) == 0x4000; } +sub psw_PStat_authentic { return ($_[$[] & 0x2000) == 0x2000; } +sub psw_PStat_reach { return ($_[$[] & 0x1000) == 0x1000; } +sub psw_PStat_sane { return ($_[$[] & 0x0800) == 0x0800; } +sub psw_PStat_dispok { return ($_[$[] & 0x0400) == 0x0400; } +sub psw_PStat { return ($_[$[] >> 10) & 0x3f; } +sub psw_PSel { return ($_[$[] >> 8) & 0x3; } +sub psw_PCnt { return ($_[$[] >> 4) & 0xf; } +sub psw_PCode { return $_[$[] & 0xf; } + +%PeerSelection = (0, "sel_reject", + 1, "sel_candidate", + 2, "sel_selcand", + 3, "sel_sys.peer", + "-", "PeerSel", + ); +%PeerEvent = (0, "event_unspec", + 1, "event_ip_err", + 2, "event_authen", + 3, "event_unreach", + 4, "event_reach", + 5, "event_clock_excptn", + 6, "event_stratum_chg", + "-", "event", + ); + +sub PeerSelection +{ + &getval(&psw_PSel($_[$[]),*PeerSelection); +} +sub PeerEvent +{ + &getval(&psw_PCode($_[$[]),*PeerEvent); +} + +sub peer_status +{ + local($x) = (""); + $x .= "config," if &psw_PStat_config($_[$[]); + $x .= "authenable," if &psw_PStat_authenable($_[$[]); + $x .= "authentic," if &psw_PStat_authentic($_[$[]); + $x .= "reach," if &psw_PStat_reach($_[$[]); + $x .= &psw_PStat_sane($_[$[]) ? "sane," : "insane,"; + $x .= "hi_disp," unless &psw_PStat_dispok($_[$[]); + + $x .= sprintf(" %s, %d event%s, %s", &PeerSelection($_[$[]), + &psw_PCnt($_[$[]), ((&psw_PCnt($_[$[]) == 1) ? "" : "s"), + &PeerEvent($_[$[])); + return $x; +} + +;#--------------------------------- +;# clock status +;# +;# format: |CStat|CEvnt| CStat=8bit CEvnt=8bit +sub csw_CStat { return ($_[$[] >> 8) & 0xff; } +sub csw_CEvnt { return $_[$[] & 0xff; } + +%ClockStatus = (0, "clk_nominal", + 1, "clk_timeout", + 2, "clk_badreply", + 3, "clk_fault", + 4, "clk_prop", + 5, "clk_baddate", + 6, "clk_badtime", + "-", "clk", + ); + +sub clock_status +{ + return sprintf("%s, last %s", + &getval(&csw_CStat($_[$[]),*ClockStatus), + &getval(&csw_CEvnt($_[$[]),*ClockStatus)); +} + +;#--------------------------------- +;# error status +;# +;# format: |Err|reserved| Err=8bit +;# +sub esw_Err { return ($_[$[] >> 8) & 0xff; } + +%ErrorStatus = (0, "err_unspec", + 1, "err_auth_fail", + 2, "err_invalid_fmt", + 3, "err_invalid_opcode", + 4, "err_unknown_assoc", + 5, "err_unknown_var", + 6, "err_invalid_value", + 7, "err_adm_prohibit", + ); + +sub error_status +{ + return sprintf("%s", &getval(&esw_Err($_[$[]),*ErrorStatus)); +} + +;#----------------------------------------------------------------------------- +;# +;# cntrl op name translation + +%CntrlOpName = (1, "read_status", + 2, "read_variables", + 3, "write_variables", + 4, "read_clock_variables", + 5, "write_clock_variables", + 6, "set_trap", + 7, "trap_response", + 31, "unset_trap", # !!! unofficial !!! + "-", "cntrlop", + ); + +sub cntrlop_name +{ + return &getval($_[$[],*CntrlOpName); +} + +;#----------------------------------------------------------------------------- + +$STAT_short_pkt = 0; +$STAT_pkt = 0; + +;# process a NTP control message (response) packet +;# returns a list ($ret,$data,$status,$associd,$op,$seq,$auth_keyid) +;# $ret: undef --> not yet complete +;# "" --> complete packet received +;# "ERROR" --> error during receive, bad packet, ... +;# else --> error packet - list may contain useful info + + +sub handle_packet +{ + local($pkt,$from) = @_; # parameters + local($len_pkt) = (length($pkt)); +;# local(*FRAGS,*lastseen); + local($li_vn_mode,$r_e_m_op,$seq,$status,$associd,$offset,$count,$data); + local($autch_keyid,$auth_cksum); + + $STAT_pkt++; + if ($len_pkt < 12) + { + $STAT_short_pkt++; + return ("ERROR","short packet received"); + } + + ;# now break packet apart + ($li_vn_mode,$r_e_m_op,$seq,$status,$associd,$offset,$count,$data) = + unpack("C2n5a".($len_pkt-12),$pkt); + $data=substr($data,$[,$count); + if ((($len_pkt - 12) - &pad($count,4)) >= 12) + { + ;# looks like an authenticator + ($auth_keyid,$auth_cksum) = + unpack("Na8",substr($pkt,$len_pkt-12+$[,12)); + $STAT_auth++; + ;# no checking of auth_cksum (yet ?) + } + + if (&pkt_VN($li_vn_mode) != $NTP_version) + { + $STAT_bad_version++; + return ("ERROR","version ".&pkt_VN($li_vn_mode)."packet ignored"); + } + + if (&pkt_MODE($li_vn_mode) != $ctrl_mode) + { + $STAT_bad_mode++; + return ("ERROR", "mode ".&pkt_MODE($li_vn_mode)." packet ignored"); + } + + ;# handle single fragment fast + if ($offset == 0 && &pkt_M($r_e_m_op) == 0) + { + $STAT_single_frag++; + if (&pkt_E($r_e_m_op)) + { + $STAT_err_pkt++; + return (&error_status($status), + $data,$status,$associd,&pkt_OP($r_e_m_op),$seq, + $auth_keyid); + } + else + { + return ("", + $data,$status,$associd,&pkt_OP($r_e_m_op),$seq, + $auth_keyid); + } + } + else + { + ;# fragment - set up local name space + $id = "$from$seq".&pkt_OP($r_e_m_op); + $ID{$id} = 1; + *FRAGS = "$id FRAGS"; + *lastseen = "$id lastseen"; + + $STAT_frag++; + + $lastseen = 1 if !&pkt_M($r_e_m_op); + if (!defined(%FRAGS)) + { + # (&pkt_M($r_e_m_op) ? " more" : "")."\n"; + $FRAGS{$offset} = $data; + ;# save other info + @FRAGS = ($status,$associd,&pkt_OP($r_e_m_op),$seq,$auth_keyid,$r_e_m_op); + } + else + { + # (&pkt_M($r_e_m_op) ? " more" : "")."\n"; + ;# add frag to previous - combine on the fly + if (defined($FRAGS{$offset})) + { + $STAT_dup_frag++; + return ("ERROR","duplicate fragment at $offset seq=$seq"); + } + + $FRAGS{$offset} = $data; + + undef($loff); + foreach $off (sort numerical keys(%FRAGS)) + { + next unless defined($FRAGS{$off}); + if (defined($loff) && + ($loff + length($FRAGS{$loff})) == $off) + { + $FRAGS{$loff} .= $FRAGS{$off}; + delete $FRAGS{$off}; + last; + } + $loff = $off; + } + + ;# return packet if all frags arrived + ;# at most two frags with possible padding ??? + if ($lastseen && defined($FRAGS{0}) && + (((scalar(@x=sort numerical keys(%FRAGS)) == 2) && + (length($FRAGS{0}) + 8) > $x[$[+1]) || + (scalar(@x=sort numerical keys(%FRAGS)) < 2))) + { + @x=((&pkt_E($r_e_m_op) ? &error_status($status) : ""), + $FRAGS{0},@FRAGS); + &pkt_E($r_e_m_op) ? $STAT_err_frag++ : $STAT_frag_all++; + undef(%FRAGS); + undef(@FRAGS); + undef($lastseen); + delete $ID{$id}; + &main'clear_timeout($id); + return @x; + } + else + { + &main'set_timeout($id,time+$timeout,"&ntp'handle_packet_timeout(\"".unpack("H*",$id)."\");"); #'"; + } + } + return (undef); + } +} + +sub handle_packet_timeout +{ + local($id) = @_; + local($r_e_m_op,*FRAGS,*lastseen,@x) = (@FRAGS[$[+5]); + + *FRAGS = "$id FRAGS"; + *lastseen = "$id lastseen"; + + @x=((&pkt_E($r_e_m_op) ? &error_status($status) : "TIMEOUT"), + $FRAGS{0},@FRAGS[$[ .. $[+4]); + $STAT_frag_timeout++; + undef(%FRAGS); + undef(@FRAGS); + undef($lastseen); + delete $ID{$id}; + return @x; +} + + +sub pad +{ + return $_[$[+1] * int(($_[$[] + $_[$[+1] - 1) / $_[$[+1]); +} + +1; diff --git a/contrib/ntp/scripts/monitoring/ntploopstat b/contrib/ntp/scripts/monitoring/ntploopstat new file mode 100644 index 0000000..75cdff2 --- /dev/null +++ b/contrib/ntp/scripts/monitoring/ntploopstat @@ -0,0 +1,457 @@ +#!/local/bin/perl -w--*-perl-*- +;# +;# ntploopstat,v 3.1 1993/07/06 01:09:11 jbj Exp +;# +;# Poll NTP server using NTP mode 7 loopinfo request. +;# Log info and timestamp to file for processing by ntploopwatch. +;# +;# +;# Copyright (c) 1992 +;# Rainer Pruy Friedrich-Alexander Universitaet Erlangen-Nuernberg +;# +;################################################################# +;# +;# The format written to the logfile is the same as used by xntpd +;# for the loopstats file. +;# This script however allows to gather loop filter statistics from +;# remote servers where you do not have access to the loopstats logfile. +;# +;# Please note: Communication delays affect the accuracy of the +;# timestamps recorded. Effects from these delays will probably +;# not show up, as timestamps are recorded to the second only. +;# (Should have implemented &gettimeofday()..) +;# + +$0 =~ s!^.*/([^/]+)$!\1!; # beautify script name + +$ntpserver = 'localhost'; # default host to poll +$delay = 60; # default sampling rate + ;# keep it shorter than minpoll (=64) + ;# to get all values + +require "ctime.pl"; +;# handle bug in early ctime distributions +$ENV{'TZ'} = 'MET' unless defined($ENV{'TZ'}) || $] > 4.010; + +if (defined(@ctime'MoY)) +{ + *MonthName = *ctime'MoY; +} +else +{ + @MonthName = ('Jan','Feb','Mar','Apr','May','Jun', + 'Jul','Aug','Sep','Oct','Nov','Dec'); +} + +;# this routine can be redefined to point to syslog if necessary +sub msg +{ + return unless $verbose; + + print STDERR "$0: "; + printf STDERR @_; +} + +;############################################################# +;# +;# process command line +$usage = <<"E-O-S"; + +usage: + $0 [-d<delay>] [-t<timeout>] [-l <logfile>] [-v] [ntpserver] +E-O-S + +while($_ = shift) +{ + /^-v(\d*)$/ && ($verbose=($1 eq '') ? 1 : $1,1) && next; + /^-d(\d*)$/ && + do { + ($1 ne '') && ($delay = $1,1) && next; + @ARGV || die("$0: delay value missing after -d\n$usage"); + $delay = shift; + ($delay >= 0) || die("$0: bad delay value \"$delay\"\n$usage"); + next; + }; + /^-l$/ && + do { + @ARGV || die("$0: logfile missing after -l\n$usage"); + $logfile = shift; + next; + }; + /^-t(\d*(\.\d*)?)$/ && + do { + ($1 ne '') && ($timeout = $1,1) && next; + @ARGV || die("$0: timeout value missing after -t\n$usage\n"); + $timeout = shift; + ($timeout > 0) || + die("$0: bad timeout value \"$timeout\"\n$usage"); + next; + }; + + /^-/ && die("$0: unknown option \"$_\"\n$usage"); + + ;# any other argument is server to poll + $ntpserver = $_; + last; +} + +if (@ARGV) +{ + warn("unexpected arguments: ".join(" ",@ARGV).".\n"); + die("$0: too many servers specified\n$usage"); +} + +;# logfile defaults to include server name +;# The name of the current month is appended and +;# the file is opened and closed for each sample. +;# +$logfile = "loopstats:$ntpserver." unless defined($logfile); +$timeout = 12.0 unless defined($timeout); # wait $timeout seconds for reply + +$MAX_FAIL = 60; # give up after $MAX_FAIL failed polls + + +$MJD_1970 = 40587; + +if (eval 'require "syscall.ph";') +{ + if (defined(&SYS_gettimeofday)) + { + ;# assume standard + ;# gettimeofday(struct timeval *tp,struct timezone *tzp) + ;# syntax for gettimeofday syscall + ;# tzp = NULL -> undef + ;# tp = (long,long) + eval 'sub time { local($tz) = pack("LL",0,0); + (&msg("gettimeofday failed: $!\n"), + return (time)) + unless syscall(&SYS_gettimeofday,$tz,undef) == 0; + local($s,$us) = unpack("LL",$tz); + return $s + $us/1000000; }'; + local($t1,$t2,$t3); + $t1 = time; + eval '$t2 = &time;'; + $t3 = time; + die("$0: gettimeofday failed: $@.\n") if defined($@) && $@; + die("$0: gettimeofday inconsistency time=$t1,gettimeofday=$t2,time=$t2\n") + if (int($t1) != int($t2) && int($t3) != int($t2)); + &msg("Using gettimeofday for timestamps\n"); + } + else + { + warn("No gettimeofday syscall found - using time builtin for timestamps\n"); + eval 'sub time { return time; }'; + } +} +else +{ + warn("No syscall.ph file found - using time builtin for timestamps\n"); + eval 'sub time { return time; }'; +} + + +;#------------------+ +;# from ntp_request.h +;#------------------+ + +;# NTP mode 7 packet format: +;# Byte 1: ResponseBit MoreBit Version(3bit) Mode(3bit)==7 +;# Byte 2: AuthBit Sequence # - 0 - 127 see MoreBit +;# Byte 3: Implementation # +;# Byte 4: Request Code +;# +;# Short 1: Err(3bit) NumItems(12bit) +;# Short 2: MBZ(3bit)=0 DataItemSize(12bit) +;# 0 - 500 byte Data +;# if AuthBit is set: +;# Long: KeyId +;# 2xLong: AuthCode + +;# +$IMPL_XNTPD = 2; +$REQ_LOOP_INFO = 8; + + +;# request packet for REQ_LOOP_INFO: +;# B1: RB=0 MB=0 V=2 M=7 +;# B2: S# = 0 +;# B3: I# = IMPL_XNTPD +;# B4: RC = REQ_LOOP_INFO +;# S1: E=0 NI=0 +;# S2: MBZ=0 DIS=0 +;# data: 32 byte 0 padding +;# 8byte timestamp if encryption, 0 padding otherwise +$loopinfo_reqpkt = + pack("CCCC nn x32 x8", 0x17, 0, $IMPL_XNTPD, $REQ_LOOP_INFO, 0, 0); + +;# ignore any auth data in packets +$loopinfo_response_size = + 1+1+1+1+2+2 # header size like request pkt + + 8 # l_fp last_offset + + 8 # l_fp drift_comp + + 4 # u_long compliance + + 4 # u_long watchdog_timer + ; +$loopinfo_response_fmt = "C4n2N2N2NN"; +$loopinfo_response_fmt_v2 = "C4n2N2N2N2N"; + +;# +;# prepare connection to server +;# + +;# workaround for broken socket.ph on dynix_ptx +eval 'sub INTEL {1;}' unless defined(&INTEL); +eval 'sub ATT {1;}' unless defined(&ATT); + +require "sys/socket.ph"; + +require 'netinet/in.ph'; + +;# if you do not have netinet/in.ph enable the following lines +;#eval 'sub INADDR_ANY { 0x00000000; }' unless defined(&INADDR_ANY); +;#eval 'sub IPPRORO_UDP { 17; }' unless defined(&IPPROTO_UDP); + +if ($ntpserver =~ /^((0x?)?\w+)\.((0x?)?\w+)\.((0x?)?\w+)\.((0x?)?\w+)$/) +{ + local($a,$b,$c,$d) = ($1,$3,$5,$7); + $a = oct($a) if defined($2); + $b = oct($b) if defined($4); + $c = oct($c) if defined($6); + $d = oct($d) if defined($8); + $server_addr = pack("C4", $a,$b,$c,$d); + + $server_mainname + = (gethostbyaddr($server_addr,&AF_INET))[$[] || $ntpserver; +} +else +{ + ($server_mainname,$server_addr) + = (gethostbyname($ntpserver))[$[,$[+4]; + + die("$0: host \"$ntpserver\" is unknown\n") + unless defined($server_addr); +} +&msg ("Address of server \"$ntpserver\" is \"%d.%d.%d.%d\"\n", + unpack("C4",$server_addr)); + +$proto_udp = (getprotobyname('udp'))[$[+2] || &IPPROTO_UDP; + +$ntp_port = + (getservbyname('ntp','udp'))[$[+2] || + (warn "Could not get port number for service \"ntp/udp\" using 123\n"), + ($ntp_port=123); + +;# +0 && &SOCK_DGRAM; # satisfy perl -w ... +socket(S, &AF_INET, &SOCK_DGRAM, $proto_udp) || + die("Cannot open socket: $!\n"); + +bind(S, pack("S n N x8", &AF_INET, 0, &INADDR_ANY)) || + die("Cannot bind: $!\n"); + +($my_port, $my_addr) = (unpack("S n a4 x8",getsockname(S)))[$[+1,$[+2]; + +&msg("Listening at address %d.%d.%d.%d port %d\n", + unpack("C4",$my_addr), $my_port); + +$server_inaddr = pack("Sna4x8", &AF_INET, $ntp_port, $server_addr); + +;############################################################ +;# +;# the main loop: +;# send request +;# get reply +;# wait til next sample time + +undef($lasttime); +$lostpacket = 0; + +while(1) +{ + $stime = &time; + + &msg("Sending request $stime...\n"); + + $ret = send(S,$loopinfo_reqpkt,0,$server_inaddr); + + if (! defined($ret) || $ret < length($loopinfo_reqpkt)) + { + warn("$0: send failed ret=($ret): $!\n"); + $fail++; + next; + } + + &msg("Waiting for reply...\n"); + + $mask = ""; vec($mask,fileno(S),1) = 1; + $ret = select($mask,undef,undef,$timeout); + + if (! defined($ret)) + { + warn("$0: select failed: $!\n"); + $fail++; + next; + } + elsif ($ret == 0) + { + warn("$0: request to $ntpserver timed out ($timeout seconds)\n"); + ;# do not count this event as failure + ;# it usually this happens due to dropped udp packets on noisy and + ;# havily loaded lines, so just try again; + $lostpacket = 1; + next; + } + + &msg("Receiving reply...\n"); + + $len = 520; # max size of a mode 7 packet + $reply = ""; # just make it defined for -w + $ret = recv(S,$reply,$len,0); + + if (!defined($ret)) + { + warn("$0: recv failed: $!\n"); + $fail++; + next; + } + + $etime = &time; + &msg("Received at\t$etime\n"); + + ;#$time = ($stime + $etime) / 2; # symmetric delay assumed + $time = $etime; # the above assumption breaks for X25 + ;# so taking etime makes timestamps be a + ;# little late, but keeps them increasing + ;# monotonously + + &msg(sprintf("Reply from %d.%d.%d.%d took %f seconds\n", + (unpack("SnC4",$ret))[$[+2 .. $[+5], ($etime - $stime))); + + if ($len < $loopinfo_response_size) + { + warn("$0: short packet ($len bytes) received ($loopinfo_response_size bytes expected\n"); + $fail++; + next; + } + + ($b1,$b2,$b3,$b4,$s1,$s2, + $offset_i,$offset_f,$drift_i,$drift_f,$compl,$watchdog) + = unpack($loopinfo_response_fmt,$reply); + + ;# check reply + if (($s1 >> 12) != 0) # error ! + { + die("$0: got error reply ".($s1>>12)."\n"); + } + if (($b1 != 0x97 && $b1 != 0x9f) || # Reply NotMore V=2 M=7 + ($b2 != 0 && $b2 != 0x80) || # S=0 Auth no/yes + $b3 != $IMPL_XNTPD || # ! IMPL_XNTPD + $b4 != $REQ_LOOP_INFO || # Ehh.. not loopinfo reply ? + $s1 != 1 || # ???? + ($s2 != 24 && $s2 != 28) # + ) + { + warn("$0: Bad/unexpected reply from server:\n"); + warn(" \"".unpack("H*",$reply)."\"\n"); + warn(" ".sprintf("b1=%x b2=%x b3=%x b4=%x s1=%d s2=%d\n", + $b1,$b2,$b3,$b4,$s1,$s2)); + $fail++; + next; + } + elsif ($s2 == 28) + { + ;# seems to be a version 2 xntpd + ($b1,$b2,$b3,$b4,$s1,$s2, + $offset_i,$offset_f,$drift_i,$drift_f,$compl_i,$compl_f,$watchdog) + = unpack($loopinfo_response_fmt_v2,$reply); + $compl = &lfptoa($compl_i, $compl_f); + } + + $time -= $watchdog; + + $offset = &lfptoa($offset_i, $offset_f); + $drift = &lfptoa($drift_i, $drift_f); + + &log($time,$offset,$drift,$compl) && ($fail = 0);; +} +continue +{ + die("$0: Too many failures - terminating\n") if $fail > $MAX_FAIL; + &msg("Sleeping " . ($lostpacket ? ($delay / 2) : $delay) . " seconds...\n"); + + sleep($lostpacket ? ($delay / 2) : $delay); + $lostpacket = 0; +} + +sub log +{ + local($time,$offs,$freq,$cmpl) = @_; + local($y,$m,$d); + local($fname,$suff) = ($logfile); + + + ;# silently drop sample if distance to last sample is too low + if (defined($lasttime) && ($lasttime + 2) >= $time) + { + &msg("Dropped packet - old sample\n"); + return 1; + } + + ;# $suff determines which samples end up in the same file + ;# could have used $year (;-) or WeekOfYear, DayOfYear,.... + ;# Change it to your suit... + + ($d,$m,$y) = (localtime($time))[$[+3 .. $[+5]; + $suff = sprintf("%04d%02d%02d",$y+1900,$m+1,$d); + $fname .= $suff; + if (!open(LOG,">>$fname")) + { + warn("$0: open($fname) failed: $!\n"); + $fail++; + return 0; + } + else + { + ;# file format + ;# MJD seconds offset drift compliance + printf LOG ("%d %.3lf %.8lf %.7lf %d\n", + int($time/86400)+$MJD_1970, + $time - int($time/86400) * 86400, + $offs,$freq,$cmpl); + close(LOG); + $lasttime = $time; + } + return 1; +} + +;# see ntp_fp.h to understand this +sub lfptoa +{ + local($i,$f) = @_; + local($sign) = 1; + + + if ($i & 0x80000000) + { + if ($f == 0) + { + $i = -$i; + } + else + { + $f = -$f; + $i = ~$i; + $i += 1; # 2s complement + } + $sign = -1; + ;#print "NEG: $i $f\n"; + } + else + { + ;#print "POS: $i $f\n"; + } + ;# unlike xntpd I have perl do the dirty work. + ;# Using floats here may affect precision, but + ;# currently these bits aren't significant anyway + return $sign * ($i + $f/2**32); +} diff --git a/contrib/ntp/scripts/monitoring/ntploopwatch b/contrib/ntp/scripts/monitoring/ntploopwatch new file mode 100644 index 0000000..db661d3 --- /dev/null +++ b/contrib/ntp/scripts/monitoring/ntploopwatch @@ -0,0 +1,1667 @@ +#!/usr/bin/perl -w +;# --*-perl-*-- +;# +;# /src/NTP/ntp-4/scripts/monitoring/ntploopwatch,v 4.3 1999/02/21 12:18:38 kardel RELEASE_19990228_A +;# RELEASE_19990228_A +;# +;# process loop filter statistics file and either +;# - show statistics periodically using gnuplot +;# - or print a single plot +;# +;# Copyright (c) 1992-1998 +;# Rainer Pruy, Friedrich-Alexander Universität Erlangen-Nürnberg +;# +;# +;############################################################# +$0 =~ s!^.*/([^/]+)$!$1!; +$F = ' ' x length($0); +$|=1; + +$ENV{'SHELL'} = '/bin/sh'; # use bourne shell + +undef($config); +undef($workdir); +undef($PrintIt); +undef($samples); +undef($StartTime); +undef($EndTime); +($a,$b) if 0; # keep -w happy +$usage = <<"E-O-P"; +usage: + to watch statistics permanently: + $0 [-v[<level>]] [-c <config-file>] [-d <working-dir>] + $F [-h <hostname>] + + to get a single print out specify also + $F -P[<printer>] [-s<samples>] + $F [-S <start-time>] [-E <end-time>] + $F [-Y <MaxOffs>] [-y <MinOffs>] + +If You like long option names, You can use: + -help + -c +config + -d +directory + -h +host + -v +verbose[=<level>] + -P +printer[=<printer>] + -s +samples[=<samples>] + -S +starttime + -E +endtime + -Y +maxy + -y +miny + +If <printer> contains a '/' (slash character) output is directed to +a file of this name instead of delivered to a printer. +E-O-P + +;# add directory to look for lr.pl and timelocal.pl (in front of current list) +unshift(@INC,"/usr/local/xntp/monitoring"); + +require "lr.pl"; # linear regresion routines + +$MJD_1970 = 40587; # from ntp.h (V3) +$RecordSize = 48; # usually a line fits into 42 bytes +$MinClip = 1; # clip Y scales with greater range than this + +;# largest extension of Y scale from mean value, factor for standart deviation +$FuzzLow = 2.2; # for side closer to zero +$FuzzBig = 1.8; # for side farther from zero + +require "ctime.pl"; +require "timelocal.pl"; +;# early distributions of ctime.pl had a bug +$ENV{'TZ'} = 'MET' unless defined $ENV{'TZ'} || $[ > 4.010; +if (defined(@ctime'MoY)) +{ + *Month=*ctime'MoY; + *Day=*ctime'DoW; +} # ' re-sync emacs fontification +else +{ + @Month = ('Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'); + @Day = ('Sun','Mon','Tue','Wed','Thu','Fri','Sat'); +} +print @ctime'DoW if 0; # ' re-sync emacs fontification + +;# max number of days per month +@MaxNumDaysPerMonth = (31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31); + +;# config settable parameters +$delay = 60; +$srcprefix = "./var\@\$STATHOST/loopstats."; +$showoffs = 1; +$showfreq = 1; +$showcmpl = 0; +$showoreg = 0; +$showfreg = 0; +undef($timebase); +undef($freqbase); +undef($cmplscale); +undef($MaxY); +undef($MinY); +$deltaT = 512; # indicate sample data gaps greater than $deltaT seconds +$verbose = 1; + +while($_ = shift(@ARGV)) +{ + (/^[+-]help$/) && die($usage); + + (/^-c$/ || /^\+config$/) && + (@ARGV || die($usage), $config = shift(@ARGV), next); + + (/^-d$/ || /^\+directory$/) && + (@ARGV || die($usage), $workdir = shift(@ARGV), next); + + (/^-h$/ || /^\+host$/) && + (@ARGV || die($usage), $STATHOST = shift, next); + + (/^-v(\d*)$/ || /^\+verbose=?(\d*)$/) && + ($verbose=($1 eq "") ? 1 : $1, next); + + (/^-P(\S*)$/ || /^\+[Pp]rinter=?(\S*)$/) && + ($PrintIt = $1, $verbose==1 && ($verbose = 0), next); + + (/^-s(\d*)$/ || /^\+samples=?(\d*)$/) && + (($samples = ($1 eq "") ? (shift || die($usage)): $1), next); + + (/^-S$/ || /^\+[Ss]tart[Tt]ime$/) && + (@ARGV || die($usage), $StartTime=&date_time_spec2seconds(shift),next); + + (/^-E$/ || /^\+[Ee]nd[Tt]ime$/) && + (@ARGV || die($usage), $EndTime = &date_time_spec2seconds(shift),next); + + (/^-Y$/ || /^\+[Mm]ax[Yy]$/) && + (@ARGV || die($usage), $MaxY = shift, next); + + (/^-y$/ || /^\+[Mm]in[Yy]$/) && + (@ARGV || die($usage), $MinY = shift, next); + + die("$0: unexpected argument \"$_\"\n$usage"); +} + +if (defined($workdir)) +{ + chdir($workdir) || + die("$0: failed to change working dir to \"$workdir\": $!\n"); +} + +$PrintIt = "ps" if defined($PrintIt) && $PrintIt eq ""; + +if (!defined($PrintIt)) +{ + defined($samples) && + print "WARNING: your samples value may be shadowed by config file settings\n"; + defined($StartTime) && + print "WARNING: your StartTime value may be shadowed by config file settings\n"; + defined($EndTime) && + print "WARNING: your EndTime value may be shadowed by config file settings\n"; + defined($MaxY) && + print "WARNING: your MaxY value may be shadowed by config file settings\n"; + defined($MinY) && + print "WARNING: your MinY value may be shadowed by config file settings\n"; + + ;# check operating environment + ;# + ;# gnuplot usually has X support + ;# I vaguely remember there was one with sunview support + ;# + ;# If Your plotcmd can display graphics using some other method + ;# (Tek window,..) fix the following test + ;# (or may be, just disable it) + ;# + !(defined($ENV{'DISPLAY'}) || defined($ENV{'WINDOW_PARENT'})) && + die("Need window system to monitor statistics\n"); +} + +;# configuration file +$config = "loopwatch.config" unless defined($config); +($STATHOST = $config) =~ s!.*loopwatch\.config.([^/\.]*)$!$1! + unless defined($STATHOST); +($STATTAG = $STATHOST) =~ s/^([^\.\*\s]+)\..*$/$1/; + +$srcprefix =~ s/\$STATHOST/$STATHOST/g; + +;# plot command +@plotcmd=("gnuplot", + '-title', "Ntp loop filter statistics $STATHOST", + '-name', "NtpLoopWatch_$STATTAG"); +$tmpfile = "/tmp/ntpstat.$$"; + +;# other variables +$doplot = ""; # assembled command for @plotcmd to display plot +undef($laststat); + +;# plot value ranges +undef($mintime); +undef($maxtime); +undef($minoffs); +undef($maxoffs); +undef($minfreq); +undef($maxfreq); +undef($mincmpl); +undef($maxcmpl); +undef($miny); +undef($maxy); + +;# stop operation if plot command dies +sub sigchld +{ + local($pid) = wait; + unlink($tmpfile); + warn(sprintf("%s: %s died: exit status: %d signal %d\n", + $0, + (defined($Plotpid) && $Plotpid == $pid) + ? "plotcmd" : "unknown child $pid", + $?>>8,$? & 0xff)) if $?; + exit(1) if $? && defined($Plotpid) && $pid == $Plotpid; +} +&sigchld if 0; +$SIG{'CHLD'} = "sigchld"; +$SIG{'CLD'} = "sigchld"; + +sub abort +{ + unlink($tmpfile); + defined($Plotpid) && kill('TERM',$Plotpid); + die("$0: received signal SIG$_[$[] - exiting\n"); +} +&abort if 0; # make -w happy - &abort IS used +$SIG{'INT'} = $SIG{'HUP'} = $SIG{'QUIT'} = $SIG{'TERM'} = $SIG{'PIPE'} = "abort"; + +;# +sub abs +{ + ($_[$[] < 0) ? -($_[$[]) : $_[$[]; +} + +sub boolval +{ + local($v) = ($_[$[]); + + return 1 if ($v eq 'yes') || ($v eq 'y'); + return 1 if ($v =~ /^[0-9]*$/) && ($v != 0); + return 0; +} + +;##################### +;# start of real work + +print "starting plot command (" . join(" ",@plotcmd) . ")\n" if $verbose > 1; + +$Plotpid = open(PLOT,"|-"); +select((select(PLOT),$|=1)[$[]); # make PLOT line bufferd + +defined($Plotpid) || + die("$0: failed to start plot command: $!\n"); + +unless ($Plotpid) +{ + ;# child == plot command + close(STDOUT); + open(STDOUT,">&STDERR") || + die("$0: failed to redirect STDOUT of plot command: $!\n"); + + print STDOUT "plot command running as $$\n"; + + exec @plotcmd; + die("$0: failed to exec (@plotcmd): $!\n"); + exit(1); # in case ... +} + +sub read_config +{ + local($at) = (stat($config))[$[+9]; + local($_,$c,$v); + + (undef($laststat),(print("stat $config failed: $!\n")),return) if ! defined($at); + return if (defined($laststat) && ($laststat == $at)); + $laststat = $at; + + print "reading configuration from \"$config\"\n" if $verbose; + + open(CF,"<$config") || + (warn("$0: failed to read \"$config\" - using old settings ($!)\n"), + return); + while(<CF>) + { + chop; + s/^([^\#]*[^\#\s]?)\s*\#.*$//; + next if /^\s*$/; + + s/^\s*([^=\s]*)\s*=\s*(.*\S)\s*$/$1=$2/; + + ($c,$v) = split(/=/,$_,2); + print "processing \"$c=$v\"\n" if $verbose > 3; + ($c eq "delay") && ($delay = $v,1) && next; + ($c eq 'samples') && (!defined($PrintIt) || !defined($samples)) && + ($samples = $v,1) && next; + ($c eq 'srcprefix') && (($srcprefix=$v)=~s/\$STATHOST/$STATHOST/g,1) + && next; + ($c eq 'showoffs') && + ($showoffs = boolval($v),1) && next; + ($c eq 'showfreq') && + ($showfreq = boolval($v),1) && next; + ($c eq 'showcmpl') && + ($showcmpl = boolval($v),1) && next; + ($c eq 'showoreg') && + ($showoreg = boolval($v),1) && next; + ($c eq 'showfreg') && + ($showfreg = boolval($v),1) && next; + + ($c eq 'exit') && (unlink($tmpfile),die("$0: exit by config request\n")); + + ($c eq 'freqbase' || + $c eq 'cmplscale') && + do { + if (! defined($v) || $v eq "" || $v eq 'dynamic') + { + eval "undef(\$$c);"; + } + else + { + eval "\$$c = \$v;"; + } + next; + }; + ($c eq 'timebase') && + do { + if (! defined($v) || $v eq "" || $v eq "dynamic") + { + undef($timebase); + } + else + { + $timebase=&date_time_spec2seconds($v); + } + }; + ($c eq 'EndTime') && + do { + next if defined($EndTime) && defined($PrintIt); + if (! defined($v) || $v eq "" || $v eq "none") + { + undef($EndTime); + } + else + { + $EndTime=&date_time_spec2seconds($v); + } + }; + ($c eq 'StartTime') && + do { + next if defined($StartTime) && defined($PrintIt); + if (! defined($v) || $v eq "" || $v eq "none") + { + undef($StartTime); + } + else + { + $StartTime=&date_time_spec2seconds($v); + } + }; + + ($c eq 'MaxY') && + do { + next if defined($MaxY) && defined($PrintIt); + if (! defined($v) || $v eq "" || $v eq "none") + { + undef($MaxY); + } + else + { + $MaxY=$v; + } + }; + + ($c eq 'MinY') && + do { + next if defined($MinY) && defined($PrintIt); + if (! defined($v) || $v eq "" || $v eq "none") + { + undef($MinY); + } + else + { + $MinY=$v; + } + }; + + ($c eq 'deltaT') && + do { + if (!defined($v) || $v eq "") + { + undef($deltaT); + } + else + { + $deltaT = $v; + } + next; + }; + ($c eq 'verbose') && ! defined($PrintIt) && + do { + if (!defined($v) || $v == 0) + { + $verbose = 0; + } + else + { + $verbose = $v; + } + next; + }; + ;# otherwise: silently ignore unrecognized config line + } + close(CF); + ;# set show defaults when nothing selected + $showoffs = $showfreq = $showcmpl = 1 + unless $showoffs || $showfreq || $showcmpl; + if ($verbose > 3) + { + print "new configuration:\n"; + print " delay\t= $delay\n"; + print " samples\t= $samples\n"; + print " srcprefix\t= $srcprefix\n"; + print " showoffs\t= $showoffs\n"; + print " showfreq\t= $showfreq\n"; + print " showcmpl\t= $showcmpl\n"; + print " showoreg\t= $showoreg\n"; + print " showfreg\t= $showfreg\n"; + printf " timebase\t= %s",defined($timebase)?&ctime($timebase):"dynamic\n"; + printf " freqbase\t= %s\n",defined($freqbase) ?"$freqbase":"dynamic"; + printf " cmplscale\t= %s\n",defined($cmplscale)?"$cmplscale":"dynamic"; + printf " StartTime\t= %s",defined($StartTime)?&ctime($StartTime):"none\n"; + printf " EndTime\t= %s", defined($EndTime) ? &ctime($EndTime):"none\n"; + printf " MaxY\t= %s",defined($MaxY)? $MaxY :"none\n"; + printf " MinY\t= %s",defined($MinY)? $MinY :"none\n"; + print " verbose\t= $verbose\n"; + } +print "configuration file read\n" if $verbose > 2; +} + +sub make_doplot +{ + local($c) = (""); + local($fmt) + = ("%s \"%s\" using 1:%d title '%s <%lf %lf> %6s' with lines"); + local($regfmt) + = ("%s ((%lf * x) + %lf) title 'lin. approx. %s (%f t[h]) %s %f <%f> %6s' with lines"); + + $doplot = " set title 'NTP loopfilter statistics for $STATHOST " . + "(last $LastCnt samples from $srcprefix*)'\n"; + + local($xts,$xte,$i,$t); + + local($s,$c) = (""); + + ;# number of integral seconds to get at least 12 tic marks on x axis + $t = int(($maxtime - $mintime) / 12 + 0.5); + $t = 1 unless $t; # prevent $t to be zero + foreach $i (30, + 60,5*60,15*60,30*60, + 60*60,2*60*60,6*60*60,12*60*60, + 24*60*60,48*60*60) + { + last if $t < $i; + $t = $t - ($t % $i); + } + print "time label resolution: $t seconds\n" if $verbose > 1; + + ;# make gnuplot use wall clock time labels instead of NTP seconds + for ($c="", $i = $mintime - ($mintime % $t); + $i <= $maxtime + $t; + $i += $t, $c=",") + { + $s .= $c; + ((int($i / $t) % 2) && + ($s .= sprintf("'' %lf",($i - $LastTimeBase)/3600))) || + (($t <= 60) && + ($s .= sprintf("'%d:%02d:%02d' %lf", + (localtime($i))[$[+2,$[+1,$[+0], + ($i - $LastTimeBase)/3600))) + || (($t <= 2*60*60) && + ($s .= sprintf("'%d:%02d' %lf", + (localtime($i))[$[+2,$[+1], + ($i - $LastTimeBase)/3600))) + || (($t <= 12*60*60) && + ($s .= sprintf("'%s %d:00' %lf", + $Day[(localtime($i))[$[+6]], + (localtime($i))[$[+2], + ($i - $LastTimeBase)/3600))) + || ($s .= sprintf("'%d.%d-%d:00' %lf", + (localtime($i))[$[+3,$[+4,$[+2], + ($i - $LastTimeBase)/3600)); + } + $doplot .= "set xtics ($s)\n"; + + chop($xts = &ctime($mintime)); + chop($xte = &ctime($maxtime)); + $doplot .= "set xlabel 'Start: $xts -- Time Scale -- End: $xte'\n"; + $doplot .= "set yrange [" ; + $doplot .= defined($MinY) ? sprintf("%lf", $MinY) : $miny; + $doplot .= ':'; + $doplot .= defined($MaxY) ? sprintf("%lf", $MaxY) : $maxy; + $doplot .= "]\n"; + + $doplot .= " plot"; + $c = ""; + $showoffs && + ($doplot .= sprintf($fmt,$c,$tmpfile,2, + "offset", + $minoffs,$maxoffs, + "[ms]"), + $c = ","); + $LastCmplScale = 1 if ! defined($LastCmplScale); + $showcmpl && + ($doplot .= sprintf($fmt,$c,$tmpfile,4, + "compliance" . + (&abs($LastCmplScale) > 1 + ? " / $LastCmplScale" + : (&abs($LastCmplScale) == 1 ? "" : " * ".(1/$LastCmplScale))), + $mincmpl/$LastCmplScale,$maxcmpl/$LastCmplScale, + ""), + $c = ","); + $LastFreqBase = 0 if ! defined($LastFreqBase); + $LastFreqBaseString = "?" if ! defined($LastFreqBaseString); + $FreqScale = 1 if ! defined($FreqScale); + $FreqScaleInv = 1 if ! defined($FreqScaleInv); + $showfreq && + ($doplot .= sprintf($fmt,$c,$tmpfile,3, + "frequency" . + ($LastFreqBase > 0 + ? " - $LastFreqBaseString" + : ($LastFreqBase == 0 ? "" : " + $LastFreqBaseString")), + $minfreq * $FreqScale - $LastFreqBase, + $maxfreq * $FreqScale - $LastFreqBase, + "[${FreqScaleInv}ppm]"), + $c = ","); + $showoreg && $showoffs && + ($doplot .= sprintf($regfmt, $c, + &lr_B('offs'),&lr_A('offs'), + "offset ", + &lr_B('offs'), + ((&lr_A('offs')) < 0 ? '-' : '+'), + &abs(&lr_A('offs')), &lr_r('offs'), + "[ms]"), + $c = ","); + $showfreg && $showfreq && + ($doplot .= sprintf($regfmt, $c, + &lr_B('freq') * $FreqScale, + (&lr_A('freq') + $minfreq) * $FreqScale - $LastFreqBase, + "frequency", + &lr_B('freq') * $FreqScale, + ((&lr_A('freq') + $minfreq) * $FreqScale - $LastFreqBase) < 0 ? '-' : '+', + &abs((&lr_A('freq') + $minfreq) * $FreqScale - $LastFreqBase), + &lr_r('freq'), + "[${FreqScaleInv}ppm]"), + $c = ","); + $doplot .= "\n"; +} + +%F_key = (); +%F_name = (); +%F_size = (); +%F_mtime = (); +%F_first = (); +%F_last = (); + +sub genfile +{ + local($cnt,$in,$out,@fpos) = @_; + + local(@F,@t,$t,$lastT) = (); + local(@break,@time,@offs,@freq,@cmpl,@loffset,@filekey) = (); + local($lm,$l,@f); + + local($sdir,$sname); + + ;# allocate some storage for the tables + ;# otherwise realloc may get into troubles + if (defined($StartTime) && defined($EndTime)) + { + $l = ($EndTime-$StartTime) -$[+1 +1; # worst case: 1 sample per second + } + else + { + $l = $cnt + 10; + } + print "preextending arrays to $l entries\n" if $verbose > 2; + $#break = $l; for ($i=$[; $i<=$l;$i++) { $break[$i] = 0; } + $#time = $l; for ($i=$[; $i<=$l;$i++) { $time[$i] = 0; } + $#offs = $l; for ($i=$[; $i<=$l;$i++) { $offs[$i] = 0; } + $#freq = $l; for ($i=$[; $i<=$l;$i++) { $freq[$i] = 0; } + $#cmpl = $l; for ($i=$[; $i<=$l;$i++) { $cmpl[$i] = 0; } + $#loffset = $l; for ($i=$[; $i<=$l;$i++) { $loffset[$i] = 0; } + $#filekey = $l; for ($i=$[; $i<=$l;$i++) { $filekey[$i] = 0; } + ;# now reduce size again + $#break = $[ - 1; + $#time = $[ - 1; + $#offs = $[ - 1; + $#freq = $[ - 1; + $#cmpl = $[ - 1; + $#loffset = $[ - 1; + $#filekey = $[ - 1; + print "memory allocation ready\n" if $verbose > 2; + sleep(3) if $verbose > 1; + + $fpos[$[] = '' if !defined($fpos[$[]); + + if (index($in,"/") < $[) + { + $sdir = "."; + $sname = $in; + } + else + { + ($sdir,$sname) = ($in =~ m!^(.*)/([^/]*)!); + $sname = "" unless defined($sname); + } + + $Ltime = -1 if ! defined($Ltime); + if (!defined($Lsdir) || $Lsdir ne $sdir || $Ltime != (stat($sdir))[$[+9] || + grep($F_mtime{$_} != (stat($F_name{$_}))[$[+9], @F_files)) + + { + print "rescanning directory \"$sdir\" for files \"$sname*\"\n" + if $verbose > 1; + + ;# rescan directory on changes + $Lsdir = $sdir; + $Ltime = (stat($sdir))[$[+9]; + </X{> if 0; # dummy line - calm down my formatter + local(@newfiles) = < ${in}*[0-9] >; + local($st_dev,$st_ino,$st_mtime,$st_size,$name,$key,$modified); + + foreach $name (@newfiles) + { + ($st_dev,$st_ino,$st_size,$st_mtime) = + (stat($name))[$[,$[+1,$[+7,$[+9]; + $modified = 0; + $key = sprintf("%lx|%lu", $st_dev, $st_ino); + + print "candidate file \"$name\"", + (defined($st_dev) ? "" : " failed: $!"),"\n" + if $verbose > 2; + + if (! defined($F_key{$name}) || $F_key{$name} ne $key) + { + $F_key{$name} = $key; + $modified++; + } + if (!defined($F_name{$key}) || $F_name{$key} ne $name) + { + $F_name{$key} = $name; + $modified++; + } + if (!defined($F_size{$key}) || $F_size{$key} != $st_size) + { + $F_size{$key} = $st_size; + $modified++; + } + if (!defined($F_mtime{$key}) || $F_mtime{$key} != $st_mtime) + { + $F_mtime{$key} = $st_mtime; + $modified++; + } + if ($modified) + { + print "new data \"$name\" key: $key;\n" if $verbose > 1; + print " size: $st_size; mtime: $st_mtime;\n" + if $verbose > 1; + $F_last{$key} = $F_first{$key} = $st_mtime; + $F_first{$key}--; # prevent zero divide later on + ;# now compute derivated attributes + open(IN, "<$name") || + do { + warn "$0: failed to open \"$name\": $!"; + next; + }; + + while(<IN>) + { + @F = split; + next if @F < 5; + next if $F[$[] eq ""; + $t = ($F[$[] - $MJD_1970) * 24 * 60 * 60; + $t += $F[$[+1]; + $F_first{$key} = $t; + print "\tfound first entry: $t ",&ctime($t) + if $verbose > 4; + last; + } + seek(IN, + ($st_size > 4*$RecordSize) ? $st_size - 4*$RecordSize : 0, + 0); + while(<IN>) + { + @F = split; + next if @F < 5; + next if $F[$[] eq ""; + $t = ($F[$[] - $MJD_1970) * 24 * 60 * 60; + $t += $F[$[+1]; + $F_last{$key} = $t; + $_ = <IN>; + print "\tfound last entry: $t ", &ctime($t) + if $verbose > 4 && ! defined($_); + last unless defined($_); + redo; + ;# Ok, calm down... + ;# using $_ = <IN> in conjunction with redo + ;# is semantically equivalent to the while loop, but + ;# I needed a one line look ahead and this solution + ;# was what I thought of first + ;# and.. If you do not like it dont look + } + close(IN); + print(" first: ",$F_first{$key}, + " last: ",$F_last{$key},"\n") if $verbose > 1; + } + } + ;# now reclaim memory used for files no longer referenced ... + local(%Names); + grep($Names{$_} = 1,@newfiles); + foreach (keys %F_key) + { + next if defined($Names{$_}); + delete $F_key{$_}; + $verbose > 2 && print "no longer referenced: \"$_\"\n"; + } + %Names = (); + + grep($Names{$_} = 1,values(%F_key)); + foreach (keys %F_name) + { + next if defined($Names{$_}); + delete $F_name{$_}; + $verbose > 2 && print "unref name($_)= $F_name{$_}\n"; + } + foreach (keys %F_size) + { + next if defined($Names{$_}); + delete $F_size{$_}; + $verbose > 2 && print "unref size($_)\n"; + } + foreach (keys %F_mtime) + { + next if defined($Names{$_}); + delete $F_mtime{$_}; + $verbose > 2 && print "unref mtime($_)\n"; + } + foreach (keys %F_first) + { + next if defined($Names{$_}); + delete $F_first{$_}; + $verbose > 2 && print "unref first($_)\n"; + } + foreach (keys %F_last) + { + next if defined($Names{$_}); + delete $F_last{$_}; + $verbose > 2 && print "unref last($_)\n"; + } + ;# create list sorted by time + @F_files = sort {$F_first{$a} <=> $F_first{$b}; } keys(%F_name); + if ($verbose > 1) + { + print "Resulting file list:\n"; + foreach (@F_files) + { + print "\t$_\t$F_name{$_}\n"; + } + } + } + + printf("processing %s; output \"$out\" (%d input files)\n", + ((defined($StartTime) && defined($EndTime)) + ? "time range" + : (defined($StartTime) ? "$cnt samples from StartTime" : + (defined($EndTime) ? "$cnt samples to EndTime" : + "last $cnt samples"))), + scalar(@F_files)) + if $verbose > 1; + + ;# open output file - will be input for plotcmd + open(OUT,">$out") || + do { + warn("$0: cannot create \"$out\": $!\n"); + }; + + @f = @F_files; + if (defined($StartTime)) + { + while (@f && ($F_last{$f[$[]} < $StartTime)) + { + print("shifting ", $F_name{$f[$[]}, + " last: ", $F_last{$f[$[]}, + " < StartTime: $StartTime\n") + if $verbose > 3; + shift(@f); + } + + + } + if (defined($EndTime)) + { + while (@f && ($F_first{$f[$#f]} > $EndTime)) + { + print("popping ", $F_name{$f[$#f]}, + " first: ", $F_first{$f[$#f]}, + " > EndTime: $EndTime\n") + if $verbose > 3; + pop(@f); + } + } + + if (@f) + { + if (defined($StartTime)) + { + print "guess start according to StartTime ($StartTime)\n" + if $verbose > 3; + + if ($fpos[$[] eq 'start') + { + if (grep($_ eq $fpos[$[+1],@f)) + { + shift(@f) while @f && $f[$[] ne $fpos[$[+1]; + } + else + { + @fpos = ('start', $f[$[], undef); + } + } + else + { + @fpos = ('start' , $f[$[], undef); + } + + if (!defined($fpos[$[+2])) + { + if ($StartTime <= $F_first{$f[$[]}) + { + $fpos[$[+2] = 0; + } + else + { + $fpos[$[+2] = + int($F_size{$f[$[]} * + (($StartTime - $F_first{$f[$[]})/ + ($F_last{$f[$[]} - $F_first{$f[$[]}))); + $fpos[$[+2] = ($fpos[$[+2] <= 2 * $RecordSize) + ? 0 : $fpos[$[+2] - 2 * $RecordSize; + ;# anyway as the data may contain "time holes" + ;# our heuristics may baldly fail + ;# so just start at 0 + $fpos[$[+2] = 0; + } + } + } + elsif (defined($EndTime)) + { + print "guess starting point according to EndTime ($EndTime)\n" + if $verbose > 3; + + if ($fpos[$[] eq 'end') + { + if (grep($_ eq $fpos[$[+1],@f)) + { + shift(@f) while @f && $f[$[] ne $fpos[$[+1]; + } + else + { + @fpos = ('end', $f[$[], undef); + } + } + else + { + @fpos = ('end', $f[$[], undef); + } + + if (!defined($fpos[$[+2])) + { + local(@x) = reverse(@f); + local($s,$c) = (0,$cnt); + if ($EndTime < $F_last{$x[$[]}) + { + ;# last file will only be used partially + $s = int($F_size{$x[$[]} * + (($EndTime - $F_first{$x[$[]}) / + ($F_last{$x[$[]} - $F_first{$x[$[]}))); + $s = int($s/$RecordSize); + $c -= $s - 1; + if ($c <= 0) + { + ;# start is in the same file + $fpos[$[+1] = $x[$[]; + $fpos[$[+2] = ($c >=-2) ? 0 : (-$c - 2) * $RecordSize; + shift(@f) while @f && ($f[$[] ne $x[$[]); + } + else + { + shift(@x); + } + } + + if (!defined($fpos[$[+2])) + { + local($_); + while($_ = shift(@x)) + { + $s = int($F_size{$_}/$RecordSize); + $c -= $s - 1; + if ($c <= 0) + { + $fpos[$[+1] = $_; + $fpos[$[+2] = ($c>-2) ? 0 : (-$c - 2) * $RecordSize; + shift(@f) while @f && ($f[$[] ne $_); + last; + } + } + } + } + } + else + { + print "guessing starting point according to count ($cnt)\n" + if $verbose > 3; + ;# guess offset to get last available $cnt samples + if ($fpos[$[] eq 'cnt') + { + if (grep($_ eq $fpos[$[+1],@f)) + { + print "old positioning applies\n" if $verbose > 3; + shift(@f) while @f && $f[$[] ne $fpos[$[+1]; + } + else + { + @fpos = ('cnt', $f[$[], undef); + } + } + else + { + @fpos = ('cnt', $f[$[], undef); + } + + if (!defined($fpos[$[+2])) + { + local(@x) = reverse(@f); + local($s,$c) = (0,$cnt); + + local($_); + while($_ = shift(@x)) + { + print "examing \"$_\" $c samples still needed\n" + if $verbose > 4; + $s = int($F_size{$_}/$RecordSize); + $c -= $s - 1; + if ($c <= 0) + { + $fpos[$[+1] = $_; + $fpos[$[+2] = ($c>-2) ? 0 : (-$c - 2) * $RecordSize; + shift(@f) while @f && ($f[$[] ne $_); + last; + } + } + if (!defined($fpos[$[+2])) + { + print "no starting point yet - using start of data\n" + if $verbose > 2; + $fpos[$[+2] = 0; + } + } + } + } + print "Ooops, no suitable input file ??\n" + if $verbose > 1 && @f <= 0; + + printf("Starting at (%s) \"%s\" offset %ld using %d files\n", + $fpos[$[+1], + $F_name{$fpos[$[+1]}, + $fpos[$[+2], + scalar(@f)) + if $verbose > 2; + + $lm = 1; + $l = 0; + foreach $key (@f) + { + $file = $F_name{$key}; + print "processing file \"$file\"\n" if $verbose > 2; + + open(IN,"<$file") || + (warn("$0: cannot read \"$file\": $!\n"), next); + + ;# try to seek to a position nearer to the start of the interesting lines + ;# should always affect only first item in @f + ($key eq $fpos[$[+1]) && + (($verbose > 1) && + print("Seeking to offset $fpos[$[+2]\n"), + seek(IN,$fpos[$[+2],0) || + warn("$0: seek(\"$F_name{$key}\" failed: $|\n")); + + while(<IN>) + { + $l++; + ($verbose > 3) && + (($l % $lm) == 0 && print("\t$l lines read\n") && + (($l == 2) && ($lm = 10) || + ($l == 100) && ($lm = 100) || + ($l == 500) && ($lm = 500) || + ($l == 1000) && ($lm = 1000) || + ($l == 5000) && ($lm = 5000) || + ($l == 10000) && ($lm = 10000))); + + @F = split; + + next if @F < 6; # no valid input line is this short + next if $F[$[] eq ""; + next if ($F[$[] !~ /^\d+$/); + ($F[$[] !~ /^\d+$/) && # A 'never should have happend' error + die("$0: unexpected input line: >$_<\n"); + + ;# modified Julian to UNIX epoch + $t = ($F[$[] - $MJD_1970) * 24 * 60 * 60; + $t += $F[$[+1]; # add seconds + fraction + + ;# multiply offset by 1000 to get ms - try to avoid float op + (($F[$[+2] =~ s/(\d*)\.(\d{3})(\d*)/$1$2.$3/) && + $F[$[+2] =~ s/0+([\d\.])/($1 eq '.') ? '0.' : $1/e) # strip leading zeros + || ($F[$[+2] *= 1000); + + + ;# skip samples out of specified time range + next if (defined($StartTime) && $StartTime > $t); + next if (defined($EndTime) && $EndTime < $t); + + next if defined($lastT) && $t < $lastT; # backward in time ?? + + push(@offs,$F[$[+2]); + push(@freq,$F[$[+3] * (2**20/10**6)); + push(@cmpl,$F[$[+5]); + + push(@break, (defined($lastT) && ($t - $lastT > $deltaT))); + $lastT = $t; + push(@time,$t); + push(@loffset, tell(IN) - length($_)); + push(@filekey, $key); + + shift(@break),shift(@time),shift(@offs), + shift(@freq), shift(@cmpl),shift(@loffset), + shift(@filekey) + if @time > $cnt && + ! (defined($StartTime) && defined($EndTime)); + + last if @time >= $cnt && defined($StartTime) && !defined($EndTime); + } + close(IN); + last if @time >= $cnt && defined($StartTime) && !defined($EndTime); + } + print "input scanned ($l lines/",scalar(@time)," samples)\n" + if $verbose > 1; + + &lr_init('offs'); + &lr_init('freq'); + + if (@time) + { + local($_,@F); + + local($timebase) unless defined($timebase); + local($freqbase) unless defined($freqbase); + local($cmplscale) unless defined($cmplscale); + + undef $mintime; + undef $maxtime; + undef $minoffs; + undef $maxoffs; + undef $minfreq; + undef $maxfreq; + undef $mincmpl; + undef $maxcmpl; + undef $miny; + undef $maxy ; + + print "computing ranges\n" if $verbose > 2; + + $LastCnt = @time; + + ;# @time is in ascending order (;-) + $mintime = $time[$[]; + $maxtime = $time[$#time]; + unless (defined($timebase)) + { + local($time,@X) = (time); + @X = localtime($time); + + ;# compute today 00:00:00 + $timebase = $time - ((($X[$[+2]*60)+$X[$[+1])*60+$X[$[]); + + } + $LastTimeBase = $timebase; + + if ($showoffs) + { + local($i,$m,$f); + + $minoffs = &min(@offs); + $maxoffs = &max(@offs); + + ;# I know, it is not perl style using indices to access arrays, + ;# but I have to proccess two arrays in sync, non-destructively + ;# (otherwise a (shift(@a1),shift(a2)) would do), + ;# I dont like to make copies of these arrays as they may be huge + $i = $[; + &lr_sample(($time[$i]-$timebase)/3600,$offs[$i],'offs'),$i++ + while $i <= $#time; + + ($minoffs == $maxoffs) && ($minoffs -= 0.1,$maxoffs += 0.1); + + $i = &lr_sigma('offs'); + $m = &lr_mean('offs'); + + print "mean offset: $m sigma: $i\n" if $verbose > 2; + + if (($maxoffs - $minoffs) > $MinClip) + { + $f = (&abs($minoffs) < &abs($maxoffs)) ? $FuzzLow : $FuzzBig; + $miny = (($m - $minoffs) <= ($f * $i)) + ? $minoffs : ($m - $f * $i); + $f = ($f == $FuzzLow) ? $FuzzBig : $FuzzLow; + $maxy = (($maxoffs - $m) <= ($f * $i)) + ? $maxoffs : ($m + $f * $i); + } + else + { + $miny = $minoffs; + $maxy = $maxoffs; + } + ($maxy-$miny) == 0 && + (($maxy,$miny) + = (($maxoffs - $minoffs) > 0) + ? ($maxoffs,$minoffs) : ($MinClip,-$MinClip)); + + $maxy = $MaxY if defined($MaxY) && $MaxY < $maxy; + $miny = $MinY if defined($MinY) && $MinY > $miny; + + print "offset min clipped from $minoffs to $miny\n" + if $verbose > 2 && $minoffs != $miny; + print "offset max clipped from $maxoffs to $maxy\n" + if $verbose > 2 && $maxoffs != $maxy; + } + + if ($showfreq) + { + local($i,$m); + + $minfreq = &min(@freq); + $maxfreq = &max(@freq); + + $i = $[; + &lr_sample(($time[$i]-$timebase)/3600,$freq[$i]-$minfreq,'freq'), + $i++ + while $i <= $#time; + + $i = &lr_sigma('freq'); + $m = &lr_mean('freq') + $minfreq; + + print "mean frequency: $m sigma: $i\n" if $verbose > 2; + + if (defined($maxy)) + { + local($s) = + ($maxfreq - $minfreq) + ? ($maxy - $miny) / ($maxfreq - $minfreq) : 1; + + if (defined($freqbase)) + { + $FreqScale = 1; + $FreqScaleInv = ""; + } + else + { + $FreqScale = 1; + $FreqScale = 10 ** int(log($s)/log(10) - 0.9999); + $FreqScaleInv = + ("$FreqScale" =~ /^10(0*)$/) ? "0.${1}1" : + ($FreqScale == 1 ? "" : (1/$FreqScale)); + + $freqbase = ($maxfreq + $minfreq)/ 2 * $FreqScale; #$m * $FreqScale; + $freqbase -= ($maxy + $miny) / 2; #&lr_mean('offs'); + + ;# round resulting freqbase + ;# to precision of min max difference + $s = -12; + $s = int(log(($maxfreq-$minfreq)*$FreqScale)/log(10))-1 + unless ($maxfreq-$minfreq) < 1e-12; + $s = 10 ** $s; + $freqbase = int($freqbase / $s) * $s; + } + } + else + { + $FreqScale = 1; + $FreqScaleInv = ""; + $freqbase = $m unless defined($freqbase); + if (($maxfreq - $minfreq) > $MinClip) + { + $f = (&abs($minfreq) < &abs($maxfreq)) + ? $FuzzLow : $FuzzBig; + $miny = (($freqbase - $minfreq) <= ($f * $i)) + ? ($minfreq-$freqbase) : (- $f * $i); + $f = ($f == $FuzzLow) ? $FuzzBig : $FuzzLow; + $maxy = (($maxfreq - $freqbase) <= ($f * $i)) + ? ($maxfreq-$freqbase) : ($f * $i); + } + else + { + $miny = $minfreq - $freqbase; + $maxy = $maxfreq - $freqbase; + } + ($maxy - $miny) == 0 && + (($maxy,$miny) = + (($maxfreq - $minfreq) > 0) + ? ($maxfreq-$freqbase,$minfreq-$freqbase) : (0.5,-0.5)); + + $maxy = $MaxY if defined($MaxY) && $MaxY < $maxy; + $miny = $MinY if defined($MinY) && $MinY > $miny; + + print("frequency min clipped from ",$minfreq-$freqbase, + " to $miny\n") + if $verbose > 2 && $miny != ($minfreq - $freqbase); + print("frequency max clipped from ",$maxfreq-$freqbase, + " to $maxy\n") + if $verbose > 2 && $maxy != ($maxfreq - $freqbase); + } + $LastFreqBaseString = + sprintf("%g",$freqbase >= 0 ? $freqbase : -$freqbase); + $LastFreqBase = $freqbase; + print "LastFreqBaseString now \"$LastFreqBaseString\"\n" + if $verbose > 5; + } + else + { + $FreqScale = 1; + $FreqScaleInv = ""; + $LastFreqBase = 0; + $LastFreqBaseString = ""; + } + + if ($showcmpl) + { + $mincmpl = &min(@cmpl); + $maxcmpl = &max(@cmpl); + + if (!defined($cmplscale)) + { + if (defined($maxy)) + { + local($cmp) + = (&abs($miny) > &abs($maxy)) ? &abs($miny) : $maxy; + $cmplscale = $cmp == $maxy ? 1 : -1; + + foreach (0.01, 0.02, 0.05, + 0.1, 0.2, 0.25, 0.4, 0.5, + 1, 2, 4, 5, + 10, 20, 25, 50, + 100, 200, 250, 500, 1000) + { + $cmplscale *= $_, last if $maxcmpl/$_ <= $cmp; + } + } + else + { + $cmplscale = 1; + $miny = $mincmpl ? 0 : -$MinClip; + $maxy = $maxcmpl+$MinClip; + } + } + $LastCmplScale = $cmplscale; + } + else + { + $LastCmplScale = 1; + } + + print "creating plot command input file\n" if $verbose > 2; + + + print OUT ("# preprocessed NTP statistics file for $STATHOST\n"); + print OUT ("# timebase is: ",&ctime($LastTimeBase)) + if defined($LastTimeBase); + print OUT ("# frequency is offset by ", + ($LastFreqBase >= 0 ? "+" : "-"), + "$LastFreqBaseString [${FreqScaleInv}ppm]\n"); + print OUT ("# compliance is scaled by $LastCmplScale\n"); + print OUT ("# time [h]\toffset [ms]\tfrequency [${FreqScaleInv}ppm]\tcompliance\n"); + + printf OUT ("%s%lf\t%lf\t%lf\t%lf\n", + (shift(@break) ? "\n" : ""), + (shift(@time) - $LastTimeBase)/3600, + shift(@offs), + shift(@freq) * $FreqScale - $LastFreqBase, + shift(@cmpl) / $LastCmplScale) + while(@time); + } + else + { + ;# prevent plotcmd from processing empty file + print "Creating plot command dummy...\n" if $verbose > 2; + print OUT "# dummy samples\n0 1 2 3\n1 1 2 3\n"; + &lr_sample(0,1,'offs'); + &lr_sample(1,1,'offs'); + &lr_sample(0,2,'freq'); + &lr_sample(1,2,'freq'); + @time = (0, 1); $maxtime = 1; $mintime = 0; + @offs = (1, 1); $maxoffs = 1; $minoffs = 1; + @freq = (2, 2); $maxfreq = 2; $minfreq = 2; + @cmpl = (3, 3); $maxcmpl = 3; $mincmpl = 3; + $LastCnt = 2; + $LastFreqBase = 0; + $LastCmplScale = 1; + $LastTimeBase = 0; + $miny = -$MinClip; + $maxy = 3 + $MinClip; + } + close(OUT); + + print "plot command input file created\n" + if $verbose > 2; + + + if (($fpos[$[] eq 'cnt' && scalar(@loffset) >= $cnt) || + ($fpos[$[] eq 'start' && $mintime <= $StartTime) || + ($fpos[$[] eq 'end')) + { + return ($fpos[$[],$filekey[$[],$loffset[$[]); + } + else # found to few lines - next time start search earlier in file + { + if ($fpos[$[] eq 'start') + { + ;# the timestamps we got for F_first and F_last guaranteed + ;# that no file is left out + ;# the only thing that could happen is: + ;# we guessed the starting point wrong + ;# compute a new guess from the first record found + ;# if this equals our last guess use data of first record + ;# otherwise try new guess + + if ($fpos[$[+1] eq $filekey[$[] && $loffset[$[] > $fpos[$[+2]) + { + local($noff); + $noff = $loffset[$[] - ($cnt - @loffset + 1) * $RecordSize; + $noff = 0 if $noff < 0; + + return (@fpos[$[,$[+1], ($noff == $fpos[$[+2]) ? $loffset[$[] : $noff); + } + return ($fpos[$[],$filekey[$[],$loffset[$[]); + } + elsif ($fpos[$[] eq 'end' || $fpos[$[] eq 'cnt') + { + ;# try to start earlier in file + ;# if we already started at the beginning + ;# try to use previous file + ;# this assumes distance to better starting point is at most one file + ;# the primary guess at top of genfile() should usually allow this + ;# assumption + ;# if the offset of the first sample used is within + ;# a different file than we guessed it must have occurred later + ;# in the sequence of files + ;# this only can happen if our starting file did not contain + ;# a valid sample from the starting point we guessed + ;# however this does not invalidate our assumption, no check needed + local($noff,$key); + if ($fpos[$[+2] > 0) + { + $noff = $fpos[$[+2] - $RecordSize * ($cnt - @loffset + 1); + $noff = 0 if $noff < 0; + return (@fpos[$[,$[+1],$noff); + } + else + { + if ($fpos[$[+1] eq $F_files[$[]) + { + ;# first file - and not enough samples + ;# use data of first sample + return ($fpos[$[], $filekey[$[], $loffset[$[]); + } + else + { + ;# search key of previous file + $key = $F_files[$[]; + @F = reverse(@F_files); + while ($_ = shift(@F)) + { + if ($_ eq $fpos[$[+1]) + { + $key = shift(@F) if @F; + last; + } + } + $noff = int($F_size{$key} / $RecordSize); + $noff -= $cnt - @loffset; + $noff = 0 if $noff < 0; + $noff *= $RecordSize; + return ($fpos[$[], $key, $noff); + } + } + } + else + { + return (); + } + + return 0 if @loffset <= 1 || ($loffset[$#loffset] - $loffset[$[]) <= 1; + + ;# EOF - 1.1 * avg(line) * $cnt + local($val) = $loffset[$#loffset] + - $cnt * 11 * (($loffset[$#loffset] - $loffset[$[]) / @loffset) / 10; + return ($val < 0) ? 0 : $val; + } +} + +$Ltime = -1 if ! defined($Ltime); +$LastFreqBase = 0; +$LastFreqBaseString = "??"; + +;# initial setup of plot +print "initialize plotting\n" if $verbose; +if (defined($PrintIt)) +{ + if ($PrintIt =~ m,/,) + { + print "Saving plot to file $PrintIt\n"; + print PLOT "set output '$PrintIt'\n"; + } + else + { + print "Printing plot on printer $PrintIt\n"; + print PLOT "set output '| lpr -P$PrintIt -h'\n"; + } + print PLOT "set terminal postscript landscape color solid 'Helvetica' 10\n"; +} +print PLOT "set grid\n"; +print PLOT "set tics out\n"; +print PLOT "set format y '%g '\n"; +printf PLOT "set time 47\n" unless defined($PrintIt); + +@filepos =(); +while(1) +{ + print &ctime(time) if $verbose; + + ;# update diplay characteristics + &read_config;# unless defined($PrintIt); + + unlink($tmpfile); + @filepos = &genfile($samples,$srcprefix,$tmpfile,@filepos); + + ;# make plotcmd display samples + &make_doplot; + print "Displaying plot...\n" if $verbose > 1; + print "command for plot sub process:\n$doplot----\n" if $verbose > 3; + print PLOT $doplot; +} +continue +{ + if (defined($PrintIt)) + { + delete $SIG{'CHLD'}; + print PLOT "quit\n"; + close(PLOT); + if ($PrintIt =~ m,/,) + { + print "Plot saved to file $PrintIt\n"; + } + else + { + print "Plot spooled to printer $PrintIt\n"; + } + unlink($tmpfile); + exit(0); + } + ;# wait $delay seconds + print "waiting $delay seconds ..." if $verbose > 2; + sleep($delay); + print " continuing\n" if $verbose > 2; + undef($LastFreqBaseString); +} + + +sub date_time_spec2seconds +{ + local($_) = @_; + ;# a date_time_spec consistes of: + ;# YYYY-MM-DD_HH:MM:SS.ms + ;# values can be omitted from the beginning and default than to + ;# values of current date + ;# values omitted from the end default to lowest possible values + + local($time) = time; + local($sec,$min,$hour,$mday,$mon,$year) + = localtime($time); + + local($last) = (); + + s/^\D*(.*\d)\D*/$1/; # strip off garbage + + PARSE: + { + if (s/^(\d{4})(-|$)//) + { + if ($1 < 1970) + { + warn("$0: can not handle years before 1970 - year $1 ignored\n"); + return undef; + } + elsif ( $1 >= 2070) + { + warn("$0: can not handle years past 2070 - year $1 ignored\n"); + return undef; + } + else + { + $year = $1 % 100; # 0<= $year < 100 + ;# - interpreted 70 .. 99,00 .. 69 + } + $last = $[ + 5; + last PARSE if $_ eq ''; + warn("$0: bad date_time_spec: \"$_\" found after YEAR\n"), + return(undef) + if $2 eq ''; + } + + if (s/^(\d{1,2})(-|$)//) + { + warn("$0: implausible month $1\n"),return(undef) + if $1 < 1 || $1 > 12; + $mon = $1 - 1; + $last = $[ + 4; + last PARSE if $_ eq ''; + warn("$0: bad date_time_spec: \"$_\" found after MONTH\n"), + return(undef) + if $2 eq ''; + } + else + { + warn("$0: bad date_time_spec \"$_\"\n"),return(undef) + if defined($last); + + } + + if (s/^(\d{1,2})([_ ]|$)//) + { + warn("$0: implausible month day $1 for month ".($mon+1)." (". + $MaxNumDaysPerMonth[$mon].")$mon\n"), + return(undef) + if $1 < 1 || $1 > $MaxNumDaysPerMonth[$mon]; + $mday = $1; + $last = $[ + 3; + last PARSE if $_ eq ''; + warn("$0: bad date_time_spec \"$_\" found after MDAY\n"), + return(undef) + if $2 eq ''; + } + else + { + warn("$0: bad date_time_spec \"$_\"\n"), return undef + if defined($last); + } + + ;# now we face a problem: + ;# if ! defined($last) a prefix of "07:" + ;# can be either 07:MM or 07:ss + ;# to get the second interpretation make the user add + ;# a msec fraction part and check for this special case + if (! defined($last) && s/^(\d{1,2}):(\d{1,2}\.\d+)//) + { + warn("$0: implausible minute $1\n"), return undef + if $1 < 0 || $1 >= 60; + warn("$0: implausible second $1\n"), return undef + if $2 < 0 || $2 >= 60; + $min = $1; + $sec = $2; + $last = $[ + 1; + last PARSE if $_ eq ''; + warn("$0: bad date_time_spec \"$_\" after SECONDS\n"); + return undef; + } + + if (s/^(\d{1,2})(:|$)//) + { + warn("$0: implausible hour $1\n"), return undef + if $1 < 0 || $1 > 24; + $hour = $1; + $last = $[ + 2; + last PARSE if $_ eq ''; + warn("$0: bad date_time_spec found \"$_\" after HOUR\n"), + return undef + if $2 eq ''; + } + else + { + warn("$0: bad date_time_spec \"$_\"\n"), return undef + if defined($last); + } + + if (s/^(\d{1,2})(:|$)//) + { + warn("$0: implausible minute $1\n"), return undef + if $1 < 0 || $1 >=60; + $min = $1; + $last = $[ + 1; + last PARSE if $_ eq ''; + warn("$0: bad date_time_spec found \"$_\" after MINUTE\n"), + return undef + if $2 eq ''; + } + else + { + warn("$0: bad date_time_spec \"$_\"\n"), return undef + if defined($last); + } + + if (s/^(\d{1,2}(\.\d+)?)//) + { + warn("$0: implausible second $1\n"), return undef + if $1 < 0 || $1 >=60; + $sec = $1; + $last = $[; + last PARSE if $_ eq ''; + warn("$0: bad date_time_spec found \"$_\" after SECOND\n"); + return undef; + } + } + + return $time unless defined($last); + + $sec = 0 if $last > $[; + $min = 0 if $last > $[ + 1; + $hour = 0 if $last > $[ + 2; + $mday = 1 if $last > $[ + 3; + $mon = 0 if $last > $[ + 4; + local($rtime) = &timelocal($sec,$min,$hour,$mday,$mon,$year, 0,0, 0); + + ;# $rtime may be off if daylight savings time is in effect at given date + return $rtime + ($sec - int($sec)) + if $hour == (localtime($rtime))[$[+2]; + return + &timelocal($sec,$min,$hour,$mday,$mon,$year, 0,0, 1) + + ($sec - int($sec)); +} + + +sub min +{ + local($m) = shift; + + grep((($m > $_) && ($m = $_),0),@_); + $m; +} + +sub max +{ + local($m) = shift; + + grep((($m < $_) && ($m = $_),0),@_); + $m; +} diff --git a/contrib/ntp/scripts/monitoring/ntptrap b/contrib/ntp/scripts/monitoring/ntptrap new file mode 100644 index 0000000..5a1bcb1 --- /dev/null +++ b/contrib/ntp/scripts/monitoring/ntptrap @@ -0,0 +1,463 @@ +#!/local/bin/perl --*-perl-*- +;# +;# ntptrap,v 3.1 1993/07/06 01:09:15 jbj Exp +;# +;# a client for the xntp mode 6 trap mechanism +;# +;# Copyright (c) 1992 +;# Rainer Pruy Friedrich-Alexander Universitaet Erlangen-Nuernberg +;# +;# +;############################################################# +$0 =~ s!^.*/([^/]+)$!$1!; # strip to filename +;# enforce STDOUT and STDERR to be line buffered +$| = 1; +select((select(STDERR),$|=1)[$[]); + +;####################################### +;# load utility routines and definitions +;# +require('ntp.pl'); # implementation of the NTP protocol +use Socket; + +#eval { require('sys/socket.ph'); require('netinet/in.ph') unless defined(&INADDR_ANY); } || +#do { + #die("$0: $@") unless $[ == index($@, "Can't locate "); + #warn "$0: $@"; + #warn "$0: supplying some default definitions\n"; + #eval 'sub INADDR_ANY { 0; } sub AF_INET {2;} sub SOCK_DGRAM {2;} 1;' || die "$0: $@"; +#}; +require('getopts.pl'); # option parsing +require('ctime.pl'); # date/time formatting + +;###################################### +;# define some global constants +;# +$BASE_TIMEOUT=10; +$FRAG_TIMEOUT=10; +$MAX_TRY = 5; +$REFRESH_TIME=60*15; # 15 minutes (server uses 1 hour) +$ntp'timeout = $FRAG_TIMEOUT; #'; +$ntp'timeout if 0; + +;###################################### +;# now process options +;# +sub usage +{ + die("usage: $0 [-n] [-p <port>] [-l <logfile>] [host] ...\n"); +} + +$opt_l = "/dev/null"; # where to write debug messages to +$opt_p = 0; # port to use locally - (0 does mean: will be choosen by kernel) + +&usage unless &Getopts('l:p:'); +&Getopts if 0; # make -w happy + +@Hosts = ($#ARGV < $[) ? ("localhost") : @ARGV; + +;# setup for debug output +$DEBUGFILE=$opt_l; +$DEBUGFILE="&STDERR" if $DEBUGFILE eq '-'; + +open(DEBUG,">>$DEBUGFILE") || die("Cannot open \"$DEBUGFILE\": $!\n"); +select((select(DEBUG),$|=1)[$[]); + +;# &log prints a single trap record (adding a (local) time stamp) +sub log +{ + chop($date=&ctime(time)); + print "$date ",@_,"\n"; +} + +sub debug +{ + print DEBUG @_,"\n"; +} +;# +$proto_udp = (getprotobyname('udp'))[$[+2] || + (warn("$0: Could not get protocoll number for 'udp' using 17"), 17); + +$ntp_port = (getservbyname('ntp','udp'))[$[+2] || + (warn("$0: Could not get port number for service ntp/udp using 123"), 123); + +;# +socket(S, &AF_INET, &SOCK_DGRAM, $proto_udp) || die("Cannot open socket: $!\n"); + +;# +bind(S, pack("S n a4 x8", &AF_INET, $opt_p, &INADDR_ANY)) || + die("Cannot bind: $!\n"); + +($my_port, $my_addr) = (unpack("S n a4 x8",getsockname(S)))[$[+1,$[+2]; +&log(sprintf("Listening at address %d.%d.%d.%d port %d", + unpack("C4",$my_addr), $my_port)); + +;# disregister with all servers in case of termination +sub cleanup +{ + &log("Aborted by signal \"$_[$[]\"") if defined($_[$[]); + + foreach (@Hosts) + { + if ( ! defined($Host{$_}) ) + { + print "no info for host '$_'\n"; + next; + } + &ntp'send(S,31,0,"",pack("Sna4x8",&AF_INET,$ntp_port,$Host{$_})); #'; + } + close(S); + exit(2); +} + +$SIG{'HUP'} = 'cleanup'; +$SIG{'INT'} = 'cleanup'; +$SIG{'QUIT'} = 'cleanup'; +$SIG{'TERM'} = 'cleanup'; + +0 && $a && $b; +sub timeouts # sort timeout id array +{ + $TIMEOUTS{$a} <=> $TIMEOUTS{$b}; +} + +;# a Request element looks like: pack("a4SC",addr,associd,op) +@Requests= (); + +;# compute requests for set trap control msgs to each host given +{ + local($name,$addr); + + foreach (@Hosts) + { + if (/^(\d+)\.(\d+)\.(\d+)\.(\d+)$/) + { + ($name,$addr) = + (gethostbyaddr(pack("C4",$1,$2,$3,$4),&AF_INET))[$[,$[+4]; + unless (defined($name)) + { + $name = sprintf("[[%d.%d.%d.%d]]",$1,$2,$3,$4); + $addr = pack("C4",$1,$2,$3,$4); + } + } + else + { + ($name,$addr) = (gethostbyname($_))[$[,$[+4]; + unless (defined($name)) + { + warn "$0: unknown host \"$_\" - ignored\n"; + next; + } + } + next if defined($Host{$name}); + $Host{$name} = $addr; + $Host{$_} = $addr; + push(@Requests,pack("a4SC",$addr,0,6)); # schedule a set trap request for $name + } +} + +sub hostname +{ + local($addr) = @_; + return $HostName{$addr} if defined($HostName{$addr}); + local($name) = gethostbyaddr($addr,&AF_INET); + &debug(sprintf("hostname(%d.%d.%d.%d) = \"%s\"",unpack("C4",$addr),$name)) + if defined($name); + defined($name) && ($HostName{$addr} = $name) && (return $name); + &debug(sprintf("Failed to get name for %d.%d.%d.%d",unpack("C4",$addr))); + return sprintf("[%d.%d.%d.%d]",unpack("C4",$addr)); +} + +;# when no hosts were given on the commandline no requests have been scheduled +&usage unless (@Requests); + +&debug(sprintf("%d request(s) scheduled",scalar(@Requests))); +grep(&debug(" - ".$_),keys(%Host)); + +;# allocate variables; +$addr=""; +$assoc=0; +$op = 0; +$timeout = 0; +$ret=""; +%TIMEOUTS = (); +%TIMEOUT_PROCS = (); +@TIMEOUTS = (); + +$len = 512; +$buf = " " x $len; + +while (1) +{ + if (@Requests || @TIMEOUTS) # if there is some work pending + { + if (@Requests) + { + ($addr,$assoc,$op) = unpack("a4SC",($req = shift(@Requests))); + &debug(sprintf("Request: %s: %s(%d)",&hostname($addr), &ntp'cntrlop_name($op), $assoc)); #';)) + $ret = &ntp'send(S,$op,$assoc,"", #'( + pack("Sna4x8",&AF_INET,$ntp_port,$addr)); + &set_timeout("retry-".unpack("H*",$req),time+$BASE_TIMEOUT, + sprintf("&retry(\"%s\");",unpack("H*",$req))); + + last unless (defined($ret)); # warn called by ntp'send(); + + ;# if there are more requests just have a quick look for new messages + ;# otherwise grant server time for a response + $timeout = @Requests ? 0 : $BASE_TIMEOUT; + } + if ($timeout && @TIMEOUTS) + { + ;# ensure not to miss a timeout + if ($timeout + time > $TIMEOUTS{$TIMEOUTS[$[]}) + { + $timeout = $TIMEOUTS{$TIMEOUTS[$[]} - time; + $timeout = 0 if $timeout < 0; + } + } + } + else + { + ;# no work yet - wait for some messages dropping in + ;# usually this will not hapen as the refresh semantic will + ;# always have a pending timeout + undef($timeout); + } + + vec($mask="",fileno(S),1) = 1; + $ret = select($mask,undef,undef,$timeout); + + warn("$0: select: $!\n"),last if $ret < 0; # give up on error return from select + + if ($ret == 0) + { + ;# timeout + if (@TIMEOUTS && time > $TIMEOUTS{$TIMEOUTS[$[]}) + { + ;# handle timeout + $timeout_proc = + (delete $TIMEOUT_PROCS{$TIMEOUTS[$[]}, + delete $TIMEOUTS{shift(@TIMEOUTS)})[$[]; + eval $timeout_proc; + die "timeout eval (\"$timeout_proc\"): $@\n" if $@; + } + ;# else: there may be something to be sent + } + else + { + ;# data avail + $from = recv(S,$buf,$len,0); + ;# give up on error return from recv + warn("$0: recv: $!\n"), last unless (defined($from)); + + $from = (unpack("Sna4",$from))[$[+2]; # keep host addr only + ;# could check for ntp_port - but who cares + &debug("-Packet from ",&hostname($from)); + + ;# stuff packet into ntp mode 6 receive machinery + ($ret,$data,$status,$associd,$op,$seq,$auth_keyid) = + &ntp'handle_packet($buf,$from); # '; + &debug(sprintf("%s uses auth_keyid %d",&hostname($from),$auth_keyid)) if defined($auth_keyid); + next unless defined($ret); + + if ($ret eq "") + { + ;# handle packet + ;# simple trap response messages have neither timeout nor retries + &clear_timeout("retry-".unpack("H*",pack("a4SC",$from,$associd,$op))) unless $op == 7; + delete $RETRY{pack("a4SC",$from,$associd,$op)} unless $op == 7; + + &process_response($from,$ret,$data,$status,$associd,$op,$seq,$auth_keyid); + } + else + { + ;# some kind of error + &log(sprintf("%50s: %s: %s",(gethostbyaddr($from,&AF_INET))[$[],$ret,$data)); + if ($ret ne "TIMEOUT" && $ret ne "ERROR") + { + &clear_timeout("retry-".unpack("H*",pack("a4SC",$from,$associd,$op))); + } + } + } + +} + +warn("$0: terminating\n"); +&cleanup; +exit 0; + +;################################################## +;# timeout support +;# +sub set_timeout +{ + local($id,$time,$proc) = @_; + + $TIMEOUTS{$id} = $time; + $TIMEOUT_PROCS{$id} = $proc; + @TIMEOUTS = sort timeouts keys(%TIMEOUTS); + chop($date=&ctime($time)); + &debug(sprintf("Schedule timeout \"%s\" for %s", $id, $date)); +} + +sub clear_timeout +{ + local($id) = @_; + delete $TIMEOUTS{$id}; + delete $TIMEOUT_PROCS{$id}; + @TIMEOUTS = sort timeouts keys(%TIMEOUTS); + &debug("Clear timeout \"$id\""); +} + +0 && &refresh; +sub refresh +{ + local($addr) = @_[$[]; + $addr = pack("H*",$addr); + &debug(sprintf("Refreshing trap for %s", &hostname($addr))); + push(@Requests,pack("a4SC",$addr,0,6)); +} + +0 && &retry; +sub retry +{ + local($tag) = @_; + $tag = pack("H*",$tag); + $RETRY{$tag} = 0 if (!defined($RETRY{$tag})); + + if (++$RETRY{$tag} > $MAX_TRY) + { + &debug(sprintf("Retry failed: %s assoc %5d op %d", + &hostname(substr($tag,$[,4)), + unpack("x4SC",$tag))); + return; + } + &debug(sprintf("Retrying: %s assoc %5d op %d", + &hostname(substr($tag,$[,4)), + unpack("x4SC",$tag))); + push(@Requests,$tag); +} + +sub process_response +{ + local($from,$ret,$data,$status,$associd,$op,$seq,$auth_keyid) = @_; + + $msg=""; + if ($op == 7) # trap response + { + $msg .= sprintf("%40s trap#%-5d", + &hostname($from),$seq); + &debug (sprintf("\nTrap %d associd %d:\n%s\n===============\n",$seq,$associd,$data)); + if ($associd == 0) # system event + { + $msg .= " SYSTEM "; + $evnt = &ntp'SystemEvent($status); #'; + $msg .= "$evnt "; + ;# for special cases add additional info + ($stratum) = ($data =~ /stratum=(\d+)/); + ($refid) = ($data =~ /refid=([\w\.]+)/); + $msg .= "stratum=$stratum refid=$refid"; + if ($refid =~ /\[?(\d+)\.(\d+)\.(\d+)\.(\d+)/) + { + local($x) = (gethostbyaddr(pack("C4",$1,$2,$3,$4),&AF_INET)); + $msg .= " " . $x if defined($x) + } + if ($evnt eq "event_sync_chg") + { + $msg .= sprintf("%s %s ", + &ntp'LI($status), #', + &ntp'ClockSource($status) #' + ); + } + elsif ($evnt eq "event_sync/strat_chg") + { + ($peer) = ($data =~ /peer=([0-9]+)/); + $msg .= " peer=$peer"; + } + elsif ($evnt eq "event_clock_excptn") + { + if (($device) = ($data =~ /device=\"([^\"]+)\"/)) + { + ($cstatus) = ($data =~ /refclockstatus=0?x?([\da-fA-F]+)/); + $Cstatus = hex($cstatus); + $msg .= sprintf("- %-32s",&ntp'clock_status($Cstatus)); #'); + ($timecode) = ($data =~ /timecode=\"([^\"]+)\"/); + $msg .= " \"$device\" \"$timecode\""; + } + else + { + push(@Requests,pack("a4SC",$from, $associd, 4)); + } + } + } + else # peer event + { + $msg .= sprintf("peer %5d ",$associd); + ($srcadr) = ($data =~ /srcadr=\[?([\d\.]+)/); + $msg .= sprintf("%-18s %40s ", "[$srcadr]", + &hostname(pack("C4",split(/\./,$srcadr)))); + $evnt = &ntp'PeerEvent($status); #'; + $msg .= "$evnt "; + ;# for special cases include additional info + if ($evnt eq "event_clock_excptn") + { + if (($device) = ($data =~ /device=\"([^\"]+)\"/)) + { + ;#&debug("----\n$data\n====\n"); + ($cstatus) = ($data =~ /refclockstatus=0?x?([\da-fA-F]+)/); + $Cstatus = hex($cstatus); + $msg .= sprintf("- %-32s",&ntp'clock_status($Cstatus)); #'); + ($timecode) = ($data =~ /timecode=\"([^\"]+)\"/); + $msg .= " \"$device\" \"$timecode\""; + } + else + { + ;# no clockvars included - post a cv request + push(@Requests,pack("a4SC",$from, $associd, 4)); + } + } + elsif ($evnt eq "event_stratum_chg") + { + ($stratum) = ($data =~ /stratum=(\d+)/); + $msg .= "new stratum $stratum"; + } + } + } + elsif ($op == 6) # set trap resonse + { + &debug("Set trap ok from ",&hostname($from)); + &set_timeout("refresh-".unpack("H*",$from),time+$REFRESH_TIME, + sprintf("&refresh(\"%s\");",unpack("H*",$from))); + return; + } + elsif ($op == 4) # read clock variables response + { + ;# status of clock + $msg .= sprintf(" %40s ", &hostname($from)); + if ($associd == 0) + { + $msg .= "system clock status: "; + } + else + { + $msg .= sprintf("peer %5d clock",$associd); + } + $msg .= sprintf("%-32s",&ntp'clock_status($status)); #'); + ($device) = ($data =~ /device=\"([^\"]+)\"/); + ($timecode) = ($data =~ /timecode=\"([^\"]+)\"/); + $msg .= " \"$device\" \"$timecode\""; + } + elsif ($op == 31) # unset trap response (UNOFFICIAL op) + { + ;# clear timeout + &debug("Clear Trap ok from ",&hostname($from)); + &clear_timeout("refresh-".unpack("H*",$from)); + return; + } + else # unexpected response + { + $msg .= "unexpected response to op $op assoc=$associd"; + $msg .= sprintf(" status=%04x",$status); + } + &log($msg); +} diff --git a/contrib/ntp/scripts/monitoring/timelocal.pl b/contrib/ntp/scripts/monitoring/timelocal.pl new file mode 100644 index 0000000..d0f73a2 --- /dev/null +++ b/contrib/ntp/scripts/monitoring/timelocal.pl @@ -0,0 +1,77 @@ +;# timelocal.pl +;# +;# Usage: +;# $time = timelocal($sec,$min,$hours,$mday,$mon,$year,$junk,$junk,$isdst); +;# $time = timegm($sec,$min,$hours,$mday,$mon,$year); + +;# These routines are quite efficient and yet are always guaranteed to agree +;# with localtime() and gmtime(). We manage this by caching the start times +;# of any months we've seen before. If we know the start time of the month, +;# we can always calculate any time within the month. The start times +;# themselves are guessed by successive approximation starting at the +;# current time, since most dates seen in practice are close to the +;# current date. Unlike algorithms that do a binary search (calling gmtime +;# once for each bit of the time value, resulting in 32 calls), this algorithm +;# calls it at most 6 times, and usually only once or twice. If you hit +;# the month cache, of course, it doesn't call it at all. + +;# timelocal is implemented using the same cache. We just assume that we're +;# translating a GMT time, and then fudge it when we're done for the timezone +;# and daylight savings arguments. The timezone is determined by examining +;# the result of localtime(0) when the package is initialized. The daylight +;# savings offset is currently assumed to be one hour. + +CONFIG: { + package timelocal; + + @epoch = localtime(0); + $tzmin = $epoch[2] * 60 + $epoch[1]; # minutes east of GMT + if ($tzmin > 0) { + $tzmin = 24 * 60 - $tzmin; # minutes west of GMT + $tzmin -= 24 * 60 if $epoch[5] == 70; # account for the date line + } + + $SEC = 1; + $MIN = 60 * $SEC; + $HR = 60 * $MIN; + $DAYS = 24 * $HR; + $YearFix = ((gmtime(946684800))[5] == 100) ? 100 : 0; +} + +sub timegm { + package timelocal; + + $ym = pack(C2, @_[5,4]); + $cheat = $cheat{$ym} || &cheat; + $cheat + $_[0] * $SEC + $_[1] * $MIN + $_[2] * $HR + ($_[3]-1) * $DAYS; +} + +sub timelocal { + package timelocal; + + $ym = pack(C2, @_[5,4]); + $cheat = $cheat{$ym} || &cheat; + $cheat + $_[0] * $SEC + $_[1] * $MIN + $_[2] * $HR + ($_[3]-1) * $DAYS + + $tzmin * $MIN - 60 * 60 * ($_[8] != 0); +} + +package timelocal; + +sub cheat { + $year = $_[5]; + $month = $_[4]; + $guess = $^T; + @g = gmtime($guess); + $year += $YearFix if $year < $epoch[5]; + while ($diff = $year - $g[5]) { + $guess += $diff * (364 * $DAYS); + @g = gmtime($guess); + } + while ($diff = $month - $g[4]) { + $guess += $diff * (28 * $DAYS); + @g = gmtime($guess); + } + $g[3]--; + $guess -= $g[0] * $SEC + $g[1] * $MIN + $g[2] * $HR + $g[3] * $DAYS; + $cheat{$ym} = $guess; +} diff --git a/contrib/ntp/scripts/ntp-groper b/contrib/ntp/scripts/ntp-groper new file mode 100755 index 0000000..1fd0cfe --- /dev/null +++ b/contrib/ntp/scripts/ntp-groper @@ -0,0 +1,95 @@ +#!/bin/sh +# +# ntpgroper host ... +# +# This script checks each hostname given as an argument to see if +# it is running NTP. It reports one of the following messages (assume +# the host is named "dumbo.hp.com": +# +# dumbo.hp.com not registered in DNS +# dumbo.hp.com not responding to ping +# dumbo.hp.com refused ntpq connection +# dumbo.hp.com not responding to NTP +# dumbo.hp.com answers NTP version 2, stratum: 3, ref: telford.nsa.hp.com +# dumbo.hp.com answers NTP version 3, stratum: 3, ref: telford.nsa.hp.com +# +# It ain't pretty, but it is kinda useful. +# +# Walter Underwood, 11 Feb 1993, wunder@hpl.hp.com +# +# converted to /bin/sh from /bin/ksh by scott@ee.udel.edu 24 Mar 1993 + +PATH="/usr/local/etc:$PATH" export PATH + +verbose=1 +logfile=/tmp/cntp-log$$ +ntpqlog=/tmp/cntp-ntpq$$ + +# I wrap the whole thing in parens so that it is possible to redirect +# all the output somewhere, if desired. +( +for host in $* +do + # echo "Trying $host." + + gethost $host > /dev/null 2>&1 + if [ $? -ne 0 ] + then + echo "$host not registered in DNS" + continue + fi + + ping $host 64 1 > /dev/null 2>&1 + if [ $? -ne 0 ] + then + echo "$host not responding to ping" + continue + fi + + # Attempt to contact with version 3 ntp, then try version 2. + for version in 3 2 + do + + ntpq -c "ntpversion $version" -p $host > $ntpqlog 2>&1 + + if fgrep -s 'Connection refused' $ntpqlog + then + echo "$host refused ntpq connection" + break + fi + + responding=1 + fgrep -s 'timed out, nothing received' $ntpqlog > /dev/null && responding=0 + + if [ $responding -eq 1 ] + then + ntpq -c "ntpversion $version" -c rl $host > $ntpqlog + + # First we extract the reference ID (usually a host or a clock) + synchost=`fgrep "refid=" $ntpqlog` + #synchost=${synchost##*refid=} # strip off the beginning of the line + #synchost=${synchost%%,*} # strip off the end + synchost=`expr "$synchost" : '.*refid=\([^,]*\),.*'` + + # Next, we get the stratum + stratum=`fgrep "stratum=" $ntpqlog` + #stratum=${stratum##*stratum=} + #stratum=${stratum%%,*} + stratum=`expr "$stratum" : '.*stratum=\([^,]*\),.*'` + + echo "$host answers NTP version $version, stratum: $stratum, ref: $synchost" + break; + fi + + if [ $version -eq 2 -a $responding -eq 0 ] + then + echo "$host not responding to NTP" + fi + done +done +) +# ) >> $logfile + +if [ -f $ntpqlog ]; then + rm $ntpqlog +fi diff --git a/contrib/ntp/scripts/ntp-restart b/contrib/ntp/scripts/ntp-restart new file mode 100755 index 0000000..d2023f0 --- /dev/null +++ b/contrib/ntp/scripts/ntp-restart @@ -0,0 +1,9 @@ +#!/bin/sh +# +# This script can be used to kill and restart the NTP daemon. Edit the +# /usr/local/bin/xntpd line to fit. +# +kill -INT `ps -ax | egrep "xntpd" | egrep -v "egrep" | sed 's/^\([ 0-9]*\) .*/\1'/` +sleep 10 +/usr/local/bin/xntpd +exit 0 diff --git a/contrib/ntp/scripts/ntpver.in b/contrib/ntp/scripts/ntpver.in new file mode 100644 index 0000000..be36897 --- /dev/null +++ b/contrib/ntp/scripts/ntpver.in @@ -0,0 +1,7 @@ +#!@PATH_SH@ +# print version string of NTP daemon +# Copyright (c) 1997 by Ulrich Windl +# Modified 970318: Harlan Stenn: rewritten... +# usage: ntpver hostname + +ntpq -c "rv 0 daemon_version" $* | awk '/daemon_version/ { print $2 }' diff --git a/contrib/ntp/scripts/plot_summary.pl b/contrib/ntp/scripts/plot_summary.pl new file mode 100755 index 0000000..5be0182 --- /dev/null +++ b/contrib/ntp/scripts/plot_summary.pl @@ -0,0 +1,333 @@ +#!/usr/bin/perl -w +# $Id: plot_summary.pl,v 1.1.1.1 1999/05/26 00:48:25 stenn Exp $ +# +# Use Gnuplot to display data in summary files produced by summary.pl. +# This script requires GNUPLOT 3.6 (pre 3.6 beta 319)! +# +# Copyright (c) 1997, Ulrich Windl <Ulrich.Windl@rz.uni-regensburg.de> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +require 5.003; # "never tested with any other version of Perl" +use strict; + +use Time::Local; +use Getopt::Long; + +# parse command line +my $summary_dir = "/tmp"; +my $identifier = `hostname`; # origin of these data +chomp $identifier; # remove newline +my $offset_limit = 0.128; # limit of absolute offset +my $output_file = ""; # output file defaults to stdout +my $output_file_number = 1; # numbering of output files +my $gnuplot_terminal = $ENV{DISPLAY} ? "x11" : "dumb"; +my $wait_after_plot = 1; +my @peer_list = (); + +my %options = ("directory=s" => \$summary_dir, + "identifier=s" => \$identifier, + "offset-limit=f" => \$offset_limit, + "output-file=s" => \$output_file, + "peer=s@" => \@peer_list, + "plot-term=s" => \$gnuplot_terminal, + "wait-after-plot!" => \$wait_after_plot, + ); +if ( !GetOptions(%options) ) { + print STDERR "usage: $0\n"; + my $opt; + foreach $opt (sort(keys %options)) { + print STDERR "\t--$opt "; + if ( ref($options{$opt}) eq "ARRAY" ) { + print STDERR "(" . join (" ", @{$options{$opt}}) . ")\n"; + } else { + print STDERR "(${$options{$opt}})\n"; + } + } + print STDERR "\n"; + die; +} + +chomp $identifier; +die "illegal offset-limit: $offset_limit" unless $offset_limit > 0.0; +$offset_limit *= 1e6; # scale to microseconds + +# return the smallest value in the given list +sub min +{ + my ($result, @rest) = @_; + map { $result = $_ if ($_ < $result) } @rest; + return($result); +} + +# return the largest value in the given list +sub max +{ + my ($result, @rest) = @_; + map { $result = $_ if ($_ > $result) } @rest; + return($result); +} + +# maybe open alternate output file +sub open_output +{ + my $file; + if ($output_file) { + while ( -r ($file = "$output_file$output_file_number") ) { + ++$output_file_number; + } + open TOUCH, ">$file" and close TOUCH or die "$file: $!"; + print "set output \"$file\"\n"; + } +} + +# make Gnuplot wait +sub maybe_add_pause +{ + print "pause -1 \"Press key to continue...\"\n" if $wait_after_plot; +} + +# plot data from loop summary +sub do_loop +{ + my $fname = shift; + my $line; + my $out_file = "/tmp/tempdata$$"; + my $cmd_file = "/tmp/tempcmd$$"; + my ($first_day, $day_out) = ("", 0); + my ($lower_bound, $upper_bound, $rms); + my ($min_offs, $max_offs) = (1e9, -1e9); + my ($min_rms, $max_rms) = (1e9, -1e9); + open INPUT, "$fname" or die "$fname: $!"; + open OUTPUT, ">$out_file" or die "$out_file: $!"; + my @Fld; + while (<INPUT>) { + chop; # strip record separator + @Fld = split; + if ($#Fld == 0) { +# loops.19960405 + $_ = $Fld[0]; s/.*([12]\d{3}[01]\d[0-3]\d)$/$1/; + m/(\d{4})(\d{2})(\d{2})/; + $line = timegm (59, 59, 23, $3, $2 - 1, $1 - 1900, 0, 0, 0); + $line = int $line / 86400; # days relative to 1970 + $first_day = "$1-$2-$3 ($line)" unless $day_out; + next; + } + if ($#Fld != 8) { + warn "Illegal number of fields in file $fname, line $."; + next; + } +# loop 216, 856106+/-874041.5, rms 117239.8, freq 67.52+/-10.335, var 4.850 + $_ = $Fld[1]; s/,/ /; $line .= " $_"; + $_ = $Fld[2]; m:(.+?)\+/-(.+),:; + $lower_bound = $1 - $2; + $upper_bound = $1 + $2; + $line .= "$1 $lower_bound $upper_bound"; + $min_offs = min($min_offs, $lower_bound); + $max_offs = max($max_offs, $upper_bound); + $_ = $Fld[4]; s/,/ /; $rms = $_; + $min_rms = min($min_rms, $rms); + $max_rms = max($max_rms, $rms); + $line .= " $rms"; + $_ = $Fld[6]; m:(.+?)\+/-(.+),:; + $line .= " $1 " . ($1-$2) . " " . ($1+$2); + $line .= " $Fld[8]"; + print OUTPUT "$line\n"; + $day_out = 1; +# 9621 216 856106 -17935.5 1730147.5 117239.8 67.52 57.185 77.855 4.850 + } + close INPUT; + close OUTPUT or die "close failed on $out_file: $!"; + my $ylimit = "["; + if ($min_offs < -$offset_limit) { + $ylimit .= "-$offset_limit"; + } + $ylimit .= ":"; + if ($max_offs > $offset_limit) { + $ylimit .= "$offset_limit"; + } + if ( $ylimit eq "[:" ) { + $ylimit = ""; + } else { + $ylimit = "[] $ylimit]"; + } + open OUTPUT, "> $cmd_file" or die "$cmd_file: $!"; + my $oldfh = select OUTPUT; + print "set term $gnuplot_terminal\n"; + open_output; + print "set grid\n"; + print "set title \"Loop Summary for $identifier: " . + "Daily mean values since $first_day\\n" . + "(Offset limit is $offset_limit microseconds)\"\n"; + print "set ylabel \"[us]\"\n"; + print "set data style yerrorbars\n"; + print "set multiplot\n"; + print "set size 1, 0.5\n"; + print "set lmargin 8\n"; + print "set origin 0, 0.5\n"; + print "plot $ylimit \"$out_file\"" . + " using 1:3:4:5 title \"mean offset\", "; + print "\"$out_file\" using 1:(\$3-\$6/2) " . + "title \"(sigma low)\" with lines, "; + print "\"$out_file\" using 1:3 smooth bezier " . + "title \"(Bezier med)\" with lines, "; + print "\"$out_file\" using 1:(\$3+\$6/2) " . + "title \"(sigma high)\" with lines\n"; + print "set ylabel \"[ppm]\"\n"; + print "set origin 0, 0.0\n"; + print "set title\n"; + print "set xlabel \"Days relative to 1970\"\n"; + print "plot \"$out_file\" using 1:7:8:9 title \"mean frequency\", "; + print "\"$out_file\" using 1:(\$7-\$10/2) " . + "title \"(sigma low)\" with lines, "; + print "\"$out_file\" using 1:7 smooth bezier " . + "title \"(Bezier med)\" with lines, "; + print "\"$out_file\" using 1:(\$7+\$10/2) " . + "title \"(sigma high)\" with lines\n"; + print "set nomultiplot\n"; + maybe_add_pause; + + my $ylimit = "["; + if ($min_rms < -$offset_limit) { + $ylimit .= "-$offset_limit"; + } + $ylimit .= ":"; + if ($max_rms > $offset_limit) { + $ylimit .= "$offset_limit"; + } + if ( $ylimit eq "[:" ) { + $ylimit = ""; + } else { + $ylimit = "[] $ylimit]"; + } + + open_output; + print "set title \"Loop Summary for $identifier: " . + "Standard deviation since $first_day\\n" . + "(Offset limit is $offset_limit microseconds)\"\n"; + print "set xlabel\n"; + print "set ylabel \"[us]\"\n"; + print "set origin 0, 0.5\n"; + print "set data style linespoints\n"; + print "set multiplot\n"; + print "plot $ylimit \"$out_file\" using 1:6 title \"Offset\", "; + print "\"$out_file\" using 1:6 smooth bezier " . + "title \"(Bezier)\" with lines\n"; + print "set title\n"; + print "set origin 0, 0.0\n"; + print "set xlabel \"Days relative to 1970\"\n"; + print "set ylabel \"[ppm]\"\n"; + print "plot \"$out_file\" using 1:10 title \"Frequency\", "; + print "\"$out_file\" using 1:10 smooth bezier " . + "title \"(Bezier)\" with lines\n"; + print "set nomultiplot\n"; + maybe_add_pause; + + close OUTPUT or die "close failed on $cmd_file: $!"; + select $oldfh; + print `gnuplot $cmd_file`; + unlink $cmd_file; + unlink $out_file; +} + +# plot data form peer summary +sub do_peer +{ + my $fname = shift; + my $peer = shift; + my $out_file = "/tmp/tempdata$$"; + my $cmd_file = "/tmp/tempcmd$$"; + my $line; + my ($first_day, $day_out) = ("", 0); + open INPUT, "$fname" or die "$fname: $!"; + open OUTPUT, ">$out_file" or die "$out_file: $!"; + my @Fld; + while (<INPUT>) { + chop; # strip record separator + @Fld = split; + if ($#Fld == 0) { +# peers.19960405 + $_ = $Fld[0]; s/.*([12]\d{3}[01]\d[0-3]\d)$/$1/; + m/(\d{4})(\d{2})(\d{2})/ or next; + $line = timegm (59, 59, 23, $3, $2 - 1, $1 - 1900, 0, 0, 0); + $line = int $line / 86400; # days relative to 1970 + $first_day = "$1-$2-$3 ($line)" unless $day_out; + next; + } + if ($#Fld != 7) { + warn "Illegal number of fields in file $fname, line $."; + next; + } + next if ($Fld[0] ne $peer); +# ident cnt mean rms max delay dist disp +# 127.127.8.1 38 30.972 189.867 1154.607 0.000 879.760 111.037 + $Fld[0] = $line; + print OUTPUT join(' ', @Fld) . "\n"; +# 9969 38 30.972 189.867 1154.607 0.000 879.760 111.037 + $day_out = 1; + } + close INPUT; + close OUTPUT or die "close failed on $out_file: $!"; + die "no data found for peer $peer" if !$day_out; + open OUTPUT, "> $cmd_file" or die "$cmd_file: $!"; + my $oldfh = select OUTPUT; + print "set term $gnuplot_terminal\n"; + open_output; + print "set grid\n"; + print "set multiplot\n"; + print "set lmargin 8\n"; + print "set size 1, 0.34\n"; + print "set origin 0, 0.66\n"; + print "set title " . + "\"Peer Summary for $peer on $identifier since $first_day\"\n"; + print "set data style linespoints\n"; + print "set ylabel \"[us]\"\n"; + print "plot \"$out_file\" using 1:3 title \"mean offset\", "; + print "\"$out_file\" using 1:3 smooth bezier " . + "title \"(Bezier)\" with lines, "; + print "\"$out_file\" using 1:(\$3-\$7/2) " . + "title \"(sigma low)\" with lines, "; + print "\"$out_file\" using 1:(\$3+\$7/2) " . + "title \"(sigma high)\" with lines\n"; + print "set title\n"; + print "set origin 0, 0.34\n"; + print "set size 1, 0.32\n"; + print "set ylabel\n"; + print "plot \"$out_file\" using 1:7 title \"dist\", "; + print "\"$out_file\" using 1:7 smooth bezier " . + "title \"(Bezier)\" with lines\n"; + print "set origin 0, 0.00\n"; + print "set size 1, 0.35\n"; + print "set xlabel \"Days relative to 1970\"\n"; + print "plot \"$out_file\" using 1:8 title \"disp\", "; + print "\"$out_file\" using 1:8 smooth bezier " . + "title \"(Bezier)\" with lines\n"; + print "set nomultiplot\n"; + maybe_add_pause; + + select $oldfh; + close OUTPUT or die "close failed on $cmd_file: $!"; + print `gnuplot $cmd_file`; + unlink $cmd_file; + unlink $out_file; +} + + +my $loop_summary ="$summary_dir/loop_summary"; +my $peer_summary ="$summary_dir/peer_summary"; +my $clock_summary="$summary_dir/clock_summary"; + +do_loop $loop_summary; +map { do_peer $peer_summary, $_ } @peer_list; diff --git a/contrib/ntp/scripts/rc1/postinstall b/contrib/ntp/scripts/rc1/postinstall new file mode 100644 index 0000000..d84b8c5 --- /dev/null +++ b/contrib/ntp/scripts/rc1/postinstall @@ -0,0 +1,2 @@ +#!/bin/sh +/etc/init.d/xntp start diff --git a/contrib/ntp/scripts/rc1/preinstall b/contrib/ntp/scripts/rc1/preinstall new file mode 100644 index 0000000..aa18639 --- /dev/null +++ b/contrib/ntp/scripts/rc1/preinstall @@ -0,0 +1,6 @@ +#!/bin/sh +if [ -x /etc/init.d/xntp ] +then + /etc/init.d/xntp stop +fi +exit 0 diff --git a/contrib/ntp/scripts/rc1/preremove b/contrib/ntp/scripts/rc1/preremove new file mode 100644 index 0000000..b870151 --- /dev/null +++ b/contrib/ntp/scripts/rc1/preremove @@ -0,0 +1,4 @@ +#!/bin/sh +/etc/init.d/xntp stop + +exit 0 diff --git a/contrib/ntp/scripts/rc1/prototype b/contrib/ntp/scripts/rc1/prototype new file mode 100644 index 0000000..3de20b0 --- /dev/null +++ b/contrib/ntp/scripts/rc1/prototype @@ -0,0 +1,19 @@ +!default 755 root bin +i pkginfo +i preinstall +i postinstall +i preremove +f none /etc/init.d/xntp=xntp 0755 root other +l none /etc/rc2.d/S79xntp=/etc/init.d/xntp +l none /etc/rc1.d/K79xntp=/etc/init.d/xntp +l none /etc/rc0.d/K79xntp=/etc/init.d/xntp +f none /usr/sbin/xntpd=xntpd/xntpd 0555 root other +f none /usr/sbin/xntpdc=xntpdc/xntpdc 0555 root other +f none /usr/sbin/ntpq=ntpq/ntpq 0555 root other +f none /usr/sbin/ntptrace=ntptrace/ntptrace 0555 root other +f none /usr/sbin/ntpdate=ntpdate/ntpdate 0555 root other +f none /usr/share/man/man1m/xntpd.1m=doc/xntpd.8 0444 root other +f none /usr/share/man/man1m/xntpdc.1m=doc/xntpdc.8 0444 root other +f none /usr/share/man/man1m/ntpdate.1m=doc/ntpdate.8 0444 root other +f none /usr/share/man/man1m/ntpq.1m=doc/ntpq.8 0444 root other +f none /usr/share/man/man1m/ntptrace.1m=doc/ntptrace.8 0444 root other diff --git a/contrib/ntp/scripts/rc1/xntp b/contrib/ntp/scripts/rc1/xntp new file mode 100644 index 0000000..227b943 --- /dev/null +++ b/contrib/ntp/scripts/rc1/xntp @@ -0,0 +1,29 @@ +#!/bin/sh + +killproc() { # kill named processes + pid=`/usr/bin/ps -e | + /usr/bin/grep $1 | + /usr/bin/sed -e 's/^ *//' -e 's/ .*//'` + [ "$pid" != "" ] && kill $pid +} + +case "$1" in +'start') + ps -e | grep xntpd > /dev/null 2>&1 + if [ $? -eq 0 ] + then + echo "ntp daemon already running. ntp start aborted" + exit 0 + fi + if [ -f /etc/inet/ntp.conf -a -x /usr/sbin/xntpd ] + then + /usr/sbin/xntpd -c /etc/inet/ntp.conf + fi + ;; +'stop') + killproc xntpd + ;; +*) + echo "Usage: /etc/init.d/xntp { start | stop }" + ;; +esac diff --git a/contrib/ntp/scripts/rc2/local.ntpd b/contrib/ntp/scripts/rc2/local.ntpd new file mode 100644 index 0000000..ba53e05 --- /dev/null +++ b/contrib/ntp/scripts/rc2/local.ntpd @@ -0,0 +1,64 @@ +#! /usr/bin/perl -w +# 980904 Harlan Stenn - created + +# vvv CHANGE THESE vvv + +$ps = "/bin/ps x |"; + +$ntp_conf = "/etc/ntp.conf"; +$ntpd = "/usr/local/bin/xntpd"; +$ntpdate = "/usr/local/bin/ntpdate -b -s 10.0.0.1 10.0.0.2"; + +# ^^^ CHANGE THESE ^^^ + +{ + if (0) + { + } + elsif ($ARGV[0] eq "start") + { + @pidlist = pidlist($ntpd); + if (defined(@pidlist)) + { + warn "NTP is already running\n"; + } + else + { + if ( -f $ntp_conf && -x $ntpd ) + { + system ($ntpdate); + system ($ntpd." -c ".$ntp_conf); + } + } + } + elsif ($ARGV[0] eq "stop") + { + @pidlist = pidlist($ntpd); + kill 'TERM', @pidlist if (scalar(@pidlist) > 0); + } + else + { + die "Usage: $0 {start,stop}\n"; + } +} + +sub pidlist ($) + { + my ($target) = @_; + my ($qt) = quotemeta($target); + my @pids; + + open(PS, $ps) || die "Can't run ps: $!\n"; + while (<PS>) + { + chomp; + next unless (/$qt/); + print "Got <$_>\n"; + if (/^\s*(\d+)\s+/) + { + push @pids, $1; + } + } + close(PS); + return @pids; + } diff --git a/contrib/ntp/scripts/stats.ulrich.patches b/contrib/ntp/scripts/stats.ulrich.patches new file mode 100644 index 0000000..fe642f6 --- /dev/null +++ b/contrib/ntp/scripts/stats.ulrich.patches @@ -0,0 +1,1003 @@ + +Received: from huey2.ee.udel.edu by mail.eecis.udel.edu id aa25207; + 10 Dec 1997 10:39 EST +Received: from copland.udel.edu by huey.udel.edu id aa16958; + 10 Dec 1997 10:39 EST +Received: from rrzs2.rz.uni-regensburg.de (rrzs2.rz.uni-regensburg.de [132.199.1.2]) by copland.udel.edu (8.8.5/8.7.3) with ESMTP id KAA21293 for <mills@udel.edu>; Wed, 10 Dec 1997 10:39:12 -0500 (EST) +Received: from ngate.ngate.uni-regensburg.de (ngate.rz.uni-regensburg.de [132.199.3.13]) + by rrzs2.rz.uni-regensburg.de (8.8.5/8.8.5) with SMTP id QAA19974 + for <mills@udel.edu>; Wed, 10 Dec 1997 16:38:42 +0100 (MET) +Received: from rkdvmks1.ngate.uni-regensburg.de by ngate.ngate.uni-regensburg.de; Wed, 10 Dec 97 16:39 MET +Received: from rkdvmks1.ngate.uni-regensburg.de by kgate.ngate.uni-regensburg.de; Wed, 10 Dec 97 15:38 GMT +Received: from RKDVMKS1/SpoolDir by rkdvmks1.ngate.uni-regensburg.de (Mercury 1.32); + 10 Dec 97 16:38:34 +0100 +Received: from SpoolDir by RKDVMKS1 (Mercury 1.32); 10 Dec 97 16:38:06 +0100 +From: Ulrich Windl <ulrich.windl@rz.uni-regensburg.de> +Organization: Universitaet Regensburg, Klinikum +To: mills@udel.edu +Date: Wed, 10 Dec 1997 16:38:04 +0100 +MIME-Version: 1.0 +Content-Type: text/plain; charset=US-ASCII +Content-transfer-encoding: 7BIT +Subject: Big patch to scripts/monitoring +Priority: normal +X-mailer: Pegasus Mail for Windows (v2.53/R1) +Message-ID: <103AB9D209F5@rkdvmks1.ngate.uni-regensburg.de> + +Dave, there's another big patch against scripts/monitoring. The Perl +programs in there are rather old. As they are quite nice thogh, I +decided to update them for the latest version of Perl, namely 5.004. + +I'll include the description of changes and the patch. + +Ulrich + +Here is a description of changes made in ntploopwatch: + +Corrected most warnings that PERL 5.004 might emit. Corrected signal +handlers to make them work again. Corrected scaling (at least I +think). Supported case when output is sent to file or printer and +there is no X11 available. Fixed number of month in xlabels of the +plot. + +Added the ability to specify printer for GNUplot other that +PostScript. Use hostname if $STATHOST is not given in configuration +file. Corrected verbosity level for some messages. Added ability to +specify a non-standard print command. + +Perl 5.004_04 does no longer ignore ``-w--*-perl-*-''. Made some +cosmetic changes and added a timescale of 10 minutes. + +(Other programs are functionally unchanged. lr.pl is a PERL module now.) + + +Index: README +=================================================================== +RCS file: /home/windl/NTP/mon-REP/monitoring/README,v +retrieving revision 1.1.1.1 +retrieving revision 1.2 +diff -u -r1.1.1.1 -r1.2 +--- README 1993/08/24 19:29:34 1.1.1.1 ++++ README 1997/10/23 17:51:37 1.2 +@@ -1,14 +1,14 @@ + This directory contains support for monitoring the local clock of xntp daemons. + +-WARNING: The scripts and routines contained in this directory are bete realease! +- Do not depend on their correct operation. They are, however, in regular +- use at University of Erlangen-Nuernberg. No severe problems are known +- for this code. ++WARNING: The scripts and routines contained in this directory are beta ++ release! Do not depend on their correct operation. They are, ++ however, in regular use at University of Erlangen-Nuernberg. ++ No severe problems are known for this code. + + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + PLEASE THINK TWICE BEFORE STARTING MONITORING REMOTE XNTP DEAMONS !!!! + MONITORING MAY INCREASE THE LOAD OF THE DEAMON MONITORED AND MAY +-INCREASE THE NETWORK LOAD SIGNIFICANTLY ++INCREASE THE NETWORK LOAD SIGNIFICANTLY + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + + +@@ -23,8 +23,8 @@ + It sends a set_trap request to each server given and dumps the + trap messages received. It handles refresh of set_trap. + Currently it handles only NTP V2, however the NTP V3 servers +- also accept v2 requests. It will not interpret v3 system and peer +- stati correctly. ++ also accept v2 requests. It will not interpret v3 system and ++ peer stati correctly. + + usage: + ntptrap [-n] [-p <port>] [-l <debug-output>] servers... +@@ -72,7 +72,9 @@ + + if a timeout occurs the next sample is tried after delay/2 seconds + +- The script will terminate after MAX_FAIL (currently 60) consecutive errors. ++ The script will terminate after MAX_FAIL (currently 60) ++ consecutive errors. ++ + Errors are counted for: + - error on send call + - error on select call +@@ -114,10 +116,10 @@ + command line values would be replaced by settings from the config file. + + printer: specify printer to print plot +- BSD print systems semantics apply; if printer is omitted +- the name "ps" is used; plots are prepared using +- PostScript, thus the printer should best accept +- postscript input ++ BSD print systems semantics apply; if printer ++ is omitted the name "ps" is used; plots are ++ prepared using PostScript, thus the printer ++ should best accept postscript input + + For the following see also the comments in loopwatch.config.SAMPLE + +@@ -139,8 +141,10 @@ + within display range + + timelocal.pl: +- used during conversion of ISO_DATE_TIME values specified in loopwatch +- config files to unix epoch values (seconds since 1970-01-01_00:00_00 UTC) ++ ++ used during conversion of ISO_DATE_TIME values specified in ++ loopwatch config files to unix epoch values (seconds since ++ 1970-01-01_00:00_00 UTC) + + A version of this file is distributed with perl-4.x, however, + it has a bug related to dates crossing 1970, causing endless loops.. +Index: lr.pl +=================================================================== +RCS file: /home/windl/NTP/mon-REP/monitoring/lr.pl,v +retrieving revision 1.1.1.1 +retrieving revision 1.4 +diff -u -r1.1.1.1 -r1.4 +--- lr.pl 1993/08/24 19:29:33 1.1.1.1 ++++ lr.pl 1997/10/23 17:51:37 1.4 +@@ -9,9 +9,14 @@ + ;# Frank Kardel, Rainer Pruy + ;# Friedrich-Alexander Universitaet Erlangen-Nuernberg + ;# ++;# Copyright (c) 1997 by ++;# Ulrich Windl <Ulrich.Windl@rz.uni-regensburg.de> ++;# (Converted to a PERL 5.004 package) + ;# + ;############################################################# + ++package lr; ++ + ## + ## y = A + Bx + ## +@@ -23,123 +28,124 @@ + ## + ## interface + ## +-*lr_init = *lr'lr_init; #';# &lr_init(tag); initialize data set for tag +-*lr_sample = *lr'lr_sample; #';# &lr_sample(x,y,tag); enter sample +-*lr_Y = *lr'lr_Y; #';# &lr_Y(x,tag); compute y for given x +-*lr_X = *lr'lr_X; #';# &lr_X(y,tag); compute x for given y +-*lr_r = *lr'lr_r; #';# &lr_r(tag); regression coeffizient +-*lr_cov = *lr'lr_cov; #';# &lr_cov(tag); covariance +-*lr_A = *lr'lr_A; #';# &lr_A(tag); +-*lr_B = *lr'lr_B; #';# &lr_B(tag); +-*lr_sigma = *lr'lr_sigma; #';# &lr_sigma(tag); standard deviation +-*lr_mean = *lr'lr_mean; #';# &lr_mean(tag); ++;# init(tag); initialize data set for tag ++;# sample(x, y, tag); enter sample ++;# Y(x, tag); compute y for given x ++;# X(y, tag); compute x for given y ++;# r(tag); regression coefficient ++;# cov(tag); covariance ++;# A(tag); ++;# B(tag); ++;# sigma(tag); standard deviation ++;# mean(tag); + ######################### + +-package lr; +- +-sub tagify +-{ +- local($tag) = @_; +- if (defined($tag)) +- { +- *lr_n = eval "*${tag}_n"; +- *lr_sx = eval "*${tag}_sx"; +- *lr_sx2 = eval "*${tag}_sx2"; +- *lr_sxy = eval "*${tag}_sxy"; +- *lr_sy = eval "*${tag}_sy"; +- *lr_sy2 = eval "*${tag}_sy2"; +- } +-} +- +-sub lr_init ++sub init + { +- &tagify($_[$[]) if defined($_[$[]); ++ my $self = shift; + +- $lr_n = 0; +- $lr_sx = 0.0; +- $lr_sx2 = 0.0; +- $lr_sxy = 0.0; +- $lr_sy = 0.0; +- $lr_sy2 = 0.0; ++ $self->{n} = 0; ++ $self->{sx} = 0.0; ++ $self->{sx2} = 0.0; ++ $self->{sxy} = 0.0; ++ $self->{sy} = 0.0; ++ $self->{sy2} = 0.0; + } + +-sub lr_sample ++sub sample($$$) + { +- local($_x, $_y) = @_; +- +- &tagify($_[$[+2]) if defined($_[$[+2]); ++ my $self = shift; ++ my($_x, $_y) = @_; + +- $lr_n++; +- $lr_sx += $_x; +- $lr_sy += $_y; +- $lr_sxy += $_x * $_y; +- $lr_sx2 += $_x**2; +- $lr_sy2 += $_y**2; ++ ++($self->{n}); ++ $self->{sx} += $_x; ++ $self->{sy} += $_y; ++ $self->{sxy} += $_x * $_y; ++ $self->{sx2} += $_x**2; ++ $self->{sy2} += $_y**2; + } + +-sub lr_B ++sub B($) + { +- &tagify($_[$[]) if defined($_[$[]); ++ my $self = shift; + +- return 1 unless ($lr_n * $lr_sx2 - $lr_sx**2); +- return ($lr_n * $lr_sxy - $lr_sx * $lr_sy) / ($lr_n * $lr_sx2 - $lr_sx**2); ++ return 1 unless ($self->{n} * $self->{sx2} - $self->{sx}**2); ++ return ($self->{n} * $self->{sxy} - $self->{sx} * $self->{sy}) ++ / ($self->{n} * $self->{sx2} - $self->{sx}**2); + } + +-sub lr_A ++sub A($) + { +- &tagify($_[$[]) if defined($_[$[]); ++ my $self = shift; + +- return ($lr_sy - &lr_B * $lr_sx) / $lr_n; ++ return ($self->{sy} - B($self) * $self->{sx}) / $self->{n}; + } + +-sub lr_Y ++sub Y($$) + { +- &tagify($_[$[]) if defined($_[$[]); ++ my $self = shift; + +- return &lr_A + &lr_B * $_[$[]; ++ return A($self) + B($self) * $_[$[]; + } + +-sub lr_X ++sub X($$) + { +- &tagify($_[$[]) if defined($_[$[]); ++ my $self = shift; + +- return ($_[$[] - &lr_A) / &lr_B; ++ return ($_[$[] - A($self)) / B($self); + } + +-sub lr_r ++sub r($) + { +- &tagify($_[$[]) if defined($_[$[]); ++ my $self = shift; + +- local($s) = ($lr_n * $lr_sx2 - $lr_sx**2) * ($lr_n * $lr_sy2 - $lr_sy**2); ++ my $s = ($self->{n} * $self->{sx2} - $self->{sx}**2) ++ * ($self->{n} * $self->{sy2} - $self->{sy}**2); + + return 1 unless $s; + +- return ($lr_n * $lr_sxy - $lr_sx * $lr_sy) / sqrt($s); ++ return ($self->{n} * $self->{sxy} - $self->{sx} * $self->{sy}) / sqrt($s); + } + +-sub lr_cov ++sub cov($) + { +- &tagify($_[$[]) if defined($_[$[]); ++ my $self = shift; + +- return ($lr_sxy - $lr_sx * $lr_sy / $lr_n) / ($lr_n - 1); ++ return ($self->{sxy} - $self->{sx} * $self->{sy} / $self->{n}) ++ / ($self->{n} - 1); + } + +-sub lr_sigma ++sub sigma($) + { +- &tagify($_[$[]) if defined($_[$[]); ++ my $self = shift; + +- return 0 if $lr_n <= 1; +- return sqrt(($lr_sy2 - ($lr_sy * $lr_sy) / $lr_n) / ($lr_n)); ++ return 0 if $self->{n} <= 1; ++ return sqrt(($self->{sy2} - ($self->{sy} * $self->{sy}) / $self->{n}) ++ / ($self->{n})); + } + +-sub lr_mean ++sub mean($) + { +- &tagify($_[$[]) if defined($_[$[]); ++ my $self = shift; + +- return 0 if $lr_n <= 0; +- return $lr_sy / $lr_n; ++ return 0 if $self->{n} <= 0; ++ return $self->{sy} / $self->{n}; + } + +-&lr_init(); ++sub new ++{ ++ my $class = shift; ++ my $self = { ++ (n => undef, ++ sx => undef, ++ sx2 => undef, ++ sxy => undef, ++ sy => undef, ++ sy2 => undef) ++ }; ++ bless $self, $class; ++ init($self); ++ return $self; ++} + + 1; +Index: ntp.pl +=================================================================== +RCS file: /home/windl/NTP/mon-REP/monitoring/ntp.pl,v +retrieving revision 1.1.1.1 +retrieving revision 1.3 +diff -u -r1.1.1.1 -r1.3 +--- ntp.pl 1993/08/24 19:29:34 1.1.1.1 ++++ ntp.pl 1997/10/23 18:19:41 1.3 +@@ -1,4 +1,4 @@ +-#!/local/bin/perl ++#!/usr/bin/perl -w + ;# + ;# ntp.pl,v 3.1 1993/07/06 01:09:09 jbj Exp + ;# +@@ -43,7 +43,7 @@ + ;# N key + ;# N2 checksum + +-;# first bye of packet ++;# first byte of packet + sub pkt_LI { return ($_[$[] >> 6) & 0x3; } + sub pkt_VN { return ($_[$[] >> 3) & 0x7; } + sub pkt_MODE { return ($_[$[] ) & 0x7; } +@@ -223,6 +223,7 @@ + { + &getval(&psw_PSel($_[$[]),*PeerSelection); + } ++ + sub PeerEvent + { + &getval(&psw_PCode($_[$[]),*PeerEvent); +@@ -394,14 +395,14 @@ + $lastseen = 1 if !&pkt_M($r_e_m_op); + if (!defined(%FRAGS)) + { +- (&pkt_M($r_e_m_op) ? " more" : "")."\n"; ++ print((&pkt_M($r_e_m_op) ? " more" : "")."\n"); + $FRAGS{$offset} = $data; + ;# save other info + @FRAGS = ($status,$associd,&pkt_OP($r_e_m_op),$seq,$auth_keyid,$r_e_m_op); + } + else + { +- (&pkt_M($r_e_m_op) ? " more" : "")."\n"; ++ print((&pkt_M($r_e_m_op) ? " more" : "")."\n"); + ;# add frag to previous - combine on the fly + if (defined($FRAGS{$offset})) + { +Index: ntploopstat +=================================================================== +RCS file: /home/windl/NTP/mon-REP/monitoring/ntploopstat,v +retrieving revision 1.1.1.1 +retrieving revision 1.3 +diff -u -r1.1.1.1 -r1.3 +--- ntploopstat 1993/08/24 19:29:32 1.1.1.1 ++++ ntploopstat 1997/11/23 19:07:12 1.3 +@@ -1,4 +1,5 @@ +-#!/local/bin/perl -w--*-perl-*- ++#!/usr/bin/perl -w ++# --*-perl-*- + ;# + ;# ntploopstat,v 3.1 1993/07/06 01:09:11 jbj Exp + ;# +@@ -22,7 +23,7 @@ + ;# (Should have implemented &gettimeofday()..) + ;# + +-$0 =~ s!^.*/([^/]+)$!\1!; # beautify script name ++$0 =~ s!^.*/([^/]+)$!$1!; # beautify script name + + $ntpserver = 'localhost'; # default host to poll + $delay = 60; # default sampling rate +Index: ntploopwatch +=================================================================== +RCS file: /home/windl/NTP/mon-REP/monitoring/ntploopwatch,v +retrieving revision 1.1.1.1 +retrieving revision 1.14 +diff -u -r1.1.1.1 -r1.14 +--- ntploopwatch 1993/10/22 14:28:18 1.1.1.1 ++++ ntploopwatch 1997/12/07 17:06:36 1.14 +@@ -1,4 +1,5 @@ +-#!/local/bin/perl -w--*-perl-*- ++#!/usr/bin/perl -w ++#--*-perl-*- + ;# + ;# ntploopwatch,v 3.1 1993/07/06 01:09:13 jbj Exp + ;# +@@ -9,12 +10,17 @@ + ;# Copyright (c) 1992 + ;# Rainer Pruy Friedrich-Alexander Universitaet Erlangen-Nuernberg + ;# ++;# Copyright (c) 1997 ++;# Ulrich Windl <Ulrich.Windl@rz.uni-regensburg.de> ++;# (Corrections for Perl5 and other fixes) + ;# + ;############################################################# +-$0 =~ s!^.*/([^/]+)$!\1!; ++$0 =~ s!^.*/([^/]+)$!$1!; + $F = ' ' x length($0); + $|=1; + ++use 5.004; # require 5.004 ++ + $ENV{'SHELL'} = '/bin/sh'; # use bourne shell + + undef($config); +@@ -23,17 +29,17 @@ + undef($samples); + undef($StartTime); + undef($EndTime); +-($a,$b) if 0; # keep -w happy ++ + $usage = <<"E-O-P"; + usage: +- to watch statistics permanently: ++ to watch statistics periodically: + $0 [-v[<level>]] [-c <config-file>] [-d <working-dir>] + $F [-h <hostname>] + + to get a single print out specify also +- $F -P[<printer>] [-s<samples>] +- $F [-S <start-time>] [-E <end-time>] +- $F [-Y <MaxOffs>] [-y <MinOffs>] ++ $F -P[[<term_type:>]<printer>] ++ $F [-s<samples>] [-S <start-time>] [-E <end-time>] ++ $F [-Y <MaxOffs>] [-y <MinOffs>] + + If You like long option names, You can use: + -help +@@ -41,21 +47,28 @@ + -d +directory + -h +host + -v +verbose[=<level>] +- -P +printer[=<printer>] ++ -P +printer[=[<term_type>:]<printer>[:<print_cmd>]] + -s +samples[=<samples>] + -S +starttime + -E +endtime + -Y +maxy + -y +miny + ++If <printer> is prefixed with a <term_type> and a colon, the <term_type> ++given is used as terminal fpr gnuplot. + If <printer> contains a '/' (slash character) output is directed to + a file of this name instead of delivered to a printer. ++If suffix :<print_cmd> is given, the suffix is used as the print command, ++and <printer> is ignored. If blanks are needed inside <term_type> or ++<print_cmd>, just use underscores instead. + E-O-P + + ;# add directory to look for lr.pl and timelocal.pl (in front of current list) + unshift(@INC,"/src/NTP/v3/xntp/monitoring"); + + require "lr.pl"; # linear regresion routines ++my $lr_offs = new lr; ++my $lr_freq = new lr; + + $MJD_1970 = 40587; # from ntp.h (V3) + $RecordSize = 48; # usually a line fits into 42 bytes +@@ -171,16 +184,20 @@ + + ;# configuration file + $config = "loopwatch.config" unless defined($config); +-($STATHOST = $config) =~ s!.*loopwatch\.config.([^/\.]*)$!\1! ++($STATHOST = $config) =~ s!.*loopwatch\.config.([^/\.]+)$!$1! + unless defined($STATHOST); +-($STATTAG = $STATHOST) =~ s/^([^\.\*\s]+)\..*$/\1/; ++if ($STATHOST eq $config) { ++ require "hostname.pl"; ++ $STATHOST = hostname(); ++} ++($STATTAG = $STATHOST) =~ s/^([^\.\*\s]+)\..*$/$1/; + + $srcprefix =~ s/\$STATHOST/$STATHOST/g; + + ;# plot command +-@plotcmd=("gnuplot", +- '-title', "Ntp loop filter statistics $STATHOST", +- '-name', "NtpLoopWatch_$STATTAG"); ++@plotcmd=("gnuplot"); ++push(@plotcmd, '-title', "NTP loop filter statistics for $STATHOST", ++ '-name', "NtpLoopWatch_$STATTAG") unless $PrintIt; + $tmpfile = "/tmp/ntpstat.$$"; + + ;# other variables +@@ -211,9 +228,8 @@ + $?>>8,$? & 0xff)) if $?; + exit(1) if $? && defined($Plotpid) && $pid == $Plotpid; + } +-&sigchld if 0; +-$SIG{'CHLD'} = "sigchld"; +-$SIG{'CLD'} = "sigchld"; ++$SIG{'CHLD'} = \&sigchld; ++$SIG{'CLD'} = \&sigchld; + + sub abort + { +@@ -221,8 +237,7 @@ + defined($Plotpid) && kill('TERM',$Plotpid); + die("$0: received signal SIG$_[$[] - exiting\n"); + } +-&abort if 0; # make -w happy - &abort IS used +-$SIG{'INT'} = $SIG{'HUP'} = $SIG{'QUIT'} = $SIG{'TERM'} = $SIG{'PIPE'} = "abort"; ++$SIG{'INT'} = $SIG{'HUP'} = $SIG{'QUIT'} = $SIG{'TERM'} = $SIG{'PIPE'} = \&abort; + + ;# + sub abs +@@ -248,7 +263,7 @@ + open(STDOUT,">&STDERR") || + die("$0: failed to redirect STDOUT of plot command: $!\n"); + +- print STDOUT "plot command running as $$\n"; ++ print STDOUT "plot command has PID $$\n"; + + exec @plotcmd; + die("$0: failed to exec (@plotcmd): $!\n"); +@@ -275,128 +290,83 @@ + s/^([^\#]*[^\#\s]?)\s*\#.*$//; + next if /^\s*$/; + +- s/^\s*([^=\s]*)\s*=\s*(.*\S)\s*$/\1=\2/; ++ s/^\s*([^=\s]*)\s*=\s*(.*\S)\s*$/$1=$2/; + +- ($c,$v) = split(/=/,$_,2); ++ ($c,$v) = ($1, $2); + print "processing \"$c=$v\"\n" if $verbose > 3; +- ($c eq "delay") && ($delay = $v,1) && next; +- ($c eq 'samples') && (!defined($PrintIt) || !defined($samples)) && +- ($samples = $v,1) && next; +- ($c eq 'srcprefix') && (($srcprefix=$v)=~s/\$STATHOST/$STATHOST/g,1) +- && next; +- ($c eq 'showoffs') && +- ($showoffs = ($v eq 'yes' || $v eq 'y' || $v != 0),1) && next; +- ($c eq 'showfreq') && +- ($showfreq = ($v eq 'yes' || $v eq 'y' || $v != 0),1) && next; +- ($c eq 'showcmpl') && +- ($showcmpl = ($v eq 'yes' || $v eq 'y' || $v != 0),1) && next; +- ($c eq 'showoreg') && +- ($showoreg = ($v eq 'yes' || $v eq 'y' || $v != 0),1) && next; +- ($c eq 'showfreg') && +- ($showfreg = ($v eq 'yes' || $v eq 'y' || $v != 0),1) && next; +- +- ($c eq 'exit') && (unlink($tmpfile),die("$0: exit by config request\n")); +- +- ($c eq 'freqbase' || +- $c eq 'cmplscale') && +- do { +- if (! defined($v) || $v eq "" || $v eq 'dynamic') +- { +- eval "undef(\$$c);"; +- } +- else +- { +- eval "\$$c = \$v;"; +- } +- next; +- }; +- ($c eq 'timebase') && +- do { +- if (! defined($v) || $v eq "" || $v eq "dynamic") +- { +- undef($timebase); +- } +- else +- { +- $timebase=&date_time_spec2seconds($v); +- } +- }; +- ($c eq 'EndTime') && +- do { +- next if defined($EndTime) && defined($PrintIt); +- if (! defined($v) || $v eq "" || $v eq "none") +- { +- undef($EndTime); +- } +- else +- { +- $EndTime=&date_time_spec2seconds($v); +- } +- }; +- ($c eq 'StartTime') && +- do { +- next if defined($StartTime) && defined($PrintIt); +- if (! defined($v) || $v eq "" || $v eq "none") +- { +- undef($StartTime); +- } +- else +- { +- $StartTime=&date_time_spec2seconds($v); +- } +- }; +- +- ($c eq 'MaxY') && +- do { +- next if defined($MaxY) && defined($PrintIt); +- if (! defined($v) || $v eq "" || $v eq "none") +- { +- undef($MaxY); +- } +- else +- { +- $MaxY=$v; +- } +- }; +- +- ($c eq 'MinY') && +- do { +- next if defined($MinY) && defined($PrintIt); +- if (! defined($v) || $v eq "" || $v eq "none") +- { +- undef($MinY); +- } +- else +- { +- $MinY=$v; +- } +- }; +- +- ($c eq 'deltaT') && +- do { +- if (!defined($v) || $v eq "") +- { +- undef($deltaT); +- } +- else +- { +- $deltaT = $v; +- } +- next; +- }; +- ($c eq 'verbose') && ! defined($PrintIt) && +- do { +- if (!defined($v) || $v == 0) +- { +- $verbose = 0; +- } +- else +- { +- $verbose = $v; +- } +- next; +- }; +- ;# otherwise: silently ignore unrecognized config line ++ if ($c eq "delay") { ++ $delay = $v; ++ } elsif ($c eq 'samples') { ++ $samples = $v if (!defined($PrintIt) || !defined($samples)); ++ } elsif ($c eq 'srcprefix') { ++ ($srcprefix = $v) =~ s/\$STATHOST/$STATHOST/g; ++ } elsif ($c eq 'showoffs') { ++ $showoffs = ($v =~ /^yes$|^y$|^1$/); ++ } elsif ($c eq 'showfreq') { ++ $showfreq = ($v =~ /^yes$|^y$|^1$/); ++ } elsif ($c eq 'showcmpl') { ++ $showcmpl = ($v =~ /^yes$|^y$|^1$/); ++ } elsif ($c eq 'showoreg') { ++ $showoreg = ($v =~ /^yes$|^y$|^1$/); ++ } elsif ($c eq 'showfreg') { ++ $showfreg = ($v =~ /^yes$|^y$|^1$/); ++ } elsif ($c eq 'exit') { ++ unlink($tmpfile); die("$0: exit by config request\n"); ++ } elsif ($c eq 'freqbase' || $c eq 'cmplscale') { ++ if (! defined($v) || $v eq "" || $v eq 'dynamic') { ++ eval "undef(\$$c);"; ++ } else { ++ eval "\$$c = \$v;"; ++ } ++ } elsif ($c eq 'timebase') { ++ if (! defined($v) || $v eq "" || $v eq "dynamic") { ++ undef($timebase); ++ } else { ++ $timebase=&date_time_spec2seconds($v); ++ } ++ } elsif ($c eq 'EndTime') { ++ next if defined($EndTime) && defined($PrintIt); ++ if (! defined($v) || $v eq "" || $v eq "none") { ++ undef($EndTime); ++ } else { ++ $EndTime=&date_time_spec2seconds($v); ++ } ++ } elsif ($c eq 'StartTime') { ++ next if defined($StartTime) && defined($PrintIt); ++ if (! defined($v) || $v eq "" || $v eq "none") { ++ undef($StartTime); ++ } else { ++ $StartTime=&date_time_spec2seconds($v); ++ } ++ } elsif ($c eq 'MaxY') { ++ next if defined($MaxY) && defined($PrintIt); ++ if (! defined($v) || $v eq "" || $v eq "none") { ++ undef($MaxY); ++ } else { ++ $MaxY=$v; ++ } ++ } elsif ($c eq 'MinY') { ++ next if defined($MinY) && defined($PrintIt); ++ if (! defined($v) || $v eq "" || $v eq "none") { ++ undef($MinY); ++ } else { ++ $MinY=$v; ++ } ++ } elsif ($c eq 'deltaT') { ++ if (!defined($v) || $v eq "") { ++ undef($deltaT); ++ } else { ++ $deltaT = $v; ++ } ++ } elsif ($c eq 'verbose' && ! defined($PrintIt)) { ++ if (!defined($v) || $v == 0) { ++ $verbose = 0; ++ } else { ++ $verbose = $v; ++ } ++ } else { ++ ;# otherwise: silently ignore unrecognized config line ++ } + } + close(CF); + ;# set show defaults when nothing selected +@@ -413,16 +383,16 @@ + print " showcmpl\t= $showcmpl\n"; + print " showoreg\t= $showoreg\n"; + print " showfreg\t= $showfreg\n"; +- printf " timebase\t= %s",defined($timebase)?&ctime($timebase):"dynamic\n"; +- printf " freqbase\t= %s\n",defined($freqbase) ?"$freqbase":"dynamic"; +- printf " cmplscale\t= %s\n",defined($cmplscale)?"$cmplscale":"dynamic"; +- printf " StartTime\t= %s",defined($StartTime)?&ctime($StartTime):"none\n"; +- printf " EndTime\t= %s", defined($EndTime) ? &ctime($EndTime):"none\n"; +- printf " MaxY\t= %s",defined($MaxY)? $MaxY :"none\n"; +- printf " MinY\t= %s",defined($MinY)? $MinY :"none\n"; ++ printf " timebase\t= %s", defined($timebase) ? &ctime($timebase) : "dynamic\n"; ++ printf " freqbase\t= %s\n", defined($freqbase) ? "$freqbase" : "dynamic"; ++ printf " cmplscale\t= %s\n", defined($cmplscale) ? "$cmplscale" : "dynamic"; ++ printf " StartTime\t= %s", defined($StartTime) ? &ctime($StartTime) : "none\n"; ++ printf " EndTime\t= %s", defined($EndTime) ? &ctime($EndTime):"none\n"; ++ printf " MaxY\t= %s", defined($MaxY) ? $MaxY : "none\n"; ++ printf " MinY\t= %s", defined($MinY) ? $MinY : "none\n"; + print " verbose\t= $verbose\n"; + } +-print "configuration file read\n" if $verbose > 2; ++ print "configuration file read\n" if $verbose > 2; + } + + sub make_doplot +@@ -443,10 +413,9 @@ + ;# number of integral seconds to get at least 12 tic marks on x axis + $t = int(($maxtime - $mintime) / 12 + 0.5); + $t = 1 unless $t; # prevent $t to be zero +- foreach $i (30, +- 60,5*60,15*60,30*60, +- 60*60,2*60*60,6*60*60,12*60*60, +- 24*60*60,48*60*60) ++ foreach $i (30, 60, ++ 5*60, 10*60, 15*60, 30*60, 60*60, ++ 2*60*60, 6*60*60, 12*60*60, 24*60*60, 48*60*60) + { + last if $t < $i; + $t = $t - ($t % $i); +@@ -458,31 +427,30 @@ + $i <= $maxtime + $t; + $i += $t, $c=",") + { ++ my ($sec, $min, $hour, $mday, $mon, $year, $wday) = localtime($i); ++ + $s .= $c; + ((int($i / $t) % 2) && + ($s .= sprintf("'' %lf",($i - $LastTimeBase)/3600))) || + (($t <= 60) && + ($s .= sprintf("'%d:%02d:%02d' %lf", +- (localtime($i))[$[+2,$[+1,$[+0], +- ($i - $LastTimeBase)/3600))) ++ $hour, $min, $sec, ($i - $LastTimeBase) / 3600))) + || (($t <= 2*60*60) && + ($s .= sprintf("'%d:%02d' %lf", +- (localtime($i))[$[+2,$[+1], +- ($i - $LastTimeBase)/3600))) ++ $hour, $min, ($i - $LastTimeBase) / 3600))) + || (($t <= 12*60*60) && + ($s .= sprintf("'%s %d:00' %lf", +- $Day[(localtime($i))[$[+6]], +- (localtime($i))[$[+2], +- ($i - $LastTimeBase)/3600))) ++ $Day[$wday], $hour, ++ ($i - $LastTimeBase) / 3600))) + || ($s .= sprintf("'%d.%d-%d:00' %lf", +- (localtime($i))[$[+3,$[+4,$[+2], +- ($i - $LastTimeBase)/3600)); ++ $mday, $mon + 1, $hour, ++ ($i - $LastTimeBase) / 3600)); + } + $doplot .= "set xtics ($s)\n"; + + chop($xts = &ctime($mintime)); + chop($xte = &ctime($maxtime)); +- $doplot .= "set xlabel 'Start: $xts -- Time Scale -- End: $xte'\n"; ++ $doplot .= "set xlabel 'Start: $xts -- Time Scale -- End: $xte'\n"; + $doplot .= "set yrange [" ; + $doplot .= defined($MinY) ? sprintf("%lf", $MinY) : $miny; + $doplot .= ':'; +@@ -518,22 +486,22 @@ + $c = ","); + $showoreg && $showoffs && + ($doplot .= sprintf($regfmt, $c, +- &lr_B('offs'),&lr_A('offs'), +- "offset ", +- &lr_B('offs'), +- ((&lr_A('offs')) < 0 ? '-' : '+'), +- &abs(&lr_A('offs')), &lr_r('offs'), ++ $lr_offs->B(),$lr_offs->A(), ++ "offset", ++ $lr_offs->B(), ++ (($lr_offs->A()) < 0 ? '-' : '+'), ++ &abs($lr_offs->A()), $lr_offs->r(), + "[ms]"), + $c = ","); + $showfreg && $showfreq && + ($doplot .= sprintf($regfmt, $c, +- &lr_B('freq') * $FreqScale, +- (&lr_A('freq') + $minfreq) * $FreqScale - $LastFreqBase, ++ $lr_freq->B() * $FreqScale, ++ ($lr_freq->A() + $minfreq) * $FreqScale - $LastFreqBase, + "frequency", +- &lr_B('freq') * $FreqScale, +- ((&lr_A('freq') + $minfreq) * $FreqScale - $LastFreqBase) < 0 ? '-' : '+', +- &abs((&lr_A('freq') + $minfreq) * $FreqScale - $LastFreqBase), +- &lr_r('freq'), ++ $lr_freq->B() * $FreqScale, ++ (($lr_freq->A() + $minfreq) * $FreqScale - $LastFreqBase) < 0 ? '-' : '+', ++ &abs(($lr_freq->A() + $minfreq) * $FreqScale - $LastFreqBase), ++ $lr_freq->r(), + "[${FreqScaleInv}ppm]"), + $c = ","); + $doplot .= "\n"; +@@ -583,7 +551,7 @@ + $#loffset = $[ - 1; + $#filekey = $[ - 1; + print "memory allocation ready\n" if $verbose > 2; +- sleep(3) if $verbose > 1; ++ sleep(3) if $verbose > 2; + + if (index($in,"/") < $[) + { +@@ -606,7 +574,6 @@ + ;# rescan directory on changes + $Lsdir = $sdir; + $Ltime = (stat($sdir))[$[+9]; +- </X{> if 0; # dummy line - calm down my formatter + local(@newfiles) = < ${in}*[0-9] >; + local($st_dev,$st_ino,$st_mtime,$st_size,$name,$key,$modified); + +@@ -626,7 +593,7 @@ + $F_key{$name} = $key; + $modified++; + } +- if (!defined($F_name{$key}) || $F_name{$key} != $name) ++ if (!defined($F_name{$key}) || $F_name{$key} ne $name) + { + $F_name{$key} = $name; + $modified++; +@@ -643,9 +610,9 @@ + } + if ($modified) + { +- print "new data \"$name\" key: $key;\n" if $verbose > 1; ++ print "new data \"$name\" key: $key;\n" if $verbose > 2; + print " size: $st_size; mtime: $st_mtime;\n" +- if $verbose > 1; ++ if $verbose > 2; + $F_last{$key} = $F_first{$key} = $st_mtime; + $F_first{$key}--; # prevent zero divide later on + ;# now compute derivated attributes +@@ -692,7 +659,7 @@ + } + close(IN); + print(" first: ",$F_first{$key}, +- " last: ",$F_last{$key},"\n") if $verbose > 1; ++ " last: ",$F_last{$key},"\n") if $verbose > 2; + } + } + ;# now reclaim memory used for files no longer referenced ... +@@ -739,7 +706,7 @@ + } + ;# create list sorted by time + @F_files = sort {$F_first{$a} <=> $F_first{$b}; } keys(%F_name); +- if ($verbose > 1) ++ if ($verbose > 2) + { + print "Resulting file list:\n"; + foreach (@F_files) +@@ -797,7 +764,7 @@ + print "guess start according to StartTime ($StartTime)\n" + if $verbose > 3; + +- if ($fpos[$[] eq 'start') ++ if (defined $fpos[$[] && $fpos[$[] eq 'start') + { + if (grep($_ eq $fpos[$[+1],@f)) + { +@@ -1001,9 +968,9 @@ + $t += $F[$[+1]; # add seconds + fraction + + ;# multiply offset by 1000 to get ms - try to avoid float op +- (($F[$[+2] =~ s/(\d*)\.(\d{3})(\d*)/\1\2.\3/) && ++ (($F[$[+2] =~ s/(\d*)\.(\d{3})(\d*)/$1$2.$3/) && + $F[$[+2] =~ s/0+([\d\.])/($1 eq '.') ? '0.' : $1/e) # strip leading zeros +- || $F[$[+2] *= 1000; ++ || ($F[$[+2] *= 1000); + + + ;# skip samples out of specified time range +@@ -1036,8 +1003,8 @@ + print "input scanned ($l lines/",scalar(@time)," samples)\n" + if $verbose > 1; + +- &lr_init('offs'); +- &lr_init('freq'); ++ $lr_offs->init(); ++ $lr_freq->init(); + + if (@time) + { +@@ -1047,17 +1014,17 @@ + local($freqbase) unless defined($freqbase); + local($cmplscale) unless defined($cmplscale); + +- undef($mintime,$maxtime,$minoffs,$maxoffs, +- $minfreq,$maxfreq,$mincmpl,$maxcmpl, +- $miny,$maxy); ++ undef $mintime; undef $maxtime; undef $minoffs; undef $maxoffs; ++ undef $minfreq; undef $maxfreq; undef $mincmpl; undef $maxcmpl; ++ undef $miny; undef $maxy; + + print "computing ranges\n" if $verbose > 2; + + $LastCnt = @time; + + ;# @time is in ascending order (;-) +- $mintime = @time[$[]; +- $maxtime = @time[$#time]; ++ $mintime = $time[$[]; ++ $maxtime = $time[$#time]; + unless (defined($timebase)) + { + local($time,@X) = (time); +@@ -1081,24 +1048,24 @@ + ;# (otherwise a (shift(@a1),shift(a2)) would do), + ;# I dont like to make copies of these arrays as they may be huge + $i = $[; +- &lr_sample(($time[$i]-$timebase)/3600,$offs[$ + diff --git a/contrib/ntp/scripts/stats/README b/contrib/ntp/scripts/stats/README new file mode 100644 index 0000000..6808963 --- /dev/null +++ b/contrib/ntp/scripts/stats/README @@ -0,0 +1,39 @@ +Statistics processing scripts (README) + +This directory contains a number of scripts for use with the filegen +facility. Those files ending in .awk are for the Unix awk utility, while +those ending in .sh are for the csh utility. Normally, the summary.sh +script is called from a cron job once per day. This script processes the +daily loopstats, peerstats and clockstats files produced by the daemon, +updates the loop_summary, peer_summary and clock_summary archive files, +and deletes the daily files. + +In the case of the Austron 2201A GPS receiver, the clockstats file +contains a wealth of additional monitoring data. These data are summarized +and writted to the clock_summary file, then a series of special files are +constructed for later processing by the S utility. + +The summary.sh script invokes a number of awk scripts to actually produce +the data. This may result in multiple scans of the same input file. +The input file is deleted after processing. In fact, the shell scripts will +process all input files found of the correct type in chronological order, +deleting each one as it is scanned, except the current day file. + +The summary.sh script can produce input files for the S utility, if it +is found on the search path. This utility makes PostScript graphs of the +loopstats data for each day, as well as various statistics produced by +the Austorn 220aA GPS receiver. The S utility is automatically run +as a background job. Its control files have the .S extension. + +The psummary.awk script can be used to scan the peer_summary file and +construct an historical reprise of the daily summaries. + +The file formats are documented in the README.stats file and in the +scripts themselves. Further detail on the radio clock ASCII timecode +formats and related data are in the README.timecode file. + +David L. Mills +University of Delaware +mills@udel.edu +1 November 1993 +Revised 12 April 1994 diff --git a/contrib/ntp/scripts/stats/README.stats b/contrib/ntp/scripts/stats/README.stats new file mode 100644 index 0000000..aa8e77f --- /dev/null +++ b/contrib/ntp/scripts/stats/README.stats @@ -0,0 +1,246 @@ +Statistics file formats (README.stats) + +The xntp3 daemon can produce a variety of statistics files which are +useful for maintenance, evaluation and retrospective calibration +purposes. See the xntpd.8 man page for instructions on how to configure +this feature. Since these files can become rather large and cumbersome, +they are ordinarily reduced to summary form by running the summary.sh +shell script once per day, week or month, as appropriate. There are +three file collections presently defined: peerstats, loopstats and +clockstats, each of which is described in this note. + +peerstats + +The following data are collected in the peerstats files. The files are +reduced to summary data using the peer.sh shell script. See the peer.awk +script for further information. A line in the file is produced upon +reception of each valid update from a configured peer. + + 49236 30.756 140.173.96.1 9474 0.000603 0.37532 + + 49236 modified Julian day number + 30.756 time of day (s) past midnight UTC + 140.173.96.1 peer identifier (IP address or receiver identifier) + 9474 peer status word (hex) (see NTP specification) + 0.000603 offset (s) + 0.08929 delay (s) + 0.37532 dispersion (s) + +loopstats + +The following data are collected in the loopstats files. The files are +reduced to summary data using the loop.sh shell script. See the loop.awk +script for further information. A line in the file is produced at each +valid update of the local clock. + + 49236 11.897 -0.000004 -35.9384 0 + + 49236 modified Julian day number + 11.897 time of day (s) past midnight UTC + -0.000004 time offset (s) + -35.9384 frequency offset (ppm) + 0 phase-lock loop time constant + +clockstats + +The following data are collected in the clockstats files. The files are +reduced to summary data using the clock.sh shell script, which also +updates the ensemble, etf, itf and tdata data files as well. See the +clock.awk, ensemble.awk, etf.awk, itf.awk and tdta.awk scripts for +further information. A line in the file is produced at each valid update +received from a configured radio clock. Data are at present recorded for +several radios. The first part of each data line is similar for all +radios, e.g.: + + 49234 60517.826 127.127.4.1 93 247 16:48:21.814 + + 49234 modified Julian day number + 60517.826 time of day (s) past midnight UTC + 127.127.4.1 receiver identifier (Spectracom 8170/Netclock-2) + 93 247 16:48:21.814 timecode (format varies) + +In the case of the Austron GPS receiver, a good deal of additional +information is extracted from the radio, as described below. The formats +shown consist of one line with all the fields shown in order. The +timecode formats specific to each radio follow. See the file +README.timecodes for detailed information on the timecode formats used +by these radios. + +Spectracom 8170/Netclock-2 WWVB receiver + + 49234 60517.826 127.127.4.1 ?A93 247 16:48:21.814 + + The '?' and 'A' characters are present only when the receiver is + unsynchronized; otherwise, they are replaced by space ' ' characters. + +IRIG audio decoder + + 49234 60517.826 127.127.6.0 247 16:48:21? + + The '?' character is present only when the receiver is unsynchronized. + +Austron 2200A/2201A GPS receiver + + 49234 60580.843 127.127.10.1 93:247:16:49:24.814? + + The '?' character is present only when the receiver is unsynchronized. + +Depending on the installed options, the Austron 2200A/2201A recognizes a +number of special commands that report various data items. See the +refclock_as2201.c source module for a list of the commands used. These +data are collected only if the following line is included in the +configuration file ntp.conf: + + fudge 127.127.10.1 flag4 1 # enable extended statistics collection + +The format of each data line returned is summarized in the following +list. + +External time/frequency data (requires input buffer option IN) + +These data determine the deviations of external time/frequency inputs +relative to receiver oscillator time. The following data are typical +using an external cesium oscillator PPS and 5-MHz outputs. + + 49234 60580.843 127.127.10.1 93:247:16:49:24.814 ETF + + -85.9 time interval (ns) + -89.0 average time interval (ns) + 4.0 time interval sigma (ns) + +1.510E-11 time interval rate + -4.500E-11 deltaf/f + +1.592E-11 average deltaf/f + 5.297E-13 sigma deltaf/f + 500 number of samples + +Model and option identifiers + +These data show the receiver model number and option configuration. + + 49234 60708.848 127.127.10.1 93:247:16:51:32.817 ID;OPT;VER + + GPS 2201A model ident (must be "GPS 2200A" or "GPS 2201A") + TTY1 rs232 option present (required) + TC1 IRIG option present (optional) + LORAN LORAN assist option present (optional) + IN input buffer option present (optional) + OUT1 output buffer option present (required) + B.00 data processor software version ("B.00" or later) + B.00 signal processor software version ("B.00" or later) + 28-Apr-93 software version date ("28-Apr-93" or later) + +Internal time/frequency data + +These data determine the deviations of the receiver oscillator with +respect to satellite time. + + 49234 60564.846 127.127.10.1 93:247:16:49:08.816 ITF + + COCO current mode (must be "COCO") + 0 code coast mode (must be zero) + +6.6152E-08 code sigma (s) + -3.5053E-08 code delta t (s) + -4.0361E-11 deltat/t + -6.4746E-11 oscillator ageing rate + 500.00 loop time constant + 4.984072 electrical tuning (V) + +GPS/LORAN ensemble data (requires LORAN assist option LORAN) + +These data determine the deviations and weights to calculate ensemble +time from GPS and LORAN data. + + 49234 60596.852 127.127.10.1 93:247:16:49:40.812 LORAN ENSEMBLE + + +9.06E-08 GPS t (s) + +3.53E-08 GPS sigma (s) + .532 GPS weight + +3.71E-08 LORAN t (s) + +3.76E-08 LORAN sigma (s) + .468 LORAN weight + +6.56E-08 ensemble t + +6.94E-08 ensemble sigma (s) + +LORAN stationkeeping data (requires LORAN assist option LORAN) + +These data determine which stations of the LORAN chain are being +tracked, together with individual signal/noise ratios, deviations and +weights. + + 49234 60532.850 127.127.10.1 93:247:16:48:36.820 LORAN TDATA + + M station identifier; data follows + OK status (must be "OK" for tracking) + 0 cw flag + 0 sw flag + 1162.17 time of arrival + -4.6 snr (-30.0 if not "OK" status) + 1.67E-07 2-sample phase-time deviation + .507 weight (included only if "OK" status) + W AQ 0 0 3387.80 -31.0 station identifier and data + X OK 0 0 1740.27 -11.2 2.20E-07 .294 station identifier and data + Y OK 0 0 2180.71 -4.6 2.68E-07 .198 station identifier and data + Z CV 0 0 3392.94 -30.0 station identifier and data + +Oscillator status and environment + +These data determine the receiver oscillator type, mode, status and +environment. Nominal operating conditions are shown below. + + 49234 60628.847 127.127.10.1 93:247:16:50:12.817 OSC;ET;TEMP + + 1121 Software Control oscillator model and mode (must be + "Software Control") + Locked status (must be "Locked") + 4.979905 electrical tuning (V) + 44.81 oscillator cavity temperature + +Receiver position, status and offsets + +These data determine the receiver position and elevation, together with +programmable delay corrections for the antenna cable and receiver. + + 49234 60788.847 127.127.10.1 93:247:16:52:52.817 POS;PPS;PPSOFF + + +39:40:48.425 receiver latitude (N) + -075:45:02.392 receiver longitude (E) + +74.09 receiver elevation (m) + Stored position status (must be "Stored") + UTC PPS/PPM alignment (must be "UTC") + 0 receiver delay (ns) (should be zero for calibrated + receiver) + 200 cable delay (ns) + 0 user time bias (ns) (must be zero) + +Satellite tracking status + +These data determine how many satellites are being tracked. At the +present state of constellation development, there should be at least +three visible satellites in view. Much of the time the maximum of +seven are being tracked; rarely this number drops to two. + + 49234 60612.850 127.127.10.1 93:247:16:49:56.820 TRSTAT + + 24 T satellite prn and status (T = track, A = acquire) + 16 A 13 T 20 T 18 T 07 T 12 T list continued + +UTC leap-second information + +These data determine when the next leap second is to occur. The exact +method to use is obscure. + + 49234 60548.847 127.127.10.1 93:247:16:48:52.818 UTC + + -1.2107E-08 A0 term (s) + -1.2790E-13 A1 term (s) + +9.0000E+00 current leap seconds (s) + +2.0480E+05 time for leap seconds (s) + +2.0100E+02 week number for delta leap (weeks) + +1.9100E+02 week number for future leap (weeks) + +4.0000E+00 day number for future leap (days) + +9.0000E+00 future leap seconds (s) + +David L. Mills +University of Delaware +mills@udel.edu +23 October 1993 diff --git a/contrib/ntp/scripts/stats/README.timecodes b/contrib/ntp/scripts/stats/README.timecodes new file mode 100644 index 0000000..00b5ba5 --- /dev/null +++ b/contrib/ntp/scripts/stats/README.timecodes @@ -0,0 +1,149 @@ +Radio Timecode Formats (README.timecodes) + +Following are examples of the serial timecode formats used by various +timecode receivers as given in the instruction manuals. These examples +are intended only for illustration and not as the basis of system +design. The following symbols are used to identify the timecode +character that begins a subfield. The values given after this symbol +represent the character offset from the beginning of the timecode string +as edited to remove control characters. + +C on-time character (start bit) +Y year of century +T time of day +D day of year or month/day +A alarm indicator (format specific) +Q quality indicator (format specific) +<LF> ASCII line feed (hex 0a) +<CR> ASCII carriage return (hex 0d) +<SP> ASCII space (hex 20) + +In order to promote uniform behavior in the various implementations, it +is useful to have a common interpretation of alarm conditions and signal +quality. When the alarm indicator it on, the receiver is not operating +correctly or has never synchronized to the broadcast signal. When the +alarm indicator is off and the quality indicator is on, the receiver has +synchronized to the broadcast signal, then lost the signal and is +coasting on its internal oscillator. + +In the following uppercase letters, punctuation marks and spaces <SP> +stand for themselves; lowercase letters stand for fields as described. +Special characters other than <LF>, <CR> and <SP> are preceded by ^. + +Spectracom 8170 and Netclock/2 WWV Synchonized Clock (format 0) + +"<CR><LF>i ddd hh:mm:ss TZ=zz<CR><LF>" + C A D T + + poll: ?; offsets: Y = none, D = 3, T = 7, A = 0, Q = none + i = synchronization flag (<SP> = in synch, ? = out synch) + ddd = day of year + hh:mm:ss = hours, minutes, seconds + zz = timezone offset (hours from UTC) + + Note: alarm condition is indicated by other than <SP> at A, which + occurs during initial synchronization and when received signal has + been lost for about ten hours + + example: " 216 15:36:43 TZ=0" + A D T + +Netclock/2 WWV Synchonized Clock (format 2) + +"<CR><LF>iqyy ddd hh:mm:ss.fff ld" + C AQY D T + + poll: ?; offsets: Y = 2, D = 5, T = 9, A = 0, Q = 1 + i = synchronization flag (<SP> = in synch, ? = out synch) + q = quality indicator (<SP> < 1ms, A < 10 ms, B < 100 ms, C < 500 + ms, D > 500 ms) + yy = year (as broadcast) + ddd = day of year + hh:mm:ss.fff = hours, minutes, seconds, milliseconds of day + l = leap-second warning (L indicates leap at end of month) + d = standard/daylight time indicator (<SP> standard, D daylight) + + Note: alarm condition is indicated by other than <SP> at A, which + occurs during initial synchronization and when received signal has + been lost for about ten hours; unlock condition is indicated by + other than <SP> at Q, with time since last lock indicated by the + letter code A < 13 min, B < 1.5 hr, C < 7 hr, D > 7 hr. + + example: " 92 216 15:36:43.640 D" + AQ D T + +TrueTime 468-DC Satellite Synchronized Clock (and other TrueTime +receivers) + +"<CR><LF><^A>ddd:hh:mm:ssq<CR>" + D T QC + + poll: none; offsets: Y = none, D = 0, T = 4, A = 12, Q = 12 + hh:mm:ss = hours, minutes, seconds + q = quality/alarm indicator (<SP> = locked, ? = alarm) + + Note: alarm condition is indicated by ? at A, which occurs during + initial synchronization and when received signal is lost for an + extended period; unlock condition is indicated by other than <SP> + at Q + + example: "216:15:36:43 " + D T Q + +Heath GC-1000 Most Accurate Clock (WWV/H) + +"<CR>hh:mm:ss.f dd/mm/yy<CR>" + C T A D + + poll: none; offsets: Y = none, D = 15, T = 0, A = 9, Q = none + hh:mm:ss = hours, minutes, seconds + f = deciseconds (? when out of spec) + dd/mm = day, month + yy = year of century (from DIPswitches) + + Note: 0?:??:??.? is displayed before synch is first established and + hh:mm:ss.? once synch is established and then lost again for about + a day. + + example: "15:36:43.6 04/08/91" + T A D Y + +PST/Traconex 1020 Time Source (WWV/H) (firmware revision V4.01) + +"frdzycchhSSFTttttuuxx<CR>" "ahh:mm:ss.fffs<CR>" "yy/dd/mm/ddd<CR>" + A Q T Y D + + poll: "QMQDQT"; offsets: Y = 0, D = 3 T = 1,, A = 11, Q = 13 + f = frequency enable (O = all frequencies enabled) + r = baud rate (3 = 1200, 6 = 9600) + d = features indicator (@ = month/day display enabled) + z = time zone (0 = UTC) + y = year (5 = 1991) + cc = WWV propagation delay (52 = 22 ms) + hh = WWVH propagation delay (81 = 33 ms) + SS = status (80 or 82 = operating correctly) + F = current receive frequency (1-5 = 2.5, 5, 10, 15, 20 MHz) + T = transmitter (C = WWV, H = WWVH) + tttt = time since last update (minutes) + uu = flush character (03 = ^C) + xx = 94 (unknown) (firmware revision X4.01.999 only) + + a = AM/PM indicator (A = AM, P = PM, <SP> - 24-hour format) + hh:mm:ss.fff = hours, minutes, seconds, milliseconds of day + s = daylight-saving indicator (<SP> standard, D daylight) + + yy = year of century (from DIPswitches) + dd/mm/ddd = day of month, month of year, day of year + + Note: The alarm condition is indicated by other than ? at A, which + occurs during initial synchronization and when received signal is + lost for an extended period. A receiver unlock condition is + indicated by other than "0000" in the tttt subfield at Q. + + example: "O3@055281824C00000394 91/08/04/216 15:36:43.640" + T Y D T + +David L. Mills +University of Delaware +mills@udel.edu +23 October 1993 diff --git a/contrib/ntp/scripts/stats/clock.awk b/contrib/ntp/scripts/stats/clock.awk new file mode 100755 index 0000000..ef62da9 --- /dev/null +++ b/contrib/ntp/scripts/stats/clock.awk @@ -0,0 +1,431 @@ +# awk program to scan clockstat files and report errors/statistics +# +# usage: awk -f check.awk clockstats +# +# This program works for the following radios: +# PST/Traconex 1020 WWV reciever +# Arbiter 1088 GPS receiver +# Spectracom 8170/Netclock-2 WWVB receiver +# IRIG audio decoder +# Austron 2200A/2201A GPS receiver (see README.austron file) +# +BEGIN { + etf_min = osc_vmin = osc_tmin = 1e9 + etf_max = osc_vmax = osc_tmax = -1e9 +} +# +# scan all records in file +# +{ + # + # select PST/Traconex WWV records + # 00:00:37.234 96/07/08/190 O6@0:5281825C07510394 + # + if (NF >= 4 && $3 == "127.127.3.1") { + if (substr($6, 14, 4) > "0010") + wwv_sync++ + if (substr($6, 13, 1) == "C") + wwv_wwv++ + if (substr($6, 13, 1) == "H") + wwv_wwvh++ + x = substr($6, 12, 1) + if (x == "1") + wwv_2.5++ + else if (x == "2") + wwv_5++ + else if (x == "3") + wwv_10++ + else if (x == "4") + wwv_15++ + else if (x == "5") + wwv_20++ + continue + } + # + # select Arbiter GPS records + # 96 190 00:00:37.000 0 V=08 S=44 T=3 P=10.6 E=00 + # N39:42:00.951 W075:46:54.880 210.55 2.50 0.00 + # + if (NF >= 4 && $3 == "127.127.11.1") { + if (NF > 8) { + arb_count++ + if ($7 != 0) + arb_sync++ + x = substr($10, 3, 1) + if (x == "0") + arb_0++ + else if (x == "1") + arb_1++ + else if (x == "2") + arb_2++ + else if (x == "3") + arb_3++ + else if (x == "4") + arb_4++ + else if (x == "5") + arb_5++ + else if (x == "6") + arb_6++ + } else if (NF == 8) { + arbn++ + arb_mean += $7 + arb_rms += $7 * $7 + if (arbn > 0) { + x = $7 - arb_val + arb_var += x * x + } + arb_val = $7 + } + continue + } + # + # select Spectracom WWVB records + # see summary for decode + # 96 189 23:59:32.248 D + # + if (NF >= 4 && $3 == "127.127.4.1") { + if ($4 == "SIGNAL" || NF > 7) + printf "%s\n", $0 + else { + wwvb_count++ + if ($4 ~ /\?/) + wwvb_x++ + else if ($4 ~ /A/) + wwvb_a++ + else if ($4 ~ /B/) + wwvb_b++ + else if ($4 ~ /C/) + wwvb_c++ + else if ($4 ~ /D/) + wwvb_d++ + } + continue + } + # + # select IRIG audio decoder records + # see summary for decode + # + if (NF >= 4 && $3 == "127.127.6.0") { + irig_count++ + if ($5 ~ /\?/) + irig_error++ + continue + } + # + # select Austron GPS LORAN ENSEMBLE records + # see summary for decode + # + else if (NF >= 13 && $6 == "ENSEMBLE") { + ensemble_count++ + if ($9 <= 0) + ensemble_badgps++ + else if ($12 <= 0) + ensemble_badloran++ + else { + if ($13 > 200e-9 || $13 < -200e-9) + ensemble_200++ + else if ($13 > 100e-9 || $13 < -100e-9) + ensemble_100++ + ensemble_mean += $13 + ensemble_rms += $13 * $13 + } + continue + } + # + # select Austron LORAN TDATA records + # see summary for decode; note that signal quality log is simply + # copied to output + # + else if (NF >= 7 && $6 == "TDATA") { + tdata_count++ + for (i = 7; i < NF; i++) { + if ($i == "M" && $(i+1) == "OK") { + i += 5 + m += $i + tdata_m++ + } + else if ($i == "W" && $(i+1) == "OK") { + i += 5 + w += $i + tdata_w++ + } + else if ($i == "X" && $(i+1) == "OK") { + i += 5 + x += $i + tdata_x++ + } + else if ($i == "Y" && $(i+1) == "OK") { + i += 5 + y += $i + tdata_y++ + } + else if ($i == "Z" && $(i+1) == "OK") { + i += 5 + z += $i + tdata_z++ + } + } + continue + } + # + # select Austron ITF records + # see summary for decode + # + else if (NF >= 13 && $5 == "ITF" && $12 >= 100) { + itf_count++ + if ($9 > 200e-9 || $9 < -200e-9) + itf_200++ + else if ($9 > 100e-9 || $9 < -100e-9) + itf_100++ + itf_mean += $9 + itf_rms += $9 * $9 + itf_var += $10 * $10 + continue + } + # + # select Austron ETF records + # see summary for decode + # + else if (NF >= 13 && $5 == "ETF" && $13 >= 100) { + etf_count++ + if ($6 > etf_max) + etf_max = $6 + else if ($6 < etf_min) + etf_min = $6 + etf_mean += $6 + etf_rms += $6 * $6 + etf_var += $9 * $9 + continue + } + # + # select Austron TRSTAT records + # see summary for decode + # + else if (NF >= 5 && $5 == "TRSTAT") { + trstat_count++ + j = 0 + for (i = 6; i <= NF; i++) + if ($i == "T") + j++ + trstat_sat[j]++ + continue + } + # + # select Austron ID;OPT;VER records + # + # config GPS 2201A TTY1 TC1 LORAN IN OUT1 B.00 B.00 28-Apr-93 + # + # GPS 2201A receiver model + # TTY1 rs232 moduel + # TC1 IRIG module + # LORAN LORAN assist module + # IN input module + # OUT1 output module + # B.00 B.00 firmware revision + # 28-Apr-9 firmware date3 + # + else if (NF >= 5 && $5 == "ID;OPT;VER") { + id_count++ + id_temp = "" + for (i = 6; i <= NF; i++) + id_temp = id_temp " " $i + if (id_string != id_temp) + printf "config%s\n", id_temp + id_string = id_temp + continue + } + # + # select Austron POS;PPS;PPSOFF records + # + # position +39:40:48.425 -075:45:02.392 +74.09 Stored UTC 0 200 0 + # + # +39:40:48.425 position north latitude + # -075:45:02.392 position east longitude + # +74.09 elevation (meters) + # Stored position is stored + # UTC time is relative to UTC + # 0 200 0 PPS offsets + # + else if (NF >= 5 && $5 == "POS;PPS;PPSOFF") { + pos_count++ + pos_temp = "" + for (i = 6; i <= NF; i++) + pos_temp = pos_temp " " $i + if (pos_string != pos_temp) + printf "position%s\n", pos_temp + pos_string = pos_temp + continue + } + # + # select Austron OSC;ET;TEMP records + # + # loop 1121 Software Control Locked + # + # 1121 oscillator type + # Software Control loop is under software control + # Locked loop is locked + # + else if (NF >= 5 && $5 == "OSC;ET;TEMP") { + osc_count++ + osc_temp = $6 " " $7 " " $8 " " $9 + if (osc_status != osc_temp) + printf "loop %s\n", osc_temp + osc_status = osc_temp + if ($10 > osc_vmax) + osc_vmax = $10 + if ($10 < osc_vmin) + osc_vmin = $10 + if ($11 > osc_tmax) + osc_tmax = $11 + if ($11 < osc_tmin) + osc_tmin = $11 + continue + } + # + # select Austron UTC records + # these ain't ready yet + # + else if (NF >= 5 && $5 == "UTC") { + utc_count++ + utc_temp = "" + for (i = 6; i <= NF; i++) + utc_temp = utc_temp " " $i + if (utc_string != utc_temp) +# printf "utc%s\n", utc_temp + utc_string = utc_temp + continue + } +} END { +# +# PST/Traconex WWV summary data +# + if (wwv_wwv + wwv_wwvh > 0) + printf "wwv %d, wwvh %d, err %d, MHz (2.5) %d, (5) %d, (10) %d, (15) %d, (20) %d\n", wwv_wwv, wwv_wwvh, wwv_sync, wwv_2.5, wwv_5, wwv_10, wwv_15, wwv_20 +# +# Arbiter 1088 summary data +# +# gps record count +# err error count +# sats(0-6) satellites tracked +# mean 1 PPS mean (us) +# rms 1 PPS rms error (us) +# var 1 PPS Allan variance +# + if (arb_count > 0) { + printf "gps %d, err %d, sats(0-6) %d %d %d %d %d %d %d", arb_count, arb_sync, arb_0, arb_1, arb_2, arb_3, arb_4, arb_5, arb_6 + if (arbn > 1) { + arb_mean /= arbn + arb_rms = sqrt(arb_rms / arbn - arb_mean * arb_mean) + arb_var = sqrt(arb_var / (2 * (arbn - 1))) + printf ", mean %.2f, rms %.2f, var %.2e\n", arb_mean, arb_rms, arb_var * 1e-6 + } else { + printf "\n" + } + } +# +# ensemble summary data +# +# ensemble record count +# badgps gps data unavailable +# badloran loran data unavailable +# rms ensemble rms error (ns) +# >200 ensemble error >200 ns +# >100 100 ns < ensemble error < 200 ns +# + if (ensemble_count > 0) { + ensemble_mean /= ensemble_count + ensemble_rms = sqrt(ensemble_rms / ensemble_count - ensemble_mean * ensemble_mean) * 1e9 + printf "ensemble %d, badgps %d, badloran %d, rms %.1f, >200 %d, >100 %d\n", ensemble_count, ensemble_badgps, ensemble_badloran, ensemble_rms, ensemble_200, ensemble_100 + } +# +# wwvb summary data +# +# wwvb record count +# ? unsynchronized +# >1 error > 1 ms +# >10 error > 10 ms +# >100 error > 100 ms +# >500 error > 500 ms +# + if (wwvb_count > 0) + printf "wwvb %d, ? %d, >1 %d, >10 %d, >100 %d, >500 %d\n", wwvb_count, wwvb_x, wwvb_a, wwvb_b, wwvb_c, wwvb_d +# +# irig summary data +# +# irig record count +# err error count +# + if (irig_count > 0) + printf "irig %d, err %d\n", irig_count, irig_error +# +# tdata summary data +# +# tdata record count +# m M master OK-count, mean level (dB) +# w W slave OK-count, mean level (dB) +# x X slave OK-count, mean level (dB) +# y Y slave OK-count, mean level (dB) +# z Z slave OK-count, mean level (dB) +# + if (tdata_count > 0 ) { + if (tdata_m > 0) + m /= tdata_count + if (tdata_x > 0) + w /= tdata_count + if (tdata_x > 0) + x /= tdata_count + if (tdata_y > 0) + y /= tdata_count + if (tdata_z > 0) + z /= tdata_count + printf "tdata %d, m %d %.1f, w %d %.1f, x %d %.1f, y %d %.1f, z %d %.1f\n", tdata_count, tdata_m, m, tdata_w, w, tdata_x, x, tdata_y, y, tdata_z, z + } +# +# itf summary data +# +# itf record count +# rms itf rms error (ns) +# >200 itf error > 200 ns +# >100 itf error > 100 ns +# var Allan variance +# + if (itf_count > 1) { + itf_mean /= itf_count + itf_rms = sqrt(itf_rms / itf_count - itf_mean * itf_mean) * 1e9 + itf_var = sqrt(itf_var / (2 * (itf_count - 1))) + printf "itf %d, rms %.1f, >200 %d, >100 %d, var %.2e\n", itf_count, itf_rms, itf_200, itf_100, itf_var + } +# +# etf summary data +# +# etf record count +# mean etf mean (ns) +# rms etf rms error (ns) +# max etf maximum (ns) +# min etf minimum (ns) +# var Allan variance +# + if (etf_count > 0) { + etf_mean /= etf_count + etf_rms = sqrt(etf_rms / etf_count - etf_mean * etf_mean) + etf_var = sqrt(etf_var / (2 * (etf_count - 1))) + printf "etf %d, mean %.1f, rms %.1f, max %d, min %d, var %.2e\n", etf_count, etf_mean, etf_rms, etf_max, etf_min, etf_var + } +# +# trstat summary data +# +# trstat record count +# sat histogram of tracked satellites (0 - 7) +# + if (trstat_count > 0) + printf "trstat %d, sat %d %d %d %d %d %d %d %d\n", trstat_count, trstat_sat[0], trstat_sat[1], trstat_sat[2], trstat_sat[2], trstat_sat[3], trstat_sat[4], trstat_sat[5], trstat_sat[6], trstat_sat[7] +# +# osc summary data +# +# osc record count +# control control midrange (V) +/- deviation (mV) +# temp oven temperature midrange +/- deviation (deg C) +# + if (osc_count > 0) + printf "osc %d, control %.3f+/-%.3f, temp %.1f+/-%.2f\n", osc_count, (osc_vmax + osc_vmin) / 2, (osc_vmax - osc_vmin) / 2 * 1e3, (osc_tmax + osc_tmin) / 2, (osc_tmax - osc_tmin) / 2 +} diff --git a/contrib/ntp/scripts/stats/dupe.awk b/contrib/ntp/scripts/stats/dupe.awk new file mode 100755 index 0000000..317c2a4 --- /dev/null +++ b/contrib/ntp/scripts/stats/dupe.awk @@ -0,0 +1,8 @@ +# +# delete duplicate lines +# +{ + if (old != $0) + printf "%s\n", $0 + old = $0 +} diff --git a/contrib/ntp/scripts/stats/ensemble.S b/contrib/ntp/scripts/stats/ensemble.S new file mode 100755 index 0000000..32a4dba --- /dev/null +++ b/contrib/ntp/scripts/stats/ensemble.S @@ -0,0 +1,5 @@ +ensemble <- scan(file1, list(day=0, sec=0, gps=0, gpsw=0, loran=0, loranw=0, ensemble=0, std=0)) +str <- paste("eps/", file1, ".eps", sep="") +postscript(str, , , , 5, pointsize=18) +par(mgp=c(1, 0, 0), tck = 0.03, mar = c(2, 2, 1, 1)) +plot(ensemble$sec, ensemble$ensemble, type="l", xlab=paste("MJD", ensemble$day, "Time (s)"), ylab="Ensemble Offset (ns)", ylim=c(-400, 400)) diff --git a/contrib/ntp/scripts/stats/ensemble.awk b/contrib/ntp/scripts/stats/ensemble.awk new file mode 100755 index 0000000..136b33d --- /dev/null +++ b/contrib/ntp/scripts/stats/ensemble.awk @@ -0,0 +1,17 @@ +# program to produce loran ensemble statistics from clockstats files +# +# usage: awk -f ensemble.awk clockstats +# +# format of input record (time values in seconds) +# 49165 8.628 127.127.10.1 93:178:00:00:07.241 LORAN ENSEMBLE +# -6.43E-08 +5.02E-08 .091 +5.98E-08 +1.59E-08 .909 +4.85E-08 +3.52E-08 +# +# format of output record (time values in nanoseconds) +# MJD sec GPS wgt LORAN wgt avg sigma +# 49165 8.628 -64.3 0.091 59.8 0.909 48.5 35.2 +# +# select LORAN ENSEMBLE records with valid format and weights +{ + if (NF >= 14 && $6 == "ENSEMBLE" && $9 > 0 && $12 > 0) + printf "%5s %9.3f %7.1f %6.3f %7.1f %6.3f %7.1f %7.1f\n", $1, $2, $7*1e9, $9, $10*1e9, $12, $13*1e9, $14*1e9 +} diff --git a/contrib/ntp/scripts/stats/etf.S b/contrib/ntp/scripts/stats/etf.S new file mode 100755 index 0000000..9b9c68b --- /dev/null +++ b/contrib/ntp/scripts/stats/etf.S @@ -0,0 +1,15 @@ +options(digits=4) +file2 <- "etf_summary" +etf <- scan(file1, list(day=0, sec=0, offset=0, stab=0)) +r <- lsfit(etf$sec, etf$offset) +count<-length(etf$sec) +mean<-r$coef[[1]] +std<-sqrt(var(r$residuals)) +slope<-r$coef[[2]] * 1000 +cat("\n", file=file2 , append=TRUE, fill=FALSE, sep="") +cat(file1, "\n", file=file2, append=TRUE, fill=FALSE, sep="") +cat("etf1 ", count, ", T ", mean, " ns, R ", slope, " ps/s, std ", std, " us\n", file=file2, append=TRUE, fill=FALSE, sep="") +str <- paste("eps/", file1, ".eps", sep="") +postscript(str, , , , 5, pointsize=18) +par(mgp=c(1, 0, 0), tck=0.03, mar=c(2, 2, 1, 1)) +plot(etf$sec, etf$offset, type="l", xlab=paste("MJD", etf$day, "Time (s)"), ylab="External Offset (ns)", ylim=c(-400, 400)) diff --git a/contrib/ntp/scripts/stats/etf.awk b/contrib/ntp/scripts/stats/etf.awk new file mode 100755 index 0000000..8e6e334 --- /dev/null +++ b/contrib/ntp/scripts/stats/etf.awk @@ -0,0 +1,19 @@ +# program to produce external time/frequence statistics from clockstats files +# +# usage: awk -f etf.awk clockstats +# +# format of input record +# 49165 40.473 127.127.10.1 93:178:00:00:39.238 ETF +# +175.0 +176.8 2.0 +3.729E-11 +1.000E-10 +3.511E-11 4.005E-13 500 +# +# format of output record (time values in nanoseconds) +# MJD sec time freq +# 49165 40.473 175.0 3.729e-11 +# +# select ETF records with valid format +{ + if (NF >= 9 && $5 == "ETF") { + printf "%5s %9.3f %7.1f %10.3e\n", $1, $2, $6, $9 + } +} + diff --git a/contrib/ntp/scripts/stats/itf.S b/contrib/ntp/scripts/stats/itf.S new file mode 100755 index 0000000..56c8c8d --- /dev/null +++ b/contrib/ntp/scripts/stats/itf.S @@ -0,0 +1,5 @@ +itf <- scan(file1, list(day=0, sec=0, offset=0, stab=0)) +str <- paste("eps/", file1, ".eps", sep="") +postscript(str, , , , 5, pointsize=18) +par(mgp=c(1, 0, 0), tck=0.03, mar=c(2, 2, 1, 1)) +plot(itf$sec, itf$offset, type="l", xlab=paste("MJD", itf$day, "Time (s)"), ylab="Internal Offset (ns)", ylim=c(-400, 400)) diff --git a/contrib/ntp/scripts/stats/itf.awk b/contrib/ntp/scripts/stats/itf.awk new file mode 100755 index 0000000..2b21c5b --- /dev/null +++ b/contrib/ntp/scripts/stats/itf.awk @@ -0,0 +1,19 @@ +# program to produce intewrnal time/frequence statistics from clockstats files +# +# usage: awk -f itf.awk clockstats +# +# format of input record +# 49227 67.846 127.127.10.1 93:240:00:00:51.816 ITF +# COCO 0 +2.0579E-07 -3.1037E-08 -7.7723E-11 +6.5455E-10 500.00 4.962819 +# +# format of output record (time values in nanoseconds) +# MJD sec time freq +# 49227 67.846 +2.0579E-07 -7.7723E-11 +# +# select ITF records with valid format +{ + if (NF >= 10 && $5 == "ITF") { + printf "%5s %9.3f %7.1f %10.3e\n", $1, $2, $8 * 1e9, $10 + } +} + diff --git a/contrib/ntp/scripts/stats/loop.S b/contrib/ntp/scripts/stats/loop.S new file mode 100755 index 0000000..8e564b6 --- /dev/null +++ b/contrib/ntp/scripts/stats/loop.S @@ -0,0 +1,7 @@ +options(digits=4) +loop <- scan(file1, list(day=0, sec=0, offset=0, freq=0, tc=0)) +loop$offset <- loop$offset * 1e6 +str <- paste("eps/", file1, ".eps", sep="") +postscript(str, , , , 5, pointsize=18) +par(mgp=c(1, 0, 0), tck=0.03, mar=c(2, 2, 1, 1)) +plot(loop$sec, loop$offset, type="l", xlab=paste("MJD", loop$day, "Time (s)"), ylab="PLL Offset (us)", ylim=c(-400, 400)) diff --git a/contrib/ntp/scripts/stats/loop.awk b/contrib/ntp/scripts/stats/loop.awk new file mode 100755 index 0000000..bac90db --- /dev/null +++ b/contrib/ntp/scripts/stats/loop.awk @@ -0,0 +1,45 @@ +# awk program to scan loopstats files and report errors/statistics +# +# usage: awk -f loop.awk loopstats +# +# format of loopstats record +# MJD sec time (s) freq (ppm) poll +# 49235 3.943 0.000016 22.4716 6 +# +# format of output dataset (time values in milliseconds, freq in ppm) +# loopstats.19960706 +# loop 1180, 0+/-11.0, rms 2.3, freq -24.45+/-0.045, var 0.019 +# +BEGIN { + loop_tmax = loop_fmax = -1e9 + loop_tmin = loop_fmin = 1e9 +} +# +# scan all records in file +# +{ + if (NF >= 5) { + loop_count++ + if ($3 > loop_tmax) + loop_tmax = $3 + if ($3 < loop_tmin) + loop_tmin = $3 + if ($4 > loop_fmax) + loop_fmax = $4 + if ($4 < loop_fmin) + loop_fmin = $4 + loop_time += $3 + loop_time_rms += $3 * $3 + loop_freq += $4 + loop_freq_rms += $4 * $4 + } +} END { + if (loop_count > 0) { + loop_time /= loop_count + loop_time_rms = sqrt(loop_time_rms / loop_count - loop_time * loop_time) + loop_freq /= loop_count + loop_freq_rms = sqrt(loop_freq_rms / loop_count - loop_freq * loop_freq) + printf "loop %d, %.0f+/-%.1f, rms %.1f, freq %.2f+/-%0.3f, var %.3f\n", loop_count, (loop_tmax + loop_tmin) / 2 * 1e6, (loop_tmax - loop_tmin) / 2 * 1e6, loop_time_rms * 1e6, (loop_fmax + loop_fmin) / 2, (loop_fmax - loop_fmin) / 2, loop_freq_rms + } +} + diff --git a/contrib/ntp/scripts/stats/loop_summary b/contrib/ntp/scripts/stats/loop_summary new file mode 100755 index 0000000..35479ec --- /dev/null +++ b/contrib/ntp/scripts/stats/loop_summary @@ -0,0 +1,2 @@ + +loopstats.[1-9] diff --git a/contrib/ntp/scripts/stats/peer.awk b/contrib/ntp/scripts/stats/peer.awk new file mode 100755 index 0000000..5fe260e --- /dev/null +++ b/contrib/ntp/scripts/stats/peer.awk @@ -0,0 +1,68 @@ +# awk program to scan peerstats files and report errors/statistics +# +# usage: awk -f peer.awk peerstats +# +# format of peerstats record +# MJD sec ident stat offset (s) delay (s) disp (s) +# 49235 11.632 128.4.2.7 f414 -0.000041 0.21910 0.00084 +# +# format of output dataset (time values in milliseconds) +# peerstats.19960706 +# ident cnt mean rms max delay dist disp +# ========================================================================== +# 140.173.112.2 85 -0.509 1.345 4.606 80.417 49.260 1.092 +# 128.4.1.20 1364 0.058 0.364 4.465 3.712 10.540 1.101 +# 140.173.16.1 1415 -0.172 0.185 1.736 3.145 5.020 0.312 +#... +# +BEGIN { + n = 0 + MAXDISTANCE = 1.0 +} +# +# scan all records in file +# +# we toss out all distances greater than one second on the assumption the +# peer is in initial acquisition +# +{ + if (NF >= 7 && ($7 + $6 / 2) < MAXDISTANCE) { + i = n + for (j = 0; j < n; j++) { + if ($3 == peer_ident[j]) + i = j + } + if (i == n) { + peer_ident[i] = $3 + peer_tmax[i] = peer_dist[i] = -1e9 + peer_tmin[i] = 1e9 + n++ + } + peer_count[i]++ + if ($5 > peer_tmax[i]) + peer_tmax[i] = $5 + if ($5 < peer_tmin[i]) + peer_tmin[i] = $5 + dist = $7 + $6 / 2 + if (dist > peer_dist[i]) + peer_dist[i] = dist + peer_time[i] += $5 + peer_time_rms[i] += $5 * $5 + peer_delay[i] += $6 + peer_disp[i] += $7 + } +} END { + printf " ident cnt mean rms max delay dist disp\n" + printf "==========================================================================\n" + for (i = 0; i < n; i++) { + peer_time[i] /= peer_count[i] + peer_time_rms[i] = sqrt(peer_time_rms[i] / peer_count[i] - peer_time[i] * peer_time[i]) + peer_delay[i] /= peer_count[i] + peer_disp[i] /= peer_count[i] + peer_tmax[i] = peer_tmax[i] - peer_time[i] + peer_tmin[i] = peer_time[i] - peer_tmin[i] + if (peer_tmin[i] > peer_tmax[i]) + peer_tmax[i] = peer_tmin[i] + printf "%-15s%5d%9.3f%9.3f%9.3f%9.3f%9.3f%9.3f\n", peer_ident[i], peer_count[i], peer_time[i] * 1e3, peer_time_rms[i] * 1e3, peer_tmax[i] * 1e3, peer_delay[i] * 1e3, peer_dist[i] * 1e3, peer_disp[i] * 1e3 + } +} diff --git a/contrib/ntp/scripts/stats/psummary.awk b/contrib/ntp/scripts/stats/psummary.awk new file mode 100755 index 0000000..ec06b0c --- /dev/null +++ b/contrib/ntp/scripts/stats/psummary.awk @@ -0,0 +1,82 @@ +# program to scan peer_summary file and produce summary of daily summaries +# +# usage: awk -f psummary.awk peer_summary +# +# format of input records +# peerstats.19960706 +# ident cnt mean rms max delay dist disp +# ========================================================================== +# 140.173.112.2 85 -0.509 1.345 4.606 80.417 49.260 1.092 +# 128.4.1.20 1364 0.058 0.364 4.465 3.712 10.540 1.101 +# ... +# +# format of output records (actual data from rackety.udel.edu) +# host days mean rms max >1 >5 >10 >50 +# ================================================================== +# 127.127.22.1 1090 0.001 0.401 99.800 19 14 13 10 +# 127.0.0.1 1188 0.060 1.622 105.004 78 65 51 32 +# 127.127.4.1 586 0.000 0.000 0.000 0 0 0 0 +# 140.173.64.1 975 -0.010 2.552 257.595 399 192 114 8 +# 128.175.1.3 1121 0.447 8.637 204.123 479 460 397 147 +# 140.173.16.1 1106 0.027 1.014 267.857 242 38 31 23 +# 128.4.1.4 1119 0.023 1.037 267.748 223 41 34 23 +# 128.4.1.2 850 1.202 1.654 267.704 196 53 45 34 +# 128.4.1.20 1101 0.088 1.139 268.322 430 111 83 16 +# 140.173.32.1 979 -0.949 2.344 257.671 396 217 136 7 +# 140.173.112.2 1066 0.040 2.111 152.969 442 315 152 16 +# 140.173.80.1 1059 0.019 1.858 87.690 438 348 150 9 +# 140.173.96.1 1015 0.110 2.007 266.744 399 314 170 17 +# 140.173.128.1 1103 -0.002 2.600 257.672 465 262 132 13 +# 140.222.135.1 347 -4.626 8.804 196.394 135 135 134 95 +# 140.173.128.2 1081 -0.046 2.967 261.448 463 342 172 17 +# 140.222.141.1 354 0.820 8.809 195.333 142 141 139 100 +# 140.173.144.2 1058 -0.107 2.805 270.498 448 341 163 17 +# 140.222.134.1 354 -0.056 8.479 172.458 142 141 141 100 +# 140.222.144.1 415 -1.456 9.964 191.684 161 161 161 123 +# 140.222.136.1 234 0.902 7.707 182.431 62 62 62 48 +# 128.175.1.1 774 0.890 4.838 266.799 358 291 200 83 +# 127.127.10.1 1086 -0.002 1.462 231.128 240 239 60 57 +# 140.173.48.2 576 0.016 4.092 350.512 213 126 88 16 +# 128.4.1.11 3 0.000 0.000 0.000 0 0 0 0 +# 128.4.1.26 386 -1.363 20.251 341.284 164 164 161 132 +# +# select table beginning with "ident" +{ + if (NF < 8 || $1 == "ident") + continue + i = n + for (j = 0; j < n; j++) { + if ($1 == peer_ident[j]) + i = j + } + if (i == n) { + peer_ident[i] = $1 + n++ + } + peer_count[i]++ + if (($7 - $6 / 2) < 400) { + peer_count[i]++ + peer_mean[i] += $3 + peer_var[i] += $4 * $4 + if ($5 > peer_max[i]) + peer_max[i] = $5 + if ($5 > 1) + peer_1[i]++ + if ($5 > 5) + peer_2[i]++ + if ($5 > 10) + peer_3[i]++ + if ($5 > 50) + peer_4[i]++ + } +} END { + printf " host days mean rms max >1 >5 >10 >50\n" + printf "==================================================================\n" + for (i = 0; i < n; i++) { + if (peer_count[i] <= 0) + continue + peer_mean[i] /= peer_count[i] + peer_var[i] = sqrt(peer_var[i] / peer_count[i]) + printf "%-15s%4d%10.3f%10.3f%10.3f%4d%4d%4d%4d\n", peer_ident[i], peer_count[i], peer_mean[i], peer_var[i], peer_max[i], peer_1[i], peer_2[i], peer_3[i], peer_4[i] + } +} diff --git a/contrib/ntp/scripts/stats/summary.sh b/contrib/ntp/scripts/stats/summary.sh new file mode 100755 index 0000000..655c4be --- /dev/null +++ b/contrib/ntp/scripts/stats/summary.sh @@ -0,0 +1,88 @@ +#!/bin/sh +# +# Script to summarize ipeerstats, loopstats and clockstats files +# +# This script can be run from a cron job once per day, week or month. It +# runs the file-specific summary script and appends the summary data to +# designated files. +# +DATE=`date +19%y%m%d` +S=/usr/local/bin/S +SIN=S.in +SOUT=S.out +LOOP=loop_summary +PEER=peer_summary +CLOCK=clock_summary + +rm -f $SIN $SOUT + +# +# Summarize loopstats files +# +for f in loopstats.[12][0-9][0-9][0-9][0-1][0-9][0-3][0-9]; do + d=`echo $f | cut -f2 -d.` + if [ -f $f ] && [ $DATE != $d ]; then + echo " " >>$LOOP + echo $f >>$LOOP + awk -f loop.awk $f >>$LOOP + if [ -f $S ]; then + echo "file1<-"\"${f}\" >>$SIN + echo "source("\""loop.S"\"")" >>$SIN + echo "unix("\""rm ${f}"\"")" >>$SIN + else + rm -f $f + fi + fi +done + +# +# Summarize peerstats files +# +for f in peerstats.199[4-9][0-1][0-9][0-3][0-9]; do + d=`echo $f | cut -f2 -d.` + if [ -f $f ] && [ $DATE != $d ]; then + echo " " >>$PEER + echo $f >>$PEER + awk -f peer.awk $f >>$PEER + rm -f $f + fi +done + +# +# Summarize clockstats files +# +for f in clockstats.199[4-9][0-1][0-9][0-3][0-9]; do + d=`echo $f | cut -f2 -d.` + if [ -f $f ] && [ $DATE != $d ]; then + echo " " >>$CLOCK + echo $f >>$CLOCK + awk -f clock.awk $f >>$CLOCK + if [ -f /dev/gps[0-9] ]; then + awk -f itf.awk $f >itf.$d + awk -f etf.awk $f >etf.$d + awk -f ensemble.awk $f >ensemble.$d + awk -f tdata.awk $f >tdata.$d + fi + rm -f $f + fi +done + +# +# Process clockstat files with S and generate PostScript plots +# +for f in itf etf ensemble tdata; do + for d in ${f}.199[4-9][0-1][0-9][0-3][0-9]; do + if [ -f $d ]; then + if [ -f $S ]; then + echo "file1<-"\"${d}\" >>$SIN + echo "source("\"${f}.S\"")" >>$SIN + echo "unix("\""rm ${d}"\"")" >>$SIN + else + rm -f $d + fi + fi + done +done +if [ -f $SIN ]; then + $S BATCH $SIN $SOUT +fi diff --git a/contrib/ntp/scripts/stats/tdata.S b/contrib/ntp/scripts/stats/tdata.S new file mode 100755 index 0000000..f360a24 --- /dev/null +++ b/contrib/ntp/scripts/stats/tdata.S @@ -0,0 +1,5 @@ +tdata <- scan(file1, list(day=0, sec=0, m=0, w=0, x=0, y=0, z=0)) +str <- paste("eps/", file1, ".eps", sep="") +postscript(str, , , , 5, pointsize=18) +par(mgp=c(1, 0, 0), tck=0.03, mar=c(2, 2, 1, 1)) +plot(tdata$sec, tdata$m, type="l", xlab=paste("MJD", tdata$day, "Time (s)"), ylab="LORAN-M SNR (dB)") diff --git a/contrib/ntp/scripts/stats/tdata.awk b/contrib/ntp/scripts/stats/tdata.awk new file mode 100755 index 0000000..5be9c04 --- /dev/null +++ b/contrib/ntp/scripts/stats/tdata.awk @@ -0,0 +1,45 @@ +# program to produce loran tdata statistics from clockstats files +# +# usage: awk -f tdata.awk clockstats +# +# format of input record (missing replaced by -40.0) +# 49228 36.852 127.127.10.1 93:241:00:00:20.812 LORAN TDATA +# M OK 0 0 1169.14 -7.4 3.16E-07 .424 +# W CV 0 0 3329.30 -16.4 1.81E-06 +# X OK 0 0 1737.19 -10.5 3.44E-07 .358 +# Y OK 0 0 2182.07 -9.0 4.41E-07 .218 +# +# format of output record (time in nanoseconds, signal values in dB) +# MJD sec time M W X Y Z +# 49228 36.852 175.0 -7.4 -16.4 -10.5 -9.0 +# +# select LORAN TDATA records with valid format +{ + if (NF >= 7 && $6 == "TDATA") { + m = w = x = y = z = -40.0 + for (i = 7; i < NF - 5; i++) { + if ($i == "M" && $(i+1) == "OK") { + i += 5 + m = $i + } + else if ($i == "W" && $(i+1) == "OK") { + i += 5 + w = $i + } + else if ($i == "X" && $(i+1) == "OK") { + i += 5 + x = $i + } + else if ($i == "Y" && $(i+1) == "OK") { + i += 5 + y = $i + } + else if ($i == "Z" && $(i+1) == "OK") { + i += 5 + z = $i + } + } + printf "%5s %9.3f %6.1f %6.1f %6.1f %6.1f %6.1f\n", $1, $2, m, w, x, y, z + } +} + diff --git a/contrib/ntp/scripts/summary.pl b/contrib/ntp/scripts/summary.pl new file mode 100644 index 0000000..c9deda9 --- /dev/null +++ b/contrib/ntp/scripts/summary.pl @@ -0,0 +1,357 @@ +#!/usr/bin/perl -w +# $Id: summary.pl,v 1.1.1.1 1999/05/26 00:48:25 stenn Exp $ +# Perl version of (summary.sh, loop.awk, peer.awk): +# Create summaries from xntpd's loop and peer statistics. +# +# Copyright (c) 1997, Ulrich Windl <Ulrich.Windl@rz.uni-regensburg.de> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +require 5.003; # "never tested with any other version of Perl" +use strict; + +use Getopt::Long; + +my $statsdir = "."; +my $skip_time_steps = 3600.0; # ignore time offsets larger that this +my $startdate = "19700101"; # first data file to use +my $enddate=`date -u +%Y%m%d`; chomp $enddate; --$enddate; +my $peer_dist_limit = 400.0; + +my %options = ("directory=s" => \$statsdir, + "skip-time-steps:f" => \$skip_time_steps, + "start-date=s" => \$startdate, + "end-date=s" => \$enddate, + "peer-dist-limit=f" => \$peer_dist_limit); + +if ( !GetOptions(%options) ) +{ + print STDERR "valid options for $0 are:\n"; + my $opt; + foreach $opt (sort(keys %options)) { + print STDERR "\t--$opt "; + if ( ref($options{$opt}) eq "ARRAY" ) { + print STDERR "(" . join (" ", @{$options{$opt}}) . ")\n"; + } else { + print STDERR "(${$options{$opt}})\n"; + } + } + print STDERR "\n"; + die; +} + +die "$statsdir: no such directory" unless (-d $statsdir); +die "$skip_time_steps: skip-time-steps must be positive" + unless ($skip_time_steps >= 0.0); +die "$startdate: invalid start date" + unless ($startdate =~ m/.*([12]\d{3}[01]\d[0-3]\d)$/); +die "$enddate: invalid end date" + unless ($enddate =~ m/.*([12]\d{3}[01]\d[0-3]\d)$/); + +$skip_time_steps = 0.128 if ($skip_time_steps == 0); + +sub min +{ + my ($result, @rest) = @_; + map { $result = $_ if ($_ < $result) } @rest; + return($result); +} + +sub max +{ + my ($result, @rest) = @_; + map { $result = $_ if ($_ > $result) } @rest; + return($result); +} + +# calculate mean, range, and standard deviation for offset and frequency +sub do_loop +{ + my ($directory, $fname, $out_file) = @_; + print "$directory/$fname\n"; + open INPUT, "$directory/$fname"; + open OUTPUT, ">>$out_file" or die "can't open $out_file: $!"; + print OUTPUT "$fname\n"; + my ($loop_tmax, $loop_fmax) = (-1e9, -1e9); + my ($loop_tmin, $loop_fmin) = (1e9, 1e9); + my ($loop_time_rms, $loop_freq_rms) = (0, 0); + my $loop_count = 0; + my $loop_time = 0; + my $loop_freq = 0; + my ($freq, $offs); + my @Fld; + while (<INPUT>) { + chop; # strip record separator + @Fld = split; + next if ($#Fld < 4); +# 50529 74356.259 -0.000112 16.1230 8 + if ($Fld[2] > $skip_time_steps || $Fld[2] < -$skip_time_steps) { + warn "ignoring loop offset $Fld[2] (file $fname, line $.)\n"; + next + } + $loop_count++; + ($offs, $freq) = ($Fld[2], $Fld[3]); + $loop_tmax = max($loop_tmax, $offs); + $loop_tmin = min($loop_tmin, $offs); + $loop_fmax = max($loop_fmax, $freq); + $loop_fmin = min($loop_fmin, $freq); + $loop_time += $offs; + $loop_time_rms += $offs * $offs; + $loop_freq += $freq; + $loop_freq_rms += $freq * $freq; + } + close INPUT; + if ($loop_count > 1) { + $loop_time /= $loop_count; + $loop_time_rms = $loop_time_rms / $loop_count - $loop_time * $loop_time; + if ($loop_time_rms < 0) { + warn "loop_time_rms: $loop_time_rms < 0"; + $loop_time_rms = 0; + } + $loop_time_rms = sqrt($loop_time_rms); + $loop_freq /= $loop_count; + $loop_freq_rms = $loop_freq_rms / $loop_count - $loop_freq * $loop_freq; + if ($loop_freq_rms < 0) { + warn "loop_freq_rms: $loop_freq_rms < 0"; + $loop_freq_rms = 0; + } + $loop_freq_rms = sqrt($loop_freq_rms); + printf OUTPUT + ("loop %d, %.0f+/-%.1f, rms %.1f, freq %.2f+/-%0.3f, var %.3f\n", + $loop_count, ($loop_tmax + $loop_tmin) / 2 * 1e6, + ($loop_tmax - $loop_tmin) / 2 * 1e6, $loop_time_rms * 1e6, + ($loop_fmax + $loop_fmin) / 2, ($loop_fmax - $loop_fmin) / 2, + $loop_freq_rms); + } + else { + warn "no valid lines in $directory/$fname"; + } + close OUTPUT +} + +# calculate mean, standard deviation, maximum offset, mean dispersion, +# and maximum distance for each peer +sub do_peer +{ + my ($directory, $fname, $out_file) = @_; + print "$directory/$fname\n"; + open INPUT, "$directory/$fname"; + open OUTPUT, ">>$out_file" or die "can't open $out_file: $!"; + print OUTPUT "$fname\n"; +# we toss out all distances greater than one second on the assumption the +# peer is in initial acquisition + my ($n, $MAXDISTANCE) = (0, 1.0); + my %peer_time; + my %peer_time_rms; + my %peer_count; + my %peer_delay; + my %peer_disp; + my %peer_dist; + my %peer_ident; + my %peer_tmin; + my %peer_tmax; + my @Fld; + my ($i, $j); + my ($dist, $offs); + while (<INPUT>) { + chop; # strip record separator + @Fld = split; + next if ($#Fld < 6); +# 50529 83316.249 127.127.8.1 9674 0.008628 0.00000 0.00700 + $dist = $Fld[6] + $Fld[5] / 2; + next if ($dist > $MAXDISTANCE); + $offs = $Fld[4]; + if ($offs > $skip_time_steps || $offs < -$skip_time_steps) { + warn "ignoring peer offset $offs (file $fname, line $.)\n"; + next + } + $i = $n; + for ($j = 0; $j < $n; $j++) { + if ($Fld[2] eq $peer_ident{$j}) { + $i = $j; # peer found + last; + } + } + if ($i == $n) { # add new peer + $peer_ident{$i} = $Fld[2]; + $peer_tmax{$i} = $peer_dist{$i} = -1e9; + $peer_tmin{$i} = 1e9; + $peer_time{$i} = $peer_time_rms{$i} = 0; + $peer_delay{$i} = $peer_disp{$i} = 0; + $peer_count{$i} = 0; + $n++; + } + $peer_count{$i}++; + $peer_tmax{$i} = max($peer_tmax{$i}, $offs); + $peer_tmin{$i} = min($peer_tmin{$i}, $offs); + $peer_dist{$i} = max($peer_dist{$i}, $dist); + $peer_time{$i} += $offs; + $peer_time_rms{$i} += $offs * $offs; + $peer_delay{$i} += $Fld[5]; + $peer_disp{$i} += $Fld[6]; + } + close INPUT; + print OUTPUT +" ident cnt mean rms max delay dist disp\n"; + print OUTPUT +"==========================================================================\n"; + my @lines = (); + for ($i = 0; $i < $n; $i++) { + next if $peer_count{$i} < 2; + $peer_time{$i} /= $peer_count{$i}; + $peer_time_rms{$i} = sqrt($peer_time_rms{$i} / $peer_count{$i} - + $peer_time{$i} * $peer_time{$i}); + $peer_delay{$i} /= $peer_count{$i}; + $peer_disp{$i} /= $peer_count{$i}; + $peer_tmax{$i} = $peer_tmax{$i} - $peer_time{$i}; + $peer_tmin{$i} = $peer_time{$i} - $peer_tmin{$i}; + if ($peer_tmin{$i} > $peer_tmax{$i}) { # can this happen at all? + $peer_tmax{$i} = $peer_tmin{$i}; + } + push @lines, sprintf + "%-15s %4d %8.3f %8.3f %8.3f %8.3f %8.3f %8.3f\n", + $peer_ident{$i}, $peer_count{$i}, $peer_time{$i} * 1e3, + $peer_time_rms{$i} * 1e3, $peer_tmax{$i} * 1e3, + $peer_delay{$i} * 1e3, $peer_dist{$i} * 1e3, $peer_disp{$i} * 1e3; + } + print OUTPUT sort @lines; + close OUTPUT; +} + +sub do_clock +{ + my ($directory, $fname, $out_file) = @_; + print "$directory/$fname\n"; + open INPUT, "$directory/$fname"; + open OUTPUT, ">>$out_file" or die "can't open $out_file: $!"; + print OUTPUT "$fname\n"; + close INPUT; + close OUTPUT; +} + +sub peer_summary +{ + my $in_file = shift; + my ($i, $j, $n); + my (%peer_ident, %peer_count, %peer_mean, %peer_var, %peer_max); + my (%peer_1, %peer_2, %peer_3, %peer_4); + my $dist; + my $max; + open INPUT, "<$in_file" or die "can't open $in_file: $!"; + my @Fld; + $n = 0; + while (<INPUT>) { + chop; # strip record separator + @Fld = split; + next if ($#Fld < 7 || $Fld[0] eq 'ident'); + $i = $n; + for ($j = 0; $j < $n; $j++) { + if ($Fld[0] eq $peer_ident{$j}) { + $i = $j; + last; # peer found + } + } + if ($i == $n) { # add new peer + $peer_count{$i} = $peer_mean{$i} = $peer_var{$i} = 0; + $peer_max{$i} = 0; + $peer_1{$i} = $peer_2{$i} = $peer_3{$i} = $peer_4{$i} = 0; + $peer_ident{$i} = $Fld[0]; + ++$n; + } + $dist = $Fld[6] - $Fld[5] / 2; + if ($dist < $peer_dist_limit) { + $peer_count{$i}++; + $peer_mean{$i} += $Fld[2]; + $peer_var{$i} += $Fld[3] * $Fld[3]; + $max = $Fld[4]; + $peer_max{$i} = max($peer_max{$i}, $max); + if ($max > 1) { + $peer_1{$i}++; + if ($max > 5) { + $peer_2{$i}++; + if ($max > 10) { + $peer_3{$i}++; + if ($max > 50) { + $peer_4{$i}++; + } + } + } + } + } + else { + warn "dist exceeds limit: $dist (file $in_file, line $.)\n"; + } + } + close INPUT; + my @lines = (); + print + " host days mean rms max >1 >5 >10 >50\n"; + print + "==================================================================\n"; + for ($i = 0; $i < $n; $i++) { + next if ($peer_count{$i} < 2); + $peer_mean{$i} /= $peer_count{$i}; + $peer_var{$i} = sqrt($peer_var{$i} / $peer_count{$i} - + $peer_mean{$i} * $peer_mean{$i}); + push @lines, sprintf + "%-15s %3d %9.3f% 9.3f %9.3f %3d %3d %3d %3d\n", + $peer_ident{$i}, $peer_count{$i}, $peer_mean{$i}, $peer_var{$i}, + $peer_max{$i}, $peer_1{$i}, $peer_2{$i}, $peer_3{$i}, $peer_4{$i}; + } + print sort @lines; +} + +my $loop_summary="/tmp/loop_summary"; +my $peer_summary="/tmp/peer_summary"; +my $clock_summary="/tmp/clock_summary"; +my (@loopfiles, @peerfiles, @clockfiles); + +print STDERR "Creating summaries from $statsdir ($startdate to $enddate)\n"; + +opendir SDIR, $statsdir or die "directory ${statsdir}: $!"; +rewinddir SDIR; +@loopfiles=sort grep /loop.*[12]\d{3}[01]\d[0-3]\d/, readdir SDIR; +rewinddir SDIR; +@peerfiles=sort grep /peer.*[12]\d{3}[01]\d[0-3]\d/, readdir SDIR; +rewinddir SDIR; +@clockfiles=sort grep /clock.*[12]\d{3}[01]\d[0-3]\d/, readdir SDIR; +closedir SDIR; + +map { unlink $_ if -f $_ } ($loop_summary, $peer_summary, $clock_summary); + +my $date; +map { + $date = $_; $date =~ s/.*([12]\d{3}[01]\d[0-3]\d)$/$1/; + if ($date ge $startdate && $date le $enddate) { + do_loop $statsdir, $_, $loop_summary; + } +} @loopfiles; + +map { + $date = $_; $date =~ s/.*([12]\d{3}[01]\d[0-3]\d)$/$1/; + if ($date ge $startdate && $date le $enddate) { + do_peer $statsdir, $_, $peer_summary; + } +} @peerfiles; + +map { + $date = $_; $date =~ s/.*([12]\d{3}[01]\d[0-3]\d)$/$1/; + if ($date ge $startdate && $date le $enddate) { + do_clock $statsdir, $_, $clock_summary; + } +} @clockfiles; + +print STDERR "Creating peer summary with limit $peer_dist_limit\n"; +peer_summary $peer_summary if (-f $peer_summary); diff --git a/contrib/ntp/scripts/support/README b/contrib/ntp/scripts/support/README new file mode 100644 index 0000000..812965b --- /dev/null +++ b/contrib/ntp/scripts/support/README @@ -0,0 +1,73 @@ +The bin and etc directories contain several scripts (sh and perl) that +should ease startup and configuration of NTP sites. + + bin/monl is a monitoring script that prints out new, current and + old customers of an NTP timeserver when monitoring is + in effect. + monl has following options: + -i <regexp> (regular expression matchin IP addres to be ignored + -d <directory> where the current state is kept (default /tmp) + -v debug output + -n do not translate IP addresses into hostnames + <host> host to be analyzed + + monl uses xntpdc for information gathering and is thus + limited to the NTP version xntpdc is compiled for. + + bin/mvstats moves compresses and removes statistics files (useful mainly + for reference servers + + etc/install creates the locally needed directories for NTP (if not residung in /etc) + + etc/rc starts up daemon with configuration file and key file + etc/cron cron called monitor statistic (uses bin/monl) + etc/crontab crontab prototype for reference time servers + etc/setup sh script sourced by the other scripts for variable setup + +YOU MUST EDIT THESE FILES TO REFLECT YOUR LOCAL SETUP ! + +READ THIS BEFORE USING THE STARTUP SCRIPTS + +The startupscript etc/rc has been written for Suns and HPs. They are not +guaranteed to work elsewhere. Following assumptions have been made: + + All NTP related files reside in ONE directory having following structure: + + bin/* - all executables (daemon, control, date, scripts) + etc/* - startup scripts and cron scripts + conf/* - NTP configuration files + +The variable NTPROOT (etc/rc, etc/install) must be edited to reflect +the NTP directory (e.g. /usr/local/NTP) + +NTP config files are located via Suns arch command and have the name +conf/`arch`.`arch -k`. +These are the default configurations (usually clients). If a file with the name +conf/`arch`.`arch -k`.`hostname` is present this file will be preferred (Reference host, +gateway). If the arch command is not available no-arch is used. The arch command +is usually a shell script which echoes a string unique the the current machine +architecture. + +The tickadj command has its own conf/tickconf file which is used to set host +specific tickadj values. The line with DEFAULT specifies the default tickadj +parameters, all other lines consists of <hostname> <hostid> +<tickadj parameters>. These lines need only be entered if the specified host +needs parameters different from the default parameters. + +Reference clock support is provided for DCF77. If you need to initialize +certain things for reference clock support (e.g. loading STREAMS modules), +you need to edit etc/rc. + +The current config files of Erlangen are included in the conf directory. +They are just for reference, but might help you a bit in setting up a +synchronisation network. + +The advantage of keeping all config files centralized is the easier +administration. + +We replicate the NTP directory via NFS and rdist. + +When you have set up the local config files (YOUR OWN!) you can call +<NTPROOT>/etc/rc for daemon startup. + +For more information: time@informatik.uni-erlangen.de diff --git a/contrib/ntp/scripts/support/bin/monl b/contrib/ntp/scripts/support/bin/monl new file mode 100644 index 0000000..f0c48db --- /dev/null +++ b/contrib/ntp/scripts/support/bin/monl @@ -0,0 +1,213 @@ +#!/local/bin/perl + +%service = ( 0, "unspec", + 1, "Active", + 2, "Passive", + 3, "Client", + 4, "Server", + 5, "Broadcast", + 6, "Control", + 7, "Private" ); +%nc = (); +@ignpat = (); +$noname = 0; +$verbose = 0; +$retries = 5; +$lastkey = 0; + +sub timedelta { + local($tm, $days, $h, $m, $s); + + $tm = @_[$[]; + $days = 0; + $days = sprintf("%dd+", $days) if $days = int($tm / (60*60*24)); + $days = "" unless $days; + $tm = $tm % (60*60*24); + $h = int($tm / (60*60)); + $tm = $tm % (60*60); + $m = int($tm / 60); + $s = $tm % 60; + + return sprintf("%s%02d:%02d:%02d", $days, $h, $m, $s); +} + +sub listentry { + local($host, $mode) = split("$;" , @_[$[]); + local($count, $version, $firsttime) = split("$;" , $_[$[+1]); + local($name); + + if (grep($host =~ m/$_/, @ignpat)) + { + print "ignored $host ...\n" if $verbose; + return; + } + + return if ! $count; + + if (defined($nc{$host})) + { + $name = $nc{$host}; + } + else + { + if ($noname) + { + $nc{$host} = $name = $host; + } + else + { + $name = (gethostbyaddr(pack("C4", split(/\./, $host)), 2))[$[]; + $nc{$host} = $name = $host if ! defined($name); + } + } + + printf ($fmt, ($lastkey eq $host) ? "" : $name, $service{$mode}, $count, $version, &timedelta($firsttime), $firsttime / $count); + + if (@_[$[+2]) + { + $hostcnt++ if $lastkey ne $host; + $packcnt += $count; + $maxtime = $firsttime if $firsttime > $maxtime; + } + + $lastkey = $host; +} + +while ($ARGV[$[] =~ /^-[nvid]$/) + { + if ($ARGV[$[] eq "-i") + { + shift; + push(@ignpat, shift) unless ! defined($ARGV[$[]); + } + elsif ($ARGV[$[] eq "-d") + { + shift; + $dir = shift unless ! defined($ARGV[$[]); + } + elsif ($ARGV[$[] eq "-n") + { + shift; + $noname = 1; + } + elsif ($ARGV[$[] eq "-v") + { + shift; + $verbose = 1; + } + } + +$dir = "/tmp" unless defined($dir); +$gone = 60*60*48; +$fmt = "%48s %10s %7d %7d %13s %14.3f\n"; +$sfmt = "%48s %10s %7s %7s %13s %14s\n"; +@lbl = ("Host", "Mode", "Count", "Version", "Time active", "Packetinterval"); + +if (!defined($ARGV[$[])) + { + $hostname = `hostname`; + chop($hostname); + unshift(@ARGV, $hostname); + } + +foreach $hostname (@ARGV) + { + $dbmfile = $dir . "/monlstats-" . $hostname; + $monl = "xntpdc -c 'hostnames no' -c monl $hostname | tail +3 |"; + $hostcnt = 0; + $packcnt = 0; + $maxtime = 0; + %Seen = (); + %New = (); + %Old = (); + + print "Monitor Status of $hostname\n\n"; + + $cnt = $retries; + do + { + open(MONL, $monl) || die("$monl failed $!"); + @monlout = <MONL>; + close(MONL); + } while (! @monlout && $cnt--); + + if (! @monlout) + { + print "not available.\n"; + next; + } + + dbmopen(Clients, $dbmfile, 0644) || die("dbmopen(.., $dbmfile, ...): $!"); + + foreach (@monlout) + { + chop; + split; + ($host, $count, $mode, $version, $lasttime, $firsttime) = + (@_[$[, $[+2 .. $[+4, $#_-1,$#_]); + + $Seen{$host, $mode} = 1; + + if (!defined($Clients{$host, $mode})) + { + if ($lasttime <= $gone) + { + ## got a new one + $Clients{$host, $mode} = $New{$host, $mode} = join("$;", $count, $version, $firsttime, $lasttime); + } + } + else + { + ## throw out the old ones + if ($lasttime > $gone) + { + $Old{$host, $mode} = $Clients{$host, $mode}; + delete $Clients{$host, $mode}; + } + else + { + $Clients{$host, $mode} = join("$;", $count, $version, $firsttime, $lasttime); + } + } + } + + grep(($Seen{$_} || ($Old{$_} = delete $Clients{$_})), keys(%Clients)); + + if (grep(($tmp = $_ , !grep($tmp =~ m/$_/, @ignpat)), keys(%New))) + { + print "New customers\n"; + print "-------------\n"; + printf $sfmt, @lbl; + grep( &listentry($_, $New{$_}, 1), sort(keys(%New)) ); + print "\n"; + } + + + if (grep((!defined($New{$_}) && ($tmp = $_, !grep($tmp =~ m/$_/, @ignpat))), keys(%Clients))) + { + print "Current customers\n"; + print "-----------------\n"; + printf $sfmt, @lbl; + grep( defined($New{$_}) || &listentry($_, $Clients{$_}, 1) , sort(keys(%Clients)) ); + print "\n"; + } + + if (grep(($tmp = $_, !grep($tmp =~ m/$_/, @ignpat)), keys(%Old))) + { + print "Discarded customers\n"; + print "-------------------\n"; + printf $sfmt, @lbl; + grep( &listentry($_, $Old{$_}, 0) , sort(keys(%Old)) ); + print "\n"; + } + + dbmclose(Clients); + + print "\nSummary:\n"; + print "--------\n"; + printf("Elapsed time: %13s\n", &timedelta($maxtime)); + printf(" Hosts: %13d\n", $hostcnt); + printf(" Packets: %13d\n", $packcnt); + printf(" Rate: %13.2f\n", $packcnt / $maxtime) if $maxtime; + print "\n"; + } diff --git a/contrib/ntp/scripts/support/bin/mvstats b/contrib/ntp/scripts/support/bin/mvstats new file mode 100644 index 0000000..e33dc792 --- /dev/null +++ b/contrib/ntp/scripts/support/bin/mvstats @@ -0,0 +1,23 @@ +#!/bin/sh +# +# mvstats,v 3.1 1993/07/06 01:10:24 jbj Exp +# +# mvstats is called by cron for keeping the log files together +# usually only used on reference hosts +# +# Files reside in /var/NTP +# Files older than 2 days will be compressed, +# Files older than 64 days will be removed. +# +# mvstats,v +# Revision 3.1 1993/07/06 01:10:24 jbj +# XNTP release 3.1 +# +# +# Revision 1.1 1992/12/10 12:58:24 kardel +# Prerelease NTP V3 / DCF +# +# +cd /var/NTP +find . ! -name '*.Z' -mtime +2 -exec compress -f {} \; +find . -mtime +64 -exec rm -f {} \; diff --git a/contrib/ntp/scripts/support/conf/hp300.hp300 b/contrib/ntp/scripts/support/conf/hp300.hp300 new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/contrib/ntp/scripts/support/conf/hp300.hp300 diff --git a/contrib/ntp/scripts/support/conf/hp700.hp700 b/contrib/ntp/scripts/support/conf/hp700.hp700 new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/contrib/ntp/scripts/support/conf/hp700.hp700 diff --git a/contrib/ntp/scripts/support/conf/hp700.hp700.faui47 b/contrib/ntp/scripts/support/conf/hp700.hp700.faui47 new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/contrib/ntp/scripts/support/conf/hp700.hp700.faui47 diff --git a/contrib/ntp/scripts/support/conf/hp800.hp800 b/contrib/ntp/scripts/support/conf/hp800.hp800 new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/contrib/ntp/scripts/support/conf/hp800.hp800 diff --git a/contrib/ntp/scripts/support/conf/ntp.conf b/contrib/ntp/scripts/support/conf/ntp.conf new file mode 100644 index 0000000..2d6bb85 --- /dev/null +++ b/contrib/ntp/scripts/support/conf/ntp.conf @@ -0,0 +1,3 @@ +# +# put your default configuration (e.g. broadcastclient) in here +# diff --git a/contrib/ntp/scripts/support/conf/sun3.sun3 b/contrib/ntp/scripts/support/conf/sun3.sun3 new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/contrib/ntp/scripts/support/conf/sun3.sun3 diff --git a/contrib/ntp/scripts/support/conf/sun4.sun4.faui01 b/contrib/ntp/scripts/support/conf/sun4.sun4.faui01 new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/contrib/ntp/scripts/support/conf/sun4.sun4.faui01 diff --git a/contrib/ntp/scripts/support/conf/sun4.sun4.faui10 b/contrib/ntp/scripts/support/conf/sun4.sun4.faui10 new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/contrib/ntp/scripts/support/conf/sun4.sun4.faui10 diff --git a/contrib/ntp/scripts/support/conf/sun4.sun4.faui45 b/contrib/ntp/scripts/support/conf/sun4.sun4.faui45 new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/contrib/ntp/scripts/support/conf/sun4.sun4.faui45 diff --git a/contrib/ntp/scripts/support/conf/sun4.sun4c b/contrib/ntp/scripts/support/conf/sun4.sun4c new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/contrib/ntp/scripts/support/conf/sun4.sun4c diff --git a/contrib/ntp/scripts/support/conf/sun4.sun4c.Lucifer b/contrib/ntp/scripts/support/conf/sun4.sun4c.Lucifer new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/contrib/ntp/scripts/support/conf/sun4.sun4c.Lucifer diff --git a/contrib/ntp/scripts/support/conf/sun4.sun4m b/contrib/ntp/scripts/support/conf/sun4.sun4m new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/contrib/ntp/scripts/support/conf/sun4.sun4m diff --git a/contrib/ntp/scripts/support/conf/sun4.sun4m.faui42 b/contrib/ntp/scripts/support/conf/sun4.sun4m.faui42 new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/contrib/ntp/scripts/support/conf/sun4.sun4m.faui42 diff --git a/contrib/ntp/scripts/support/conf/sun4.sun4m.faui45m b/contrib/ntp/scripts/support/conf/sun4.sun4m.faui45m new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/contrib/ntp/scripts/support/conf/sun4.sun4m.faui45m diff --git a/contrib/ntp/scripts/support/conf/tickconf b/contrib/ntp/scripts/support/conf/tickconf new file mode 100644 index 0000000..b17dbe8 --- /dev/null +++ b/contrib/ntp/scripts/support/conf/tickconf @@ -0,0 +1,19 @@ +DEFAULT -A -p -s -q +Lucifer 55406cfa -a 1 -p -s -q -t 10001 +faui45 24000f9b -a 1 -p -s -q +faui10 2440213c -a 1 -p -s -q +faui1b 54001418 -A -p -s -q -t 10001 +faui4p 5100344d -A -p -s -q -t 9999 +faui02g 1200be20 -A -p -s -q -t 9999 +faui02e 1200bbab -A -p -s -q -t 9999 +faui02f 1200bedb -A -p -s -q -t 9999 +faui03b 1200b92b -A -p -s -q -t 9999 +faui45m 726001ac -A -p -s -q -t 10001 +faui45o 72600272 -A -p -s -q -t 10001 +faui45p 7260028f -A -p -s -q -t 10001 +faui45r 72400cc7 -A -p -s -q -t 10001 +faui45s 726045be -A -p -s -q -t 10001 +faui45v 72604487 -A -p -s -q -t 10001 +faui45x 726044eb -A -p -s -q -t 10001 +faui45y 7260476d -A -p -s -q -t 10001 +faui45z 726045a1 -A -p -s -q -t 10001 diff --git a/contrib/ntp/scripts/support/etc/cron b/contrib/ntp/scripts/support/etc/cron new file mode 100644 index 0000000..07ed189 --- /dev/null +++ b/contrib/ntp/scripts/support/etc/cron @@ -0,0 +1,18 @@ +#!/bin/sh +# +# cron,v 3.1 1993/07/06 01:10:50 jbj Exp +# +# called by cron for statistics gathering +# +# cron,v +# Revision 3.1 1993/07/06 01:10:50 jbj +# XNTP release 3.1 +# +# +# Revision 1.1 1992/12/10 12:59:18 kardel +# Prerelease NTP V3 / DCF +# +# +PATH="${PATH}:/local/NTP/bin" +export PATH +monl -d /local/NTP/monitor -i '127\.0\.0\.1' faui10 faui45 lucifer rackety.udel.edu diff --git a/contrib/ntp/scripts/support/etc/crontab b/contrib/ntp/scripts/support/etc/crontab new file mode 100644 index 0000000..2b2d19c --- /dev/null +++ b/contrib/ntp/scripts/support/etc/crontab @@ -0,0 +1,8 @@ +# +# NTP statistics periodic cleanup - REFERENCE SERVER ONLY +# +#55 23 * * * sh /local/NTP/etc/mvstats +# +# gather NTP client statistics - REFERENCE SERVER ONLY +# +0 8,18 * * * /local/NTP/etc/cron 2>/dev/null | /usr/ucb/mail -s "NTP statistics" time@informatik.uni-erlangen.de diff --git a/contrib/ntp/scripts/support/etc/install b/contrib/ntp/scripts/support/etc/install new file mode 100644 index 0000000..169a7e5 --- /dev/null +++ b/contrib/ntp/scripts/support/etc/install @@ -0,0 +1,67 @@ +#!/bin/sh +# +# install,v 3.1 1993/07/06 01:10:53 jbj Exp +# +# install,v +# Revision 3.1 1993/07/06 01:10:53 jbj +# XNTP release 3.1 +# +# +# Revision 1.1 1992/12/10 12:59:21 kardel +# Prerelease NTP V3 / DCF +# +# Revision 1.1 1992/06/18 14:50:08 kardel +# Initial revision +# +# +NTPROOT=/local/NTP # SITE SPECIFIC: where NTP resides +# +# where the local NTP state files reside (xntp.drift) ussualle /etc +# this directory must not be shared as machine dependent data ist stored there +# +NTPDIR="/+private/local/NTP" +# +# get the initial setup +# +if [ ! -r $NTPROOT/etc/setup ]; then + echo "ERROR: $NTPROOT/etc/setup missing - incorrect installation." + exit 1 +else + . $NTPROOT/etc/setup +fi + +umask 022 # SITE SPECIFIC: local policy - watch out for NFS and "root" rights + +Mkdir() { + p="" + IFS="/" + set -- $@ + IFS=' +' + for pnc do + if [ ! -d "$p/$pnc" ]; then + ECHO -n "creating directory $p/$pnc" + if mkdir "$p/$pnc"; then + ECHO "" + else + ECHO " - FAILED" + break; + fi + fi + p="$p/$pnc" + done +} + +if [ ! -d "$NTPDIR" ]; then + ECHO "installing NTP private data area ($NTPDIR)" + if Mkdir "$NTPDIR"; then + chmod 755 "$NTPDIR" + ECHO "$NTPDIR created." + fi +else + ECHO "NTP already installed." + if [ -f "$NTPDIR/xntp.drift" ]; then + ECHO "currently saved drift value:" `cat "$NTPDIR/xntp.drift"` + fi +fi + diff --git a/contrib/ntp/scripts/support/etc/rc b/contrib/ntp/scripts/support/etc/rc new file mode 100644 index 0000000..ef8834a --- /dev/null +++ b/contrib/ntp/scripts/support/etc/rc @@ -0,0 +1,198 @@ +#!/bin/sh +# NTP time synchronisation +# +# /src/NTP/REPOSITORY/v3/supportscripts/etc/rc,v 1.11 1993/07/09 13:17:00 kardel Exp +# +# rc,v +# Revision 1.11 1993/07/09 13:17:00 kardel +# local NTPROOT +# +# Revision 1.10 1993/07/09 11:37:29 kardel +# Initial restructured version + GPS support +# +# Revision 1.9 1993/06/23 14:10:36 kardel +# June 21st reconcilation +# +# Revision 1.7 1993/06/02 12:04:43 kardel +# May 28th reconcilation & clenaup +# +# +# non reference clock hosts will try to do an ntpdate on NTPSERVERS +# +NTPSERVERS="ntps1-0 ntps1-1 ntps2-0 ntps2-1" +NTPROOT=/local/NTP + +# +# get the initial setup +# +if [ ! -r $NTPROOT/etc/setup ]; then + echo "ERROR: $NTPROOT/etc/setup missing - incorrect installation." + exit 1 +else + . $NTPROOT/etc/setup +fi + +umask 022 # SITE SPECIFIC: local policy - watch out for NFS and "root" rights + +msg="" +# +# default configuration files are named $NTPROOT/conf/<ARCH>.<KARCH> +# +CF=$NTPROOT/conf/$ARCH.$KARCH # default configuration file +# +# Host specific config file (reference clocks) have the hostname tagged on +# +CFH="$CF"."$HOSTNAME" # specific configuration file +# +# where to find the tickadj command +# +KFIX=$NTPROOT/bin/tickadj # kernel variable fix +# +# where to find special tickadj parameters +# +TC=$NTPROOT/conf/tickconf # special tickadj parameters +# +# where to find the keys file (if not found $KEY.dumb will be used) +# +KEY=$NTPROOT/conf/ntp.keys # private key file +# +# the daemon +# +XD=$NTPROOT/bin/xntpd # NTP daemon +# +# HP adjtimed +# +ADJTIMED=$NTPROOT/bin/adjtimed # HP special (adjtime() emulation) +# +# ntpdate command +# +NTPDATE=$NTPROOT/bin/ntpdate + +# +# secondary timed support +# The word "TIMED" must be in the config file for timed to start +# Note that this times is a special version which does not ever set or +# adjust the time. Ask time@informatik.uni-erlangen.de for patches +# +TIMED=$NTPROOT/bin/timed # timed (Berkeley) secondary time service + # here used in a *HARMLESS* version + # to provide time to "inferior" systems +# +# ISREFHOST is a command that returns exit status 0 for a reference host +# Site specific: sample for dcf77 is given +# +ISREFHOST="[ -f $NTPROOT/.karch.$KARCH/sys/OBJ/parsestreams.o -a -f /dev/refclock-0 ]" +# +# SETUP_REFCLOCK +# +# what to do in order to set up a local reference clock +# usually this will load a STREAMS module or initialize other things +# needed +# +SETUP_REFCLOCK() { + if modstat | grep -s 'PARSE'; then + ECHO "loadable PARSER STREAMS module already loaded." + else + ECHO "attempting to load PARSER STREAMS module..." + MDLFILE="/tmp/mdl.$$" + if modload $NTPROOT/.karch.$KARCH/sys/OBJ/parsestreams.o -o $MDLFILE 2>&1; then + modstat + else + echo WARNING: load FAILED + fi | LOG + rm -f $MDLFILE + unset MDLFILE + fi +} + +kargs() { + MATCH=NO + HOSTID="`(hostid) 2>/dev/null || echo 000000`" + if [ -r "$TC" ]; then + exec 0< "$TC" + while [ "$MATCH" != "YES" ] && read HOST ID PARAM; do + if [ "$HOST" = "DEFAULT" ]; then + DEFAULT="$ID $PARAM" + else + if [ "$ID" = "$HOSTID" -o "$HOST" = "$HOSTNAME" ]; then + echo "$PARAM" + MATCH=YES + fi + fi + done + if [ "$MATCH" != "YES" ]; then + if [ -z "$DEFAULT" ]; then + echo "-A -p -s -q"; + else + echo "$DEFAULT"; + fi + fi + else + echo "-A -p -s -q"; + fi +} + +if [ -x $XD ]; then + if [ -x "$ADJTIMED" ]; then + $ADJTIMED && ECHO "adjusttimesupport: adjtimed." + fi + # + # WARNING: check ps command first, or you might kill things you don't want to + # + PID="`(ps -efa 2>/dev/null || ps auxww 2>/dev/null || echo "") | grep xntp | grep -v grep | awk '{ print $2 }'`" + + if [ ! -z "$PID" ]; then + ECHO "killing old NTP daemon (PID=$PID)" + # + # enable this after checking for correctness + # kill $PID + ECHO "should do a kill $PID, if this is the right PID - check rc script" + fi + # + # try an ntpdate when timeservers are configured + # + if [ ! -z "$NTPSERVERS" -a -x $NTPDATE ]; then + ECHO "NTP initial time setting" + $NTPDATE -v $NTPSERVERS | LOG + fi + # + # look for reference clock equipment + # + if $ISREFHOST; then + ECHO "REFERENCE CLOCK SUPPORT (initializing...)" + SETUP_REFCLOCK + fi + + if [ -r "$CFH" ]; then + CF="$CFH" + else + if [ ! -r "$KEY" ]; then + KEY="$KEY.dumb" + fi + fi + + ECHO "NTP configuration file: $CF" + ECHO -n "time daemon startup:" + + if [ -r "$CF" ]; then + if [ -x "$KFIX" ]; then + KARGS="`kargs`" + if [ ! -z "$KARGS" ]; then + $KFIX $KARGS && ECHO -n "tickadj $KARGS" + fi + fi + $XD -c "$CF" -k "$KEY" && ECHO -n ' xntpd' + if [ -x "$TIMED" ] && grep -s TIMED "$CF"; then + $TIMED -M -N && ECHO -n ' timed' + fi + else + msg="configuration file ($CF) not present." + fi +else + msg="daemon binary ($XD) not present." +fi +ECHO "." + +if [ "$msg" ]; then + NLECHO "WARNING: NO NTP time sychronisation: $msg" +fi diff --git a/contrib/ntp/scripts/support/etc/setup b/contrib/ntp/scripts/support/etc/setup new file mode 100644 index 0000000..d4ea75e --- /dev/null +++ b/contrib/ntp/scripts/support/etc/setup @@ -0,0 +1,72 @@ +# +# setup,v 3.1 1993/07/06 01:10:55 jbj Exp +# +# /bin/sh sourced file for environment setup +# expects NTPROOT variable initialized +# +# if not set it will be initialized to /usr/local/NTP +# +# setup,v +# Revision 3.1 1993/07/06 01:10:55 jbj +# XNTP release 3.1 +# +# +# Revision 1.1 1992/12/10 12:59:25 kardel +# Prerelease NTP V3 / DCF +# +# Revision 1.1 1992/12/10 10:14:46 kardel +# Initial revision +# +# +NTPROOT=${NTPROOT-/usr/local/NTP} + +# +# we so use our own echos, as we somes want to substitute them with a +# file logging version durin the /etc/rc.local phase +# +set `type ECHO` + +PATH="${PATH}:$NTPROOT/bin" +export PATH + +if [ "$2" = "is" ]; then + : +else + # + # find out the way echos work (Rest of rc thinks BSD echo) + # + ECHOREP="`echo -n x`" + if [ "$ECHOREP" = "-n x" ]; then + ECHO () { + if [ "$1" = "-n" ]; then + shift + echo "$@\c" + else + echo "$@" + fi + } + #ECHO "System V style echo" + else + ECHO () { + echo "$@" + } + #ECHO "BSD style echo" + fi + + NLECHO () { + echo "$@" + } + + LOG () { + while read _line; do + ECHO "$_line" + done + } + # + # carefully find out some configuration Variables + # + ARCH="`(arch) 2>/dev/null || ((uname) > /dev/null && uname -a | awk '{ print $6; }') 2>/dev/null || echo 'no-arch'`" + KARCH="`(arch -k) 2>/dev/null || ((uname) > /dev/null && uname -a | awk '{ print $5 }') || echo 'no-arch'`" + HOSTNAME="`(hostname) 2>/dev/null || uname -n`" +fi + |