diff options
Diffstat (limited to 'contrib/ntp/ntpq/ntpq.c')
-rw-r--r-- | contrib/ntp/ntpq/ntpq.c | 3228 |
1 files changed, 0 insertions, 3228 deletions
diff --git a/contrib/ntp/ntpq/ntpq.c b/contrib/ntp/ntpq/ntpq.c deleted file mode 100644 index bc12725..0000000 --- a/contrib/ntp/ntpq/ntpq.c +++ /dev/null @@ -1,3228 +0,0 @@ -/* - * ntpq - query an NTP server using mode 6 commands - */ - -#include <stdio.h> - -#include "ntpq.h" -#include "ntp_unixtime.h" -#include "ntp_calendar.h" -#include "ntp_io.h" -#include "ntp_select.h" -#include "ntp_stdlib.h" -/* Don't include ISC's version of IPv6 variables and structures */ -#define ISC_IPV6_H 1 -#include "isc/net.h" -#include "isc/result.h" - -#include <ctype.h> -#include <signal.h> -#include <setjmp.h> -#include <sys/types.h> -#include <sys/time.h> -#include <netdb.h> -#ifdef SYS_WINNT -# include <io.h> -#else -#define closesocket close -#endif /* SYS_WINNT */ - -#if defined(HAVE_LIBREADLINE) || defined(HAVE_LIBEDIT) -# include <readline/readline.h> -# include <readline/history.h> -#endif /* HAVE_LIBREADLINE || HAVE_LIBEDIT */ - -#ifdef SYS_VXWORKS -/* vxWorks needs mode flag -casey*/ -#define open(name, flags) open(name, flags, 0777) -#define SERVER_PORT_NUM 123 -#endif - -/* - * Because we potentially understand a lot of commands we will run - * interactive if connected to a terminal. - */ -int interactive = 0; /* set to 1 when we should prompt */ -const char *prompt = "ntpq> "; /* prompt to ask him about */ - - -/* - * Keyid used for authenticated requests. Obtained on the fly. - */ -u_long info_auth_keyid = 0; - -/* - * Type of key md5 - */ -#define KEY_TYPE_MD5 4 - -static int info_auth_keytype = KEY_TYPE_MD5; /* MD5 */ -u_long current_time; /* needed by authkeys; not used */ - -/* - * Flag which indicates we should always send authenticated requests - */ -int always_auth = 0; - -/* - * Flag which indicates raw mode output. - */ -int rawmode = 0; - -/* - * Packet version number we use - */ -u_char pktversion = NTP_OLDVERSION + 1; - -/* - * Don't jump if no set jmp. - */ -volatile int jump = 0; - -/* - * Format values - */ -#define PADDING 0 -#define TS 1 /* time stamp */ -#define FL 2 /* l_fp type value */ -#define FU 3 /* u_fp type value */ -#define FS 4 /* s_fp type value */ -#define UI 5 /* unsigned integer value */ -#define SI 6 /* signed integer value */ -#define HA 7 /* host address */ -#define NA 8 /* network address */ -#define ST 9 /* string value */ -#define RF 10 /* refid (sometimes string, sometimes not) */ -#define LP 11 /* leap (print in binary) */ -#define OC 12 /* integer, print in octal */ -#define MD 13 /* mode */ -#define AR 14 /* array of times */ -#define FX 15 /* test flags */ -#define EOV 255 /* end of table */ - - -/* - * System variable values. The array can be indexed by - * the variable index to find the textual name. - */ -struct ctl_var sys_var[] = { - { 0, PADDING, "" }, /* 0 */ - { CS_LEAP, LP, "leap" }, /* 1 */ - { CS_STRATUM, UI, "stratum" }, /* 2 */ - { CS_PRECISION, SI, "precision" }, /* 3 */ - { CS_ROOTDELAY, FS, "rootdelay" }, /* 4 */ - { CS_ROOTDISPERSION, FU, "rootdispersion" }, /* 5 */ - { CS_REFID, RF, "refid" }, /* 6 */ - { CS_REFTIME, TS, "reftime" }, /* 7 */ - { CS_POLL, UI, "poll" }, /* 8 */ - { CS_PEERID, UI, "peer" }, /* 9 */ - { CS_STATE, UI, "state" }, /* 10 */ - { CS_OFFSET, FL, "offset" }, /* 11 */ - { CS_DRIFT, FS, "frequency" }, /* 12 */ - { CS_JITTER, FU, "jitter" }, /* 13 */ - { CS_CLOCK, TS, "clock" }, /* 14 */ - { CS_PROCESSOR, ST, "processor" }, /* 15 */ - { CS_SYSTEM, ST, "system" }, /* 16 */ - { CS_VERSION, ST, "version" }, /* 17 */ - { CS_STABIL, FS, "stability" }, /* 18 */ - { CS_VARLIST, ST, "sys_var_list" }, /* 19 */ - { 0, EOV, "" } -}; - - -/* - * Peer variable list - */ -struct ctl_var peer_var[] = { - { 0, PADDING, "" }, /* 0 */ - { CP_CONFIG, UI, "config" }, /* 1 */ - { CP_AUTHENABLE, UI, "authenable" }, /* 2 */ - { CP_AUTHENTIC, UI, "authentic" }, /* 3 */ - { CP_SRCADR, HA, "srcadr" }, /* 4 */ - { CP_SRCPORT, UI, "srcport" }, /* 5 */ - { CP_DSTADR, NA, "dstadr" }, /* 6 */ - { CP_DSTPORT, UI, "dstport" }, /* 7 */ - { CP_LEAP, LP, "leap" }, /* 8 */ - { CP_HMODE, MD, "hmode" }, /* 9 */ - { CP_STRATUM, UI, "stratum" }, /* 10 */ - { CP_PPOLL, UI, "ppoll" }, /* 11 */ - { CP_HPOLL, UI, "hpoll" }, /* 12 */ - { CP_PRECISION, SI, "precision" }, /* 13 */ - { CP_ROOTDELAY, FS, "rootdelay" }, /* 14 */ - { CP_ROOTDISPERSION, FU, "rootdispersion" }, /* 15 */ - { CP_REFID, RF, "refid" }, /* 16 */ - { CP_REFTIME, TS, "reftime" }, /* 17 */ - { CP_ORG, TS, "org" }, /* 18 */ - { CP_REC, TS, "rec" }, /* 19 */ - { CP_XMT, TS, "xmt" }, /* 20 */ - { CP_REACH, OC, "reach" }, /* 21 */ - { CP_VALID, UI, "valid" }, /* 22 */ - { CP_TIMER, UI, "timer" }, /* 23 */ - { CP_DELAY, FS, "delay" }, /* 24 */ - { CP_OFFSET, FL, "offset" }, /* 25 */ - { CP_JITTER, FU, "jitter" }, /* 26 */ - { CP_DISPERSION, FU, "dispersion" }, /* 27 */ - { CP_KEYID, UI, "keyid" }, /* 28 */ - { CP_FILTDELAY, AR, "filtdelay" }, /* 29 */ - { CP_FILTOFFSET, AR, "filtoffset" }, /* 30 */ - { CP_PMODE, ST, "pmode" }, /* 31 */ - { CP_RECEIVED, UI, "received" }, /* 32 */ - { CP_SENT, UI, "sent" }, /* 33 */ - { CP_FILTERROR, AR, "filtdisp" }, /* 34 */ - { CP_FLASH, FX, "flash" }, /* 35 */ - { CP_TTL, UI, "ttl" }, /* 36 */ - /* - * These are duplicate entries so that we can - * process deviant version of the ntp protocol. - */ - { CP_SRCADR, HA, "peeraddr" }, /* 4 */ - { CP_SRCPORT, UI, "peerport" }, /* 5 */ - { CP_PPOLL, UI, "peerpoll" }, /* 11 */ - { CP_HPOLL, UI, "hostpoll" }, /* 12 */ - { CP_FILTERROR, AR, "filterror" }, /* 34 */ - { 0, EOV, "" } -}; - - -/* - * Clock variable list - */ -struct ctl_var clock_var[] = { - { 0, PADDING, "" }, /* 0 */ - { CC_TYPE, UI, "type" }, /* 1 */ - { CC_TIMECODE, ST, "timecode" }, /* 2 */ - { CC_POLL, UI, "poll" }, /* 3 */ - { CC_NOREPLY, UI, "noreply" }, /* 4 */ - { CC_BADFORMAT, UI, "badformat" }, /* 5 */ - { CC_BADDATA, UI, "baddata" }, /* 6 */ - { CC_FUDGETIME1, FL, "fudgetime1" }, /* 7 */ - { CC_FUDGETIME2, FL, "fudgetime2" }, /* 8 */ - { CC_FUDGEVAL1, UI, "stratum" }, /* 9 */ - { CC_FUDGEVAL2, RF, "refid" }, /* 10 */ - { CC_FLAGS, UI, "flags" }, /* 11 */ - { CC_DEVICE, ST, "device" }, /* 12 */ - { 0, EOV, "" } -}; - - -/* - * flasher bits - */ -static const char *tstflagnames[] = { - "dup_pkt", /* TEST1 */ - "bogus_pkt", /* TEST2 */ - "proto_unsync", /* TEST3 */ - "no_access", /* TEST4 */ - "bad_auth", /* TEST5 */ - "peer_unsync", /* TEST6 */ - "peer_stratum", /* TEST7 */ - "root_bounds", /* TEST8 */ - "peer_bounds", /* TEST9 */ - "bad_autokey", /* TEST10 */ - "not_proventic" /* TEST11*/ -}; - - -int ntpqmain P((int, char **)); -/* - * Built in command handler declarations - */ -static int openhost P((const char *)); -static int sendpkt P((char *, int)); -static int getresponse P((int, int, u_short *, int *, char **, int)); -static int sendrequest P((int, int, int, int, char *)); -static char * tstflags P((u_long)); -static void getcmds P((void)); -static RETSIGTYPE abortcmd P((int)); -static void docmd P((const char *)); -static void tokenize P((const char *, char **, int *)); -static int findcmd P((char *, struct xcmd *, struct xcmd *, struct xcmd **)); -static int getarg P((char *, int, arg_v *)); -static int rtdatetolfp P((char *, l_fp *)); -static int decodearr P((char *, int *, l_fp *)); -static void help P((struct parse *, FILE *)); -#ifdef QSORT_USES_VOID_P -static int helpsort P((const void *, const void *)); -#else -static int helpsort P((char **, char **)); -#endif -static void printusage P((struct xcmd *, FILE *)); -static void timeout P((struct parse *, FILE *)); -static void auth_delay P((struct parse *, FILE *)); -static void host P((struct parse *, FILE *)); -static void ntp_poll P((struct parse *, FILE *)); -static void keyid P((struct parse *, FILE *)); -static void keytype P((struct parse *, FILE *)); -static void passwd P((struct parse *, FILE *)); -static void hostnames P((struct parse *, FILE *)); -static void setdebug P((struct parse *, FILE *)); -static void quit P((struct parse *, FILE *)); -static void version P((struct parse *, FILE *)); -static void raw P((struct parse *, FILE *)); -static void cooked P((struct parse *, FILE *)); -static void authenticate P((struct parse *, FILE *)); -static void ntpversion P((struct parse *, FILE *)); -static void warning P((const char *, const char *, const char *)); -static void error P((const char *, const char *, const char *)); -static u_long getkeyid P((const char *)); -static void atoascii P((int, char *, char *)); -static void makeascii P((int, char *, FILE *)); -static void rawprint P((int, int, char *, int, FILE *)); -static void startoutput P((void)); -static void output P((FILE *, char *, char *)); -static void endoutput P((FILE *)); -static void outputarr P((FILE *, char *, int, l_fp *)); -static void cookedprint P((int, int, char *, int, FILE *)); -#ifdef QSORT_USES_VOID_P -static int assoccmp P((const void *, const void *)); -#else -static int assoccmp P((struct association *, struct association *)); -#endif /* sgi || bsdi */ - - -/* - * Built-in commands we understand - */ -struct xcmd builtins[] = { - { "?", help, { OPT|STR, NO, NO, NO }, - { "command", "", "", "" }, - "tell the use and syntax of commands" }, - { "help", help, { OPT|STR, NO, NO, NO }, - { "command", "", "", "" }, - "tell the use and syntax of commands" }, - { "timeout", timeout, { OPT|UINT, NO, NO, NO }, - { "msec", "", "", "" }, - "set the primary receive time out" }, - { "delay", auth_delay, { OPT|INT, NO, NO, NO }, - { "msec", "", "", "" }, - "set the delay added to encryption time stamps" }, - { "host", host, { OPT|STR, OPT|STR, NO, NO }, - { "-4|-6", "hostname", "", "" }, - "specify the host whose NTP server we talk to" }, - { "poll", ntp_poll, { OPT|UINT, OPT|STR, NO, NO }, - { "n", "verbose", "", "" }, - "poll an NTP server in client mode `n' times" }, - { "passwd", passwd, { NO, NO, NO, NO }, - { "", "", "", "" }, - "specify a password to use for authenticated requests"}, - { "hostnames", hostnames, { OPT|STR, NO, NO, NO }, - { "yes|no", "", "", "" }, - "specify whether hostnames or net numbers are printed"}, - { "debug", setdebug, { OPT|STR, NO, NO, NO }, - { "no|more|less", "", "", "" }, - "set/change debugging level" }, - { "quit", quit, { NO, NO, NO, NO }, - { "", "", "", "" }, - "exit ntpq" }, - { "exit", quit, { NO, NO, NO, NO }, - { "", "", "", "" }, - "exit ntpq" }, - { "keyid", keyid, { OPT|UINT, NO, NO, NO }, - { "key#", "", "", "" }, - "set keyid to use for authenticated requests" }, - { "version", version, { NO, NO, NO, NO }, - { "", "", "", "" }, - "print version number" }, - { "raw", raw, { NO, NO, NO, NO }, - { "", "", "", "" }, - "do raw mode variable output" }, - { "cooked", cooked, { NO, NO, NO, NO }, - { "", "", "", "" }, - "do cooked mode variable output" }, - { "authenticate", authenticate, { OPT|STR, NO, NO, NO }, - { "yes|no", "", "", "" }, - "always authenticate requests to this server" }, - { "ntpversion", ntpversion, { OPT|UINT, NO, NO, NO }, - { "version number", "", "", "" }, - "set the NTP version number to use for requests" }, - { "keytype", keytype, { OPT|STR, NO, NO, NO }, - { "key type (md5|des)", "", "", "" }, - "set key type to use for authenticated requests (des|md5)" }, - { 0, 0, { NO, NO, NO, NO }, - { "", "", "", "" }, "" } -}; - - -/* - * Default values we use. - */ -#define DEFTIMEOUT (5) /* 5 second time out */ -#define DEFSTIMEOUT (2) /* 2 second time out after first */ -#define DEFDELAY 0x51EB852 /* 20 milliseconds, l_fp fraction */ -#define DEFHOST "localhost" /* default host name */ -#define LENHOSTNAME 256 /* host name is 256 characters long */ -#define MAXCMDS 100 /* maximum commands on cmd line */ -#define MAXHOSTS 200 /* maximum hosts on cmd line */ -#define MAXLINE 512 /* maximum line length */ -#define MAXTOKENS (1+MAXARGS+2) /* maximum number of usable tokens */ -#define MAXVARLEN 256 /* maximum length of a variable name */ -#define MAXVALLEN 400 /* maximum length of a variable value */ -#define MAXOUTLINE 72 /* maximum length of an output line */ - -/* - * Some variables used and manipulated locally - */ -struct timeval tvout = { DEFTIMEOUT, 0 }; /* time out for reads */ -struct timeval tvsout = { DEFSTIMEOUT, 0 }; /* secondary time out */ -l_fp delay_time; /* delay time */ -char currenthost[LENHOSTNAME]; /* current host name */ -struct sockaddr_in hostaddr = { 0 }; /* host address */ -int showhostnames = 1; /* show host names by default */ - -int ai_fam_templ; /* address family */ -int ai_fam_default; /* default address family */ -SOCKET sockfd; /* fd socket is opened on */ -int havehost = 0; /* set to 1 when host open */ -int s_port = 0; -struct servent *server_entry = NULL; /* server entry for ntp */ - -#ifdef SYS_WINNT -DWORD NumberOfBytesWritten; - -HANDLE TimerThreadHandle = NULL; /* 1998/06/03 - Used in ntplib/machines.c */ -void timer(void) { ; }; /* 1998/06/03 - Used in ntplib/machines.c */ - -#endif /* SYS_WINNT */ - -/* - * Sequence number used for requests. It is incremented before - * it is used. - */ -u_short sequence; - -/* - * Holds data returned from queries. Declare buffer long to be sure of - * alignment. - */ -#define MAXFRAGS 24 /* maximum number of fragments */ -#define DATASIZE (MAXFRAGS*480) /* maximum amount of data */ -long pktdata[DATASIZE/sizeof(long)]; - -/* - * Holds association data for use with the &n operator. - */ -struct association assoc_cache[MAXASSOC]; -int numassoc = 0; /* number of cached associations */ - -/* - * For commands typed on the command line (with the -c option) - */ -int numcmds = 0; -const char *ccmds[MAXCMDS]; -#define ADDCMD(cp) if (numcmds < MAXCMDS) ccmds[numcmds++] = (cp) - -/* - * When multiple hosts are specified. - */ -int numhosts = 0; -const char *chosts[MAXHOSTS]; -#define ADDHOST(cp) if (numhosts < MAXHOSTS) chosts[numhosts++] = (cp) - -/* - * Error codes for internal use - */ -#define ERR_UNSPEC 256 -#define ERR_INCOMPLETE 257 -#define ERR_TIMEOUT 258 -#define ERR_TOOMUCH 259 - -/* - * Macro definitions we use - */ -#define ISSPACE(c) ((c) == ' ' || (c) == '\t') -#define ISEOL(c) ((c) == '\n' || (c) == '\r' || (c) == '\0') -#define STREQ(a, b) (*(a) == *(b) && strcmp((a), (b)) == 0) - -/* - * Jump buffer for longjumping back to the command level - */ -jmp_buf interrupt_buf; - -/* - * Points at file being currently printed into - */ -FILE *current_output; - -/* - * Command table imported from ntpdc_ops.c - */ -extern struct xcmd opcmds[]; - -char *progname; -volatile int debug; - -#ifdef NO_MAIN_ALLOWED -CALL(ntpq,"ntpq",ntpqmain); - -void clear_globals(void) -{ - extern int ntp_optind; - extern char *ntp_optarg; - showhostnames = 0; /* don'tshow host names by default */ - ntp_optind = 0; - ntp_optarg = 0; - server_entry = NULL; /* server entry for ntp */ - havehost = 0; /* set to 1 when host open */ - numassoc = 0; /* number of cached associations */ - numcmds = 0; - numhosts = 0; -} -#endif - -/* - * main - parse arguments and handle options - */ -#ifndef NO_MAIN_ALLOWED -int -main( - int argc, - char *argv[] - ) -{ - return ntpqmain(argc, argv); -} -#endif - -int -ntpqmain( - int argc, - char *argv[] - ) -{ - int c; - int errflg = 0; - extern int ntp_optind; - extern char *ntp_optarg; - -#ifdef NO_MAIN_ALLOWED - clear_globals(); - taskPrioritySet(taskIdSelf(), 100 ); -#endif - delay_time.l_ui = 0; - delay_time.l_uf = DEFDELAY; - -#ifdef SYS_WINNT - if (!Win32InitSockets()) - { - fprintf(stderr, "No useable winsock.dll:"); - exit(1); - } -#endif /* SYS_WINNT */ - - /* Check to see if we have IPv6. Otherwise force the -4 flag */ - if (isc_net_probeipv6() != ISC_R_SUCCESS) { - ai_fam_default = AF_INET; - } - - progname = argv[0]; - ai_fam_templ = ai_fam_default; - while ((c = ntp_getopt(argc, argv, "46c:dinp")) != EOF) - switch (c) { - case '4': - ai_fam_templ = AF_INET; - break; - case '6': - ai_fam_templ = AF_INET6; - break; - case 'c': - ADDCMD(ntp_optarg); - break; - case 'd': - ++debug; - break; - case 'i': - interactive = 1; - break; - case 'n': - showhostnames = 0; - break; - case 'p': - ADDCMD("peers"); - break; - default: - errflg++; - break; - } - if (errflg) { - (void) fprintf(stderr, - "usage: %s [-46dinp] [-c cmd] host ...\n", - progname); - exit(2); - } - if (ntp_optind == argc) { - ADDHOST(DEFHOST); - } else { - for (; ntp_optind < argc; ntp_optind++) - ADDHOST(argv[ntp_optind]); - } - - if (numcmds == 0 && interactive == 0 - && isatty(fileno(stdin)) && isatty(fileno(stderr))) { - interactive = 1; - } - -#ifndef SYS_WINNT /* Under NT cannot handle SIGINT, WIN32 spawns a handler */ - if (interactive) - (void) signal_no_reset(SIGINT, abortcmd); -#endif /* SYS_WINNT */ - - if (numcmds == 0) { - (void) openhost(chosts[0]); - getcmds(); - } else { - int ihost; - int icmd; - - for (ihost = 0; ihost < numhosts; ihost++) { - if (openhost(chosts[ihost])) - for (icmd = 0; icmd < numcmds; icmd++) - docmd(ccmds[icmd]); - } - } -#ifdef SYS_WINNT - WSACleanup(); -#endif /* SYS_WINNT */ - return 0; -} - - -/* - * openhost - open a socket to a host - */ -static int -openhost( - const char *hname - ) -{ - char temphost[LENHOSTNAME]; - int a_info, i; - struct addrinfo hints, *ai = NULL; - register const char *cp; - char name[LENHOSTNAME]; - char service[5]; - - /* - * We need to get by the [] if they were entered - */ - - cp = hname; - - if(*cp == '[') { - cp++; - for(i = 0; *cp != ']'; cp++, i++) - name[i] = *cp; - name[i] = '\0'; - hname = name; - } - - /* - * First try to resolve it as an ip address and if that fails, - * do a fullblown (dns) lookup. That way we only use the dns - * when it is needed and work around some implementations that - * will return an "IPv4-mapped IPv6 address" address if you - * give it an IPv4 address to lookup. - */ - strcpy(service, "ntp"); - memset((char *)&hints, 0, sizeof(struct addrinfo)); - hints.ai_family = ai_fam_templ; - hints.ai_protocol = IPPROTO_UDP; - hints.ai_socktype = SOCK_DGRAM; - hints.ai_flags = AI_NUMERICHOST; - - a_info = getaddrinfo(hname, service, &hints, &ai); - if (a_info == EAI_NONAME || a_info == EAI_NODATA) { - hints.ai_flags = AI_CANONNAME; -#ifdef AI_ADDRCONFIG - hints.ai_flags |= AI_ADDRCONFIG; -#endif - a_info = getaddrinfo(hname, service, &hints, &ai); - } - /* Some older implementations don't like AI_ADDRCONFIG. */ - if (a_info == EAI_BADFLAGS) { - hints.ai_flags = AI_CANONNAME; - a_info = getaddrinfo(hname, service, &hints, &ai); - } - if (a_info != 0) { - (void) fprintf(stderr, "%s\n", gai_strerror(a_info)); - return 0; - } - - if (ai->ai_canonname == NULL) { - strncpy(temphost, stoa((struct sockaddr_storage *)ai->ai_addr), - LENHOSTNAME); - temphost[LENHOSTNAME-1] = '\0'; - - } else { - strncpy(temphost, ai->ai_canonname, LENHOSTNAME); - temphost[LENHOSTNAME-1] = '\0'; - } - - if (debug > 2) - printf("Opening host %s\n", temphost); - - if (havehost == 1) { - if (debug > 2) - printf("Closing old host %s\n", currenthost); - (void) closesocket(sockfd); - havehost = 0; - } - (void) strcpy(currenthost, temphost); - - /* port maps to the same location in both families */ - s_port = ((struct sockaddr_in6 *)ai->ai_addr)->sin6_port; -#ifdef SYS_VXWORKS - ((struct sockaddr_in6 *)&hostaddr)->sin6_port = htons(SERVER_PORT_NUM); - if (ai->ai_family == AF_INET) - *(struct sockaddr_in *)&hostaddr= - *((struct sockaddr_in *)ai->ai_addr); - else - *(struct sockaddr_in6 *)&hostaddr= - *((struct sockaddr_in6 *)ai->ai_addr); -#endif /* SYS_VXWORKS */ - -#ifdef SYS_WINNT - { - int optionValue = SO_SYNCHRONOUS_NONALERT; - int err; - err = setsockopt(INVALID_SOCKET, SOL_SOCKET, SO_OPENTYPE, (char *)&optionValue, sizeof(optionValue)); - if (err != NO_ERROR) { - (void) fprintf(stderr, "cannot open nonoverlapped sockets\n"); - exit(1); - } - } -#endif /* SYS_WINNT */ - - sockfd = socket(ai->ai_family, SOCK_DGRAM, 0); - if (sockfd == INVALID_SOCKET) { - error("socket", "", ""); - } - - -#ifdef NEED_RCVBUF_SLOP -# ifdef SO_RCVBUF - { int rbufsize = DATASIZE + 2048; /* 2K for slop */ - if (setsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, - &rbufsize, sizeof(int)) == -1) - error("setsockopt", "", ""); - } -# endif -#endif - -#ifdef SYS_VXWORKS - if (connect(sockfd, (struct sockaddr *)&hostaddr, - sizeof(hostaddr)) == -1) -#else - if (connect(sockfd, (struct sockaddr *)ai->ai_addr, - ai->ai_addrlen) == -1) -#endif /* SYS_VXWORKS */ - error("connect", "", ""); - if (a_info == 0) - freeaddrinfo(ai); - havehost = 1; - return 1; -} - - -/* XXX ELIMINATE sendpkt similar in ntpq.c, ntpdc.c, ntp_io.c, ntptrace.c */ -/* - * sendpkt - send a packet to the remote host - */ -static int -sendpkt( - char *xdata, - int xdatalen - ) -{ - if (debug >= 3) - printf("Sending %d octets\n", xdatalen); - - - if (send(sockfd, xdata, (size_t)xdatalen, 0) == -1) { - warning("write to %s failed", currenthost, ""); - return -1; - } - - if (debug >= 4) { - int first = 8; - printf("Packet data:\n"); - while (xdatalen-- > 0) { - if (first-- == 0) { - printf("\n"); - first = 7; - } - printf(" %02x", *xdata++ & 0xff); - } - printf("\n"); - } - return 0; -} - - - -/* - * getresponse - get a (series of) response packet(s) and return the data - */ -static int -getresponse( - int opcode, - int associd, - u_short *rstatus, - int *rsize, - char **rdata, - int timeo - ) -{ - struct ntp_control rpkt; - struct timeval tvo; - u_short offsets[MAXFRAGS+1]; - u_short counts[MAXFRAGS+1]; - u_short offset; - u_short count; - int numfrags; - int seenlastfrag; - fd_set fds; - int n; - - /* - * This is pretty tricky. We may get between 1 and MAXFRAG packets - * back in response to the request. We peel the data out of - * each packet and collect it in one long block. When the last - * packet in the sequence is received we'll know how much data we - * should have had. Note we use one long time out, should reconsider. - */ - *rsize = 0; - if (rstatus) - *rstatus = 0; - *rdata = (char *)pktdata; - - numfrags = 0; - seenlastfrag = 0; - - FD_ZERO(&fds); - - again: - if (numfrags == 0) - tvo = tvout; - else - tvo = tvsout; - - FD_SET(sockfd, &fds); - n = select(sockfd+1, &fds, (fd_set *)0, (fd_set *)0, &tvo); - -#if 0 - if (debug >= 1) - printf("select() returns %d\n", n); -#endif - - if (n == -1) { - warning("select fails", "", ""); - return -1; - } - if (n == 0) { - /* - * Timed out. Return what we have - */ - if (numfrags == 0) { - if (timeo) - (void) fprintf(stderr, - "%s: timed out, nothing received\n", - currenthost); - return ERR_TIMEOUT; - } else { - if (timeo) - (void) fprintf(stderr, - "%s: timed out with incomplete data\n", - currenthost); - if (debug) { - printf("Received fragments:\n"); - for (n = 0; n < numfrags; n++) - printf("%4d %d\n", offsets[n], - counts[n]); - if (seenlastfrag) - printf("last fragment received\n"); - else - printf("last fragment not received\n"); - } - return ERR_INCOMPLETE; - } - } - - n = recv(sockfd, (char *)&rpkt, sizeof(rpkt), 0); - if (n == -1) { - warning("read", "", ""); - return -1; - } - - if (debug >= 4) { - int len = n, first = 8; - char *data = (char *)&rpkt; - - printf("Packet data:\n"); - while (len-- > 0) { - if (first-- == 0) { - printf("\n"); - first = 7; - } - printf(" %02x", *data++ & 0xff); - } - printf("\n"); - } - - /* - * Check for format errors. Bug proofing. - */ - if (n < CTL_HEADER_LEN) { - if (debug) - printf("Short (%d byte) packet received\n", n); - goto again; - } - if (PKT_VERSION(rpkt.li_vn_mode) > NTP_VERSION - || PKT_VERSION(rpkt.li_vn_mode) < NTP_OLDVERSION) { - if (debug) - printf("Packet received with version %d\n", - PKT_VERSION(rpkt.li_vn_mode)); - goto again; - } - if (PKT_MODE(rpkt.li_vn_mode) != MODE_CONTROL) { - if (debug) - printf("Packet received with mode %d\n", - PKT_MODE(rpkt.li_vn_mode)); - goto again; - } - if (!CTL_ISRESPONSE(rpkt.r_m_e_op)) { - if (debug) - printf("Received request packet, wanted response\n"); - goto again; - } - - /* - * Check opcode and sequence number for a match. - * Could be old data getting to us. - */ - if (ntohs(rpkt.sequence) != sequence) { - if (debug) - printf( - "Received sequnce number %d, wanted %d\n", - ntohs(rpkt.sequence), sequence); - goto again; - } - if (CTL_OP(rpkt.r_m_e_op) != opcode) { - if (debug) - printf( - "Received opcode %d, wanted %d (sequence number okay)\n", - CTL_OP(rpkt.r_m_e_op), opcode); - goto again; - } - - /* - * Check the error code. If non-zero, return it. - */ - if (CTL_ISERROR(rpkt.r_m_e_op)) { - int errcode; - - errcode = (ntohs(rpkt.status) >> 8) & 0xff; - if (debug && CTL_ISMORE(rpkt.r_m_e_op)) { - printf("Error code %d received on not-final packet\n", - errcode); - } - if (errcode == CERR_UNSPEC) - return ERR_UNSPEC; - return errcode; - } - - /* - * Check the association ID to make sure it matches what - * we sent. - */ - if (ntohs(rpkt.associd) != associd) { - if (debug) - printf("Association ID %d doesn't match expected %d\n", - ntohs(rpkt.associd), associd); - /* - * Hack for silly fuzzballs which, at the time of writing, - * return an assID of sys.peer when queried for system variables. - */ -#ifdef notdef - goto again; -#endif - } - - /* - * Collect offset and count. Make sure they make sense. - */ - offset = ntohs(rpkt.offset); - count = ntohs(rpkt.count); - - if (debug >= 3) { - int shouldbesize; - u_long key; - u_long *lpkt; - int maclen; - - /* - * Usually we ignore authentication, but for debugging purposes - * we watch it here. - */ - shouldbesize = CTL_HEADER_LEN + count; - - /* round to 8 octet boundary */ - shouldbesize = (shouldbesize + 7) & ~7; - - if (n & 0x3) { - printf("Packet not padded, size = %d\n", n); - } if ((maclen = n - shouldbesize) >= MIN_MAC_LEN) { - printf( - "Packet shows signs of authentication (total %d, data %d, mac %d)\n", - n, shouldbesize, maclen); - lpkt = (u_long *)&rpkt; - printf("%08lx %08lx %08lx %08lx %08lx %08lx\n", - (u_long)ntohl(lpkt[(n - maclen)/sizeof(u_long) - 3]), - (u_long)ntohl(lpkt[(n - maclen)/sizeof(u_long) - 2]), - (u_long)ntohl(lpkt[(n - maclen)/sizeof(u_long) - 1]), - (u_long)ntohl(lpkt[(n - maclen)/sizeof(u_long)]), - (u_long)ntohl(lpkt[(n - maclen)/sizeof(u_long) + 1]), - (u_long)ntohl(lpkt[(n - maclen)/sizeof(u_long) + 2])); - key = ntohl(lpkt[(n - maclen) / sizeof(u_long)]); - printf("Authenticated with keyid %lu\n", (u_long)key); - if (key != 0 && key != info_auth_keyid) { - printf("We don't know that key\n"); - } else { - if (authdecrypt(key, (u_int32 *)&rpkt, - n - maclen, maclen)) { - printf("Auth okay!\n"); - } else { - printf("Auth failed!\n"); - } - } - } - } - - if (debug >= 2) - printf("Got packet, size = %d\n", n); - if (count > (u_short)(n-CTL_HEADER_LEN)) { - if (debug) - printf( - "Received count of %d octets, data in packet is %d\n", - count, n-CTL_HEADER_LEN); - goto again; - } - if (count == 0 && CTL_ISMORE(rpkt.r_m_e_op)) { - if (debug) - printf("Received count of 0 in non-final fragment\n"); - goto again; - } - if (offset + count > sizeof(pktdata)) { - if (debug) - printf("Offset %d, count %d, too big for buffer\n", - offset, count); - return ERR_TOOMUCH; - } - if (seenlastfrag && !CTL_ISMORE(rpkt.r_m_e_op)) { - if (debug) - printf("Received second last fragment packet\n"); - goto again; - } - - /* - * So far, so good. Record this fragment, making sure it doesn't - * overlap anything. - */ - if (debug >= 2) - printf("Packet okay\n");; - - if (numfrags == MAXFRAGS) { - if (debug) - printf("Number of fragments exceeds maximum\n"); - return ERR_TOOMUCH; - } - - for (n = 0; n < numfrags; n++) { - if (offset == offsets[n]) - goto again; /* duplicate */ - if (offset < offsets[n]) - break; - } - - if ((u_short)(n > 0 && offsets[n-1] + counts[n-1]) > offset) - goto overlap; - if (n < numfrags && (u_short)(offset + count) > offsets[n]) - goto overlap; - - { - register int i; - - for (i = numfrags; i > n; i--) { - offsets[i] = offsets[i-1]; - counts[i] = counts[i-1]; - } - } - offsets[n] = offset; - counts[n] = count; - numfrags++; - - /* - * Got that stuffed in right. Figure out if this was the last. - * Record status info out of the last packet. - */ - if (!CTL_ISMORE(rpkt.r_m_e_op)) { - seenlastfrag = 1; - if (rstatus != 0) - *rstatus = ntohs(rpkt.status); - } - - /* - * Copy the data into the data buffer. - */ - memmove((char *)pktdata + offset, (char *)rpkt.data, count); - - /* - * If we've seen the last fragment, look for holes in the sequence. - * If there aren't any, we're done. - */ - if (seenlastfrag && offsets[0] == 0) { - for (n = 1; n < numfrags; n++) { - if (offsets[n-1] + counts[n-1] != offsets[n]) - break; - } - if (n == numfrags) { - *rsize = offsets[numfrags-1] + counts[numfrags-1]; - return 0; - } - } - goto again; - - overlap: - /* - * Print debugging message about overlapping fragments - */ - if (debug) - printf("Overlapping fragments returned in response\n"); - goto again; -} - - -/* - * sendrequest - format and send a request packet - */ -static int -sendrequest( - int opcode, - int associd, - int auth, - int qsize, - char *qdata - ) -{ - struct ntp_control qpkt; - int pktsize; - - /* - * Check to make sure the data will fit in one packet - */ - if (qsize > CTL_MAX_DATA_LEN) { - (void) fprintf(stderr, - "***Internal error! qsize (%d) too large\n", - qsize); - return 1; - } - - /* - * Fill in the packet - */ - qpkt.li_vn_mode = PKT_LI_VN_MODE(0, pktversion, MODE_CONTROL); - qpkt.r_m_e_op = (u_char)(opcode & CTL_OP_MASK); - qpkt.sequence = htons(sequence); - qpkt.status = 0; - qpkt.associd = htons((u_short)associd); - qpkt.offset = 0; - qpkt.count = htons((u_short)qsize); - - /* - * If we have data, copy it in and pad it out to a 64 - * bit boundary. - */ - if (qsize > 0) { - memmove((char *)qpkt.data, qdata, (unsigned)qsize); - pktsize = qsize + CTL_HEADER_LEN; - while (pktsize & (sizeof(u_long) - 1)) { - qpkt.data[qsize++] = 0; - pktsize++; - } - } else { - pktsize = CTL_HEADER_LEN; - } - - /* - * If it isn't authenticated we can just send it. Otherwise - * we're going to have to think about it a little. - */ - if (!auth && !always_auth) { - return sendpkt((char *)&qpkt, pktsize); - } else { - const char *pass = "\0"; - int maclen = 0; - u_long my_keyid; - - /* - * Pad out packet to a multiple of 8 octets to be sure - * receiver can handle it. - */ - while (pktsize & 7) { - qpkt.data[qsize++] = 0; - pktsize++; - } - - /* - * Get the keyid and the password if we don't have one. - */ - if (info_auth_keyid == 0) { - int u_keyid = getkeyid("Keyid: "); - if (u_keyid == 0 || u_keyid > NTP_MAXKEY) { - (void) fprintf(stderr, - "Invalid key identifier\n"); - return 1; - } - info_auth_keyid = u_keyid; - } - if (!authistrusted(info_auth_keyid)) { - pass = getpass("MD5 Password: "); - if (*pass == '\0') { - (void) fprintf(stderr, - "Invalid password\n"); - return (1); - } - } - authusekey(info_auth_keyid, info_auth_keytype, (const u_char *)pass); - authtrust(info_auth_keyid, 1); - - /* - * Stick the keyid in the packet where - * cp currently points. Cp should be aligned - * properly. Then do the encryptions. - */ - my_keyid = htonl(info_auth_keyid); - memcpy(&qpkt.data[qsize], &my_keyid, sizeof my_keyid); - maclen = authencrypt(info_auth_keyid, (u_int32 *)&qpkt, - pktsize); - if (maclen == 0) { - (void) fprintf(stderr, "Key not found\n"); - return (1); - } - return sendpkt((char *)&qpkt, pktsize + maclen); - } - /*NOTREACHED*/ -} - - -/* - * doquery - send a request and process the response - */ -int -doquery( - int opcode, - int associd, - int auth, - int qsize, - char *qdata, - u_short *rstatus, - int *rsize, - char **rdata - ) -{ - int res; - int done; - - /* - * Check to make sure host is open - */ - if (!havehost) { - (void) fprintf(stderr, "***No host open, use `host' command\n"); - return -1; - } - - done = 0; - sequence++; - - again: - /* - * send a request - */ - res = sendrequest(opcode, associd, auth, qsize, qdata); - if (res != 0) - return res; - - /* - * Get the response. If we got a standard error, print a message - */ - res = getresponse(opcode, associd, rstatus, rsize, rdata, done); - - if (res > 0) { - if (!done && (res == ERR_TIMEOUT || res == ERR_INCOMPLETE)) { - if (res == ERR_INCOMPLETE) { - /* - * better bump the sequence so we don't - * get confused about differing fragments. - */ - sequence++; - } - done = 1; - goto again; - } - switch(res) { - case CERR_BADFMT: - (void) fprintf(stderr, - "***Server reports a bad format request packet\n"); - break; - case CERR_PERMISSION: - (void) fprintf(stderr, - "***Server disallowed request (authentication?)\n"); - break; - case CERR_BADOP: - (void) fprintf(stderr, - "***Server reports a bad opcode in request\n"); - break; - case CERR_BADASSOC: - (void) fprintf(stderr, - "***Association ID %d unknown to server\n",associd); - break; - case CERR_UNKNOWNVAR: - (void) fprintf(stderr, - "***A request variable unknown to the server\n"); - break; - case CERR_BADVALUE: - (void) fprintf(stderr, - "***Server indicates a request variable was bad\n"); - break; - case ERR_UNSPEC: - (void) fprintf(stderr, - "***Server returned an unspecified error\n"); - break; - case ERR_TIMEOUT: - (void) fprintf(stderr, "***Request timed out\n"); - break; - case ERR_INCOMPLETE: - (void) fprintf(stderr, - "***Response from server was incomplete\n"); - break; - case ERR_TOOMUCH: - (void) fprintf(stderr, - "***Buffer size exceeded for returned data\n"); - break; - default: - (void) fprintf(stderr, - "***Server returns unknown error code %d\n", res); - break; - } - } - return res; -} - - -/* - * getcmds - read commands from the standard input and execute them - */ -static void -getcmds(void) -{ -#if defined(HAVE_LIBREADLINE) || defined(HAVE_LIBEDIT) - char *line; - - for (;;) { - if ((line = readline(interactive?prompt:"")) == NULL) return; - if (*line) add_history(line); - docmd(line); - free(line); - } -#else /* not (HAVE_LIBREADLINE || HAVE_LIBEDIT) */ - char line[MAXLINE]; - - for (;;) { - if (interactive) { -#ifdef VMS /* work around a problem with mixing stdout & stderr */ - fputs("",stdout); -#endif - (void) fputs(prompt, stderr); - (void) fflush(stderr); - } - - if (fgets(line, sizeof line, stdin) == NULL) - return; - - docmd(line); - } -#endif /* not (HAVE_LIBREADLINE || HAVE_LIBEDIT) */ -} - -#ifndef SYS_WINNT /* Under NT cannot handle SIGINT, WIN32 spawns a handler */ -/* - * abortcmd - catch interrupts and abort the current command - */ -static RETSIGTYPE -abortcmd( - int sig - ) -{ - if (current_output == stdout) - (void) fflush(stdout); - putc('\n', stderr); - (void) fflush(stderr); - if (jump) longjmp(interrupt_buf, 1); -} -#endif /* SYS_WINNT */ - -/* - * docmd - decode the command line and execute a command - */ -static void -docmd( - const char *cmdline - ) -{ - char *tokens[1+MAXARGS+2]; - struct parse pcmd; - int ntok; - static int i; - struct xcmd *xcmd; - - /* - * Tokenize the command line. If nothing on it, return. - */ - tokenize(cmdline, tokens, &ntok); - if (ntok == 0) - return; - - /* - * Find the appropriate command description. - */ - i = findcmd(tokens[0], builtins, opcmds, &xcmd); - if (i == 0) { - (void) fprintf(stderr, "***Command `%s' unknown\n", - tokens[0]); - return; - } else if (i >= 2) { - (void) fprintf(stderr, "***Command `%s' ambiguous\n", - tokens[0]); - return; - } - - /* - * Save the keyword, then walk through the arguments, interpreting - * as we go. - */ - pcmd.keyword = tokens[0]; - pcmd.nargs = 0; - for (i = 0; i < MAXARGS && xcmd->arg[i] != NO; i++) { - if ((i+1) >= ntok) { - if (!(xcmd->arg[i] & OPT)) { - printusage(xcmd, stderr); - return; - } - break; - } - if ((xcmd->arg[i] & OPT) && (*tokens[i+1] == '>')) - break; - if (!getarg(tokens[i+1], (int)xcmd->arg[i], &pcmd.argval[i])) - return; - pcmd.nargs++; - } - - i++; - if (i < ntok && *tokens[i] == '>') { - char *fname; - - if (*(tokens[i]+1) != '\0') - fname = tokens[i]+1; - else if ((i+1) < ntok) - fname = tokens[i+1]; - else { - (void) fprintf(stderr, "***No file for redirect\n"); - return; - } - - current_output = fopen(fname, "w"); - if (current_output == NULL) { - (void) fprintf(stderr, "***Error opening %s: ", fname); - perror(""); - return; - } - i = 1; /* flag we need a close */ - } else { - current_output = stdout; - i = 0; /* flag no close */ - } - - if (interactive && setjmp(interrupt_buf)) { - jump = 0; - return; - } else { - jump++; - (xcmd->handler)(&pcmd, current_output); - jump = 0; /* HMS: 961106: was after fclose() */ - if (i) (void) fclose(current_output); - } -} - - -/* - * tokenize - turn a command line into tokens - */ -static void -tokenize( - const char *line, - char **tokens, - int *ntok - ) -{ - register const char *cp; - register char *sp; - static char tspace[MAXLINE]; - - sp = tspace; - cp = line; - for (*ntok = 0; *ntok < MAXTOKENS; (*ntok)++) { - tokens[*ntok] = sp; - while (ISSPACE(*cp)) - cp++; - if (ISEOL(*cp)) - break; - do { - *sp++ = *cp++; - } while (!ISSPACE(*cp) && !ISEOL(*cp)); - - *sp++ = '\0'; - } -} - - - -/* - * findcmd - find a command in a command description table - */ -static int -findcmd( - register char *str, - struct xcmd *clist1, - struct xcmd *clist2, - struct xcmd **cmd - ) -{ - register struct xcmd *cl; - register int clen; - int nmatch; - struct xcmd *nearmatch = NULL; - struct xcmd *clist; - - clen = strlen(str); - nmatch = 0; - if (clist1 != 0) - clist = clist1; - else if (clist2 != 0) - clist = clist2; - else - return 0; - - again: - for (cl = clist; cl->keyword != 0; cl++) { - /* do a first character check, for efficiency */ - if (*str != *(cl->keyword)) - continue; - if (strncmp(str, cl->keyword, (unsigned)clen) == 0) { - /* - * Could be extact match, could be approximate. - * Is exact if the length of the keyword is the - * same as the str. - */ - if (*((cl->keyword) + clen) == '\0') { - *cmd = cl; - return 1; - } - nmatch++; - nearmatch = cl; - } - } - - /* - * See if there is more to do. If so, go again. Sorry about the - * goto, too much looking at BSD sources... - */ - if (clist == clist1 && clist2 != 0) { - clist = clist2; - goto again; - } - - /* - * If we got extactly 1 near match, use it, else return number - * of matches. - */ - if (nmatch == 1) { - *cmd = nearmatch; - return 1; - } - return nmatch; -} - - -/* - * getarg - interpret an argument token - */ -static int -getarg( - char *str, - int code, - arg_v *argp - ) -{ - int isneg; - char *cp, *np; - static const char *digits = "0123456789"; - - switch (code & ~OPT) { - case STR: - argp->string = str; - break; - case ADD: - if (!getnetnum(str, &(argp->netnum), (char *)0, 0)) { - return 0; - } - break; - case INT: - case UINT: - isneg = 0; - np = str; - if (*np == '&') { - np++; - isneg = atoi(np); - if (isneg <= 0) { - (void) fprintf(stderr, - "***Association value `%s' invalid/undecodable\n", str); - return 0; - } - if (isneg > numassoc) { - if (numassoc == 0) { - (void) fprintf(stderr, - "***Association for `%s' unknown (max &%d)\n", - str, numassoc); - return 0; - } else { - isneg = numassoc; - } - } - argp->uval = assoc_cache[isneg-1].assid; - break; - } - - if (*np == '-') { - np++; - isneg = 1; - } - - argp->uval = 0; - do { - cp = strchr(digits, *np); - if (cp == NULL) { - (void) fprintf(stderr, - "***Illegal integer value %s\n", str); - return 0; - } - argp->uval *= 10; - argp->uval += (cp - digits); - } while (*(++np) != '\0'); - - if (isneg) { - if ((code & ~OPT) == UINT) { - (void) fprintf(stderr, - "***Value %s should be unsigned\n", str); - return 0; - } - argp->ival = -argp->ival; - } - break; - case IP_VERSION: - if (!strcmp("-6", str)) - argp->ival = 6 ; - else if (!strcmp("-4", str)) - argp->ival = 4 ; - else { - (void) fprintf(stderr, - "***Version must be either 4 or 6\n"); - return 0; - } - break; - } - - return 1; -} - - -/* - * getnetnum - given a host name, return its net number - * and (optional) full name - */ -int -getnetnum( - const char *hname, - struct sockaddr_storage *num, - char *fullhost, - int af - ) -{ - int err; - int sockaddr_len; - struct addrinfo hints, *ai = NULL; - - sockaddr_len = (af == AF_INET) - ? sizeof(struct sockaddr_in) - : sizeof(struct sockaddr_in6); - memset((char *)&hints, 0, sizeof(struct addrinfo)); - hints.ai_flags = AI_CANONNAME; -#ifdef AI_ADDRCONFIG - hints.ai_flags |= AI_ADDRCONFIG; -#endif - - /* decodenetnum works with addresses only */ - if (decodenetnum(hname, num)) { - if (fullhost != 0) { - getnameinfo((struct sockaddr *)num, sockaddr_len, - fullhost, sizeof(fullhost), NULL, 0, - NI_NUMERICHOST); - - } - return 1; - } else if ((err = getaddrinfo(hname, "ntp", &hints, &ai)) == 0) { - memmove((char *)num, ai->ai_addr, ai->ai_addrlen); - if (ai->ai_canonname != 0) - (void) strcpy(fullhost, ai->ai_canonname); - return 1; - } else { - (void) fprintf(stderr, "***Can't find host %s\n", hname); - return 0; - } - /*NOTREACHED*/ -} - -/* - * nntohost - convert network number to host name. This routine enforces - * the showhostnames setting. - */ -char * -nntohost( - struct sockaddr_storage *netnum - ) -{ - if (!showhostnames) - return stoa(netnum); - if ((netnum->ss_family == AF_INET) && ISREFCLOCKADR(netnum)) - return refnumtoa(netnum); - return socktohost(netnum); -} - - -/* - * rtdatetolfp - decode an RT-11 date into an l_fp - */ -static int -rtdatetolfp( - char *str, - l_fp *lfp - ) -{ - register char *cp; - register int i; - struct calendar cal; - char buf[4]; - static const char *months[12] = { - "Jan", "Feb", "Mar", "Apr", "May", "Jun", - "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" - }; - - cal.yearday = 0; - - /* - * An RT-11 date looks like: - * - * d[d]-Mth-y[y] hh:mm:ss - * - * (No docs, but assume 4-digit years are also legal...) - * - * d[d]-Mth-y[y[y[y]]] hh:mm:ss - */ - cp = str; - if (!isdigit((int)*cp)) { - if (*cp == '-') { - /* - * Catch special case - */ - L_CLR(lfp); - return 1; - } - return 0; - } - - cal.monthday = (u_char) (*cp++ - '0'); /* ascii dependent */ - if (isdigit((int)*cp)) { - cal.monthday = (u_char)((cal.monthday << 3) + (cal.monthday << 1)); - cal.monthday = (u_char)(cal.monthday + *cp++ - '0'); - } - - if (*cp++ != '-') - return 0; - - for (i = 0; i < 3; i++) - buf[i] = *cp++; - buf[3] = '\0'; - - for (i = 0; i < 12; i++) - if (STREQ(buf, months[i])) - break; - if (i == 12) - return 0; - cal.month = (u_char)(i + 1); - - if (*cp++ != '-') - return 0; - - if (!isdigit((int)*cp)) - return 0; - cal.year = (u_short)(*cp++ - '0'); - if (isdigit((int)*cp)) { - cal.year = (u_short)((cal.year << 3) + (cal.year << 1)); - cal.year = (u_short)(*cp++ - '0'); - } - if (isdigit((int)*cp)) { - cal.year = (u_short)((cal.year << 3) + (cal.year << 1)); - cal.year = (u_short)(cal.year + *cp++ - '0'); - } - if (isdigit((int)*cp)) { - cal.year = (u_short)((cal.year << 3) + (cal.year << 1)); - cal.year = (u_short)(cal.year + *cp++ - '0'); - } - - /* - * Catch special case. If cal.year == 0 this is a zero timestamp. - */ - if (cal.year == 0) { - L_CLR(lfp); - return 1; - } - - if (*cp++ != ' ' || !isdigit((int)*cp)) - return 0; - cal.hour = (u_char)(*cp++ - '0'); - if (isdigit((int)*cp)) { - cal.hour = (u_char)((cal.hour << 3) + (cal.hour << 1)); - cal.hour = (u_char)(cal.hour + *cp++ - '0'); - } - - if (*cp++ != ':' || !isdigit((int)*cp)) - return 0; - cal.minute = (u_char)(*cp++ - '0'); - if (isdigit((int)*cp)) { - cal.minute = (u_char)((cal.minute << 3) + (cal.minute << 1)); - cal.minute = (u_char)(cal.minute + *cp++ - '0'); - } - - if (*cp++ != ':' || !isdigit((int)*cp)) - return 0; - cal.second = (u_char)(*cp++ - '0'); - if (isdigit((int)*cp)) { - cal.second = (u_char)((cal.second << 3) + (cal.second << 1)); - cal.second = (u_char)(cal.second + *cp++ - '0'); - } - - /* - * For RT-11, 1972 seems to be the pivot year - */ - if (cal.year < 72) - cal.year += 2000; - if (cal.year < 100) - cal.year += 1900; - - lfp->l_ui = caltontp(&cal); - lfp->l_uf = 0; - return 1; -} - - -/* - * decodets - decode a timestamp into an l_fp format number, with - * consideration of fuzzball formats. - */ -int -decodets( - char *str, - l_fp *lfp - ) -{ - /* - * If it starts with a 0x, decode as hex. - */ - if (*str == '0' && (*(str+1) == 'x' || *(str+1) == 'X')) - return hextolfp(str+2, lfp); - - /* - * If it starts with a '"', try it as an RT-11 date. - */ - if (*str == '"') { - register char *cp = str+1; - register char *bp; - char buf[30]; - - bp = buf; - while (*cp != '"' && *cp != '\0' && bp < &buf[29]) - *bp++ = *cp++; - *bp = '\0'; - return rtdatetolfp(buf, lfp); - } - - /* - * Might still be hex. Check out the first character. Talk - * about heuristics! - */ - if ((*str >= 'A' && *str <= 'F') || (*str >= 'a' && *str <= 'f')) - return hextolfp(str, lfp); - - /* - * Try it as a decimal. If this fails, try as an unquoted - * RT-11 date. This code should go away eventually. - */ - if (atolfp(str, lfp)) - return 1; - return rtdatetolfp(str, lfp); -} - - -/* - * decodetime - decode a time value. It should be in milliseconds - */ -int -decodetime( - char *str, - l_fp *lfp - ) -{ - return mstolfp(str, lfp); -} - - -/* - * decodeint - decode an integer - */ -int -decodeint( - char *str, - long *val - ) -{ - if (*str == '0') { - if (*(str+1) == 'x' || *(str+1) == 'X') - return hextoint(str+2, (void *)&val); - return octtoint(str, (void *)&val); - } - return atoint(str, val); -} - - -/* - * decodeuint - decode an unsigned integer - */ -int -decodeuint( - char *str, - u_long *val - ) -{ - if (*str == '0') { - if (*(str + 1) == 'x' || *(str + 1) == 'X') - return (hextoint(str + 2, val)); - return (octtoint(str, val)); - } - return (atouint(str, val)); -} - - -/* - * decodearr - decode an array of time values - */ -static int -decodearr( - char *str, - int *narr, - l_fp *lfparr - ) -{ - register char *cp, *bp; - register l_fp *lfp; - char buf[60]; - - lfp = lfparr; - cp = str; - *narr = 0; - - while (*narr < 8) { - while (isspace((int)*cp)) - cp++; - if (*cp == '\0') - break; - - bp = buf; - while (!isspace((int)*cp) && *cp != '\0') - *bp++ = *cp++; - *bp++ = '\0'; - - if (!decodetime(buf, lfp)) - return 0; - (*narr)++; - lfp++; - } - return 1; -} - - -/* - * Finally, the built in command handlers - */ - -/* - * help - tell about commands, or details of a particular command - */ -static void -help( - struct parse *pcmd, - FILE *fp - ) -{ - int i; - int n; - struct xcmd *xcp; - char *cmd; - const char *cmdsort[100]; - int length[100]; - int maxlength; - int numperline; - static const char *spaces = " "; /* 20 spaces */ - - if (pcmd->nargs == 0) { - n = 0; - for (xcp = builtins; xcp->keyword != 0; xcp++) { - if (*(xcp->keyword) != '?') - cmdsort[n++] = xcp->keyword; - } - for (xcp = opcmds; xcp->keyword != 0; xcp++) - cmdsort[n++] = xcp->keyword; - -#ifdef QSORT_USES_VOID_P - qsort(cmdsort, (size_t)n, sizeof(char *), helpsort); -#else - qsort((char *)cmdsort, (size_t)n, sizeof(char *), helpsort); -#endif - - maxlength = 0; - for (i = 0; i < n; i++) { - length[i] = strlen(cmdsort[i]); - if (length[i] > maxlength) - maxlength = length[i]; - } - maxlength++; - numperline = 76 / maxlength; - - (void) fprintf(fp, "Commands available:\n"); - for (i = 0; i < n; i++) { - if ((i % numperline) == (numperline-1) - || i == (n-1)) - (void) fprintf(fp, "%s\n", cmdsort[i]); - else - (void) fprintf(fp, "%s%s", cmdsort[i], - spaces+20-maxlength+length[i]); - } - } else { - cmd = pcmd->argval[0].string; - n = findcmd(cmd, builtins, opcmds, &xcp); - if (n == 0) { - (void) fprintf(stderr, - "Command `%s' is unknown\n", cmd); - return; - } else if (n >= 2) { - (void) fprintf(stderr, - "Command `%s' is ambiguous\n", cmd); - return; - } - (void) fprintf(fp, "function: %s\n", xcp->comment); - printusage(xcp, fp); - } -} - - -/* - * helpsort - do hostname qsort comparisons - */ -#ifdef QSORT_USES_VOID_P -static int -helpsort( - const void *t1, - const void *t2 - ) -{ - char const * const * name1 = (char const * const *)t1; - char const * const * name2 = (char const * const *)t2; - - return strcmp(*name1, *name2); -} - -#else -static int -helpsort( - char **name1, - char **name2 - ) -{ - return strcmp(*name1, *name2); -} -#endif - -/* - * printusage - print usage information for a command - */ -static void -printusage( - struct xcmd *xcp, - FILE *fp - ) -{ - register int i; - - (void) fprintf(fp, "usage: %s", xcp->keyword); - for (i = 0; i < MAXARGS && xcp->arg[i] != NO; i++) { - if (xcp->arg[i] & OPT) - (void) fprintf(fp, " [ %s ]", xcp->desc[i]); - else - (void) fprintf(fp, " %s", xcp->desc[i]); - } - (void) fprintf(fp, "\n"); -} - - -/* - * timeout - set time out time - */ -static void -timeout( - struct parse *pcmd, - FILE *fp - ) -{ - int val; - - if (pcmd->nargs == 0) { - val = tvout.tv_sec * 1000 + tvout.tv_usec / 1000; - (void) fprintf(fp, "primary timeout %d ms\n", val); - } else { - tvout.tv_sec = pcmd->argval[0].uval / 1000; - tvout.tv_usec = (pcmd->argval[0].uval - (tvout.tv_sec * 1000)) - * 1000; - } -} - - -/* - * auth_delay - set delay for auth requests - */ -static void -auth_delay( - struct parse *pcmd, - FILE *fp - ) -{ - int isneg; - u_long val; - - if (pcmd->nargs == 0) { - val = delay_time.l_ui * 1000 + delay_time.l_uf / 4294967; - (void) fprintf(fp, "delay %lu ms\n", val); - } else { - if (pcmd->argval[0].ival < 0) { - isneg = 1; - val = (u_long)(-pcmd->argval[0].ival); - } else { - isneg = 0; - val = (u_long)pcmd->argval[0].ival; - } - - delay_time.l_ui = val / 1000; - val %= 1000; - delay_time.l_uf = val * 4294967; /* 2**32/1000 */ - - if (isneg) - L_NEG(&delay_time); - } -} - - -/* - * host - set the host we are dealing with. - */ -static void -host( - struct parse *pcmd, - FILE *fp - ) -{ - int i; - - if (pcmd->nargs == 0) { - if (havehost) - (void) fprintf(fp, "current host is %s\n", currenthost); - else - (void) fprintf(fp, "no current host\n"); - return; - } - - i = 0; - ai_fam_templ = ai_fam_default; - if (pcmd->nargs == 2) { - if (!strcmp("-4", pcmd->argval[i].string)) - ai_fam_templ = AF_INET; - else if (!strcmp("-6", pcmd->argval[i].string)) - ai_fam_templ = AF_INET6; - else { - if (havehost) - (void) fprintf(fp, - "current host remains %s\n", currenthost); - else - (void) fprintf(fp, "still no current host\n"); - return; - } - i = 1; - } - if (openhost(pcmd->argval[i].string)) { - (void) fprintf(fp, "current host set to %s\n", currenthost); - numassoc = 0; - } else { - if (havehost) - (void) fprintf(fp, - "current host remains %s\n", currenthost); - else - (void) fprintf(fp, "still no current host\n"); - } -} - - -/* - * poll - do one (or more) polls of the host via NTP - */ -/*ARGSUSED*/ -static void -ntp_poll( - struct parse *pcmd, - FILE *fp - ) -{ - (void) fprintf(fp, "poll not implemented yet\n"); -} - - -/* - * keyid - get a keyid to use for authenticating requests - */ -static void -keyid( - struct parse *pcmd, - FILE *fp - ) -{ - if (pcmd->nargs == 0) { - if (info_auth_keyid == 0) - (void) fprintf(fp, "no keyid defined\n"); - else - (void) fprintf(fp, "keyid is %lu\n", (u_long)info_auth_keyid); - } else { - /* allow zero so that keyid can be cleared. */ - if(pcmd->argval[0].uval > NTP_MAXKEY) - (void) fprintf(fp, "Invalid key identifier\n"); - info_auth_keyid = pcmd->argval[0].uval; - } -} - -/* - * keytype - get type of key to use for authenticating requests - */ -static void -keytype( - struct parse *pcmd, - FILE *fp - ) -{ - if (pcmd->nargs == 0) - fprintf(fp, "keytype is %s\n", - (info_auth_keytype == KEY_TYPE_MD5) ? "MD5" : "???"); - else - switch (*(pcmd->argval[0].string)) { - case 'm': - case 'M': - info_auth_keytype = KEY_TYPE_MD5; - break; - - default: - fprintf(fp, "keytype must be 'md5'\n"); - } -} - - - -/* - * passwd - get an authentication key - */ -/*ARGSUSED*/ -static void -passwd( - struct parse *pcmd, - FILE *fp - ) -{ - char *pass; - - if (info_auth_keyid == 0) { - int u_keyid = getkeyid("Keyid: "); - if (u_keyid == 0 || u_keyid > NTP_MAXKEY) { - (void)fprintf(fp, "Invalid key identifier\n"); - return; - } - info_auth_keyid = u_keyid; - } - pass = getpass("MD5 Password: "); - if (*pass == '\0') - (void) fprintf(fp, "Password unchanged\n"); - else { - authusekey(info_auth_keyid, info_auth_keytype, (u_char *)pass); - authtrust(info_auth_keyid, 1); - } -} - - -/* - * hostnames - set the showhostnames flag - */ -static void -hostnames( - struct parse *pcmd, - FILE *fp - ) -{ - if (pcmd->nargs == 0) { - if (showhostnames) - (void) fprintf(fp, "hostnames being shown\n"); - else - (void) fprintf(fp, "hostnames not being shown\n"); - } else { - if (STREQ(pcmd->argval[0].string, "yes")) - showhostnames = 1; - else if (STREQ(pcmd->argval[0].string, "no")) - showhostnames = 0; - else - (void)fprintf(stderr, "What?\n"); - } -} - - - -/* - * setdebug - set/change debugging level - */ -static void -setdebug( - struct parse *pcmd, - FILE *fp - ) -{ - if (pcmd->nargs == 0) { - (void) fprintf(fp, "debug level is %d\n", debug); - return; - } else if (STREQ(pcmd->argval[0].string, "no")) { - debug = 0; - } else if (STREQ(pcmd->argval[0].string, "more")) { - debug++; - } else if (STREQ(pcmd->argval[0].string, "less")) { - debug--; - } else { - (void) fprintf(fp, "What?\n"); - return; - } - (void) fprintf(fp, "debug level set to %d\n", debug); -} - - -/* - * quit - stop this nonsense - */ -/*ARGSUSED*/ -static void -quit( - struct parse *pcmd, - FILE *fp - ) -{ - if (havehost) - closesocket(sockfd); /* cleanliness next to godliness */ - exit(0); -} - - -/* - * version - print the current version number - */ -/*ARGSUSED*/ -static void -version( - struct parse *pcmd, - FILE *fp - ) -{ - - (void) fprintf(fp, "%s\n", Version); - return; -} - - -/* - * raw - set raw mode output - */ -/*ARGSUSED*/ -static void -raw( - struct parse *pcmd, - FILE *fp - ) -{ - rawmode = 1; - (void) fprintf(fp, "Output set to raw\n"); -} - - -/* - * cooked - set cooked mode output - */ -/*ARGSUSED*/ -static void -cooked( - struct parse *pcmd, - FILE *fp - ) -{ - rawmode = 0; - (void) fprintf(fp, "Output set to cooked\n"); - return; -} - - -/* - * authenticate - always authenticate requests to this host - */ -static void -authenticate( - struct parse *pcmd, - FILE *fp - ) -{ - if (pcmd->nargs == 0) { - if (always_auth) { - (void) fprintf(fp, - "authenticated requests being sent\n"); - } else - (void) fprintf(fp, - "unauthenticated requests being sent\n"); - } else { - if (STREQ(pcmd->argval[0].string, "yes")) { - always_auth = 1; - } else if (STREQ(pcmd->argval[0].string, "no")) { - always_auth = 0; - } else - (void)fprintf(stderr, "What?\n"); - } -} - - -/* - * ntpversion - choose the NTP version to use - */ -static void -ntpversion( - struct parse *pcmd, - FILE *fp - ) -{ - if (pcmd->nargs == 0) { - (void) fprintf(fp, - "NTP version being claimed is %d\n", pktversion); - } else { - if (pcmd->argval[0].uval < NTP_OLDVERSION - || pcmd->argval[0].uval > NTP_VERSION) { - (void) fprintf(stderr, "versions %d to %d, please\n", - NTP_OLDVERSION, NTP_VERSION); - } else { - pktversion = (u_char) pcmd->argval[0].uval; - } - } -} - - -/* - * warning - print a warning message - */ -static void -warning( - const char *fmt, - const char *st1, - const char *st2 - ) -{ - (void) fprintf(stderr, "%s: ", progname); - (void) fprintf(stderr, fmt, st1, st2); - (void) fprintf(stderr, ": "); - perror(""); -} - - -/* - * error - print a message and exit - */ -static void -error( - const char *fmt, - const char *st1, - const char *st2 - ) -{ - warning(fmt, st1, st2); - exit(1); -} - -/* - * getkeyid - prompt the user for a keyid to use - */ -static u_long -getkeyid( - const char *keyprompt - ) -{ - register char *p; - register int c; - FILE *fi; - char pbuf[20]; - -#ifndef SYS_WINNT - if ((fi = fdopen(open("/dev/tty", 2), "r")) == NULL) -#else - if ((fi = _fdopen((int)GetStdHandle(STD_INPUT_HANDLE), "r")) == NULL) -#endif /* SYS_WINNT */ - fi = stdin; - else - setbuf(fi, (char *)NULL); - fprintf(stderr, "%s", keyprompt); fflush(stderr); - for (p=pbuf; (c = getc(fi))!='\n' && c!=EOF;) { - if (p < &pbuf[18]) - *p++ = (char)c; - } - *p = '\0'; - if (fi != stdin) - fclose(fi); - if (strcmp(pbuf, "0") == 0) - return 0; - - return (u_long) atoi(pbuf); -} - - -/* - * atoascii - printable-ize possibly ascii data using the character - * transformations cat -v uses. - */ -static void -atoascii( - int length, - char *data, - char *outdata - ) -{ - register u_char *cp; - register u_char *ocp; - register u_char c; - - if (!data) - { - *outdata = '\0'; - return; - } - - ocp = (u_char *)outdata; - for (cp = (u_char *)data; cp < (u_char *)data + length; cp++) { - c = *cp; - if (c == '\0') - break; - if (c == '\0') - break; - if (c > 0177) { - *ocp++ = 'M'; - *ocp++ = '-'; - c &= 0177; - } - - if (c < ' ') { - *ocp++ = '^'; - *ocp++ = (u_char)(c + '@'); - } else if (c == 0177) { - *ocp++ = '^'; - *ocp++ = '?'; - } else { - *ocp++ = c; - } - if (ocp >= ((u_char *)outdata + length - 4)) - break; - } - *ocp++ = '\0'; -} - - - -/* - * makeascii - print possibly ascii data using the character - * transformations that cat -v uses. - */ -static void -makeascii( - int length, - char *data, - FILE *fp - ) -{ - register u_char *cp; - register int c; - - for (cp = (u_char *)data; cp < (u_char *)data + length; cp++) { - c = (int)*cp; - if (c > 0177) { - putc('M', fp); - putc('-', fp); - c &= 0177; - } - - if (c < ' ') { - putc('^', fp); - putc(c+'@', fp); - } else if (c == 0177) { - putc('^', fp); - putc('?', fp); - } else { - putc(c, fp); - } - } -} - - -/* - * asciize - same thing as makeascii except add a newline - */ -void -asciize( - int length, - char *data, - FILE *fp - ) -{ - makeascii(length, data, fp); - putc('\n', fp); -} - - -/* - * Some circular buffer space - */ -#define CBLEN 80 -#define NUMCB 6 - -char circ_buf[NUMCB][CBLEN]; -int nextcb = 0; - -/* - * nextvar - find the next variable in the buffer - */ -int -nextvar( - int *datalen, - char **datap, - char **vname, - char **vvalue - ) -{ - register char *cp; - register char *np; - register char *cpend; - register char *npend; /* character after last */ - int quoted = 0; - static char name[MAXVARLEN]; - static char value[MAXVALLEN]; - - cp = *datap; - cpend = cp + *datalen; - - /* - * Space past commas and white space - */ - while (cp < cpend && (*cp == ',' || isspace((int)*cp))) - cp++; - if (cp == cpend) - return 0; - - /* - * Copy name until we hit a ',', an '=', a '\r' or a '\n'. Backspace - * over any white space and terminate it. - */ - np = name; - npend = &name[MAXVARLEN]; - while (cp < cpend && np < npend && *cp != ',' && *cp != '=' - && *cp != '\r' && *cp != '\n') - *np++ = *cp++; - /* - * Check if we ran out of name space, without reaching the end or a - * terminating character - */ - if (np == npend && !(cp == cpend || *cp == ',' || *cp == '=' || - *cp == '\r' || *cp == '\n')) - return 0; - while (isspace((int)(*(np-1)))) - np--; - *np = '\0'; - *vname = name; - - /* - * Check if we hit the end of the buffer or a ','. If so we are done. - */ - if (cp == cpend || *cp == ',' || *cp == '\r' || *cp == '\n') { - if (cp != cpend) - cp++; - *datap = cp; - *datalen = cpend - cp; - *vvalue = (char *)0; - return 1; - } - - /* - * So far, so good. Copy out the value - */ - cp++; /* past '=' */ - while (cp < cpend && (isspace((int)*cp) && *cp != '\r' && *cp != '\n')) - cp++; - np = value; - npend = &value[MAXVALLEN]; - while (cp < cpend && np < npend && ((*cp != ',') || quoted)) - { - quoted ^= ((*np++ = *cp++) == '"'); - } - - /* - * Check if we overran the value buffer while still in a quoted string - * or without finding a comma - */ - if (np == npend && (quoted || *cp != ',')) - return 0; - /* - * Trim off any trailing whitespace - */ - while (np > value && isspace((int)(*(np-1)))) - np--; - *np = '\0'; - - /* - * Return this. All done. - */ - if (cp != cpend) - cp++; - *datap = cp; - *datalen = cpend - cp; - *vvalue = value; - return 1; -} - - -/* - * findvar - see if this variable is known to us - */ -int -findvar( - char *varname, - struct ctl_var *varlist - ) -{ - register char *np; - register struct ctl_var *vl; - - vl = varlist; - np = varname; - while (vl->fmt != EOV) { - if (vl->fmt != PADDING && STREQ(np, vl->text)) - return vl->code; - vl++; - } - return 0; -} - - - -/* - * printvars - print variables returned in response packet - */ -void -printvars( - int length, - char *data, - int status, - int sttype, - FILE *fp - ) -{ - if (rawmode) - rawprint(sttype, length, data, status, fp); - else - cookedprint(sttype, length, data, status, fp); -} - - -/* - * rawprint - do a printout of the data in raw mode - */ -static void -rawprint( - int datatype, - int length, - char *data, - int status, - FILE *fp - ) -{ - register char *cp; - register char *cpend; - - /* - * Essentially print the data as is. We reformat unprintables, though. - */ - cp = data; - cpend = data + length; - - (void) fprintf(fp, "status=0x%04x,\n", status); - - while (cp < cpend) { - if (*cp == '\r') { - /* - * If this is a \r and the next character is a - * \n, supress this, else pretty print it. Otherwise - * just output the character. - */ - if (cp == (cpend-1) || *(cp+1) != '\n') - makeascii(1, cp, fp); - } else if (isspace((int)*cp) || isprint((int)*cp)) { - putc(*cp, fp); - } else { - makeascii(1, cp, fp); - } - cp++; - } -} - - -/* - * Global data used by the cooked output routines - */ -int out_chars; /* number of characters output */ -int out_linecount; /* number of characters output on this line */ - - -/* - * startoutput - get ready to do cooked output - */ -static void -startoutput(void) -{ - out_chars = 0; - out_linecount = 0; -} - - -/* - * output - output a variable=value combination - */ -static void -output( - FILE *fp, - char *name, - char *value - ) -{ - int lenname; - int lenvalue; - - lenname = strlen(name); - lenvalue = strlen(value); - - if (out_chars != 0) { - putc(',', fp); - out_chars++; - out_linecount++; - if ((out_linecount + lenname + lenvalue + 3) > MAXOUTLINE) { - putc('\n', fp); - out_chars++; - out_linecount = 0; - } else { - putc(' ', fp); - out_chars++; - out_linecount++; - } - } - - fputs(name, fp); - putc('=', fp); - fputs(value, fp); - out_chars += lenname + 1 + lenvalue; - out_linecount += lenname + 1 + lenvalue; -} - - -/* - * endoutput - terminate a block of cooked output - */ -static void -endoutput( - FILE *fp - ) -{ - if (out_chars != 0) - putc('\n', fp); -} - - -/* - * outputarr - output an array of values - */ -static void -outputarr( - FILE *fp, - char *name, - int narr, - l_fp *lfp - ) -{ - register char *bp; - register char *cp; - register int i; - register int len; - char buf[256]; - - bp = buf; - /* - * Hack to align delay and offset values - */ - for (i = (int)strlen(name); i < 11; i++) - *bp++ = ' '; - - for (i = narr; i > 0; i--) { - if (i != narr) - *bp++ = ' '; - cp = lfptoms(lfp, 2); - len = strlen(cp); - if (len > 7) { - cp[7] = '\0'; - len = 7; - } - while (len < 7) { - *bp++ = ' '; - len++; - } - while (*cp != '\0') - *bp++ = *cp++; - lfp++; - } - *bp = '\0'; - output(fp, name, buf); -} - -static char * -tstflags( - u_long val - ) -{ - register char *cb, *s; - register int i; - register const char *sep; - - sep = ""; - i = 0; - s = cb = &circ_buf[nextcb][0]; - if (++nextcb >= NUMCB) - nextcb = 0; - - sprintf(cb, "%02lx", val); - cb += strlen(cb); - if (!val) { - strcat(cb, " ok"); - cb += strlen(cb); - } else { - *cb++ = ' '; - for (i = 0; i < 11; i++) { - if (val & 0x1) { - sprintf(cb, "%s%s", sep, tstflagnames[i]); - sep = ", "; - cb += strlen(cb); - } - val >>= 1; - } - } - *cb = '\0'; - return s; -} - -/* - * cookedprint - output variables in cooked mode - */ -static void -cookedprint( - int datatype, - int length, - char *data, - int status, - FILE *fp - ) -{ - register int varid; - char *name; - char *value; - char output_raw; - int fmt; - struct ctl_var *varlist; - l_fp lfp; - long ival; - struct sockaddr_storage hval; - u_long uval; - l_fp lfparr[8]; - int narr; - - switch (datatype) { - case TYPE_PEER: - varlist = peer_var; - break; - case TYPE_SYS: - varlist = sys_var; - break; - case TYPE_CLOCK: - varlist = clock_var; - break; - default: - (void) fprintf(stderr, "Unknown datatype(0x%x) in cookedprint\n", datatype); - return; - } - - (void) fprintf(fp, "status=%04x %s,\n", status, - statustoa(datatype, status)); - - startoutput(); - while (nextvar(&length, &data, &name, &value)) { - varid = findvar(name, varlist); - if (varid == 0) { - output_raw = '*'; - } else { - output_raw = 0; - fmt = varlist[varid].fmt; - switch(fmt) { - case TS: - if (!decodets(value, &lfp)) - output_raw = '?'; - else - output(fp, name, prettydate(&lfp)); - break; - case FL: - case FU: - case FS: - if (!decodetime(value, &lfp)) - output_raw = '?'; - else { - switch (fmt) { - case FL: - output(fp, name, - lfptoms(&lfp, 3)); - break; - case FU: - output(fp, name, - ulfptoms(&lfp, 3)); - break; - case FS: - output(fp, name, - lfptoms(&lfp, 3)); - break; - } - } - break; - - case UI: - if (!decodeuint(value, &uval)) - output_raw = '?'; - else - output(fp, name, uinttoa(uval)); - break; - - case SI: - if (!decodeint(value, &ival)) - output_raw = '?'; - else - output(fp, name, inttoa(ival)); - break; - - case HA: - case NA: - if (!decodenetnum(value, &hval)) - output_raw = '?'; - else if (fmt == HA){ - output(fp, name, nntohost(&hval)); - } else { - output(fp, name, stoa(&hval)); - } - break; - - case ST: - output_raw = '*'; - break; - - case RF: - if (decodenetnum(value, &hval)) { - if ((hval.ss_family == AF_INET) && - ISREFCLOCKADR(&hval)) - output(fp, name, - refnumtoa(&hval)); - else - output(fp, name, stoa(&hval)); - } else if ((int)strlen(value) <= 4) - output(fp, name, value); - else - output_raw = '?'; - break; - - case LP: - if (!decodeuint(value, &uval) || uval > 3) - output_raw = '?'; - else { - char b[3]; - b[0] = b[1] = '0'; - if (uval & 0x2) - b[0] = '1'; - if (uval & 0x1) - b[1] = '1'; - b[2] = '\0'; - output(fp, name, b); - } - break; - - case OC: - if (!decodeuint(value, &uval)) - output_raw = '?'; - else { - char b[10]; - - (void) sprintf(b, "%03lo", uval); - output(fp, name, b); - } - break; - - case MD: - if (!decodeuint(value, &uval)) - output_raw = '?'; - else - output(fp, name, uinttoa(uval)); - break; - - case AR: - if (!decodearr(value, &narr, lfparr)) - output_raw = '?'; - else - outputarr(fp, name, narr, lfparr); - break; - - case FX: - if (!decodeuint(value, &uval)) - output_raw = '?'; - else - output(fp, name, tstflags(uval)); - break; - - default: - (void) fprintf(stderr, - "Internal error in cookedprint, %s=%s, fmt %d\n", - name, value, fmt); - break; - } - - } - if (output_raw != 0) { - char bn[401]; - char bv[401]; - int len; - - atoascii(400, name, bn); - atoascii(400, value, bv); - if (output_raw != '*') { - len = strlen(bv); - bv[len] = output_raw; - bv[len+1] = '\0'; - } - output(fp, bn, bv); - } - } - endoutput(fp); -} - - -/* - * sortassoc - sort associations in the cache into ascending order - */ -void -sortassoc(void) -{ - if (numassoc > 1) - qsort( -#ifdef QSORT_USES_VOID_P - (void *) -#else - (char *) -#endif - assoc_cache, (size_t)numassoc, - sizeof(struct association), assoccmp); -} - - -/* - * assoccmp - compare two associations - */ -#ifdef QSORT_USES_VOID_P -static int -assoccmp( - const void *t1, - const void *t2 - ) -{ - const struct association *ass1 = (const struct association *)t1; - const struct association *ass2 = (const struct association *)t2; - - if (ass1->assid < ass2->assid) - return -1; - if (ass1->assid > ass2->assid) - return 1; - return 0; -} -#else -static int -assoccmp( - struct association *ass1, - struct association *ass2 - ) -{ - if (ass1->assid < ass2->assid) - return -1; - if (ass1->assid > ass2->assid) - return 1; - return 0; -} -#endif /* not QSORT_USES_VOID_P */ |