154359Sroberto/* 254359Sroberto * ntpq - query an NTP server using mode 6 commands 354359Sroberto */ 482498Sroberto 554359Sroberto#include <stdio.h> 682498Sroberto 7182007Sroberto#include <ctype.h> 8182007Sroberto#include <signal.h> 9182007Sroberto#include <setjmp.h> 10182007Sroberto#include <sys/types.h> 11182007Sroberto#include <sys/time.h> 12182007Sroberto 1382498Sroberto#include "ntpq.h" 1482498Sroberto#include "ntp_unixtime.h" 1582498Sroberto#include "ntp_calendar.h" 1682498Sroberto#include "ntp_io.h" 1782498Sroberto#include "ntp_select.h" 1882498Sroberto#include "ntp_stdlib.h" 19132451Sroberto/* Don't include ISC's version of IPv6 variables and structures */ 20132451Sroberto#define ISC_IPV6_H 1 21132451Sroberto#include "isc/net.h" 22132451Sroberto#include "isc/result.h" 2382498Sroberto 24182007Sroberto#include "ntpq-opts.h" 25182007Sroberto 2654359Sroberto#ifdef SYS_WINNT 27182007Sroberto# include <Mswsock.h> 2854359Sroberto# include <io.h> 2954359Sroberto#else 30182007Sroberto# define closesocket close 3154359Sroberto#endif /* SYS_WINNT */ 3254359Sroberto 33132451Sroberto#if defined(HAVE_LIBREADLINE) || defined(HAVE_LIBEDIT) 34106163Sroberto# include <readline/readline.h> 35106163Sroberto# include <readline/history.h> 36132451Sroberto#endif /* HAVE_LIBREADLINE || HAVE_LIBEDIT */ 37106163Sroberto 3854359Sroberto#ifdef SYS_VXWORKS 39182007Sroberto /* vxWorks needs mode flag -casey*/ 40182007Sroberto# define open(name, flags) open(name, flags, 0777) 41182007Sroberto# define SERVER_PORT_NUM 123 4254359Sroberto#endif 4354359Sroberto 44182007Sroberto/* we use COMMAND as an autogen keyword */ 45182007Sroberto#ifdef COMMAND 46182007Sroberto# undef COMMAND 47182007Sroberto#endif 48182007Sroberto 4954359Sroberto/* 5054359Sroberto * Because we potentially understand a lot of commands we will run 5154359Sroberto * interactive if connected to a terminal. 5254359Sroberto */ 5354359Srobertoint interactive = 0; /* set to 1 when we should prompt */ 5454359Srobertoconst char *prompt = "ntpq> "; /* prompt to ask him about */ 5554359Sroberto 5654359Sroberto 5754359Sroberto/* 58182007Sroberto * for get_systime() 59182007Sroberto */ 60182007Srobertos_char sys_precision; /* local clock precision (log2 s) */ 61182007Sroberto 62182007Sroberto/* 6354359Sroberto * Keyid used for authenticated requests. Obtained on the fly. 6454359Sroberto */ 65132451Srobertou_long info_auth_keyid = 0; 6654359Sroberto 6754359Sroberto/* 68132451Sroberto * Type of key md5 6954359Sroberto */ 7054359Sroberto#define KEY_TYPE_MD5 4 7154359Sroberto 7254359Srobertostatic int info_auth_keytype = KEY_TYPE_MD5; /* MD5 */ 7354359Srobertou_long current_time; /* needed by authkeys; not used */ 7454359Sroberto 7554359Sroberto/* 7654359Sroberto * Flag which indicates we should always send authenticated requests 7754359Sroberto */ 7854359Srobertoint always_auth = 0; 7954359Sroberto 8054359Sroberto/* 8154359Sroberto * Flag which indicates raw mode output. 8254359Sroberto */ 8354359Srobertoint rawmode = 0; 8454359Sroberto 8554359Sroberto/* 8654359Sroberto * Packet version number we use 8754359Sroberto */ 8854359Srobertou_char pktversion = NTP_OLDVERSION + 1; 8954359Sroberto 9054359Sroberto/* 9154359Sroberto * Don't jump if no set jmp. 9254359Sroberto */ 9354359Srobertovolatile int jump = 0; 9454359Sroberto 9554359Sroberto/* 9654359Sroberto * Format values 9754359Sroberto */ 9854359Sroberto#define PADDING 0 9954359Sroberto#define TS 1 /* time stamp */ 10054359Sroberto#define FL 2 /* l_fp type value */ 10154359Sroberto#define FU 3 /* u_fp type value */ 10254359Sroberto#define FS 4 /* s_fp type value */ 10354359Sroberto#define UI 5 /* unsigned integer value */ 10454359Sroberto#define SI 6 /* signed integer value */ 10554359Sroberto#define HA 7 /* host address */ 10654359Sroberto#define NA 8 /* network address */ 10754359Sroberto#define ST 9 /* string value */ 10854359Sroberto#define RF 10 /* refid (sometimes string, sometimes not) */ 10954359Sroberto#define LP 11 /* leap (print in binary) */ 11054359Sroberto#define OC 12 /* integer, print in octal */ 11154359Sroberto#define MD 13 /* mode */ 11254359Sroberto#define AR 14 /* array of times */ 11354359Sroberto#define FX 15 /* test flags */ 11454359Sroberto#define EOV 255 /* end of table */ 11554359Sroberto 11654359Sroberto 11754359Sroberto/* 11854359Sroberto * System variable values. The array can be indexed by 11954359Sroberto * the variable index to find the textual name. 12054359Sroberto */ 12154359Srobertostruct ctl_var sys_var[] = { 12254359Sroberto { 0, PADDING, "" }, /* 0 */ 12354359Sroberto { CS_LEAP, LP, "leap" }, /* 1 */ 12454359Sroberto { CS_STRATUM, UI, "stratum" }, /* 2 */ 12554359Sroberto { CS_PRECISION, SI, "precision" }, /* 3 */ 12654359Sroberto { CS_ROOTDELAY, FS, "rootdelay" }, /* 4 */ 12754359Sroberto { CS_ROOTDISPERSION, FU, "rootdispersion" }, /* 5 */ 12854359Sroberto { CS_REFID, RF, "refid" }, /* 6 */ 12954359Sroberto { CS_REFTIME, TS, "reftime" }, /* 7 */ 13054359Sroberto { CS_POLL, UI, "poll" }, /* 8 */ 13154359Sroberto { CS_PEERID, UI, "peer" }, /* 9 */ 13254359Sroberto { CS_STATE, UI, "state" }, /* 10 */ 13382498Sroberto { CS_OFFSET, FL, "offset" }, /* 11 */ 13454359Sroberto { CS_DRIFT, FS, "frequency" }, /* 12 */ 13582498Sroberto { CS_JITTER, FU, "jitter" }, /* 13 */ 13654359Sroberto { CS_CLOCK, TS, "clock" }, /* 14 */ 13754359Sroberto { CS_PROCESSOR, ST, "processor" }, /* 15 */ 13854359Sroberto { CS_SYSTEM, ST, "system" }, /* 16 */ 13982498Sroberto { CS_VERSION, ST, "version" }, /* 17 */ 14082498Sroberto { CS_STABIL, FS, "stability" }, /* 18 */ 14182498Sroberto { CS_VARLIST, ST, "sys_var_list" }, /* 19 */ 14254359Sroberto { 0, EOV, "" } 14354359Sroberto}; 14454359Sroberto 14554359Sroberto 14654359Sroberto/* 14754359Sroberto * Peer variable list 14854359Sroberto */ 14954359Srobertostruct ctl_var peer_var[] = { 15054359Sroberto { 0, PADDING, "" }, /* 0 */ 15154359Sroberto { CP_CONFIG, UI, "config" }, /* 1 */ 15254359Sroberto { CP_AUTHENABLE, UI, "authenable" }, /* 2 */ 15354359Sroberto { CP_AUTHENTIC, UI, "authentic" }, /* 3 */ 15454359Sroberto { CP_SRCADR, HA, "srcadr" }, /* 4 */ 15554359Sroberto { CP_SRCPORT, UI, "srcport" }, /* 5 */ 15654359Sroberto { CP_DSTADR, NA, "dstadr" }, /* 6 */ 15754359Sroberto { CP_DSTPORT, UI, "dstport" }, /* 7 */ 15854359Sroberto { CP_LEAP, LP, "leap" }, /* 8 */ 15954359Sroberto { CP_HMODE, MD, "hmode" }, /* 9 */ 16054359Sroberto { CP_STRATUM, UI, "stratum" }, /* 10 */ 16154359Sroberto { CP_PPOLL, UI, "ppoll" }, /* 11 */ 16254359Sroberto { CP_HPOLL, UI, "hpoll" }, /* 12 */ 16354359Sroberto { CP_PRECISION, SI, "precision" }, /* 13 */ 16454359Sroberto { CP_ROOTDELAY, FS, "rootdelay" }, /* 14 */ 16554359Sroberto { CP_ROOTDISPERSION, FU, "rootdispersion" }, /* 15 */ 16654359Sroberto { CP_REFID, RF, "refid" }, /* 16 */ 16754359Sroberto { CP_REFTIME, TS, "reftime" }, /* 17 */ 16854359Sroberto { CP_ORG, TS, "org" }, /* 18 */ 16954359Sroberto { CP_REC, TS, "rec" }, /* 19 */ 17054359Sroberto { CP_XMT, TS, "xmt" }, /* 20 */ 17154359Sroberto { CP_REACH, OC, "reach" }, /* 21 */ 172182007Sroberto { CP_UNREACH, UI, "unreach" }, /* 22 */ 17354359Sroberto { CP_TIMER, UI, "timer" }, /* 23 */ 17454359Sroberto { CP_DELAY, FS, "delay" }, /* 24 */ 17554359Sroberto { CP_OFFSET, FL, "offset" }, /* 25 */ 17654359Sroberto { CP_JITTER, FU, "jitter" }, /* 26 */ 17754359Sroberto { CP_DISPERSION, FU, "dispersion" }, /* 27 */ 17854359Sroberto { CP_KEYID, UI, "keyid" }, /* 28 */ 17954359Sroberto { CP_FILTDELAY, AR, "filtdelay" }, /* 29 */ 18054359Sroberto { CP_FILTOFFSET, AR, "filtoffset" }, /* 30 */ 18154359Sroberto { CP_PMODE, ST, "pmode" }, /* 31 */ 18254359Sroberto { CP_RECEIVED, UI, "received" }, /* 32 */ 18354359Sroberto { CP_SENT, UI, "sent" }, /* 33 */ 18454359Sroberto { CP_FILTERROR, AR, "filtdisp" }, /* 34 */ 18554359Sroberto { CP_FLASH, FX, "flash" }, /* 35 */ 18682498Sroberto { CP_TTL, UI, "ttl" }, /* 36 */ 18754359Sroberto /* 18854359Sroberto * These are duplicate entries so that we can 18954359Sroberto * process deviant version of the ntp protocol. 19054359Sroberto */ 19154359Sroberto { CP_SRCADR, HA, "peeraddr" }, /* 4 */ 19254359Sroberto { CP_SRCPORT, UI, "peerport" }, /* 5 */ 19354359Sroberto { CP_PPOLL, UI, "peerpoll" }, /* 11 */ 19454359Sroberto { CP_HPOLL, UI, "hostpoll" }, /* 12 */ 19554359Sroberto { CP_FILTERROR, AR, "filterror" }, /* 34 */ 19654359Sroberto { 0, EOV, "" } 19754359Sroberto}; 19854359Sroberto 19954359Sroberto 20054359Sroberto/* 20154359Sroberto * Clock variable list 20254359Sroberto */ 20354359Srobertostruct ctl_var clock_var[] = { 20454359Sroberto { 0, PADDING, "" }, /* 0 */ 20554359Sroberto { CC_TYPE, UI, "type" }, /* 1 */ 20654359Sroberto { CC_TIMECODE, ST, "timecode" }, /* 2 */ 20754359Sroberto { CC_POLL, UI, "poll" }, /* 3 */ 20854359Sroberto { CC_NOREPLY, UI, "noreply" }, /* 4 */ 20954359Sroberto { CC_BADFORMAT, UI, "badformat" }, /* 5 */ 21054359Sroberto { CC_BADDATA, UI, "baddata" }, /* 6 */ 21154359Sroberto { CC_FUDGETIME1, FL, "fudgetime1" }, /* 7 */ 21254359Sroberto { CC_FUDGETIME2, FL, "fudgetime2" }, /* 8 */ 21354359Sroberto { CC_FUDGEVAL1, UI, "stratum" }, /* 9 */ 21454359Sroberto { CC_FUDGEVAL2, RF, "refid" }, /* 10 */ 21554359Sroberto { CC_FLAGS, UI, "flags" }, /* 11 */ 21654359Sroberto { CC_DEVICE, ST, "device" }, /* 12 */ 21754359Sroberto { 0, EOV, "" } 21854359Sroberto}; 21954359Sroberto 22054359Sroberto 22154359Sroberto/* 22254359Sroberto * flasher bits 22354359Sroberto */ 22454359Srobertostatic const char *tstflagnames[] = { 225182007Sroberto "pkt_dup", /* TEST1 */ 226182007Sroberto "pkt_bogus", /* TEST2 */ 227182007Sroberto "pkt_proto", /* TEST3 */ 228182007Sroberto "pkt_denied", /* TEST4 */ 229182007Sroberto "pkt_auth", /* TEST5 */ 230182007Sroberto "pkt_synch", /* TEST6 */ 231182007Sroberto "pkt_dist", /* TEST7 */ 232182007Sroberto "pkt_autokey", /* TEST8 */ 233182007Sroberto "pkt_crypto", /* TEST9 */ 234182007Sroberto "peer_stratum", /* TEST10 */ 235182007Sroberto "peer_dist", /* TEST11 */ 236182007Sroberto "peer_loop", /* TEST12 */ 237182007Sroberto "peer_unfit" /* TEST13 */ 23854359Sroberto}; 23954359Sroberto 24054359Sroberto 24154359Srobertoint ntpqmain P((int, char **)); 24254359Sroberto/* 24354359Sroberto * Built in command handler declarations 24454359Sroberto */ 24554359Srobertostatic int openhost P((const char *)); 24654359Srobertostatic int sendpkt P((char *, int)); 24754359Srobertostatic int getresponse P((int, int, u_short *, int *, char **, int)); 24854359Srobertostatic int sendrequest P((int, int, int, int, char *)); 24954359Srobertostatic char * tstflags P((u_long)); 25054359Srobertostatic void getcmds P((void)); 25154359Srobertostatic RETSIGTYPE abortcmd P((int)); 25254359Srobertostatic void docmd P((const char *)); 25354359Srobertostatic void tokenize P((const char *, char **, int *)); 25454359Srobertostatic int findcmd P((char *, struct xcmd *, struct xcmd *, struct xcmd **)); 25554359Srobertostatic int getarg P((char *, int, arg_v *)); 25654359Srobertostatic int rtdatetolfp P((char *, l_fp *)); 25754359Srobertostatic int decodearr P((char *, int *, l_fp *)); 25854359Srobertostatic void help P((struct parse *, FILE *)); 25954359Sroberto#ifdef QSORT_USES_VOID_P 26054359Srobertostatic int helpsort P((const void *, const void *)); 26154359Sroberto#else 26254359Srobertostatic int helpsort P((char **, char **)); 26354359Sroberto#endif 26454359Srobertostatic void printusage P((struct xcmd *, FILE *)); 26554359Srobertostatic void timeout P((struct parse *, FILE *)); 26654359Srobertostatic void auth_delay P((struct parse *, FILE *)); 26754359Srobertostatic void host P((struct parse *, FILE *)); 26854359Srobertostatic void ntp_poll P((struct parse *, FILE *)); 26954359Srobertostatic void keyid P((struct parse *, FILE *)); 27054359Srobertostatic void keytype P((struct parse *, FILE *)); 27154359Srobertostatic void passwd P((struct parse *, FILE *)); 27254359Srobertostatic void hostnames P((struct parse *, FILE *)); 27354359Srobertostatic void setdebug P((struct parse *, FILE *)); 27454359Srobertostatic void quit P((struct parse *, FILE *)); 27554359Srobertostatic void version P((struct parse *, FILE *)); 27654359Srobertostatic void raw P((struct parse *, FILE *)); 27754359Srobertostatic void cooked P((struct parse *, FILE *)); 27854359Srobertostatic void authenticate P((struct parse *, FILE *)); 27954359Srobertostatic void ntpversion P((struct parse *, FILE *)); 28054359Srobertostatic void warning P((const char *, const char *, const char *)); 28154359Srobertostatic void error P((const char *, const char *, const char *)); 28254359Srobertostatic u_long getkeyid P((const char *)); 28354359Srobertostatic void atoascii P((int, char *, char *)); 28454359Srobertostatic void makeascii P((int, char *, FILE *)); 28554359Srobertostatic void rawprint P((int, int, char *, int, FILE *)); 28654359Srobertostatic void startoutput P((void)); 28754359Srobertostatic void output P((FILE *, char *, char *)); 28854359Srobertostatic void endoutput P((FILE *)); 28954359Srobertostatic void outputarr P((FILE *, char *, int, l_fp *)); 29054359Srobertostatic void cookedprint P((int, int, char *, int, FILE *)); 29154359Sroberto#ifdef QSORT_USES_VOID_P 29254359Srobertostatic int assoccmp P((const void *, const void *)); 29354359Sroberto#else 29454359Srobertostatic int assoccmp P((struct association *, struct association *)); 29554359Sroberto#endif /* sgi || bsdi */ 29654359Sroberto 29754359Sroberto 29854359Sroberto/* 29954359Sroberto * Built-in commands we understand 30054359Sroberto */ 30154359Srobertostruct xcmd builtins[] = { 302182007Sroberto { "?", help, { OPT|NTP_STR, NO, NO, NO }, 30354359Sroberto { "command", "", "", "" }, 30454359Sroberto "tell the use and syntax of commands" }, 305182007Sroberto { "help", help, { OPT|NTP_STR, NO, NO, NO }, 30654359Sroberto { "command", "", "", "" }, 30754359Sroberto "tell the use and syntax of commands" }, 308182007Sroberto { "timeout", timeout, { OPT|NTP_UINT, NO, NO, NO }, 30954359Sroberto { "msec", "", "", "" }, 31054359Sroberto "set the primary receive time out" }, 311182007Sroberto { "delay", auth_delay, { OPT|NTP_INT, NO, NO, NO }, 31254359Sroberto { "msec", "", "", "" }, 31354359Sroberto "set the delay added to encryption time stamps" }, 314182007Sroberto { "host", host, { OPT|NTP_STR, OPT|NTP_STR, NO, NO }, 315132451Sroberto { "-4|-6", "hostname", "", "" }, 31654359Sroberto "specify the host whose NTP server we talk to" }, 317182007Sroberto { "poll", ntp_poll, { OPT|NTP_UINT, OPT|NTP_STR, NO, NO }, 31854359Sroberto { "n", "verbose", "", "" }, 31954359Sroberto "poll an NTP server in client mode `n' times" }, 32054359Sroberto { "passwd", passwd, { NO, NO, NO, NO }, 32154359Sroberto { "", "", "", "" }, 32254359Sroberto "specify a password to use for authenticated requests"}, 323182007Sroberto { "hostnames", hostnames, { OPT|NTP_STR, NO, NO, NO }, 32454359Sroberto { "yes|no", "", "", "" }, 32554359Sroberto "specify whether hostnames or net numbers are printed"}, 326182007Sroberto { "debug", setdebug, { OPT|NTP_STR, NO, NO, NO }, 32754359Sroberto { "no|more|less", "", "", "" }, 32854359Sroberto "set/change debugging level" }, 32954359Sroberto { "quit", quit, { NO, NO, NO, NO }, 33054359Sroberto { "", "", "", "" }, 33154359Sroberto "exit ntpq" }, 33254359Sroberto { "exit", quit, { NO, NO, NO, NO }, 33354359Sroberto { "", "", "", "" }, 33454359Sroberto "exit ntpq" }, 335182007Sroberto { "keyid", keyid, { OPT|NTP_UINT, NO, NO, NO }, 33654359Sroberto { "key#", "", "", "" }, 33754359Sroberto "set keyid to use for authenticated requests" }, 33854359Sroberto { "version", version, { NO, NO, NO, NO }, 33954359Sroberto { "", "", "", "" }, 34054359Sroberto "print version number" }, 34154359Sroberto { "raw", raw, { NO, NO, NO, NO }, 34254359Sroberto { "", "", "", "" }, 34354359Sroberto "do raw mode variable output" }, 34454359Sroberto { "cooked", cooked, { NO, NO, NO, NO }, 34554359Sroberto { "", "", "", "" }, 34654359Sroberto "do cooked mode variable output" }, 347182007Sroberto { "authenticate", authenticate, { OPT|NTP_STR, NO, NO, NO }, 34854359Sroberto { "yes|no", "", "", "" }, 34954359Sroberto "always authenticate requests to this server" }, 350182007Sroberto { "ntpversion", ntpversion, { OPT|NTP_UINT, NO, NO, NO }, 35154359Sroberto { "version number", "", "", "" }, 35254359Sroberto "set the NTP version number to use for requests" }, 353182007Sroberto { "keytype", keytype, { OPT|NTP_STR, NO, NO, NO }, 35454359Sroberto { "key type (md5|des)", "", "", "" }, 35554359Sroberto "set key type to use for authenticated requests (des|md5)" }, 35654359Sroberto { 0, 0, { NO, NO, NO, NO }, 35754359Sroberto { "", "", "", "" }, "" } 35854359Sroberto}; 35954359Sroberto 36054359Sroberto 36154359Sroberto/* 36254359Sroberto * Default values we use. 36354359Sroberto */ 36454359Sroberto#define DEFTIMEOUT (5) /* 5 second time out */ 36554359Sroberto#define DEFSTIMEOUT (2) /* 2 second time out after first */ 36654359Sroberto#define DEFDELAY 0x51EB852 /* 20 milliseconds, l_fp fraction */ 367132451Sroberto#define DEFHOST "localhost" /* default host name */ 36854359Sroberto#define LENHOSTNAME 256 /* host name is 256 characters long */ 36954359Sroberto#define MAXCMDS 100 /* maximum commands on cmd line */ 37054359Sroberto#define MAXHOSTS 200 /* maximum hosts on cmd line */ 37154359Sroberto#define MAXLINE 512 /* maximum line length */ 37254359Sroberto#define MAXTOKENS (1+MAXARGS+2) /* maximum number of usable tokens */ 37354359Sroberto#define MAXVARLEN 256 /* maximum length of a variable name */ 37454359Sroberto#define MAXVALLEN 400 /* maximum length of a variable value */ 37554359Sroberto#define MAXOUTLINE 72 /* maximum length of an output line */ 376182007Sroberto#define SCREENWIDTH 76 /* nominal screen width in columns */ 37754359Sroberto 37854359Sroberto/* 37954359Sroberto * Some variables used and manipulated locally 38054359Sroberto */ 38154359Srobertostruct timeval tvout = { DEFTIMEOUT, 0 }; /* time out for reads */ 38254359Srobertostruct timeval tvsout = { DEFSTIMEOUT, 0 }; /* secondary time out */ 38354359Srobertol_fp delay_time; /* delay time */ 38454359Srobertochar currenthost[LENHOSTNAME]; /* current host name */ 38554359Srobertostruct sockaddr_in hostaddr = { 0 }; /* host address */ 38654359Srobertoint showhostnames = 1; /* show host names by default */ 38754359Sroberto 388132451Srobertoint ai_fam_templ; /* address family */ 389132451Srobertoint ai_fam_default; /* default address family */ 390132451SrobertoSOCKET sockfd; /* fd socket is opened on */ 39154359Srobertoint havehost = 0; /* set to 1 when host open */ 392132451Srobertoint s_port = 0; 39354359Srobertostruct servent *server_entry = NULL; /* server entry for ntp */ 39454359Sroberto 39554359Sroberto#ifdef SYS_WINNT 39654359SrobertoDWORD NumberOfBytesWritten; 39754359Sroberto 39854359SrobertoHANDLE TimerThreadHandle = NULL; /* 1998/06/03 - Used in ntplib/machines.c */ 39954359Srobertovoid timer(void) { ; }; /* 1998/06/03 - Used in ntplib/machines.c */ 40054359Sroberto 40154359Sroberto#endif /* SYS_WINNT */ 40254359Sroberto 40354359Sroberto/* 40454359Sroberto * Sequence number used for requests. It is incremented before 40554359Sroberto * it is used. 40654359Sroberto */ 40754359Srobertou_short sequence; 40854359Sroberto 40954359Sroberto/* 41054359Sroberto * Holds data returned from queries. Declare buffer long to be sure of 41154359Sroberto * alignment. 41254359Sroberto */ 41354359Sroberto#define MAXFRAGS 24 /* maximum number of fragments */ 41454359Sroberto#define DATASIZE (MAXFRAGS*480) /* maximum amount of data */ 41554359Srobertolong pktdata[DATASIZE/sizeof(long)]; 41654359Sroberto 41754359Sroberto/* 41854359Sroberto * Holds association data for use with the &n operator. 41954359Sroberto */ 42054359Srobertostruct association assoc_cache[MAXASSOC]; 42154359Srobertoint numassoc = 0; /* number of cached associations */ 42254359Sroberto 42354359Sroberto/* 42454359Sroberto * For commands typed on the command line (with the -c option) 42554359Sroberto */ 42654359Srobertoint numcmds = 0; 42754359Srobertoconst char *ccmds[MAXCMDS]; 42854359Sroberto#define ADDCMD(cp) if (numcmds < MAXCMDS) ccmds[numcmds++] = (cp) 42954359Sroberto 43054359Sroberto/* 43154359Sroberto * When multiple hosts are specified. 43254359Sroberto */ 43354359Srobertoint numhosts = 0; 43454359Srobertoconst char *chosts[MAXHOSTS]; 43554359Sroberto#define ADDHOST(cp) if (numhosts < MAXHOSTS) chosts[numhosts++] = (cp) 43654359Sroberto 43754359Sroberto/* 43854359Sroberto * Error codes for internal use 43954359Sroberto */ 44054359Sroberto#define ERR_UNSPEC 256 44154359Sroberto#define ERR_INCOMPLETE 257 44254359Sroberto#define ERR_TIMEOUT 258 44354359Sroberto#define ERR_TOOMUCH 259 44454359Sroberto 44554359Sroberto/* 44654359Sroberto * Macro definitions we use 44754359Sroberto */ 44854359Sroberto#define ISSPACE(c) ((c) == ' ' || (c) == '\t') 44954359Sroberto#define ISEOL(c) ((c) == '\n' || (c) == '\r' || (c) == '\0') 45054359Sroberto#define STREQ(a, b) (*(a) == *(b) && strcmp((a), (b)) == 0) 45154359Sroberto 45254359Sroberto/* 45354359Sroberto * Jump buffer for longjumping back to the command level 45454359Sroberto */ 45554359Srobertojmp_buf interrupt_buf; 45654359Sroberto 45754359Sroberto/* 45854359Sroberto * Points at file being currently printed into 45954359Sroberto */ 46054359SrobertoFILE *current_output; 46154359Sroberto 46254359Sroberto/* 46354359Sroberto * Command table imported from ntpdc_ops.c 46454359Sroberto */ 46554359Srobertoextern struct xcmd opcmds[]; 46654359Sroberto 46754359Srobertochar *progname; 46854359Srobertovolatile int debug; 46954359Sroberto 47054359Sroberto#ifdef NO_MAIN_ALLOWED 47154359SrobertoCALL(ntpq,"ntpq",ntpqmain); 47254359Sroberto 47354359Srobertovoid clear_globals(void) 47454359Sroberto{ 47554359Sroberto extern int ntp_optind; 47654359Sroberto showhostnames = 0; /* don'tshow host names by default */ 47754359Sroberto ntp_optind = 0; 47854359Sroberto server_entry = NULL; /* server entry for ntp */ 47954359Sroberto havehost = 0; /* set to 1 when host open */ 48054359Sroberto numassoc = 0; /* number of cached associations */ 48154359Sroberto numcmds = 0; 48254359Sroberto numhosts = 0; 48354359Sroberto} 48454359Sroberto#endif 48554359Sroberto 48654359Sroberto/* 48754359Sroberto * main - parse arguments and handle options 48854359Sroberto */ 48954359Sroberto#ifndef NO_MAIN_ALLOWED 49054359Srobertoint 49154359Srobertomain( 49254359Sroberto int argc, 49354359Sroberto char *argv[] 49454359Sroberto ) 49554359Sroberto{ 49654359Sroberto return ntpqmain(argc, argv); 49754359Sroberto} 49854359Sroberto#endif 49954359Sroberto 50054359Srobertoint 50154359Srobertontpqmain( 50254359Sroberto int argc, 50354359Sroberto char *argv[] 50454359Sroberto ) 50554359Sroberto{ 50654359Sroberto extern int ntp_optind; 50754359Sroberto 508182007Sroberto#ifdef SYS_VXWORKS 509182007Sroberto clear_globals(); 510182007Sroberto taskPrioritySet(taskIdSelf(), 100 ); 51154359Sroberto#endif 512182007Sroberto 51354359Sroberto delay_time.l_ui = 0; 51454359Sroberto delay_time.l_uf = DEFDELAY; 51554359Sroberto 516132451Sroberto#ifdef SYS_WINNT 517132451Sroberto if (!Win32InitSockets()) 518132451Sroberto { 519132451Sroberto fprintf(stderr, "No useable winsock.dll:"); 520132451Sroberto exit(1); 521132451Sroberto } 522132451Sroberto#endif /* SYS_WINNT */ 523132451Sroberto 524132451Sroberto /* Check to see if we have IPv6. Otherwise force the -4 flag */ 525132451Sroberto if (isc_net_probeipv6() != ISC_R_SUCCESS) { 526132451Sroberto ai_fam_default = AF_INET; 527132451Sroberto } 528132451Sroberto 52954359Sroberto progname = argv[0]; 530182007Sroberto 531182007Sroberto { 532182007Sroberto int optct = optionProcess(&ntpqOptions, argc, argv); 533182007Sroberto argc -= optct; 534182007Sroberto argv += optct; 535182007Sroberto } 536182007Sroberto 537182007Sroberto switch (WHICH_IDX_IPV4) { 538182007Sroberto case INDEX_OPT_IPV4: 539182007Sroberto ai_fam_templ = AF_INET; 540182007Sroberto break; 541182007Sroberto case INDEX_OPT_IPV6: 542182007Sroberto ai_fam_templ = AF_INET6; 543182007Sroberto break; 544182007Sroberto default: 545182007Sroberto ai_fam_templ = ai_fam_default; 546182007Sroberto break; 547182007Sroberto } 548182007Sroberto 549182007Sroberto if (HAVE_OPT(COMMAND)) { 550182007Sroberto int cmdct = STACKCT_OPT( COMMAND ); 551182007Sroberto const char** cmds = STACKLST_OPT( COMMAND ); 552182007Sroberto 553182007Sroberto while (cmdct-- > 0) { 554182007Sroberto ADDCMD(*cmds++); 555182007Sroberto } 556182007Sroberto } 557182007Sroberto 558182007Sroberto debug = DESC(DEBUG_LEVEL).optOccCt; 559182007Sroberto 560182007Sroberto if (HAVE_OPT(INTERACTIVE)) { 561182007Sroberto interactive = 1; 562182007Sroberto } 563182007Sroberto 564182007Sroberto if (HAVE_OPT(NUMERIC)) { 565182007Sroberto showhostnames = 0; 566182007Sroberto } 567182007Sroberto 568182007Sroberto if (HAVE_OPT(PEERS)) { 569182007Sroberto ADDCMD("peers"); 570182007Sroberto } 571182007Sroberto 572182007Sroberto#if 0 573132451Sroberto while ((c = ntp_getopt(argc, argv, "46c:dinp")) != EOF) 57454359Sroberto switch (c) { 575132451Sroberto case '4': 576132451Sroberto ai_fam_templ = AF_INET; 577132451Sroberto break; 578132451Sroberto case '6': 579132451Sroberto ai_fam_templ = AF_INET6; 580132451Sroberto break; 58154359Sroberto case 'c': 58254359Sroberto ADDCMD(ntp_optarg); 58354359Sroberto break; 58454359Sroberto case 'd': 58554359Sroberto ++debug; 58654359Sroberto break; 58754359Sroberto case 'i': 58854359Sroberto interactive = 1; 58954359Sroberto break; 59054359Sroberto case 'n': 59154359Sroberto showhostnames = 0; 59254359Sroberto break; 59354359Sroberto case 'p': 59454359Sroberto ADDCMD("peers"); 59554359Sroberto break; 59654359Sroberto default: 59754359Sroberto errflg++; 59854359Sroberto break; 59954359Sroberto } 60054359Sroberto if (errflg) { 60154359Sroberto (void) fprintf(stderr, 602132451Sroberto "usage: %s [-46dinp] [-c cmd] host ...\n", 60354359Sroberto progname); 60454359Sroberto exit(2); 60554359Sroberto } 606182007Sroberto#endif 60754359Sroberto if (ntp_optind == argc) { 60854359Sroberto ADDHOST(DEFHOST); 60954359Sroberto } else { 61054359Sroberto for (; ntp_optind < argc; ntp_optind++) 61154359Sroberto ADDHOST(argv[ntp_optind]); 61254359Sroberto } 61354359Sroberto 61454359Sroberto if (numcmds == 0 && interactive == 0 61554359Sroberto && isatty(fileno(stdin)) && isatty(fileno(stderr))) { 61654359Sroberto interactive = 1; 61754359Sroberto } 61854359Sroberto 61954359Sroberto#ifndef SYS_WINNT /* Under NT cannot handle SIGINT, WIN32 spawns a handler */ 62054359Sroberto if (interactive) 62154359Sroberto (void) signal_no_reset(SIGINT, abortcmd); 62254359Sroberto#endif /* SYS_WINNT */ 62354359Sroberto 62454359Sroberto if (numcmds == 0) { 62554359Sroberto (void) openhost(chosts[0]); 62654359Sroberto getcmds(); 62754359Sroberto } else { 62854359Sroberto int ihost; 62954359Sroberto int icmd; 63054359Sroberto 63154359Sroberto for (ihost = 0; ihost < numhosts; ihost++) { 63254359Sroberto if (openhost(chosts[ihost])) 63354359Sroberto for (icmd = 0; icmd < numcmds; icmd++) 63454359Sroberto docmd(ccmds[icmd]); 63554359Sroberto } 63654359Sroberto } 63754359Sroberto#ifdef SYS_WINNT 63854359Sroberto WSACleanup(); 63954359Sroberto#endif /* SYS_WINNT */ 64054359Sroberto return 0; 64154359Sroberto} 64254359Sroberto 64354359Sroberto 64454359Sroberto/* 64554359Sroberto * openhost - open a socket to a host 64654359Sroberto */ 64754359Srobertostatic int 64854359Srobertoopenhost( 64954359Sroberto const char *hname 65054359Sroberto ) 65154359Sroberto{ 65254359Sroberto char temphost[LENHOSTNAME]; 653132451Sroberto int a_info, i; 654132451Sroberto struct addrinfo hints, *ai = NULL; 655132451Sroberto register const char *cp; 656132451Sroberto char name[LENHOSTNAME]; 657132451Sroberto char service[5]; 65854359Sroberto 659132451Sroberto /* 660132451Sroberto * We need to get by the [] if they were entered 661132451Sroberto */ 662132451Sroberto 663132451Sroberto cp = hname; 664132451Sroberto 665132451Sroberto if(*cp == '[') { 666132451Sroberto cp++; 667132451Sroberto for(i = 0; *cp != ']'; cp++, i++) 668132451Sroberto name[i] = *cp; 669132451Sroberto name[i] = '\0'; 670132451Sroberto hname = name; 67154359Sroberto } 67254359Sroberto 673132451Sroberto /* 674132451Sroberto * First try to resolve it as an ip address and if that fails, 675132451Sroberto * do a fullblown (dns) lookup. That way we only use the dns 676132451Sroberto * when it is needed and work around some implementations that 677132451Sroberto * will return an "IPv4-mapped IPv6 address" address if you 678132451Sroberto * give it an IPv4 address to lookup. 679132451Sroberto */ 680132451Sroberto strcpy(service, "ntp"); 681132451Sroberto memset((char *)&hints, 0, sizeof(struct addrinfo)); 682132451Sroberto hints.ai_family = ai_fam_templ; 683132451Sroberto hints.ai_protocol = IPPROTO_UDP; 684132451Sroberto hints.ai_socktype = SOCK_DGRAM; 685132451Sroberto hints.ai_flags = AI_NUMERICHOST; 686132451Sroberto 687132451Sroberto a_info = getaddrinfo(hname, service, &hints, &ai); 688182007Sroberto if (a_info == EAI_NONAME 689182007Sroberto#ifdef EAI_NODATA 690182007Sroberto || a_info == EAI_NODATA 691182007Sroberto#endif 692182007Sroberto ) { 693132451Sroberto hints.ai_flags = AI_CANONNAME; 694132451Sroberto#ifdef AI_ADDRCONFIG 695132451Sroberto hints.ai_flags |= AI_ADDRCONFIG; 696132451Sroberto#endif 697132451Sroberto a_info = getaddrinfo(hname, service, &hints, &ai); 698132451Sroberto } 699132451Sroberto /* Some older implementations don't like AI_ADDRCONFIG. */ 700132451Sroberto if (a_info == EAI_BADFLAGS) { 701132451Sroberto hints.ai_flags = AI_CANONNAME; 702132451Sroberto a_info = getaddrinfo(hname, service, &hints, &ai); 703132451Sroberto } 704132451Sroberto if (a_info != 0) { 705132451Sroberto (void) fprintf(stderr, "%s\n", gai_strerror(a_info)); 706132451Sroberto return 0; 707132451Sroberto } 708132451Sroberto 709132451Sroberto if (ai->ai_canonname == NULL) { 710132451Sroberto strncpy(temphost, stoa((struct sockaddr_storage *)ai->ai_addr), 711132451Sroberto LENHOSTNAME); 712132451Sroberto temphost[LENHOSTNAME-1] = '\0'; 713132451Sroberto 714132451Sroberto } else { 715132451Sroberto strncpy(temphost, ai->ai_canonname, LENHOSTNAME); 716132451Sroberto temphost[LENHOSTNAME-1] = '\0'; 717132451Sroberto } 718132451Sroberto 71954359Sroberto if (debug > 2) 72054359Sroberto printf("Opening host %s\n", temphost); 72154359Sroberto 72254359Sroberto if (havehost == 1) { 72354359Sroberto if (debug > 2) 72454359Sroberto printf("Closing old host %s\n", currenthost); 72554359Sroberto (void) closesocket(sockfd); 72654359Sroberto havehost = 0; 72754359Sroberto } 72854359Sroberto (void) strcpy(currenthost, temphost); 72954359Sroberto 730132451Sroberto /* port maps to the same location in both families */ 731132451Sroberto s_port = ((struct sockaddr_in6 *)ai->ai_addr)->sin6_port; 732132451Sroberto#ifdef SYS_VXWORKS 733132451Sroberto ((struct sockaddr_in6 *)&hostaddr)->sin6_port = htons(SERVER_PORT_NUM); 734132451Sroberto if (ai->ai_family == AF_INET) 735132451Sroberto *(struct sockaddr_in *)&hostaddr= 736132451Sroberto *((struct sockaddr_in *)ai->ai_addr); 737132451Sroberto else 738132451Sroberto *(struct sockaddr_in6 *)&hostaddr= 739132451Sroberto *((struct sockaddr_in6 *)ai->ai_addr); 740132451Sroberto#endif /* SYS_VXWORKS */ 74154359Sroberto 74254359Sroberto#ifdef SYS_WINNT 74354359Sroberto { 74454359Sroberto int optionValue = SO_SYNCHRONOUS_NONALERT; 74554359Sroberto int err; 746182007Sroberto 74754359Sroberto err = setsockopt(INVALID_SOCKET, SOL_SOCKET, SO_OPENTYPE, (char *)&optionValue, sizeof(optionValue)); 74854359Sroberto if (err != NO_ERROR) { 74954359Sroberto (void) fprintf(stderr, "cannot open nonoverlapped sockets\n"); 75054359Sroberto exit(1); 75154359Sroberto } 75254359Sroberto } 753132451Sroberto#endif /* SYS_WINNT */ 75454359Sroberto 755132451Sroberto sockfd = socket(ai->ai_family, SOCK_DGRAM, 0); 75654359Sroberto if (sockfd == INVALID_SOCKET) { 75754359Sroberto error("socket", "", ""); 75854359Sroberto } 75954359Sroberto 76054359Sroberto 76154359Sroberto#ifdef NEED_RCVBUF_SLOP 76254359Sroberto# ifdef SO_RCVBUF 76354359Sroberto { int rbufsize = DATASIZE + 2048; /* 2K for slop */ 76454359Sroberto if (setsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, 76554359Sroberto &rbufsize, sizeof(int)) == -1) 76654359Sroberto error("setsockopt", "", ""); 76754359Sroberto } 76854359Sroberto# endif 76954359Sroberto#endif 77054359Sroberto 771132451Sroberto#ifdef SYS_VXWORKS 77254359Sroberto if (connect(sockfd, (struct sockaddr *)&hostaddr, 77354359Sroberto sizeof(hostaddr)) == -1) 774132451Sroberto#else 775132451Sroberto if (connect(sockfd, (struct sockaddr *)ai->ai_addr, 776132451Sroberto ai->ai_addrlen) == -1) 777132451Sroberto#endif /* SYS_VXWORKS */ 77854359Sroberto error("connect", "", ""); 779132451Sroberto if (a_info == 0) 780132451Sroberto freeaddrinfo(ai); 78154359Sroberto havehost = 1; 78254359Sroberto return 1; 78354359Sroberto} 78454359Sroberto 78554359Sroberto 78654359Sroberto/* XXX ELIMINATE sendpkt similar in ntpq.c, ntpdc.c, ntp_io.c, ntptrace.c */ 78754359Sroberto/* 78854359Sroberto * sendpkt - send a packet to the remote host 78954359Sroberto */ 79054359Srobertostatic int 79154359Srobertosendpkt( 79254359Sroberto char *xdata, 79354359Sroberto int xdatalen 79454359Sroberto ) 79554359Sroberto{ 79654359Sroberto if (debug >= 3) 79754359Sroberto printf("Sending %d octets\n", xdatalen); 79854359Sroberto 79954359Sroberto 80082498Sroberto if (send(sockfd, xdata, (size_t)xdatalen, 0) == -1) { 80154359Sroberto warning("write to %s failed", currenthost, ""); 80254359Sroberto return -1; 80354359Sroberto } 80454359Sroberto 80554359Sroberto if (debug >= 4) { 80654359Sroberto int first = 8; 80754359Sroberto printf("Packet data:\n"); 80854359Sroberto while (xdatalen-- > 0) { 80954359Sroberto if (first-- == 0) { 81054359Sroberto printf("\n"); 81154359Sroberto first = 7; 81254359Sroberto } 81354359Sroberto printf(" %02x", *xdata++ & 0xff); 81454359Sroberto } 81554359Sroberto printf("\n"); 81654359Sroberto } 81754359Sroberto return 0; 81854359Sroberto} 81954359Sroberto 82054359Sroberto 82154359Sroberto 82254359Sroberto/* 82354359Sroberto * getresponse - get a (series of) response packet(s) and return the data 82454359Sroberto */ 82554359Srobertostatic int 82654359Srobertogetresponse( 82754359Sroberto int opcode, 82854359Sroberto int associd, 82954359Sroberto u_short *rstatus, 83054359Sroberto int *rsize, 83154359Sroberto char **rdata, 83254359Sroberto int timeo 83354359Sroberto ) 83454359Sroberto{ 83554359Sroberto struct ntp_control rpkt; 83654359Sroberto struct timeval tvo; 83754359Sroberto u_short offsets[MAXFRAGS+1]; 83854359Sroberto u_short counts[MAXFRAGS+1]; 83954359Sroberto u_short offset; 84054359Sroberto u_short count; 84154359Sroberto int numfrags; 84254359Sroberto int seenlastfrag; 84354359Sroberto fd_set fds; 84454359Sroberto int n; 84554359Sroberto 84654359Sroberto /* 84754359Sroberto * This is pretty tricky. We may get between 1 and MAXFRAG packets 84854359Sroberto * back in response to the request. We peel the data out of 84954359Sroberto * each packet and collect it in one long block. When the last 85054359Sroberto * packet in the sequence is received we'll know how much data we 85154359Sroberto * should have had. Note we use one long time out, should reconsider. 85254359Sroberto */ 85354359Sroberto *rsize = 0; 85454359Sroberto if (rstatus) 85554359Sroberto *rstatus = 0; 85654359Sroberto *rdata = (char *)pktdata; 85754359Sroberto 85854359Sroberto numfrags = 0; 85954359Sroberto seenlastfrag = 0; 86054359Sroberto 86154359Sroberto FD_ZERO(&fds); 86254359Sroberto 86354359Sroberto again: 86454359Sroberto if (numfrags == 0) 86554359Sroberto tvo = tvout; 86654359Sroberto else 86754359Sroberto tvo = tvsout; 86854359Sroberto 86954359Sroberto FD_SET(sockfd, &fds); 87054359Sroberto n = select(sockfd+1, &fds, (fd_set *)0, (fd_set *)0, &tvo); 87154359Sroberto 87254359Sroberto#if 0 87354359Sroberto if (debug >= 1) 87454359Sroberto printf("select() returns %d\n", n); 87554359Sroberto#endif 87654359Sroberto 87754359Sroberto if (n == -1) { 87854359Sroberto warning("select fails", "", ""); 87954359Sroberto return -1; 88054359Sroberto } 88154359Sroberto if (n == 0) { 88254359Sroberto /* 88354359Sroberto * Timed out. Return what we have 88454359Sroberto */ 88554359Sroberto if (numfrags == 0) { 88654359Sroberto if (timeo) 88754359Sroberto (void) fprintf(stderr, 88854359Sroberto "%s: timed out, nothing received\n", 88954359Sroberto currenthost); 89054359Sroberto return ERR_TIMEOUT; 89154359Sroberto } else { 89254359Sroberto if (timeo) 89354359Sroberto (void) fprintf(stderr, 89454359Sroberto "%s: timed out with incomplete data\n", 89554359Sroberto currenthost); 89654359Sroberto if (debug) { 89754359Sroberto printf("Received fragments:\n"); 89854359Sroberto for (n = 0; n < numfrags; n++) 89954359Sroberto printf("%4d %d\n", offsets[n], 90054359Sroberto counts[n]); 90154359Sroberto if (seenlastfrag) 90254359Sroberto printf("last fragment received\n"); 90354359Sroberto else 90454359Sroberto printf("last fragment not received\n"); 90554359Sroberto } 90654359Sroberto return ERR_INCOMPLETE; 90754359Sroberto } 90854359Sroberto } 90954359Sroberto 91054359Sroberto n = recv(sockfd, (char *)&rpkt, sizeof(rpkt), 0); 91154359Sroberto if (n == -1) { 91254359Sroberto warning("read", "", ""); 91354359Sroberto return -1; 91454359Sroberto } 91554359Sroberto 91654359Sroberto if (debug >= 4) { 91754359Sroberto int len = n, first = 8; 91854359Sroberto char *data = (char *)&rpkt; 91954359Sroberto 92054359Sroberto printf("Packet data:\n"); 92154359Sroberto while (len-- > 0) { 92254359Sroberto if (first-- == 0) { 92354359Sroberto printf("\n"); 92454359Sroberto first = 7; 92554359Sroberto } 92654359Sroberto printf(" %02x", *data++ & 0xff); 92754359Sroberto } 92854359Sroberto printf("\n"); 92954359Sroberto } 93054359Sroberto 93154359Sroberto /* 93254359Sroberto * Check for format errors. Bug proofing. 93354359Sroberto */ 93454359Sroberto if (n < CTL_HEADER_LEN) { 93554359Sroberto if (debug) 93654359Sroberto printf("Short (%d byte) packet received\n", n); 93754359Sroberto goto again; 93854359Sroberto } 93954359Sroberto if (PKT_VERSION(rpkt.li_vn_mode) > NTP_VERSION 94054359Sroberto || PKT_VERSION(rpkt.li_vn_mode) < NTP_OLDVERSION) { 94154359Sroberto if (debug) 94254359Sroberto printf("Packet received with version %d\n", 94354359Sroberto PKT_VERSION(rpkt.li_vn_mode)); 94454359Sroberto goto again; 94554359Sroberto } 94654359Sroberto if (PKT_MODE(rpkt.li_vn_mode) != MODE_CONTROL) { 94754359Sroberto if (debug) 94854359Sroberto printf("Packet received with mode %d\n", 94954359Sroberto PKT_MODE(rpkt.li_vn_mode)); 95054359Sroberto goto again; 95154359Sroberto } 95254359Sroberto if (!CTL_ISRESPONSE(rpkt.r_m_e_op)) { 95354359Sroberto if (debug) 95454359Sroberto printf("Received request packet, wanted response\n"); 95554359Sroberto goto again; 95654359Sroberto } 95754359Sroberto 95854359Sroberto /* 95954359Sroberto * Check opcode and sequence number for a match. 96054359Sroberto * Could be old data getting to us. 96154359Sroberto */ 96254359Sroberto if (ntohs(rpkt.sequence) != sequence) { 96354359Sroberto if (debug) 96454359Sroberto printf( 96554359Sroberto "Received sequnce number %d, wanted %d\n", 96654359Sroberto ntohs(rpkt.sequence), sequence); 96754359Sroberto goto again; 96854359Sroberto } 96954359Sroberto if (CTL_OP(rpkt.r_m_e_op) != opcode) { 97054359Sroberto if (debug) 97154359Sroberto printf( 97254359Sroberto "Received opcode %d, wanted %d (sequence number okay)\n", 97354359Sroberto CTL_OP(rpkt.r_m_e_op), opcode); 97454359Sroberto goto again; 97554359Sroberto } 97654359Sroberto 97754359Sroberto /* 97854359Sroberto * Check the error code. If non-zero, return it. 97954359Sroberto */ 98054359Sroberto if (CTL_ISERROR(rpkt.r_m_e_op)) { 98154359Sroberto int errcode; 98254359Sroberto 98354359Sroberto errcode = (ntohs(rpkt.status) >> 8) & 0xff; 98454359Sroberto if (debug && CTL_ISMORE(rpkt.r_m_e_op)) { 98554359Sroberto printf("Error code %d received on not-final packet\n", 98654359Sroberto errcode); 98754359Sroberto } 98854359Sroberto if (errcode == CERR_UNSPEC) 98954359Sroberto return ERR_UNSPEC; 99054359Sroberto return errcode; 99154359Sroberto } 99254359Sroberto 99354359Sroberto /* 99454359Sroberto * Check the association ID to make sure it matches what 99554359Sroberto * we sent. 99654359Sroberto */ 99754359Sroberto if (ntohs(rpkt.associd) != associd) { 99854359Sroberto if (debug) 99954359Sroberto printf("Association ID %d doesn't match expected %d\n", 100054359Sroberto ntohs(rpkt.associd), associd); 100154359Sroberto /* 100254359Sroberto * Hack for silly fuzzballs which, at the time of writing, 100354359Sroberto * return an assID of sys.peer when queried for system variables. 100454359Sroberto */ 100554359Sroberto#ifdef notdef 100654359Sroberto goto again; 100754359Sroberto#endif 100854359Sroberto } 100954359Sroberto 101054359Sroberto /* 101154359Sroberto * Collect offset and count. Make sure they make sense. 101254359Sroberto */ 101354359Sroberto offset = ntohs(rpkt.offset); 101454359Sroberto count = ntohs(rpkt.count); 101554359Sroberto 101654359Sroberto if (debug >= 3) { 101754359Sroberto int shouldbesize; 101854359Sroberto u_long key; 101954359Sroberto u_long *lpkt; 102054359Sroberto int maclen; 102154359Sroberto 102254359Sroberto /* 102354359Sroberto * Usually we ignore authentication, but for debugging purposes 102454359Sroberto * we watch it here. 102554359Sroberto */ 102654359Sroberto shouldbesize = CTL_HEADER_LEN + count; 102754359Sroberto 102854359Sroberto /* round to 8 octet boundary */ 102954359Sroberto shouldbesize = (shouldbesize + 7) & ~7; 103054359Sroberto 103154359Sroberto if (n & 0x3) { 103254359Sroberto printf("Packet not padded, size = %d\n", n); 103354359Sroberto } if ((maclen = n - shouldbesize) >= MIN_MAC_LEN) { 103454359Sroberto printf( 103554359Sroberto "Packet shows signs of authentication (total %d, data %d, mac %d)\n", 103654359Sroberto n, shouldbesize, maclen); 103754359Sroberto lpkt = (u_long *)&rpkt; 103854359Sroberto printf("%08lx %08lx %08lx %08lx %08lx %08lx\n", 103954359Sroberto (u_long)ntohl(lpkt[(n - maclen)/sizeof(u_long) - 3]), 104054359Sroberto (u_long)ntohl(lpkt[(n - maclen)/sizeof(u_long) - 2]), 104154359Sroberto (u_long)ntohl(lpkt[(n - maclen)/sizeof(u_long) - 1]), 104254359Sroberto (u_long)ntohl(lpkt[(n - maclen)/sizeof(u_long)]), 104354359Sroberto (u_long)ntohl(lpkt[(n - maclen)/sizeof(u_long) + 1]), 104454359Sroberto (u_long)ntohl(lpkt[(n - maclen)/sizeof(u_long) + 2])); 104554359Sroberto key = ntohl(lpkt[(n - maclen) / sizeof(u_long)]); 104654359Sroberto printf("Authenticated with keyid %lu\n", (u_long)key); 104754359Sroberto if (key != 0 && key != info_auth_keyid) { 104854359Sroberto printf("We don't know that key\n"); 104954359Sroberto } else { 105054359Sroberto if (authdecrypt(key, (u_int32 *)&rpkt, 105154359Sroberto n - maclen, maclen)) { 105254359Sroberto printf("Auth okay!\n"); 105354359Sroberto } else { 105454359Sroberto printf("Auth failed!\n"); 105554359Sroberto } 105654359Sroberto } 105754359Sroberto } 105854359Sroberto } 105954359Sroberto 106054359Sroberto if (debug >= 2) 106154359Sroberto printf("Got packet, size = %d\n", n); 106254359Sroberto if (count > (u_short)(n-CTL_HEADER_LEN)) { 106354359Sroberto if (debug) 106454359Sroberto printf( 106554359Sroberto "Received count of %d octets, data in packet is %d\n", 106654359Sroberto count, n-CTL_HEADER_LEN); 106754359Sroberto goto again; 106854359Sroberto } 106954359Sroberto if (count == 0 && CTL_ISMORE(rpkt.r_m_e_op)) { 107054359Sroberto if (debug) 107154359Sroberto printf("Received count of 0 in non-final fragment\n"); 107254359Sroberto goto again; 107354359Sroberto } 107454359Sroberto if (offset + count > sizeof(pktdata)) { 107554359Sroberto if (debug) 107654359Sroberto printf("Offset %d, count %d, too big for buffer\n", 107754359Sroberto offset, count); 107854359Sroberto return ERR_TOOMUCH; 107954359Sroberto } 108054359Sroberto if (seenlastfrag && !CTL_ISMORE(rpkt.r_m_e_op)) { 108154359Sroberto if (debug) 108254359Sroberto printf("Received second last fragment packet\n"); 108354359Sroberto goto again; 108454359Sroberto } 108554359Sroberto 108654359Sroberto /* 108754359Sroberto * So far, so good. Record this fragment, making sure it doesn't 108854359Sroberto * overlap anything. 108954359Sroberto */ 109054359Sroberto if (debug >= 2) 109154359Sroberto printf("Packet okay\n");; 109254359Sroberto 109354359Sroberto if (numfrags == MAXFRAGS) { 109454359Sroberto if (debug) 109554359Sroberto printf("Number of fragments exceeds maximum\n"); 109654359Sroberto return ERR_TOOMUCH; 109754359Sroberto } 109854359Sroberto 109954359Sroberto for (n = 0; n < numfrags; n++) { 110054359Sroberto if (offset == offsets[n]) 110154359Sroberto goto again; /* duplicate */ 110254359Sroberto if (offset < offsets[n]) 110354359Sroberto break; 110454359Sroberto } 110554359Sroberto 110654359Sroberto if ((u_short)(n > 0 && offsets[n-1] + counts[n-1]) > offset) 110754359Sroberto goto overlap; 110854359Sroberto if (n < numfrags && (u_short)(offset + count) > offsets[n]) 110954359Sroberto goto overlap; 111054359Sroberto 111154359Sroberto { 111254359Sroberto register int i; 111354359Sroberto 111454359Sroberto for (i = numfrags; i > n; i--) { 111554359Sroberto offsets[i] = offsets[i-1]; 111654359Sroberto counts[i] = counts[i-1]; 111754359Sroberto } 111854359Sroberto } 111954359Sroberto offsets[n] = offset; 112054359Sroberto counts[n] = count; 112154359Sroberto numfrags++; 112254359Sroberto 112354359Sroberto /* 112454359Sroberto * Got that stuffed in right. Figure out if this was the last. 112554359Sroberto * Record status info out of the last packet. 112654359Sroberto */ 112754359Sroberto if (!CTL_ISMORE(rpkt.r_m_e_op)) { 112854359Sroberto seenlastfrag = 1; 112954359Sroberto if (rstatus != 0) 113054359Sroberto *rstatus = ntohs(rpkt.status); 113154359Sroberto } 113254359Sroberto 113354359Sroberto /* 113454359Sroberto * Copy the data into the data buffer. 113554359Sroberto */ 113654359Sroberto memmove((char *)pktdata + offset, (char *)rpkt.data, count); 113754359Sroberto 113854359Sroberto /* 113954359Sroberto * If we've seen the last fragment, look for holes in the sequence. 114054359Sroberto * If there aren't any, we're done. 114154359Sroberto */ 114254359Sroberto if (seenlastfrag && offsets[0] == 0) { 114354359Sroberto for (n = 1; n < numfrags; n++) { 114454359Sroberto if (offsets[n-1] + counts[n-1] != offsets[n]) 114554359Sroberto break; 114654359Sroberto } 114754359Sroberto if (n == numfrags) { 114854359Sroberto *rsize = offsets[numfrags-1] + counts[numfrags-1]; 114954359Sroberto return 0; 115054359Sroberto } 115154359Sroberto } 115254359Sroberto goto again; 115354359Sroberto 115454359Sroberto overlap: 115554359Sroberto /* 115654359Sroberto * Print debugging message about overlapping fragments 115754359Sroberto */ 115854359Sroberto if (debug) 115954359Sroberto printf("Overlapping fragments returned in response\n"); 116054359Sroberto goto again; 116154359Sroberto} 116254359Sroberto 116354359Sroberto 116454359Sroberto/* 116554359Sroberto * sendrequest - format and send a request packet 116654359Sroberto */ 116754359Srobertostatic int 116854359Srobertosendrequest( 116954359Sroberto int opcode, 117054359Sroberto int associd, 117154359Sroberto int auth, 117254359Sroberto int qsize, 117354359Sroberto char *qdata 117454359Sroberto ) 117554359Sroberto{ 117654359Sroberto struct ntp_control qpkt; 117754359Sroberto int pktsize; 117854359Sroberto 117954359Sroberto /* 118054359Sroberto * Check to make sure the data will fit in one packet 118154359Sroberto */ 118254359Sroberto if (qsize > CTL_MAX_DATA_LEN) { 118354359Sroberto (void) fprintf(stderr, 118454359Sroberto "***Internal error! qsize (%d) too large\n", 118554359Sroberto qsize); 118654359Sroberto return 1; 118754359Sroberto } 118854359Sroberto 118954359Sroberto /* 119054359Sroberto * Fill in the packet 119154359Sroberto */ 119254359Sroberto qpkt.li_vn_mode = PKT_LI_VN_MODE(0, pktversion, MODE_CONTROL); 1193132451Sroberto qpkt.r_m_e_op = (u_char)(opcode & CTL_OP_MASK); 119454359Sroberto qpkt.sequence = htons(sequence); 119554359Sroberto qpkt.status = 0; 119654359Sroberto qpkt.associd = htons((u_short)associd); 119754359Sroberto qpkt.offset = 0; 119854359Sroberto qpkt.count = htons((u_short)qsize); 119954359Sroberto 120054359Sroberto /* 120154359Sroberto * If we have data, copy it in and pad it out to a 64 120254359Sroberto * bit boundary. 120354359Sroberto */ 120454359Sroberto if (qsize > 0) { 120554359Sroberto memmove((char *)qpkt.data, qdata, (unsigned)qsize); 120654359Sroberto pktsize = qsize + CTL_HEADER_LEN; 120754359Sroberto while (pktsize & (sizeof(u_long) - 1)) { 120854359Sroberto qpkt.data[qsize++] = 0; 120954359Sroberto pktsize++; 121054359Sroberto } 121154359Sroberto } else { 121254359Sroberto pktsize = CTL_HEADER_LEN; 121354359Sroberto } 121454359Sroberto 121554359Sroberto /* 121654359Sroberto * If it isn't authenticated we can just send it. Otherwise 121754359Sroberto * we're going to have to think about it a little. 121854359Sroberto */ 121954359Sroberto if (!auth && !always_auth) { 122054359Sroberto return sendpkt((char *)&qpkt, pktsize); 122154359Sroberto } else { 122254359Sroberto const char *pass = "\0"; 122354359Sroberto int maclen = 0; 122454359Sroberto u_long my_keyid; 122554359Sroberto 122654359Sroberto /* 122754359Sroberto * Pad out packet to a multiple of 8 octets to be sure 122854359Sroberto * receiver can handle it. 122954359Sroberto */ 123054359Sroberto while (pktsize & 7) { 123154359Sroberto qpkt.data[qsize++] = 0; 123254359Sroberto pktsize++; 123354359Sroberto } 123454359Sroberto 123554359Sroberto /* 123654359Sroberto * Get the keyid and the password if we don't have one. 123754359Sroberto */ 123854359Sroberto if (info_auth_keyid == 0) { 1239132451Sroberto int u_keyid = getkeyid("Keyid: "); 1240132451Sroberto if (u_keyid == 0 || u_keyid > NTP_MAXKEY) { 124154359Sroberto (void) fprintf(stderr, 124254359Sroberto "Invalid key identifier\n"); 124354359Sroberto return 1; 124454359Sroberto } 1245132451Sroberto info_auth_keyid = u_keyid; 124654359Sroberto } 124754359Sroberto if (!authistrusted(info_auth_keyid)) { 1248132451Sroberto pass = getpass("MD5 Password: "); 124954359Sroberto if (*pass == '\0') { 125054359Sroberto (void) fprintf(stderr, 125154359Sroberto "Invalid password\n"); 125254359Sroberto return (1); 125354359Sroberto } 125454359Sroberto } 125554359Sroberto authusekey(info_auth_keyid, info_auth_keytype, (const u_char *)pass); 125654359Sroberto authtrust(info_auth_keyid, 1); 125754359Sroberto 125854359Sroberto /* 125954359Sroberto * Stick the keyid in the packet where 126054359Sroberto * cp currently points. Cp should be aligned 126154359Sroberto * properly. Then do the encryptions. 126254359Sroberto */ 126354359Sroberto my_keyid = htonl(info_auth_keyid); 126454359Sroberto memcpy(&qpkt.data[qsize], &my_keyid, sizeof my_keyid); 126554359Sroberto maclen = authencrypt(info_auth_keyid, (u_int32 *)&qpkt, 126654359Sroberto pktsize); 126754359Sroberto if (maclen == 0) { 126854359Sroberto (void) fprintf(stderr, "Key not found\n"); 126954359Sroberto return (1); 127054359Sroberto } 127154359Sroberto return sendpkt((char *)&qpkt, pktsize + maclen); 127254359Sroberto } 127354359Sroberto /*NOTREACHED*/ 127454359Sroberto} 127554359Sroberto 127654359Sroberto 127754359Sroberto/* 127854359Sroberto * doquery - send a request and process the response 127954359Sroberto */ 128054359Srobertoint 128154359Srobertodoquery( 128254359Sroberto int opcode, 128354359Sroberto int associd, 128454359Sroberto int auth, 128554359Sroberto int qsize, 128654359Sroberto char *qdata, 128754359Sroberto u_short *rstatus, 128854359Sroberto int *rsize, 128954359Sroberto char **rdata 129054359Sroberto ) 129154359Sroberto{ 129254359Sroberto int res; 129354359Sroberto int done; 129454359Sroberto 129554359Sroberto /* 129654359Sroberto * Check to make sure host is open 129754359Sroberto */ 129854359Sroberto if (!havehost) { 129954359Sroberto (void) fprintf(stderr, "***No host open, use `host' command\n"); 130054359Sroberto return -1; 130154359Sroberto } 130254359Sroberto 130354359Sroberto done = 0; 130454359Sroberto sequence++; 130554359Sroberto 130654359Sroberto again: 130754359Sroberto /* 130854359Sroberto * send a request 130954359Sroberto */ 131054359Sroberto res = sendrequest(opcode, associd, auth, qsize, qdata); 131154359Sroberto if (res != 0) 131254359Sroberto return res; 131354359Sroberto 131454359Sroberto /* 131554359Sroberto * Get the response. If we got a standard error, print a message 131654359Sroberto */ 131754359Sroberto res = getresponse(opcode, associd, rstatus, rsize, rdata, done); 131854359Sroberto 131954359Sroberto if (res > 0) { 132054359Sroberto if (!done && (res == ERR_TIMEOUT || res == ERR_INCOMPLETE)) { 132154359Sroberto if (res == ERR_INCOMPLETE) { 132254359Sroberto /* 132354359Sroberto * better bump the sequence so we don't 132454359Sroberto * get confused about differing fragments. 132554359Sroberto */ 132654359Sroberto sequence++; 132754359Sroberto } 132854359Sroberto done = 1; 132954359Sroberto goto again; 133054359Sroberto } 1331182007Sroberto if (numhosts > 1) 1332182007Sroberto (void) fprintf(stderr, "server=%s ", currenthost); 133354359Sroberto switch(res) { 133454359Sroberto case CERR_BADFMT: 133554359Sroberto (void) fprintf(stderr, 133654359Sroberto "***Server reports a bad format request packet\n"); 133754359Sroberto break; 133854359Sroberto case CERR_PERMISSION: 133954359Sroberto (void) fprintf(stderr, 134054359Sroberto "***Server disallowed request (authentication?)\n"); 134154359Sroberto break; 134254359Sroberto case CERR_BADOP: 134354359Sroberto (void) fprintf(stderr, 134454359Sroberto "***Server reports a bad opcode in request\n"); 134554359Sroberto break; 134654359Sroberto case CERR_BADASSOC: 134754359Sroberto (void) fprintf(stderr, 134854359Sroberto "***Association ID %d unknown to server\n",associd); 134954359Sroberto break; 135054359Sroberto case CERR_UNKNOWNVAR: 135154359Sroberto (void) fprintf(stderr, 135254359Sroberto "***A request variable unknown to the server\n"); 135354359Sroberto break; 135454359Sroberto case CERR_BADVALUE: 135554359Sroberto (void) fprintf(stderr, 135654359Sroberto "***Server indicates a request variable was bad\n"); 135754359Sroberto break; 135854359Sroberto case ERR_UNSPEC: 135954359Sroberto (void) fprintf(stderr, 136054359Sroberto "***Server returned an unspecified error\n"); 136154359Sroberto break; 136254359Sroberto case ERR_TIMEOUT: 136354359Sroberto (void) fprintf(stderr, "***Request timed out\n"); 136454359Sroberto break; 136554359Sroberto case ERR_INCOMPLETE: 136654359Sroberto (void) fprintf(stderr, 136754359Sroberto "***Response from server was incomplete\n"); 136854359Sroberto break; 136954359Sroberto case ERR_TOOMUCH: 137054359Sroberto (void) fprintf(stderr, 137154359Sroberto "***Buffer size exceeded for returned data\n"); 137254359Sroberto break; 137354359Sroberto default: 137454359Sroberto (void) fprintf(stderr, 137554359Sroberto "***Server returns unknown error code %d\n", res); 137654359Sroberto break; 137754359Sroberto } 137854359Sroberto } 137954359Sroberto return res; 138054359Sroberto} 138154359Sroberto 138254359Sroberto 138354359Sroberto/* 138454359Sroberto * getcmds - read commands from the standard input and execute them 138554359Sroberto */ 138654359Srobertostatic void 138754359Srobertogetcmds(void) 138854359Sroberto{ 1389132451Sroberto#if defined(HAVE_LIBREADLINE) || defined(HAVE_LIBEDIT) 1390106163Sroberto char *line; 139154359Sroberto 1392106163Sroberto for (;;) { 1393106163Sroberto if ((line = readline(interactive?prompt:"")) == NULL) return; 1394106163Sroberto if (*line) add_history(line); 1395106163Sroberto docmd(line); 1396106163Sroberto free(line); 1397106163Sroberto } 1398132451Sroberto#else /* not (HAVE_LIBREADLINE || HAVE_LIBEDIT) */ 1399106163Sroberto char line[MAXLINE]; 1400106163Sroberto 1401106163Sroberto for (;;) { 1402106163Sroberto if (interactive) { 1403106163Sroberto#ifdef VMS /* work around a problem with mixing stdout & stderr */ 1404106163Sroberto fputs("",stdout); 140554359Sroberto#endif 1406106163Sroberto (void) fputs(prompt, stderr); 1407106163Sroberto (void) fflush(stderr); 1408106163Sroberto } 140954359Sroberto 1410106163Sroberto if (fgets(line, sizeof line, stdin) == NULL) 1411106163Sroberto return; 141254359Sroberto 1413106163Sroberto docmd(line); 1414106163Sroberto } 1415132451Sroberto#endif /* not (HAVE_LIBREADLINE || HAVE_LIBEDIT) */ 141654359Sroberto} 141754359Sroberto 1418132451Sroberto#ifndef SYS_WINNT /* Under NT cannot handle SIGINT, WIN32 spawns a handler */ 141954359Sroberto/* 142054359Sroberto * abortcmd - catch interrupts and abort the current command 142154359Sroberto */ 142254359Srobertostatic RETSIGTYPE 142354359Srobertoabortcmd( 142454359Sroberto int sig 142554359Sroberto ) 142654359Sroberto{ 142754359Sroberto if (current_output == stdout) 142854359Sroberto (void) fflush(stdout); 142954359Sroberto putc('\n', stderr); 143054359Sroberto (void) fflush(stderr); 143154359Sroberto if (jump) longjmp(interrupt_buf, 1); 143254359Sroberto} 1433132451Sroberto#endif /* SYS_WINNT */ 143454359Sroberto 143554359Sroberto/* 143654359Sroberto * docmd - decode the command line and execute a command 143754359Sroberto */ 143854359Srobertostatic void 143954359Srobertodocmd( 144054359Sroberto const char *cmdline 144154359Sroberto ) 144254359Sroberto{ 144354359Sroberto char *tokens[1+MAXARGS+2]; 144454359Sroberto struct parse pcmd; 144554359Sroberto int ntok; 144654359Sroberto static int i; 144754359Sroberto struct xcmd *xcmd; 144854359Sroberto 144954359Sroberto /* 145054359Sroberto * Tokenize the command line. If nothing on it, return. 145154359Sroberto */ 145254359Sroberto tokenize(cmdline, tokens, &ntok); 145354359Sroberto if (ntok == 0) 145454359Sroberto return; 145554359Sroberto 145654359Sroberto /* 145754359Sroberto * Find the appropriate command description. 145854359Sroberto */ 145954359Sroberto i = findcmd(tokens[0], builtins, opcmds, &xcmd); 146054359Sroberto if (i == 0) { 146154359Sroberto (void) fprintf(stderr, "***Command `%s' unknown\n", 146254359Sroberto tokens[0]); 146354359Sroberto return; 146454359Sroberto } else if (i >= 2) { 146554359Sroberto (void) fprintf(stderr, "***Command `%s' ambiguous\n", 146654359Sroberto tokens[0]); 146754359Sroberto return; 146854359Sroberto } 146954359Sroberto 147054359Sroberto /* 147154359Sroberto * Save the keyword, then walk through the arguments, interpreting 147254359Sroberto * as we go. 147354359Sroberto */ 147454359Sroberto pcmd.keyword = tokens[0]; 147554359Sroberto pcmd.nargs = 0; 147654359Sroberto for (i = 0; i < MAXARGS && xcmd->arg[i] != NO; i++) { 147754359Sroberto if ((i+1) >= ntok) { 147854359Sroberto if (!(xcmd->arg[i] & OPT)) { 147954359Sroberto printusage(xcmd, stderr); 148054359Sroberto return; 148154359Sroberto } 148254359Sroberto break; 148354359Sroberto } 148454359Sroberto if ((xcmd->arg[i] & OPT) && (*tokens[i+1] == '>')) 148554359Sroberto break; 148654359Sroberto if (!getarg(tokens[i+1], (int)xcmd->arg[i], &pcmd.argval[i])) 148754359Sroberto return; 148854359Sroberto pcmd.nargs++; 148954359Sroberto } 149054359Sroberto 149154359Sroberto i++; 149254359Sroberto if (i < ntok && *tokens[i] == '>') { 149354359Sroberto char *fname; 149454359Sroberto 149554359Sroberto if (*(tokens[i]+1) != '\0') 149654359Sroberto fname = tokens[i]+1; 149754359Sroberto else if ((i+1) < ntok) 149854359Sroberto fname = tokens[i+1]; 149954359Sroberto else { 150054359Sroberto (void) fprintf(stderr, "***No file for redirect\n"); 150154359Sroberto return; 150254359Sroberto } 150354359Sroberto 150454359Sroberto current_output = fopen(fname, "w"); 150554359Sroberto if (current_output == NULL) { 150654359Sroberto (void) fprintf(stderr, "***Error opening %s: ", fname); 150754359Sroberto perror(""); 150854359Sroberto return; 150954359Sroberto } 151054359Sroberto i = 1; /* flag we need a close */ 151154359Sroberto } else { 151254359Sroberto current_output = stdout; 151354359Sroberto i = 0; /* flag no close */ 151454359Sroberto } 151554359Sroberto 151654359Sroberto if (interactive && setjmp(interrupt_buf)) { 151754359Sroberto jump = 0; 151854359Sroberto return; 151954359Sroberto } else { 152054359Sroberto jump++; 152154359Sroberto (xcmd->handler)(&pcmd, current_output); 152254359Sroberto jump = 0; /* HMS: 961106: was after fclose() */ 152354359Sroberto if (i) (void) fclose(current_output); 152454359Sroberto } 152554359Sroberto} 152654359Sroberto 152754359Sroberto 152854359Sroberto/* 152954359Sroberto * tokenize - turn a command line into tokens 153054359Sroberto */ 153154359Srobertostatic void 153254359Srobertotokenize( 153354359Sroberto const char *line, 153454359Sroberto char **tokens, 153554359Sroberto int *ntok 153654359Sroberto ) 153754359Sroberto{ 153854359Sroberto register const char *cp; 153954359Sroberto register char *sp; 154054359Sroberto static char tspace[MAXLINE]; 154154359Sroberto 154254359Sroberto sp = tspace; 154354359Sroberto cp = line; 154454359Sroberto for (*ntok = 0; *ntok < MAXTOKENS; (*ntok)++) { 154554359Sroberto tokens[*ntok] = sp; 154654359Sroberto while (ISSPACE(*cp)) 154754359Sroberto cp++; 154854359Sroberto if (ISEOL(*cp)) 154954359Sroberto break; 155054359Sroberto do { 155154359Sroberto *sp++ = *cp++; 155254359Sroberto } while (!ISSPACE(*cp) && !ISEOL(*cp)); 155354359Sroberto 155454359Sroberto *sp++ = '\0'; 155554359Sroberto } 155654359Sroberto} 155754359Sroberto 155854359Sroberto 155954359Sroberto 156054359Sroberto/* 156154359Sroberto * findcmd - find a command in a command description table 156254359Sroberto */ 156354359Srobertostatic int 156454359Srobertofindcmd( 156554359Sroberto register char *str, 156654359Sroberto struct xcmd *clist1, 156754359Sroberto struct xcmd *clist2, 156854359Sroberto struct xcmd **cmd 156954359Sroberto ) 157054359Sroberto{ 157154359Sroberto register struct xcmd *cl; 157254359Sroberto register int clen; 157354359Sroberto int nmatch; 157454359Sroberto struct xcmd *nearmatch = NULL; 157554359Sroberto struct xcmd *clist; 157654359Sroberto 157754359Sroberto clen = strlen(str); 157854359Sroberto nmatch = 0; 157954359Sroberto if (clist1 != 0) 158054359Sroberto clist = clist1; 158154359Sroberto else if (clist2 != 0) 158254359Sroberto clist = clist2; 158354359Sroberto else 158454359Sroberto return 0; 158554359Sroberto 158654359Sroberto again: 158754359Sroberto for (cl = clist; cl->keyword != 0; cl++) { 158854359Sroberto /* do a first character check, for efficiency */ 158954359Sroberto if (*str != *(cl->keyword)) 159054359Sroberto continue; 159154359Sroberto if (strncmp(str, cl->keyword, (unsigned)clen) == 0) { 159254359Sroberto /* 159354359Sroberto * Could be extact match, could be approximate. 159454359Sroberto * Is exact if the length of the keyword is the 159554359Sroberto * same as the str. 159654359Sroberto */ 159754359Sroberto if (*((cl->keyword) + clen) == '\0') { 159854359Sroberto *cmd = cl; 159954359Sroberto return 1; 160054359Sroberto } 160154359Sroberto nmatch++; 160254359Sroberto nearmatch = cl; 160354359Sroberto } 160454359Sroberto } 160554359Sroberto 160654359Sroberto /* 160754359Sroberto * See if there is more to do. If so, go again. Sorry about the 160854359Sroberto * goto, too much looking at BSD sources... 160954359Sroberto */ 161054359Sroberto if (clist == clist1 && clist2 != 0) { 161154359Sroberto clist = clist2; 161254359Sroberto goto again; 161354359Sroberto } 161454359Sroberto 161554359Sroberto /* 161654359Sroberto * If we got extactly 1 near match, use it, else return number 161754359Sroberto * of matches. 161854359Sroberto */ 161954359Sroberto if (nmatch == 1) { 162054359Sroberto *cmd = nearmatch; 162154359Sroberto return 1; 162254359Sroberto } 162354359Sroberto return nmatch; 162454359Sroberto} 162554359Sroberto 162654359Sroberto 162754359Sroberto/* 162854359Sroberto * getarg - interpret an argument token 162954359Sroberto */ 163054359Srobertostatic int 163154359Srobertogetarg( 163254359Sroberto char *str, 163354359Sroberto int code, 163454359Sroberto arg_v *argp 163554359Sroberto ) 163654359Sroberto{ 163754359Sroberto int isneg; 163854359Sroberto char *cp, *np; 163954359Sroberto static const char *digits = "0123456789"; 164054359Sroberto 164154359Sroberto switch (code & ~OPT) { 1642182007Sroberto case NTP_STR: 164354359Sroberto argp->string = str; 164454359Sroberto break; 1645182007Sroberto case NTP_ADD: 1646132451Sroberto if (!getnetnum(str, &(argp->netnum), (char *)0, 0)) { 164754359Sroberto return 0; 164854359Sroberto } 164954359Sroberto break; 1650182007Sroberto case NTP_INT: 1651182007Sroberto case NTP_UINT: 165254359Sroberto isneg = 0; 165354359Sroberto np = str; 165454359Sroberto if (*np == '&') { 165554359Sroberto np++; 165654359Sroberto isneg = atoi(np); 165754359Sroberto if (isneg <= 0) { 165854359Sroberto (void) fprintf(stderr, 165954359Sroberto "***Association value `%s' invalid/undecodable\n", str); 166054359Sroberto return 0; 166154359Sroberto } 166254359Sroberto if (isneg > numassoc) { 1663132451Sroberto if (numassoc == 0) { 1664132451Sroberto (void) fprintf(stderr, 1665132451Sroberto "***Association for `%s' unknown (max &%d)\n", 1666132451Sroberto str, numassoc); 1667132451Sroberto return 0; 1668132451Sroberto } else { 1669132451Sroberto isneg = numassoc; 1670132451Sroberto } 167154359Sroberto } 167254359Sroberto argp->uval = assoc_cache[isneg-1].assid; 167354359Sroberto break; 167454359Sroberto } 167554359Sroberto 167654359Sroberto if (*np == '-') { 167754359Sroberto np++; 167854359Sroberto isneg = 1; 167954359Sroberto } 168054359Sroberto 168154359Sroberto argp->uval = 0; 168254359Sroberto do { 168354359Sroberto cp = strchr(digits, *np); 168454359Sroberto if (cp == NULL) { 168554359Sroberto (void) fprintf(stderr, 168654359Sroberto "***Illegal integer value %s\n", str); 168754359Sroberto return 0; 168854359Sroberto } 168954359Sroberto argp->uval *= 10; 169054359Sroberto argp->uval += (cp - digits); 169154359Sroberto } while (*(++np) != '\0'); 169254359Sroberto 169354359Sroberto if (isneg) { 1694182007Sroberto if ((code & ~OPT) == NTP_UINT) { 169554359Sroberto (void) fprintf(stderr, 169654359Sroberto "***Value %s should be unsigned\n", str); 169754359Sroberto return 0; 169854359Sroberto } 169954359Sroberto argp->ival = -argp->ival; 170054359Sroberto } 170154359Sroberto break; 1702132451Sroberto case IP_VERSION: 1703132451Sroberto if (!strcmp("-6", str)) 1704132451Sroberto argp->ival = 6 ; 1705132451Sroberto else if (!strcmp("-4", str)) 1706132451Sroberto argp->ival = 4 ; 1707132451Sroberto else { 1708132451Sroberto (void) fprintf(stderr, 1709132451Sroberto "***Version must be either 4 or 6\n"); 1710132451Sroberto return 0; 1711132451Sroberto } 1712132451Sroberto break; 171354359Sroberto } 171454359Sroberto 171554359Sroberto return 1; 171654359Sroberto} 171754359Sroberto 171854359Sroberto 171954359Sroberto/* 172054359Sroberto * getnetnum - given a host name, return its net number 172154359Sroberto * and (optional) full name 172254359Sroberto */ 172354359Srobertoint 172454359Srobertogetnetnum( 172554359Sroberto const char *hname, 1726132451Sroberto struct sockaddr_storage *num, 1727132451Sroberto char *fullhost, 1728132451Sroberto int af 172954359Sroberto ) 173054359Sroberto{ 1731132451Sroberto int sockaddr_len; 1732132451Sroberto struct addrinfo hints, *ai = NULL; 173354359Sroberto 1734132451Sroberto sockaddr_len = (af == AF_INET) 1735132451Sroberto ? sizeof(struct sockaddr_in) 1736132451Sroberto : sizeof(struct sockaddr_in6); 1737132451Sroberto memset((char *)&hints, 0, sizeof(struct addrinfo)); 1738132451Sroberto hints.ai_flags = AI_CANONNAME; 1739132451Sroberto#ifdef AI_ADDRCONFIG 1740132451Sroberto hints.ai_flags |= AI_ADDRCONFIG; 1741132451Sroberto#endif 1742132451Sroberto 1743132451Sroberto /* decodenetnum works with addresses only */ 174454359Sroberto if (decodenetnum(hname, num)) { 174554359Sroberto if (fullhost != 0) { 1746132451Sroberto getnameinfo((struct sockaddr *)num, sockaddr_len, 1747132451Sroberto fullhost, sizeof(fullhost), NULL, 0, 1748132451Sroberto NI_NUMERICHOST); 174954359Sroberto } 175054359Sroberto return 1; 1751182007Sroberto } else if (getaddrinfo(hname, "ntp", &hints, &ai) == 0) { 1752132451Sroberto memmove((char *)num, ai->ai_addr, ai->ai_addrlen); 1753132451Sroberto if (ai->ai_canonname != 0) 1754132451Sroberto (void) strcpy(fullhost, ai->ai_canonname); 175554359Sroberto return 1; 175654359Sroberto } else { 175754359Sroberto (void) fprintf(stderr, "***Can't find host %s\n", hname); 175854359Sroberto return 0; 175954359Sroberto } 176054359Sroberto /*NOTREACHED*/ 176154359Sroberto} 176254359Sroberto 176354359Sroberto/* 176454359Sroberto * nntohost - convert network number to host name. This routine enforces 176554359Sroberto * the showhostnames setting. 176654359Sroberto */ 176754359Srobertochar * 176854359Srobertonntohost( 1769132451Sroberto struct sockaddr_storage *netnum 177054359Sroberto ) 177154359Sroberto{ 177254359Sroberto if (!showhostnames) 1773132451Sroberto return stoa(netnum); 1774132451Sroberto if ((netnum->ss_family == AF_INET) && ISREFCLOCKADR(netnum)) 1775132451Sroberto return refnumtoa(netnum); 1776132451Sroberto return socktohost(netnum); 177754359Sroberto} 177854359Sroberto 177954359Sroberto 178054359Sroberto/* 178154359Sroberto * rtdatetolfp - decode an RT-11 date into an l_fp 178254359Sroberto */ 178354359Srobertostatic int 178454359Srobertortdatetolfp( 178554359Sroberto char *str, 178654359Sroberto l_fp *lfp 178754359Sroberto ) 178854359Sroberto{ 178954359Sroberto register char *cp; 179054359Sroberto register int i; 179154359Sroberto struct calendar cal; 179254359Sroberto char buf[4]; 179354359Sroberto static const char *months[12] = { 179454359Sroberto "Jan", "Feb", "Mar", "Apr", "May", "Jun", 179554359Sroberto "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" 179654359Sroberto }; 179754359Sroberto 179854359Sroberto cal.yearday = 0; 179954359Sroberto 180054359Sroberto /* 180154359Sroberto * An RT-11 date looks like: 180254359Sroberto * 180354359Sroberto * d[d]-Mth-y[y] hh:mm:ss 180454359Sroberto * 180554359Sroberto * (No docs, but assume 4-digit years are also legal...) 180654359Sroberto * 180754359Sroberto * d[d]-Mth-y[y[y[y]]] hh:mm:ss 180854359Sroberto */ 180954359Sroberto cp = str; 181054359Sroberto if (!isdigit((int)*cp)) { 181154359Sroberto if (*cp == '-') { 181254359Sroberto /* 181354359Sroberto * Catch special case 181454359Sroberto */ 181554359Sroberto L_CLR(lfp); 181654359Sroberto return 1; 181754359Sroberto } 181854359Sroberto return 0; 181954359Sroberto } 182054359Sroberto 1821132451Sroberto cal.monthday = (u_char) (*cp++ - '0'); /* ascii dependent */ 182254359Sroberto if (isdigit((int)*cp)) { 1823132451Sroberto cal.monthday = (u_char)((cal.monthday << 3) + (cal.monthday << 1)); 1824132451Sroberto cal.monthday = (u_char)(cal.monthday + *cp++ - '0'); 182554359Sroberto } 182654359Sroberto 182754359Sroberto if (*cp++ != '-') 182854359Sroberto return 0; 182954359Sroberto 183054359Sroberto for (i = 0; i < 3; i++) 183154359Sroberto buf[i] = *cp++; 183254359Sroberto buf[3] = '\0'; 183354359Sroberto 183454359Sroberto for (i = 0; i < 12; i++) 183554359Sroberto if (STREQ(buf, months[i])) 183654359Sroberto break; 183754359Sroberto if (i == 12) 183854359Sroberto return 0; 1839132451Sroberto cal.month = (u_char)(i + 1); 184054359Sroberto 184154359Sroberto if (*cp++ != '-') 184254359Sroberto return 0; 184354359Sroberto 184454359Sroberto if (!isdigit((int)*cp)) 184554359Sroberto return 0; 1846132451Sroberto cal.year = (u_short)(*cp++ - '0'); 184754359Sroberto if (isdigit((int)*cp)) { 1848132451Sroberto cal.year = (u_short)((cal.year << 3) + (cal.year << 1)); 1849132451Sroberto cal.year = (u_short)(*cp++ - '0'); 185054359Sroberto } 185154359Sroberto if (isdigit((int)*cp)) { 1852132451Sroberto cal.year = (u_short)((cal.year << 3) + (cal.year << 1)); 1853132451Sroberto cal.year = (u_short)(cal.year + *cp++ - '0'); 185454359Sroberto } 185554359Sroberto if (isdigit((int)*cp)) { 1856132451Sroberto cal.year = (u_short)((cal.year << 3) + (cal.year << 1)); 1857132451Sroberto cal.year = (u_short)(cal.year + *cp++ - '0'); 185854359Sroberto } 185954359Sroberto 186054359Sroberto /* 186154359Sroberto * Catch special case. If cal.year == 0 this is a zero timestamp. 186254359Sroberto */ 186354359Sroberto if (cal.year == 0) { 186454359Sroberto L_CLR(lfp); 186554359Sroberto return 1; 186654359Sroberto } 186754359Sroberto 186854359Sroberto if (*cp++ != ' ' || !isdigit((int)*cp)) 186954359Sroberto return 0; 1870132451Sroberto cal.hour = (u_char)(*cp++ - '0'); 187154359Sroberto if (isdigit((int)*cp)) { 1872132451Sroberto cal.hour = (u_char)((cal.hour << 3) + (cal.hour << 1)); 1873132451Sroberto cal.hour = (u_char)(cal.hour + *cp++ - '0'); 187454359Sroberto } 187554359Sroberto 187654359Sroberto if (*cp++ != ':' || !isdigit((int)*cp)) 187754359Sroberto return 0; 1878132451Sroberto cal.minute = (u_char)(*cp++ - '0'); 187954359Sroberto if (isdigit((int)*cp)) { 1880132451Sroberto cal.minute = (u_char)((cal.minute << 3) + (cal.minute << 1)); 1881132451Sroberto cal.minute = (u_char)(cal.minute + *cp++ - '0'); 188254359Sroberto } 188354359Sroberto 188454359Sroberto if (*cp++ != ':' || !isdigit((int)*cp)) 188554359Sroberto return 0; 1886132451Sroberto cal.second = (u_char)(*cp++ - '0'); 188754359Sroberto if (isdigit((int)*cp)) { 1888132451Sroberto cal.second = (u_char)((cal.second << 3) + (cal.second << 1)); 1889132451Sroberto cal.second = (u_char)(cal.second + *cp++ - '0'); 189054359Sroberto } 189154359Sroberto 189254359Sroberto /* 189354359Sroberto * For RT-11, 1972 seems to be the pivot year 189454359Sroberto */ 189554359Sroberto if (cal.year < 72) 189654359Sroberto cal.year += 2000; 189754359Sroberto if (cal.year < 100) 189854359Sroberto cal.year += 1900; 189954359Sroberto 190054359Sroberto lfp->l_ui = caltontp(&cal); 190154359Sroberto lfp->l_uf = 0; 190254359Sroberto return 1; 190354359Sroberto} 190454359Sroberto 190554359Sroberto 190654359Sroberto/* 190754359Sroberto * decodets - decode a timestamp into an l_fp format number, with 190854359Sroberto * consideration of fuzzball formats. 190954359Sroberto */ 191054359Srobertoint 191154359Srobertodecodets( 191254359Sroberto char *str, 191354359Sroberto l_fp *lfp 191454359Sroberto ) 191554359Sroberto{ 191654359Sroberto /* 191754359Sroberto * If it starts with a 0x, decode as hex. 191854359Sroberto */ 191954359Sroberto if (*str == '0' && (*(str+1) == 'x' || *(str+1) == 'X')) 192054359Sroberto return hextolfp(str+2, lfp); 192154359Sroberto 192254359Sroberto /* 192354359Sroberto * If it starts with a '"', try it as an RT-11 date. 192454359Sroberto */ 192554359Sroberto if (*str == '"') { 192654359Sroberto register char *cp = str+1; 192754359Sroberto register char *bp; 192854359Sroberto char buf[30]; 192954359Sroberto 193054359Sroberto bp = buf; 193154359Sroberto while (*cp != '"' && *cp != '\0' && bp < &buf[29]) 193254359Sroberto *bp++ = *cp++; 193354359Sroberto *bp = '\0'; 193454359Sroberto return rtdatetolfp(buf, lfp); 193554359Sroberto } 193654359Sroberto 193754359Sroberto /* 193854359Sroberto * Might still be hex. Check out the first character. Talk 193954359Sroberto * about heuristics! 194054359Sroberto */ 194154359Sroberto if ((*str >= 'A' && *str <= 'F') || (*str >= 'a' && *str <= 'f')) 194254359Sroberto return hextolfp(str, lfp); 194354359Sroberto 194454359Sroberto /* 194554359Sroberto * Try it as a decimal. If this fails, try as an unquoted 194654359Sroberto * RT-11 date. This code should go away eventually. 194754359Sroberto */ 194854359Sroberto if (atolfp(str, lfp)) 194954359Sroberto return 1; 195054359Sroberto return rtdatetolfp(str, lfp); 195154359Sroberto} 195254359Sroberto 195354359Sroberto 195454359Sroberto/* 195554359Sroberto * decodetime - decode a time value. It should be in milliseconds 195654359Sroberto */ 195754359Srobertoint 195854359Srobertodecodetime( 195954359Sroberto char *str, 196054359Sroberto l_fp *lfp 196154359Sroberto ) 196254359Sroberto{ 196354359Sroberto return mstolfp(str, lfp); 196454359Sroberto} 196554359Sroberto 196654359Sroberto 196754359Sroberto/* 196854359Sroberto * decodeint - decode an integer 196954359Sroberto */ 197054359Srobertoint 197154359Srobertodecodeint( 197254359Sroberto char *str, 197354359Sroberto long *val 197454359Sroberto ) 197554359Sroberto{ 197654359Sroberto if (*str == '0') { 197754359Sroberto if (*(str+1) == 'x' || *(str+1) == 'X') 1978182007Sroberto return hextoint(str+2, val); 1979182007Sroberto return octtoint(str, val); 198054359Sroberto } 198154359Sroberto return atoint(str, val); 198254359Sroberto} 198354359Sroberto 198454359Sroberto 198554359Sroberto/* 198654359Sroberto * decodeuint - decode an unsigned integer 198754359Sroberto */ 198854359Srobertoint 198954359Srobertodecodeuint( 199054359Sroberto char *str, 199154359Sroberto u_long *val 199254359Sroberto ) 199354359Sroberto{ 199454359Sroberto if (*str == '0') { 199554359Sroberto if (*(str + 1) == 'x' || *(str + 1) == 'X') 199654359Sroberto return (hextoint(str + 2, val)); 199754359Sroberto return (octtoint(str, val)); 199854359Sroberto } 199954359Sroberto return (atouint(str, val)); 200054359Sroberto} 200154359Sroberto 200254359Sroberto 200354359Sroberto/* 200454359Sroberto * decodearr - decode an array of time values 200554359Sroberto */ 200654359Srobertostatic int 200754359Srobertodecodearr( 200854359Sroberto char *str, 200954359Sroberto int *narr, 201054359Sroberto l_fp *lfparr 201154359Sroberto ) 201254359Sroberto{ 201354359Sroberto register char *cp, *bp; 201454359Sroberto register l_fp *lfp; 201554359Sroberto char buf[60]; 201654359Sroberto 201754359Sroberto lfp = lfparr; 201854359Sroberto cp = str; 201954359Sroberto *narr = 0; 202054359Sroberto 202154359Sroberto while (*narr < 8) { 202254359Sroberto while (isspace((int)*cp)) 202354359Sroberto cp++; 202454359Sroberto if (*cp == '\0') 202554359Sroberto break; 202654359Sroberto 202754359Sroberto bp = buf; 202854359Sroberto while (!isspace((int)*cp) && *cp != '\0') 202954359Sroberto *bp++ = *cp++; 203054359Sroberto *bp++ = '\0'; 203154359Sroberto 203254359Sroberto if (!decodetime(buf, lfp)) 203354359Sroberto return 0; 203454359Sroberto (*narr)++; 203554359Sroberto lfp++; 203654359Sroberto } 203754359Sroberto return 1; 203854359Sroberto} 203954359Sroberto 204054359Sroberto 204154359Sroberto/* 204254359Sroberto * Finally, the built in command handlers 204354359Sroberto */ 204454359Sroberto 204554359Sroberto/* 204654359Sroberto * help - tell about commands, or details of a particular command 204754359Sroberto */ 204854359Srobertostatic void 204954359Srobertohelp( 205054359Sroberto struct parse *pcmd, 205154359Sroberto FILE *fp 205254359Sroberto ) 205354359Sroberto{ 205454359Sroberto struct xcmd *xcp; 205554359Sroberto char *cmd; 2056182007Sroberto const char *list[100]; 2057182007Sroberto int word, words; 2058182007Sroberto int row, rows; 2059182007Sroberto int col, cols; 206054359Sroberto 206154359Sroberto if (pcmd->nargs == 0) { 2062182007Sroberto words = 0; 206354359Sroberto for (xcp = builtins; xcp->keyword != 0; xcp++) { 206454359Sroberto if (*(xcp->keyword) != '?') 2065182007Sroberto list[words++] = xcp->keyword; 206654359Sroberto } 206754359Sroberto for (xcp = opcmds; xcp->keyword != 0; xcp++) 2068182007Sroberto list[words++] = xcp->keyword; 206954359Sroberto 2070182007Sroberto qsort( 207154359Sroberto#ifdef QSORT_USES_VOID_P 2072182007Sroberto (void *) 207354359Sroberto#else 2074182007Sroberto (char *) 207554359Sroberto#endif 2076182007Sroberto (list), (size_t)(words), sizeof(char *), helpsort); 2077182007Sroberto col = 0; 2078182007Sroberto for (word = 0; word < words; word++) { 2079182007Sroberto int length = strlen(list[word]); 2080182007Sroberto if (col < length) { 2081182007Sroberto col = length; 2082182007Sroberto } 208354359Sroberto } 208454359Sroberto 2085182007Sroberto cols = SCREENWIDTH / ++col; 2086182007Sroberto rows = (words + cols - 1) / cols; 2087182007Sroberto 2088182007Sroberto (void) fprintf(fp, "ntpq commands:\n"); 2089182007Sroberto 2090182007Sroberto for (row = 0; row < rows; row++) { 2091182007Sroberto for (word = row; word < words; word += rows) { 2092182007Sroberto (void) fprintf(fp, "%-*.*s", col, col-1, list[word]); 2093182007Sroberto } 2094182007Sroberto (void) fprintf(fp, "\n"); 2095182007Sroberto } 209654359Sroberto } else { 209754359Sroberto cmd = pcmd->argval[0].string; 2098182007Sroberto words = findcmd(cmd, builtins, opcmds, &xcp); 2099182007Sroberto if (words == 0) { 210054359Sroberto (void) fprintf(stderr, 210154359Sroberto "Command `%s' is unknown\n", cmd); 210254359Sroberto return; 2103182007Sroberto } else if (words >= 2) { 210454359Sroberto (void) fprintf(stderr, 210554359Sroberto "Command `%s' is ambiguous\n", cmd); 210654359Sroberto return; 210754359Sroberto } 210854359Sroberto (void) fprintf(fp, "function: %s\n", xcp->comment); 210954359Sroberto printusage(xcp, fp); 211054359Sroberto } 211154359Sroberto} 211254359Sroberto 211354359Sroberto 211454359Sroberto/* 211554359Sroberto * helpsort - do hostname qsort comparisons 211654359Sroberto */ 211754359Sroberto#ifdef QSORT_USES_VOID_P 211854359Srobertostatic int 211954359Srobertohelpsort( 212054359Sroberto const void *t1, 212154359Sroberto const void *t2 212254359Sroberto ) 212354359Sroberto{ 2124132451Sroberto char const * const * name1 = (char const * const *)t1; 2125132451Sroberto char const * const * name2 = (char const * const *)t2; 212654359Sroberto 212754359Sroberto return strcmp(*name1, *name2); 212854359Sroberto} 212954359Sroberto 213054359Sroberto#else 213154359Srobertostatic int 213254359Srobertohelpsort( 213354359Sroberto char **name1, 213454359Sroberto char **name2 213554359Sroberto ) 213654359Sroberto{ 213754359Sroberto return strcmp(*name1, *name2); 213854359Sroberto} 213954359Sroberto#endif 214054359Sroberto 214154359Sroberto/* 214254359Sroberto * printusage - print usage information for a command 214354359Sroberto */ 214454359Srobertostatic void 214554359Srobertoprintusage( 214654359Sroberto struct xcmd *xcp, 214754359Sroberto FILE *fp 214854359Sroberto ) 214954359Sroberto{ 215054359Sroberto register int i; 215154359Sroberto 215254359Sroberto (void) fprintf(fp, "usage: %s", xcp->keyword); 215354359Sroberto for (i = 0; i < MAXARGS && xcp->arg[i] != NO; i++) { 215454359Sroberto if (xcp->arg[i] & OPT) 215554359Sroberto (void) fprintf(fp, " [ %s ]", xcp->desc[i]); 215654359Sroberto else 215754359Sroberto (void) fprintf(fp, " %s", xcp->desc[i]); 215854359Sroberto } 215954359Sroberto (void) fprintf(fp, "\n"); 216054359Sroberto} 216154359Sroberto 216254359Sroberto 216354359Sroberto/* 216454359Sroberto * timeout - set time out time 216554359Sroberto */ 216654359Srobertostatic void 216754359Srobertotimeout( 216854359Sroberto struct parse *pcmd, 216954359Sroberto FILE *fp 217054359Sroberto ) 217154359Sroberto{ 217254359Sroberto int val; 217354359Sroberto 217454359Sroberto if (pcmd->nargs == 0) { 217554359Sroberto val = tvout.tv_sec * 1000 + tvout.tv_usec / 1000; 217654359Sroberto (void) fprintf(fp, "primary timeout %d ms\n", val); 217754359Sroberto } else { 217854359Sroberto tvout.tv_sec = pcmd->argval[0].uval / 1000; 217954359Sroberto tvout.tv_usec = (pcmd->argval[0].uval - (tvout.tv_sec * 1000)) 218054359Sroberto * 1000; 218154359Sroberto } 218254359Sroberto} 218354359Sroberto 218454359Sroberto 218554359Sroberto/* 218654359Sroberto * auth_delay - set delay for auth requests 218754359Sroberto */ 218854359Srobertostatic void 218954359Srobertoauth_delay( 219054359Sroberto struct parse *pcmd, 219154359Sroberto FILE *fp 219254359Sroberto ) 219354359Sroberto{ 219454359Sroberto int isneg; 219554359Sroberto u_long val; 219654359Sroberto 219754359Sroberto if (pcmd->nargs == 0) { 219854359Sroberto val = delay_time.l_ui * 1000 + delay_time.l_uf / 4294967; 219954359Sroberto (void) fprintf(fp, "delay %lu ms\n", val); 220054359Sroberto } else { 220154359Sroberto if (pcmd->argval[0].ival < 0) { 220254359Sroberto isneg = 1; 220354359Sroberto val = (u_long)(-pcmd->argval[0].ival); 220454359Sroberto } else { 220554359Sroberto isneg = 0; 220654359Sroberto val = (u_long)pcmd->argval[0].ival; 220754359Sroberto } 220854359Sroberto 220954359Sroberto delay_time.l_ui = val / 1000; 221054359Sroberto val %= 1000; 221154359Sroberto delay_time.l_uf = val * 4294967; /* 2**32/1000 */ 221254359Sroberto 221354359Sroberto if (isneg) 221454359Sroberto L_NEG(&delay_time); 221554359Sroberto } 221654359Sroberto} 221754359Sroberto 221854359Sroberto 221954359Sroberto/* 222054359Sroberto * host - set the host we are dealing with. 222154359Sroberto */ 222254359Srobertostatic void 222354359Srobertohost( 222454359Sroberto struct parse *pcmd, 222554359Sroberto FILE *fp 222654359Sroberto ) 222754359Sroberto{ 2228132451Sroberto int i; 2229132451Sroberto 223054359Sroberto if (pcmd->nargs == 0) { 223154359Sroberto if (havehost) 223254359Sroberto (void) fprintf(fp, "current host is %s\n", currenthost); 223354359Sroberto else 223454359Sroberto (void) fprintf(fp, "no current host\n"); 2235132451Sroberto return; 2236132451Sroberto } 2237132451Sroberto 2238132451Sroberto i = 0; 2239132451Sroberto ai_fam_templ = ai_fam_default; 2240132451Sroberto if (pcmd->nargs == 2) { 2241132451Sroberto if (!strcmp("-4", pcmd->argval[i].string)) 2242132451Sroberto ai_fam_templ = AF_INET; 2243132451Sroberto else if (!strcmp("-6", pcmd->argval[i].string)) 2244132451Sroberto ai_fam_templ = AF_INET6; 2245132451Sroberto else { 2246132451Sroberto if (havehost) 2247132451Sroberto (void) fprintf(fp, 2248132451Sroberto "current host remains %s\n", currenthost); 2249132451Sroberto else 2250132451Sroberto (void) fprintf(fp, "still no current host\n"); 2251132451Sroberto return; 2252132451Sroberto } 2253132451Sroberto i = 1; 2254132451Sroberto } 2255132451Sroberto if (openhost(pcmd->argval[i].string)) { 225654359Sroberto (void) fprintf(fp, "current host set to %s\n", currenthost); 225754359Sroberto numassoc = 0; 225854359Sroberto } else { 225954359Sroberto if (havehost) 226054359Sroberto (void) fprintf(fp, 226154359Sroberto "current host remains %s\n", currenthost); 226254359Sroberto else 226354359Sroberto (void) fprintf(fp, "still no current host\n"); 226454359Sroberto } 226554359Sroberto} 226654359Sroberto 226754359Sroberto 226854359Sroberto/* 226954359Sroberto * poll - do one (or more) polls of the host via NTP 227054359Sroberto */ 227154359Sroberto/*ARGSUSED*/ 227254359Srobertostatic void 227354359Srobertontp_poll( 227454359Sroberto struct parse *pcmd, 227554359Sroberto FILE *fp 227654359Sroberto ) 227754359Sroberto{ 227854359Sroberto (void) fprintf(fp, "poll not implemented yet\n"); 227954359Sroberto} 228054359Sroberto 228154359Sroberto 228254359Sroberto/* 228354359Sroberto * keyid - get a keyid to use for authenticating requests 228454359Sroberto */ 228554359Srobertostatic void 228654359Srobertokeyid( 228754359Sroberto struct parse *pcmd, 228854359Sroberto FILE *fp 228954359Sroberto ) 229054359Sroberto{ 229154359Sroberto if (pcmd->nargs == 0) { 2292132451Sroberto if (info_auth_keyid == 0) 229354359Sroberto (void) fprintf(fp, "no keyid defined\n"); 229454359Sroberto else 229554359Sroberto (void) fprintf(fp, "keyid is %lu\n", (u_long)info_auth_keyid); 229654359Sroberto } else { 2297132451Sroberto /* allow zero so that keyid can be cleared. */ 2298132451Sroberto if(pcmd->argval[0].uval > NTP_MAXKEY) 2299132451Sroberto (void) fprintf(fp, "Invalid key identifier\n"); 230054359Sroberto info_auth_keyid = pcmd->argval[0].uval; 230154359Sroberto } 230254359Sroberto} 230354359Sroberto 230454359Sroberto/* 230554359Sroberto * keytype - get type of key to use for authenticating requests 230654359Sroberto */ 230754359Srobertostatic void 230854359Srobertokeytype( 230954359Sroberto struct parse *pcmd, 231054359Sroberto FILE *fp 231154359Sroberto ) 231254359Sroberto{ 231354359Sroberto if (pcmd->nargs == 0) 231454359Sroberto fprintf(fp, "keytype is %s\n", 2315132451Sroberto (info_auth_keytype == KEY_TYPE_MD5) ? "MD5" : "???"); 231654359Sroberto else 231754359Sroberto switch (*(pcmd->argval[0].string)) { 231854359Sroberto case 'm': 231954359Sroberto case 'M': 232054359Sroberto info_auth_keytype = KEY_TYPE_MD5; 232154359Sroberto break; 232254359Sroberto 232354359Sroberto default: 2324132451Sroberto fprintf(fp, "keytype must be 'md5'\n"); 232554359Sroberto } 232654359Sroberto} 232754359Sroberto 232854359Sroberto 232954359Sroberto 233054359Sroberto/* 233154359Sroberto * passwd - get an authentication key 233254359Sroberto */ 233354359Sroberto/*ARGSUSED*/ 233454359Srobertostatic void 233554359Srobertopasswd( 233654359Sroberto struct parse *pcmd, 233754359Sroberto FILE *fp 233854359Sroberto ) 233954359Sroberto{ 234054359Sroberto char *pass; 234154359Sroberto 2342132451Sroberto if (info_auth_keyid == 0) { 2343132451Sroberto int u_keyid = getkeyid("Keyid: "); 2344132451Sroberto if (u_keyid == 0 || u_keyid > NTP_MAXKEY) { 2345132451Sroberto (void)fprintf(fp, "Invalid key identifier\n"); 234654359Sroberto return; 234754359Sroberto } 2348132451Sroberto info_auth_keyid = u_keyid; 234954359Sroberto } 2350132451Sroberto pass = getpass("MD5 Password: "); 235154359Sroberto if (*pass == '\0') 235254359Sroberto (void) fprintf(fp, "Password unchanged\n"); 2353132451Sroberto else { 235454359Sroberto authusekey(info_auth_keyid, info_auth_keytype, (u_char *)pass); 2355132451Sroberto authtrust(info_auth_keyid, 1); 2356132451Sroberto } 235754359Sroberto} 235854359Sroberto 235954359Sroberto 236054359Sroberto/* 236154359Sroberto * hostnames - set the showhostnames flag 236254359Sroberto */ 236354359Srobertostatic void 236454359Srobertohostnames( 236554359Sroberto struct parse *pcmd, 236654359Sroberto FILE *fp 236754359Sroberto ) 236854359Sroberto{ 236954359Sroberto if (pcmd->nargs == 0) { 237054359Sroberto if (showhostnames) 237154359Sroberto (void) fprintf(fp, "hostnames being shown\n"); 237254359Sroberto else 237354359Sroberto (void) fprintf(fp, "hostnames not being shown\n"); 237454359Sroberto } else { 237554359Sroberto if (STREQ(pcmd->argval[0].string, "yes")) 237654359Sroberto showhostnames = 1; 237754359Sroberto else if (STREQ(pcmd->argval[0].string, "no")) 237854359Sroberto showhostnames = 0; 237954359Sroberto else 238054359Sroberto (void)fprintf(stderr, "What?\n"); 238154359Sroberto } 238254359Sroberto} 238354359Sroberto 238454359Sroberto 238554359Sroberto 238654359Sroberto/* 238754359Sroberto * setdebug - set/change debugging level 238854359Sroberto */ 238954359Srobertostatic void 239054359Srobertosetdebug( 239154359Sroberto struct parse *pcmd, 239254359Sroberto FILE *fp 239354359Sroberto ) 239454359Sroberto{ 239554359Sroberto if (pcmd->nargs == 0) { 239654359Sroberto (void) fprintf(fp, "debug level is %d\n", debug); 239754359Sroberto return; 239854359Sroberto } else if (STREQ(pcmd->argval[0].string, "no")) { 239954359Sroberto debug = 0; 240054359Sroberto } else if (STREQ(pcmd->argval[0].string, "more")) { 240154359Sroberto debug++; 240254359Sroberto } else if (STREQ(pcmd->argval[0].string, "less")) { 240354359Sroberto debug--; 240454359Sroberto } else { 240554359Sroberto (void) fprintf(fp, "What?\n"); 240654359Sroberto return; 240754359Sroberto } 240854359Sroberto (void) fprintf(fp, "debug level set to %d\n", debug); 240954359Sroberto} 241054359Sroberto 241154359Sroberto 241254359Sroberto/* 241354359Sroberto * quit - stop this nonsense 241454359Sroberto */ 241554359Sroberto/*ARGSUSED*/ 241654359Srobertostatic void 241754359Srobertoquit( 241854359Sroberto struct parse *pcmd, 241954359Sroberto FILE *fp 242054359Sroberto ) 242154359Sroberto{ 242254359Sroberto if (havehost) 242354359Sroberto closesocket(sockfd); /* cleanliness next to godliness */ 242454359Sroberto exit(0); 242554359Sroberto} 242654359Sroberto 242754359Sroberto 242854359Sroberto/* 242954359Sroberto * version - print the current version number 243054359Sroberto */ 243154359Sroberto/*ARGSUSED*/ 243254359Srobertostatic void 243354359Srobertoversion( 243454359Sroberto struct parse *pcmd, 243554359Sroberto FILE *fp 243654359Sroberto ) 243754359Sroberto{ 243854359Sroberto 243954359Sroberto (void) fprintf(fp, "%s\n", Version); 244054359Sroberto return; 244154359Sroberto} 244254359Sroberto 244354359Sroberto 244454359Sroberto/* 244554359Sroberto * raw - set raw mode output 244654359Sroberto */ 244754359Sroberto/*ARGSUSED*/ 244854359Srobertostatic void 244954359Srobertoraw( 245054359Sroberto struct parse *pcmd, 245154359Sroberto FILE *fp 245254359Sroberto ) 245354359Sroberto{ 245454359Sroberto rawmode = 1; 245554359Sroberto (void) fprintf(fp, "Output set to raw\n"); 245654359Sroberto} 245754359Sroberto 245854359Sroberto 245954359Sroberto/* 246054359Sroberto * cooked - set cooked mode output 246154359Sroberto */ 246254359Sroberto/*ARGSUSED*/ 246354359Srobertostatic void 246454359Srobertocooked( 246554359Sroberto struct parse *pcmd, 246654359Sroberto FILE *fp 246754359Sroberto ) 246854359Sroberto{ 246954359Sroberto rawmode = 0; 247054359Sroberto (void) fprintf(fp, "Output set to cooked\n"); 247154359Sroberto return; 247254359Sroberto} 247354359Sroberto 247454359Sroberto 247554359Sroberto/* 247654359Sroberto * authenticate - always authenticate requests to this host 247754359Sroberto */ 247854359Srobertostatic void 247954359Srobertoauthenticate( 248054359Sroberto struct parse *pcmd, 248154359Sroberto FILE *fp 248254359Sroberto ) 248354359Sroberto{ 248454359Sroberto if (pcmd->nargs == 0) { 248554359Sroberto if (always_auth) { 248654359Sroberto (void) fprintf(fp, 248754359Sroberto "authenticated requests being sent\n"); 248854359Sroberto } else 248954359Sroberto (void) fprintf(fp, 249054359Sroberto "unauthenticated requests being sent\n"); 249154359Sroberto } else { 249254359Sroberto if (STREQ(pcmd->argval[0].string, "yes")) { 249354359Sroberto always_auth = 1; 249454359Sroberto } else if (STREQ(pcmd->argval[0].string, "no")) { 249554359Sroberto always_auth = 0; 249654359Sroberto } else 249754359Sroberto (void)fprintf(stderr, "What?\n"); 249854359Sroberto } 249954359Sroberto} 250054359Sroberto 250154359Sroberto 250254359Sroberto/* 250354359Sroberto * ntpversion - choose the NTP version to use 250454359Sroberto */ 250554359Srobertostatic void 250654359Srobertontpversion( 250754359Sroberto struct parse *pcmd, 250854359Sroberto FILE *fp 250954359Sroberto ) 251054359Sroberto{ 251154359Sroberto if (pcmd->nargs == 0) { 251254359Sroberto (void) fprintf(fp, 251354359Sroberto "NTP version being claimed is %d\n", pktversion); 251454359Sroberto } else { 251554359Sroberto if (pcmd->argval[0].uval < NTP_OLDVERSION 251654359Sroberto || pcmd->argval[0].uval > NTP_VERSION) { 251754359Sroberto (void) fprintf(stderr, "versions %d to %d, please\n", 251854359Sroberto NTP_OLDVERSION, NTP_VERSION); 251954359Sroberto } else { 252054359Sroberto pktversion = (u_char) pcmd->argval[0].uval; 252154359Sroberto } 252254359Sroberto } 252354359Sroberto} 252454359Sroberto 252554359Sroberto 252654359Sroberto/* 252754359Sroberto * warning - print a warning message 252854359Sroberto */ 252954359Srobertostatic void 253054359Srobertowarning( 253154359Sroberto const char *fmt, 253254359Sroberto const char *st1, 253354359Sroberto const char *st2 253454359Sroberto ) 253554359Sroberto{ 253654359Sroberto (void) fprintf(stderr, "%s: ", progname); 253754359Sroberto (void) fprintf(stderr, fmt, st1, st2); 253854359Sroberto (void) fprintf(stderr, ": "); 253954359Sroberto perror(""); 254054359Sroberto} 254154359Sroberto 254254359Sroberto 254354359Sroberto/* 254454359Sroberto * error - print a message and exit 254554359Sroberto */ 254654359Srobertostatic void 254754359Srobertoerror( 254854359Sroberto const char *fmt, 254954359Sroberto const char *st1, 255054359Sroberto const char *st2 255154359Sroberto ) 255254359Sroberto{ 255354359Sroberto warning(fmt, st1, st2); 255454359Sroberto exit(1); 255554359Sroberto} 255654359Sroberto 255754359Sroberto/* 255854359Sroberto * getkeyid - prompt the user for a keyid to use 255954359Sroberto */ 256054359Srobertostatic u_long 256154359Srobertogetkeyid( 256254359Sroberto const char *keyprompt 256354359Sroberto ) 256454359Sroberto{ 256554359Sroberto register char *p; 256654359Sroberto register int c; 256754359Sroberto FILE *fi; 256854359Sroberto char pbuf[20]; 256954359Sroberto 257054359Sroberto#ifndef SYS_WINNT 257154359Sroberto if ((fi = fdopen(open("/dev/tty", 2), "r")) == NULL) 257254359Sroberto#else 257354359Sroberto if ((fi = _fdopen((int)GetStdHandle(STD_INPUT_HANDLE), "r")) == NULL) 257454359Sroberto#endif /* SYS_WINNT */ 257554359Sroberto fi = stdin; 257654359Sroberto else 257754359Sroberto setbuf(fi, (char *)NULL); 257854359Sroberto fprintf(stderr, "%s", keyprompt); fflush(stderr); 257954359Sroberto for (p=pbuf; (c = getc(fi))!='\n' && c!=EOF;) { 258054359Sroberto if (p < &pbuf[18]) 2581132451Sroberto *p++ = (char)c; 258254359Sroberto } 258354359Sroberto *p = '\0'; 258454359Sroberto if (fi != stdin) 258554359Sroberto fclose(fi); 258654359Sroberto if (strcmp(pbuf, "0") == 0) 258754359Sroberto return 0; 258854359Sroberto 258954359Sroberto return (u_long) atoi(pbuf); 259054359Sroberto} 259154359Sroberto 259254359Sroberto 259354359Sroberto/* 259454359Sroberto * atoascii - printable-ize possibly ascii data using the character 259554359Sroberto * transformations cat -v uses. 259654359Sroberto */ 259754359Srobertostatic void 259854359Srobertoatoascii( 259954359Sroberto int length, 260054359Sroberto char *data, 260154359Sroberto char *outdata 260254359Sroberto ) 260354359Sroberto{ 260454359Sroberto register u_char *cp; 260554359Sroberto register u_char *ocp; 260654359Sroberto register u_char c; 260754359Sroberto 260854359Sroberto if (!data) 260954359Sroberto { 261054359Sroberto *outdata = '\0'; 261154359Sroberto return; 261254359Sroberto } 261354359Sroberto 261454359Sroberto ocp = (u_char *)outdata; 261554359Sroberto for (cp = (u_char *)data; cp < (u_char *)data + length; cp++) { 261654359Sroberto c = *cp; 261754359Sroberto if (c == '\0') 261854359Sroberto break; 261954359Sroberto if (c == '\0') 262054359Sroberto break; 262154359Sroberto if (c > 0177) { 262254359Sroberto *ocp++ = 'M'; 262354359Sroberto *ocp++ = '-'; 262454359Sroberto c &= 0177; 262554359Sroberto } 262654359Sroberto 262754359Sroberto if (c < ' ') { 262854359Sroberto *ocp++ = '^'; 2629132451Sroberto *ocp++ = (u_char)(c + '@'); 263054359Sroberto } else if (c == 0177) { 263154359Sroberto *ocp++ = '^'; 263254359Sroberto *ocp++ = '?'; 263354359Sroberto } else { 263454359Sroberto *ocp++ = c; 263554359Sroberto } 263654359Sroberto if (ocp >= ((u_char *)outdata + length - 4)) 263754359Sroberto break; 263854359Sroberto } 263954359Sroberto *ocp++ = '\0'; 264054359Sroberto} 264154359Sroberto 264254359Sroberto 264354359Sroberto 264454359Sroberto/* 264554359Sroberto * makeascii - print possibly ascii data using the character 264654359Sroberto * transformations that cat -v uses. 264754359Sroberto */ 264854359Srobertostatic void 264954359Srobertomakeascii( 265054359Sroberto int length, 265154359Sroberto char *data, 265254359Sroberto FILE *fp 265354359Sroberto ) 265454359Sroberto{ 265554359Sroberto register u_char *cp; 265654359Sroberto register int c; 265754359Sroberto 265854359Sroberto for (cp = (u_char *)data; cp < (u_char *)data + length; cp++) { 265954359Sroberto c = (int)*cp; 266054359Sroberto if (c > 0177) { 266154359Sroberto putc('M', fp); 266254359Sroberto putc('-', fp); 266354359Sroberto c &= 0177; 266454359Sroberto } 266554359Sroberto 266654359Sroberto if (c < ' ') { 266754359Sroberto putc('^', fp); 266854359Sroberto putc(c+'@', fp); 266954359Sroberto } else if (c == 0177) { 267054359Sroberto putc('^', fp); 267154359Sroberto putc('?', fp); 267254359Sroberto } else { 267354359Sroberto putc(c, fp); 267454359Sroberto } 267554359Sroberto } 267654359Sroberto} 267754359Sroberto 267854359Sroberto 267954359Sroberto/* 268054359Sroberto * asciize - same thing as makeascii except add a newline 268154359Sroberto */ 268254359Srobertovoid 268354359Srobertoasciize( 268454359Sroberto int length, 268554359Sroberto char *data, 268654359Sroberto FILE *fp 268754359Sroberto ) 268854359Sroberto{ 268954359Sroberto makeascii(length, data, fp); 269054359Sroberto putc('\n', fp); 269154359Sroberto} 269254359Sroberto 269354359Sroberto 269454359Sroberto/* 269554359Sroberto * Some circular buffer space 269654359Sroberto */ 269754359Sroberto#define CBLEN 80 269854359Sroberto#define NUMCB 6 269954359Sroberto 270054359Srobertochar circ_buf[NUMCB][CBLEN]; 270154359Srobertoint nextcb = 0; 270254359Sroberto 270354359Sroberto/* 270454359Sroberto * nextvar - find the next variable in the buffer 270554359Sroberto */ 270654359Srobertoint 270754359Srobertonextvar( 270854359Sroberto int *datalen, 270954359Sroberto char **datap, 271054359Sroberto char **vname, 271154359Sroberto char **vvalue 271254359Sroberto ) 271354359Sroberto{ 271454359Sroberto register char *cp; 271554359Sroberto register char *np; 271654359Sroberto register char *cpend; 271754359Sroberto register char *npend; /* character after last */ 271854359Sroberto int quoted = 0; 271954359Sroberto static char name[MAXVARLEN]; 272054359Sroberto static char value[MAXVALLEN]; 272154359Sroberto 272254359Sroberto cp = *datap; 272354359Sroberto cpend = cp + *datalen; 272454359Sroberto 272554359Sroberto /* 272654359Sroberto * Space past commas and white space 272754359Sroberto */ 272854359Sroberto while (cp < cpend && (*cp == ',' || isspace((int)*cp))) 272954359Sroberto cp++; 273054359Sroberto if (cp == cpend) 273154359Sroberto return 0; 273254359Sroberto 273354359Sroberto /* 273454359Sroberto * Copy name until we hit a ',', an '=', a '\r' or a '\n'. Backspace 273554359Sroberto * over any white space and terminate it. 273654359Sroberto */ 273754359Sroberto np = name; 273854359Sroberto npend = &name[MAXVARLEN]; 273954359Sroberto while (cp < cpend && np < npend && *cp != ',' && *cp != '=' 274054359Sroberto && *cp != '\r' && *cp != '\n') 274154359Sroberto *np++ = *cp++; 274254359Sroberto /* 274354359Sroberto * Check if we ran out of name space, without reaching the end or a 274454359Sroberto * terminating character 274554359Sroberto */ 274654359Sroberto if (np == npend && !(cp == cpend || *cp == ',' || *cp == '=' || 274754359Sroberto *cp == '\r' || *cp == '\n')) 274854359Sroberto return 0; 274954359Sroberto while (isspace((int)(*(np-1)))) 275054359Sroberto np--; 275154359Sroberto *np = '\0'; 275254359Sroberto *vname = name; 275354359Sroberto 275454359Sroberto /* 275554359Sroberto * Check if we hit the end of the buffer or a ','. If so we are done. 275654359Sroberto */ 275754359Sroberto if (cp == cpend || *cp == ',' || *cp == '\r' || *cp == '\n') { 275854359Sroberto if (cp != cpend) 275954359Sroberto cp++; 276054359Sroberto *datap = cp; 276154359Sroberto *datalen = cpend - cp; 276254359Sroberto *vvalue = (char *)0; 276354359Sroberto return 1; 276454359Sroberto } 276554359Sroberto 276654359Sroberto /* 276754359Sroberto * So far, so good. Copy out the value 276854359Sroberto */ 276954359Sroberto cp++; /* past '=' */ 277054359Sroberto while (cp < cpend && (isspace((int)*cp) && *cp != '\r' && *cp != '\n')) 277154359Sroberto cp++; 277254359Sroberto np = value; 277354359Sroberto npend = &value[MAXVALLEN]; 277454359Sroberto while (cp < cpend && np < npend && ((*cp != ',') || quoted)) 277554359Sroberto { 277654359Sroberto quoted ^= ((*np++ = *cp++) == '"'); 277754359Sroberto } 277854359Sroberto 277954359Sroberto /* 278054359Sroberto * Check if we overran the value buffer while still in a quoted string 278154359Sroberto * or without finding a comma 278254359Sroberto */ 278354359Sroberto if (np == npend && (quoted || *cp != ',')) 278454359Sroberto return 0; 278554359Sroberto /* 278654359Sroberto * Trim off any trailing whitespace 278754359Sroberto */ 278854359Sroberto while (np > value && isspace((int)(*(np-1)))) 278954359Sroberto np--; 279054359Sroberto *np = '\0'; 279154359Sroberto 279254359Sroberto /* 279354359Sroberto * Return this. All done. 279454359Sroberto */ 279554359Sroberto if (cp != cpend) 279654359Sroberto cp++; 279754359Sroberto *datap = cp; 279854359Sroberto *datalen = cpend - cp; 279954359Sroberto *vvalue = value; 280054359Sroberto return 1; 280154359Sroberto} 280254359Sroberto 280354359Sroberto 280454359Sroberto/* 2805182007Sroberto * findvar - see if this variable is known to us. 2806182007Sroberto * If "code" is 1, return ctl_var->code. 2807182007Sroberto * Otherwise return the ordinal position of the found variable. 280854359Sroberto */ 280954359Srobertoint 281054359Srobertofindvar( 281154359Sroberto char *varname, 2812182007Sroberto struct ctl_var *varlist, 2813182007Sroberto int code 281454359Sroberto ) 281554359Sroberto{ 281654359Sroberto register char *np; 281754359Sroberto register struct ctl_var *vl; 281854359Sroberto 281954359Sroberto vl = varlist; 282054359Sroberto np = varname; 282154359Sroberto while (vl->fmt != EOV) { 282254359Sroberto if (vl->fmt != PADDING && STREQ(np, vl->text)) 2823182007Sroberto return (code) 2824182007Sroberto ? vl->code 2825182007Sroberto : (vl - varlist) 2826182007Sroberto ; 282754359Sroberto vl++; 282854359Sroberto } 282954359Sroberto return 0; 283054359Sroberto} 283154359Sroberto 283254359Sroberto 283354359Sroberto 283454359Sroberto/* 283554359Sroberto * printvars - print variables returned in response packet 283654359Sroberto */ 283754359Srobertovoid 283854359Srobertoprintvars( 283954359Sroberto int length, 284054359Sroberto char *data, 284154359Sroberto int status, 284254359Sroberto int sttype, 284354359Sroberto FILE *fp 284454359Sroberto ) 284554359Sroberto{ 284654359Sroberto if (rawmode) 284754359Sroberto rawprint(sttype, length, data, status, fp); 284854359Sroberto else 284954359Sroberto cookedprint(sttype, length, data, status, fp); 285054359Sroberto} 285154359Sroberto 285254359Sroberto 285354359Sroberto/* 285454359Sroberto * rawprint - do a printout of the data in raw mode 285554359Sroberto */ 285654359Srobertostatic void 285754359Srobertorawprint( 285854359Sroberto int datatype, 285954359Sroberto int length, 286054359Sroberto char *data, 286154359Sroberto int status, 286254359Sroberto FILE *fp 286354359Sroberto ) 286454359Sroberto{ 286554359Sroberto register char *cp; 286654359Sroberto register char *cpend; 286754359Sroberto 286854359Sroberto /* 286954359Sroberto * Essentially print the data as is. We reformat unprintables, though. 287054359Sroberto */ 287154359Sroberto cp = data; 287254359Sroberto cpend = data + length; 287354359Sroberto 287454359Sroberto (void) fprintf(fp, "status=0x%04x,\n", status); 287554359Sroberto 287654359Sroberto while (cp < cpend) { 287754359Sroberto if (*cp == '\r') { 287854359Sroberto /* 287954359Sroberto * If this is a \r and the next character is a 288054359Sroberto * \n, supress this, else pretty print it. Otherwise 288154359Sroberto * just output the character. 288254359Sroberto */ 288354359Sroberto if (cp == (cpend-1) || *(cp+1) != '\n') 288454359Sroberto makeascii(1, cp, fp); 288554359Sroberto } else if (isspace((int)*cp) || isprint((int)*cp)) { 288654359Sroberto putc(*cp, fp); 288754359Sroberto } else { 288854359Sroberto makeascii(1, cp, fp); 288954359Sroberto } 289054359Sroberto cp++; 289154359Sroberto } 289254359Sroberto} 289354359Sroberto 289454359Sroberto 289554359Sroberto/* 289654359Sroberto * Global data used by the cooked output routines 289754359Sroberto */ 289854359Srobertoint out_chars; /* number of characters output */ 289954359Srobertoint out_linecount; /* number of characters output on this line */ 290054359Sroberto 290154359Sroberto 290254359Sroberto/* 290354359Sroberto * startoutput - get ready to do cooked output 290454359Sroberto */ 290554359Srobertostatic void 290654359Srobertostartoutput(void) 290754359Sroberto{ 290854359Sroberto out_chars = 0; 290954359Sroberto out_linecount = 0; 291054359Sroberto} 291154359Sroberto 291254359Sroberto 291354359Sroberto/* 291454359Sroberto * output - output a variable=value combination 291554359Sroberto */ 291654359Srobertostatic void 291754359Srobertooutput( 291854359Sroberto FILE *fp, 291954359Sroberto char *name, 292054359Sroberto char *value 292154359Sroberto ) 292254359Sroberto{ 292354359Sroberto int lenname; 292454359Sroberto int lenvalue; 292554359Sroberto 292654359Sroberto lenname = strlen(name); 292754359Sroberto lenvalue = strlen(value); 292854359Sroberto 292954359Sroberto if (out_chars != 0) { 293054359Sroberto putc(',', fp); 293154359Sroberto out_chars++; 293254359Sroberto out_linecount++; 293354359Sroberto if ((out_linecount + lenname + lenvalue + 3) > MAXOUTLINE) { 293454359Sroberto putc('\n', fp); 293554359Sroberto out_chars++; 293654359Sroberto out_linecount = 0; 293754359Sroberto } else { 293854359Sroberto putc(' ', fp); 293954359Sroberto out_chars++; 294054359Sroberto out_linecount++; 294154359Sroberto } 294254359Sroberto } 294354359Sroberto 294454359Sroberto fputs(name, fp); 294554359Sroberto putc('=', fp); 294654359Sroberto fputs(value, fp); 294754359Sroberto out_chars += lenname + 1 + lenvalue; 294854359Sroberto out_linecount += lenname + 1 + lenvalue; 294954359Sroberto} 295054359Sroberto 295154359Sroberto 295254359Sroberto/* 295354359Sroberto * endoutput - terminate a block of cooked output 295454359Sroberto */ 295554359Srobertostatic void 295654359Srobertoendoutput( 295754359Sroberto FILE *fp 295854359Sroberto ) 295954359Sroberto{ 296054359Sroberto if (out_chars != 0) 296154359Sroberto putc('\n', fp); 296254359Sroberto} 296354359Sroberto 296454359Sroberto 296554359Sroberto/* 296654359Sroberto * outputarr - output an array of values 296754359Sroberto */ 296854359Srobertostatic void 296954359Srobertooutputarr( 297054359Sroberto FILE *fp, 297154359Sroberto char *name, 297254359Sroberto int narr, 297354359Sroberto l_fp *lfp 297454359Sroberto ) 297554359Sroberto{ 297654359Sroberto register char *bp; 297754359Sroberto register char *cp; 297854359Sroberto register int i; 297954359Sroberto register int len; 298054359Sroberto char buf[256]; 298154359Sroberto 298254359Sroberto bp = buf; 298354359Sroberto /* 298454359Sroberto * Hack to align delay and offset values 298554359Sroberto */ 298654359Sroberto for (i = (int)strlen(name); i < 11; i++) 298754359Sroberto *bp++ = ' '; 298854359Sroberto 298954359Sroberto for (i = narr; i > 0; i--) { 299054359Sroberto if (i != narr) 299154359Sroberto *bp++ = ' '; 299254359Sroberto cp = lfptoms(lfp, 2); 299354359Sroberto len = strlen(cp); 299454359Sroberto if (len > 7) { 299554359Sroberto cp[7] = '\0'; 299654359Sroberto len = 7; 299754359Sroberto } 299854359Sroberto while (len < 7) { 299954359Sroberto *bp++ = ' '; 300054359Sroberto len++; 300154359Sroberto } 300254359Sroberto while (*cp != '\0') 300354359Sroberto *bp++ = *cp++; 300454359Sroberto lfp++; 300554359Sroberto } 300654359Sroberto *bp = '\0'; 300754359Sroberto output(fp, name, buf); 300854359Sroberto} 300954359Sroberto 301054359Srobertostatic char * 301154359Srobertotstflags( 301254359Sroberto u_long val 301354359Sroberto ) 301454359Sroberto{ 301554359Sroberto register char *cb, *s; 301654359Sroberto register int i; 301754359Sroberto register const char *sep; 301854359Sroberto 301954359Sroberto sep = ""; 302054359Sroberto i = 0; 302154359Sroberto s = cb = &circ_buf[nextcb][0]; 302254359Sroberto if (++nextcb >= NUMCB) 302354359Sroberto nextcb = 0; 302454359Sroberto 302554359Sroberto sprintf(cb, "%02lx", val); 302654359Sroberto cb += strlen(cb); 302754359Sroberto if (!val) { 302854359Sroberto strcat(cb, " ok"); 302954359Sroberto cb += strlen(cb); 303054359Sroberto } else { 303154359Sroberto *cb++ = ' '; 3032182007Sroberto for (i = 0; i < 13; i++) { 303354359Sroberto if (val & 0x1) { 303454359Sroberto sprintf(cb, "%s%s", sep, tstflagnames[i]); 303554359Sroberto sep = ", "; 303654359Sroberto cb += strlen(cb); 303754359Sroberto } 303854359Sroberto val >>= 1; 303954359Sroberto } 304054359Sroberto } 304154359Sroberto *cb = '\0'; 304254359Sroberto return s; 304354359Sroberto} 304454359Sroberto 304554359Sroberto/* 304654359Sroberto * cookedprint - output variables in cooked mode 304754359Sroberto */ 304854359Srobertostatic void 304954359Srobertocookedprint( 305054359Sroberto int datatype, 305154359Sroberto int length, 305254359Sroberto char *data, 305354359Sroberto int status, 305454359Sroberto FILE *fp 305554359Sroberto ) 305654359Sroberto{ 305754359Sroberto register int varid; 305854359Sroberto char *name; 305954359Sroberto char *value; 3060132451Sroberto char output_raw; 306154359Sroberto int fmt; 306254359Sroberto struct ctl_var *varlist; 306354359Sroberto l_fp lfp; 306454359Sroberto long ival; 3065132451Sroberto struct sockaddr_storage hval; 306654359Sroberto u_long uval; 306754359Sroberto l_fp lfparr[8]; 306854359Sroberto int narr; 306954359Sroberto 307054359Sroberto switch (datatype) { 307154359Sroberto case TYPE_PEER: 307254359Sroberto varlist = peer_var; 307354359Sroberto break; 307454359Sroberto case TYPE_SYS: 307554359Sroberto varlist = sys_var; 307654359Sroberto break; 307754359Sroberto case TYPE_CLOCK: 307854359Sroberto varlist = clock_var; 307954359Sroberto break; 308054359Sroberto default: 308154359Sroberto (void) fprintf(stderr, "Unknown datatype(0x%x) in cookedprint\n", datatype); 308254359Sroberto return; 308354359Sroberto } 308454359Sroberto 308554359Sroberto (void) fprintf(fp, "status=%04x %s,\n", status, 308654359Sroberto statustoa(datatype, status)); 308754359Sroberto 308854359Sroberto startoutput(); 308954359Sroberto while (nextvar(&length, &data, &name, &value)) { 3090182007Sroberto varid = findvar(name, varlist, 0); 309154359Sroberto if (varid == 0) { 309254359Sroberto output_raw = '*'; 309354359Sroberto } else { 309454359Sroberto output_raw = 0; 309554359Sroberto fmt = varlist[varid].fmt; 309654359Sroberto switch(fmt) { 309754359Sroberto case TS: 309854359Sroberto if (!decodets(value, &lfp)) 309954359Sroberto output_raw = '?'; 310054359Sroberto else 310154359Sroberto output(fp, name, prettydate(&lfp)); 310254359Sroberto break; 310354359Sroberto case FL: 310454359Sroberto case FU: 310554359Sroberto case FS: 310654359Sroberto if (!decodetime(value, &lfp)) 310754359Sroberto output_raw = '?'; 310854359Sroberto else { 310954359Sroberto switch (fmt) { 311054359Sroberto case FL: 311154359Sroberto output(fp, name, 311254359Sroberto lfptoms(&lfp, 3)); 311354359Sroberto break; 311454359Sroberto case FU: 311554359Sroberto output(fp, name, 311654359Sroberto ulfptoms(&lfp, 3)); 311754359Sroberto break; 311854359Sroberto case FS: 311954359Sroberto output(fp, name, 312054359Sroberto lfptoms(&lfp, 3)); 312154359Sroberto break; 312254359Sroberto } 312354359Sroberto } 312454359Sroberto break; 312554359Sroberto 312654359Sroberto case UI: 312754359Sroberto if (!decodeuint(value, &uval)) 312854359Sroberto output_raw = '?'; 312954359Sroberto else 313054359Sroberto output(fp, name, uinttoa(uval)); 313154359Sroberto break; 313254359Sroberto 313354359Sroberto case SI: 313454359Sroberto if (!decodeint(value, &ival)) 313554359Sroberto output_raw = '?'; 313654359Sroberto else 313754359Sroberto output(fp, name, inttoa(ival)); 313854359Sroberto break; 313954359Sroberto 314054359Sroberto case HA: 314154359Sroberto case NA: 314254359Sroberto if (!decodenetnum(value, &hval)) 314354359Sroberto output_raw = '?'; 3144132451Sroberto else if (fmt == HA){ 3145132451Sroberto output(fp, name, nntohost(&hval)); 3146132451Sroberto } else { 3147132451Sroberto output(fp, name, stoa(&hval)); 3148132451Sroberto } 314954359Sroberto break; 315054359Sroberto 315154359Sroberto case ST: 315254359Sroberto output_raw = '*'; 315354359Sroberto break; 315454359Sroberto 315554359Sroberto case RF: 3156132451Sroberto if (decodenetnum(value, &hval)) { 3157132451Sroberto if ((hval.ss_family == AF_INET) && 3158132451Sroberto ISREFCLOCKADR(&hval)) 3159132451Sroberto output(fp, name, 3160132451Sroberto refnumtoa(&hval)); 3161132451Sroberto else 3162132451Sroberto output(fp, name, stoa(&hval)); 3163132451Sroberto } else if ((int)strlen(value) <= 4) 316454359Sroberto output(fp, name, value); 316554359Sroberto else 316654359Sroberto output_raw = '?'; 316754359Sroberto break; 316854359Sroberto 316954359Sroberto case LP: 317054359Sroberto if (!decodeuint(value, &uval) || uval > 3) 317154359Sroberto output_raw = '?'; 317254359Sroberto else { 317354359Sroberto char b[3]; 317454359Sroberto b[0] = b[1] = '0'; 317554359Sroberto if (uval & 0x2) 317654359Sroberto b[0] = '1'; 317754359Sroberto if (uval & 0x1) 317854359Sroberto b[1] = '1'; 317954359Sroberto b[2] = '\0'; 318054359Sroberto output(fp, name, b); 318154359Sroberto } 318254359Sroberto break; 318354359Sroberto 318454359Sroberto case OC: 318554359Sroberto if (!decodeuint(value, &uval)) 318654359Sroberto output_raw = '?'; 318754359Sroberto else { 3188191302Sroberto char b[12]; 318954359Sroberto 3190200576Sroberto (void) snprintf(b, sizeof b, "%03lo", uval); 319154359Sroberto output(fp, name, b); 319254359Sroberto } 319354359Sroberto break; 319454359Sroberto 319554359Sroberto case MD: 319654359Sroberto if (!decodeuint(value, &uval)) 319754359Sroberto output_raw = '?'; 319854359Sroberto else 319954359Sroberto output(fp, name, uinttoa(uval)); 320054359Sroberto break; 320154359Sroberto 320254359Sroberto case AR: 320354359Sroberto if (!decodearr(value, &narr, lfparr)) 320454359Sroberto output_raw = '?'; 320554359Sroberto else 320654359Sroberto outputarr(fp, name, narr, lfparr); 320754359Sroberto break; 320854359Sroberto 320954359Sroberto case FX: 321054359Sroberto if (!decodeuint(value, &uval)) 321154359Sroberto output_raw = '?'; 321254359Sroberto else 321354359Sroberto output(fp, name, tstflags(uval)); 321454359Sroberto break; 321554359Sroberto 321654359Sroberto default: 321754359Sroberto (void) fprintf(stderr, 321854359Sroberto "Internal error in cookedprint, %s=%s, fmt %d\n", 321954359Sroberto name, value, fmt); 322054359Sroberto break; 322154359Sroberto } 322254359Sroberto 322354359Sroberto } 322454359Sroberto if (output_raw != 0) { 322554359Sroberto char bn[401]; 322654359Sroberto char bv[401]; 322754359Sroberto int len; 322854359Sroberto 322954359Sroberto atoascii(400, name, bn); 323054359Sroberto atoascii(400, value, bv); 323154359Sroberto if (output_raw != '*') { 323254359Sroberto len = strlen(bv); 323354359Sroberto bv[len] = output_raw; 323454359Sroberto bv[len+1] = '\0'; 323554359Sroberto } 323654359Sroberto output(fp, bn, bv); 323754359Sroberto } 323854359Sroberto } 323954359Sroberto endoutput(fp); 324054359Sroberto} 324154359Sroberto 324254359Sroberto 324354359Sroberto/* 324454359Sroberto * sortassoc - sort associations in the cache into ascending order 324554359Sroberto */ 324654359Srobertovoid 324754359Srobertosortassoc(void) 324854359Sroberto{ 324954359Sroberto if (numassoc > 1) 325054359Sroberto qsort( 325154359Sroberto#ifdef QSORT_USES_VOID_P 325254359Sroberto (void *) 325354359Sroberto#else 325454359Sroberto (char *) 325554359Sroberto#endif 325682498Sroberto assoc_cache, (size_t)numassoc, 325754359Sroberto sizeof(struct association), assoccmp); 325854359Sroberto} 325954359Sroberto 326054359Sroberto 326154359Sroberto/* 326254359Sroberto * assoccmp - compare two associations 326354359Sroberto */ 326454359Sroberto#ifdef QSORT_USES_VOID_P 326554359Srobertostatic int 326654359Srobertoassoccmp( 326754359Sroberto const void *t1, 326854359Sroberto const void *t2 326954359Sroberto ) 327054359Sroberto{ 327154359Sroberto const struct association *ass1 = (const struct association *)t1; 327254359Sroberto const struct association *ass2 = (const struct association *)t2; 327354359Sroberto 327454359Sroberto if (ass1->assid < ass2->assid) 327554359Sroberto return -1; 327654359Sroberto if (ass1->assid > ass2->assid) 327754359Sroberto return 1; 327854359Sroberto return 0; 327954359Sroberto} 328054359Sroberto#else 328154359Srobertostatic int 328254359Srobertoassoccmp( 328354359Sroberto struct association *ass1, 328454359Sroberto struct association *ass2 328554359Sroberto ) 328654359Sroberto{ 328754359Sroberto if (ass1->assid < ass2->assid) 328854359Sroberto return -1; 328954359Sroberto if (ass1->assid > ass2->assid) 329054359Sroberto return 1; 329154359Sroberto return 0; 329254359Sroberto} 329354359Sroberto#endif /* not QSORT_USES_VOID_P */ 3294