2 * ntpq - query an NTP server using mode 6 commands
8 #include "ntp_unixtime.h"
9 #include "ntp_calendar.h"
11 #include "ntp_select.h"
12 #include "ntp_stdlib.h"
21 #define closesocket close
22 #endif /* SYS_WINNT */
25 /* vxWorks needs mode flag -casey*/
26 #define open(name, flags) open(name, flags, 0777)
27 #define SERVER_PORT_NUM 123
31 * Because we potentially understand a lot of commands we will run
32 * interactive if connected to a terminal.
34 int interactive = 0; /* set to 1 when we should prompt */
35 const char *prompt = "ntpq> "; /* prompt to ask him about */
39 * Keyid used for authenticated requests. Obtained on the fly.
41 u_long info_auth_keyid = NTP_MAXKEY;
44 * Type of key md5 or des
46 #define KEY_TYPE_DES 3
47 #define KEY_TYPE_MD5 4
49 static int info_auth_keytype = KEY_TYPE_MD5; /* MD5 */
50 u_long current_time; /* needed by authkeys; not used */
53 * Flag which indicates we should always send authenticated requests
58 * Flag which indicates raw mode output.
63 * Packet version number we use
65 u_char pktversion = NTP_OLDVERSION + 1;
68 * Don't jump if no set jmp.
70 volatile int jump = 0;
76 #define TS 1 /* time stamp */
77 #define FL 2 /* l_fp type value */
78 #define FU 3 /* u_fp type value */
79 #define FS 4 /* s_fp type value */
80 #define UI 5 /* unsigned integer value */
81 #define SI 6 /* signed integer value */
82 #define HA 7 /* host address */
83 #define NA 8 /* network address */
84 #define ST 9 /* string value */
85 #define RF 10 /* refid (sometimes string, sometimes not) */
86 #define LP 11 /* leap (print in binary) */
87 #define OC 12 /* integer, print in octal */
88 #define MD 13 /* mode */
89 #define AR 14 /* array of times */
90 #define FX 15 /* test flags */
91 #define EOV 255 /* end of table */
95 * System variable values. The array can be indexed by
96 * the variable index to find the textual name.
98 struct ctl_var sys_var[] = {
99 { 0, PADDING, "" }, /* 0 */
100 { CS_LEAP, LP, "leap" }, /* 1 */
101 { CS_STRATUM, UI, "stratum" }, /* 2 */
102 { CS_PRECISION, SI, "precision" }, /* 3 */
103 { CS_ROOTDELAY, FS, "rootdelay" }, /* 4 */
104 { CS_ROOTDISPERSION, FU, "rootdispersion" }, /* 5 */
105 { CS_REFID, RF, "refid" }, /* 6 */
106 { CS_REFTIME, TS, "reftime" }, /* 7 */
107 { CS_POLL, UI, "poll" }, /* 8 */
108 { CS_PEERID, UI, "peer" }, /* 9 */
109 { CS_STATE, UI, "state" }, /* 10 */
110 { CS_OFFSET, FL, "offset" }, /* 11 */
111 { CS_DRIFT, FS, "frequency" }, /* 12 */
112 { CS_JITTER, FU, "jitter" }, /* 13 */
113 { CS_CLOCK, TS, "clock" }, /* 14 */
114 { CS_PROCESSOR, ST, "processor" }, /* 15 */
115 { CS_SYSTEM, ST, "system" }, /* 16 */
116 { CS_VERSION, ST, "version" }, /* 17 */
117 { CS_STABIL, FS, "stability" }, /* 18 */
118 { CS_VARLIST, ST, "sys_var_list" }, /* 19 */
126 struct ctl_var peer_var[] = {
127 { 0, PADDING, "" }, /* 0 */
128 { CP_CONFIG, UI, "config" }, /* 1 */
129 { CP_AUTHENABLE, UI, "authenable" }, /* 2 */
130 { CP_AUTHENTIC, UI, "authentic" }, /* 3 */
131 { CP_SRCADR, HA, "srcadr" }, /* 4 */
132 { CP_SRCPORT, UI, "srcport" }, /* 5 */
133 { CP_DSTADR, NA, "dstadr" }, /* 6 */
134 { CP_DSTPORT, UI, "dstport" }, /* 7 */
135 { CP_LEAP, LP, "leap" }, /* 8 */
136 { CP_HMODE, MD, "hmode" }, /* 9 */
137 { CP_STRATUM, UI, "stratum" }, /* 10 */
138 { CP_PPOLL, UI, "ppoll" }, /* 11 */
139 { CP_HPOLL, UI, "hpoll" }, /* 12 */
140 { CP_PRECISION, SI, "precision" }, /* 13 */
141 { CP_ROOTDELAY, FS, "rootdelay" }, /* 14 */
142 { CP_ROOTDISPERSION, FU, "rootdispersion" }, /* 15 */
143 { CP_REFID, RF, "refid" }, /* 16 */
144 { CP_REFTIME, TS, "reftime" }, /* 17 */
145 { CP_ORG, TS, "org" }, /* 18 */
146 { CP_REC, TS, "rec" }, /* 19 */
147 { CP_XMT, TS, "xmt" }, /* 20 */
148 { CP_REACH, OC, "reach" }, /* 21 */
149 { CP_VALID, UI, "valid" }, /* 22 */
150 { CP_TIMER, UI, "timer" }, /* 23 */
151 { CP_DELAY, FS, "delay" }, /* 24 */
152 { CP_OFFSET, FL, "offset" }, /* 25 */
153 { CP_JITTER, FU, "jitter" }, /* 26 */
154 { CP_DISPERSION, FU, "dispersion" }, /* 27 */
155 { CP_KEYID, UI, "keyid" }, /* 28 */
156 { CP_FILTDELAY, AR, "filtdelay" }, /* 29 */
157 { CP_FILTOFFSET, AR, "filtoffset" }, /* 30 */
158 { CP_PMODE, ST, "pmode" }, /* 31 */
159 { CP_RECEIVED, UI, "received" }, /* 32 */
160 { CP_SENT, UI, "sent" }, /* 33 */
161 { CP_FILTERROR, AR, "filtdisp" }, /* 34 */
162 { CP_FLASH, FX, "flash" }, /* 35 */
163 { CP_TTL, UI, "ttl" }, /* 36 */
164 { CP_TTLMAX, UI, "ttlmax" }, /* 37 */
166 * These are duplicate entries so that we can
167 * process deviant version of the ntp protocol.
169 { CP_SRCADR, HA, "peeraddr" }, /* 4 */
170 { CP_SRCPORT, UI, "peerport" }, /* 5 */
171 { CP_PPOLL, UI, "peerpoll" }, /* 11 */
172 { CP_HPOLL, UI, "hostpoll" }, /* 12 */
173 { CP_FILTERROR, AR, "filterror" }, /* 34 */
179 * Clock variable list
181 struct ctl_var clock_var[] = {
182 { 0, PADDING, "" }, /* 0 */
183 { CC_TYPE, UI, "type" }, /* 1 */
184 { CC_TIMECODE, ST, "timecode" }, /* 2 */
185 { CC_POLL, UI, "poll" }, /* 3 */
186 { CC_NOREPLY, UI, "noreply" }, /* 4 */
187 { CC_BADFORMAT, UI, "badformat" }, /* 5 */
188 { CC_BADDATA, UI, "baddata" }, /* 6 */
189 { CC_FUDGETIME1, FL, "fudgetime1" }, /* 7 */
190 { CC_FUDGETIME2, FL, "fudgetime2" }, /* 8 */
191 { CC_FUDGEVAL1, UI, "stratum" }, /* 9 */
192 { CC_FUDGEVAL2, RF, "refid" }, /* 10 */
193 { CC_FLAGS, UI, "flags" }, /* 11 */
194 { CC_DEVICE, ST, "device" }, /* 12 */
202 static const char *tstflagnames[] = {
203 "dup_pkt", /* TEST1 */
204 "bogus_pkt", /* TEST2 */
205 "proto_unsync", /* TEST3 */
206 "no_access", /* TEST4 */
207 "bad_auth", /* TEST5 */
208 "peer_unsync", /* TEST6 */
209 "peer_stratum", /* TEST7 */
210 "root_bounds", /* TEST8 */
211 "peer_bounds", /* TEST9 */
212 "bad_autokey", /* TEST10 */
213 "not_proventic" /* TEST11*/
217 int ntpqmain P((int, char **));
219 * Built in command handler declarations
221 static int openhost P((const char *));
222 static int sendpkt P((char *, int));
223 static int getresponse P((int, int, u_short *, int *, char **, int));
224 static int sendrequest P((int, int, int, int, char *));
225 static char * tstflags P((u_long));
226 static void getcmds P((void));
227 static RETSIGTYPE abortcmd P((int));
228 static void docmd P((const char *));
229 static void tokenize P((const char *, char **, int *));
230 static int findcmd P((char *, struct xcmd *, struct xcmd *, struct xcmd **));
231 static int getarg P((char *, int, arg_v *));
232 static int rtdatetolfp P((char *, l_fp *));
233 static int decodearr P((char *, int *, l_fp *));
234 static void help P((struct parse *, FILE *));
235 #ifdef QSORT_USES_VOID_P
236 static int helpsort P((const void *, const void *));
238 static int helpsort P((char **, char **));
240 static void printusage P((struct xcmd *, FILE *));
241 static void timeout P((struct parse *, FILE *));
242 static void auth_delay P((struct parse *, FILE *));
243 static void host P((struct parse *, FILE *));
244 static void ntp_poll P((struct parse *, FILE *));
245 static void keyid P((struct parse *, FILE *));
246 static void keytype P((struct parse *, FILE *));
247 static void passwd P((struct parse *, FILE *));
248 static void hostnames P((struct parse *, FILE *));
249 static void setdebug P((struct parse *, FILE *));
250 static void quit P((struct parse *, FILE *));
251 static void version P((struct parse *, FILE *));
252 static void raw P((struct parse *, FILE *));
253 static void cooked P((struct parse *, FILE *));
254 static void authenticate P((struct parse *, FILE *));
255 static void ntpversion P((struct parse *, FILE *));
256 static void warning P((const char *, const char *, const char *));
257 static void error P((const char *, const char *, const char *));
258 static u_long getkeyid P((const char *));
259 static void atoascii P((int, char *, char *));
260 static void makeascii P((int, char *, FILE *));
261 static void rawprint P((int, int, char *, int, FILE *));
262 static void startoutput P((void));
263 static void output P((FILE *, char *, char *));
264 static void endoutput P((FILE *));
265 static void outputarr P((FILE *, char *, int, l_fp *));
266 static void cookedprint P((int, int, char *, int, FILE *));
267 #ifdef QSORT_USES_VOID_P
268 static int assoccmp P((const void *, const void *));
270 static int assoccmp P((struct association *, struct association *));
271 #endif /* sgi || bsdi */
275 * Built-in commands we understand
277 struct xcmd builtins[] = {
278 { "?", help, { OPT|STR, NO, NO, NO },
279 { "command", "", "", "" },
280 "tell the use and syntax of commands" },
281 { "help", help, { OPT|STR, NO, NO, NO },
282 { "command", "", "", "" },
283 "tell the use and syntax of commands" },
284 { "timeout", timeout, { OPT|UINT, NO, NO, NO },
285 { "msec", "", "", "" },
286 "set the primary receive time out" },
287 { "delay", auth_delay, { OPT|INT, NO, NO, NO },
288 { "msec", "", "", "" },
289 "set the delay added to encryption time stamps" },
290 { "host", host, { OPT|STR, NO, NO, NO },
291 { "hostname", "", "", "" },
292 "specify the host whose NTP server we talk to" },
293 { "poll", ntp_poll, { OPT|UINT, OPT|STR, NO, NO },
294 { "n", "verbose", "", "" },
295 "poll an NTP server in client mode `n' times" },
296 { "passwd", passwd, { NO, NO, NO, NO },
298 "specify a password to use for authenticated requests"},
299 { "hostnames", hostnames, { OPT|STR, NO, NO, NO },
300 { "yes|no", "", "", "" },
301 "specify whether hostnames or net numbers are printed"},
302 { "debug", setdebug, { OPT|STR, NO, NO, NO },
303 { "no|more|less", "", "", "" },
304 "set/change debugging level" },
305 { "quit", quit, { NO, NO, NO, NO },
308 { "exit", quit, { NO, NO, NO, NO },
311 { "keyid", keyid, { OPT|UINT, NO, NO, NO },
312 { "key#", "", "", "" },
313 "set keyid to use for authenticated requests" },
314 { "version", version, { NO, NO, NO, NO },
316 "print version number" },
317 { "raw", raw, { NO, NO, NO, NO },
319 "do raw mode variable output" },
320 { "cooked", cooked, { NO, NO, NO, NO },
322 "do cooked mode variable output" },
323 { "authenticate", authenticate, { OPT|STR, NO, NO, NO },
324 { "yes|no", "", "", "" },
325 "always authenticate requests to this server" },
326 { "ntpversion", ntpversion, { OPT|UINT, NO, NO, NO },
327 { "version number", "", "", "" },
328 "set the NTP version number to use for requests" },
329 { "keytype", keytype, { OPT|STR, NO, NO, NO },
330 { "key type (md5|des)", "", "", "" },
331 "set key type to use for authenticated requests (des|md5)" },
332 { 0, 0, { NO, NO, NO, NO },
333 { "", "", "", "" }, "" }
338 * Default values we use.
340 #define DEFTIMEOUT (5) /* 5 second time out */
341 #define DEFSTIMEOUT (2) /* 2 second time out after first */
342 #define DEFDELAY 0x51EB852 /* 20 milliseconds, l_fp fraction */
343 #define DEFHOST "127.0.0.1" /* default host name */
344 #define LENHOSTNAME 256 /* host name is 256 characters long */
345 #define MAXCMDS 100 /* maximum commands on cmd line */
346 #define MAXHOSTS 200 /* maximum hosts on cmd line */
347 #define MAXLINE 512 /* maximum line length */
348 #define MAXTOKENS (1+MAXARGS+2) /* maximum number of usable tokens */
349 #define MAXVARLEN 256 /* maximum length of a variable name */
350 #define MAXVALLEN 400 /* maximum length of a variable value */
351 #define MAXOUTLINE 72 /* maximum length of an output line */
354 * Some variables used and manipulated locally
356 struct timeval tvout = { DEFTIMEOUT, 0 }; /* time out for reads */
357 struct timeval tvsout = { DEFSTIMEOUT, 0 }; /* secondary time out */
358 l_fp delay_time; /* delay time */
359 char currenthost[LENHOSTNAME]; /* current host name */
360 struct sockaddr_in hostaddr = { 0 }; /* host address */
361 int showhostnames = 1; /* show host names by default */
363 int sockfd; /* fd socket is opened on */
364 int havehost = 0; /* set to 1 when host open */
365 struct servent *server_entry = NULL; /* server entry for ntp */
368 WORD wVersionRequested;
370 DWORD NumberOfBytesWritten;
372 HANDLE TimerThreadHandle = NULL; /* 1998/06/03 - Used in ntplib/machines.c */
373 void timer(void) { ; }; /* 1998/06/03 - Used in ntplib/machines.c */
375 #endif /* SYS_WINNT */
378 * Sequence number used for requests. It is incremented before
384 * Holds data returned from queries. Declare buffer long to be sure of
387 #define MAXFRAGS 24 /* maximum number of fragments */
388 #define DATASIZE (MAXFRAGS*480) /* maximum amount of data */
389 long pktdata[DATASIZE/sizeof(long)];
392 * Holds association data for use with the &n operator.
394 struct association assoc_cache[MAXASSOC];
395 int numassoc = 0; /* number of cached associations */
398 * For commands typed on the command line (with the -c option)
401 const char *ccmds[MAXCMDS];
402 #define ADDCMD(cp) if (numcmds < MAXCMDS) ccmds[numcmds++] = (cp)
405 * When multiple hosts are specified.
408 const char *chosts[MAXHOSTS];
409 #define ADDHOST(cp) if (numhosts < MAXHOSTS) chosts[numhosts++] = (cp)
412 * Error codes for internal use
414 #define ERR_UNSPEC 256
415 #define ERR_INCOMPLETE 257
416 #define ERR_TIMEOUT 258
417 #define ERR_TOOMUCH 259
420 * Macro definitions we use
422 #define ISSPACE(c) ((c) == ' ' || (c) == '\t')
423 #define ISEOL(c) ((c) == '\n' || (c) == '\r' || (c) == '\0')
424 #define STREQ(a, b) (*(a) == *(b) && strcmp((a), (b)) == 0)
427 * Jump buffer for longjumping back to the command level
429 jmp_buf interrupt_buf;
432 * Points at file being currently printed into
434 FILE *current_output;
437 * Command table imported from ntpdc_ops.c
439 extern struct xcmd opcmds[];
444 #ifdef NO_MAIN_ALLOWED
445 CALL(ntpq,"ntpq",ntpqmain);
447 void clear_globals(void)
449 extern int ntp_optind;
450 extern char *ntp_optarg;
451 showhostnames = 0; /* don'tshow host names by default */
454 server_entry = NULL; /* server entry for ntp */
455 havehost = 0; /* set to 1 when host open */
456 numassoc = 0; /* number of cached associations */
463 * main - parse arguments and handle options
465 #ifndef NO_MAIN_ALLOWED
472 return ntpqmain(argc, argv);
484 extern int ntp_optind;
485 extern char *ntp_optarg;
487 #ifdef NO_MAIN_ALLOWED
489 taskPrioritySet(taskIdSelf(), 100 );
492 delay_time.l_uf = DEFDELAY;
495 while ((c = ntp_getopt(argc, argv, "c:dinp")) != EOF)
517 (void) fprintf(stderr,
518 "usage: %s [-dinp] [-c cmd] host ...\n",
522 if (ntp_optind == argc) {
525 for (; ntp_optind < argc; ntp_optind++)
526 ADDHOST(argv[ntp_optind]);
529 if (numcmds == 0 && interactive == 0
530 && isatty(fileno(stdin)) && isatty(fileno(stderr))) {
534 #ifndef SYS_WINNT /* Under NT cannot handle SIGINT, WIN32 spawns a handler */
536 (void) signal_no_reset(SIGINT, abortcmd);
537 #endif /* SYS_WINNT */
540 wVersionRequested = MAKEWORD(1,1);
541 if (WSAStartup(wVersionRequested, &wsaData)) {
542 fprintf(stderr, "No useable winsock.dll");
545 #endif /* SYS_WINNT */
548 (void) openhost(chosts[0]);
554 for (ihost = 0; ihost < numhosts; ihost++) {
555 if (openhost(chosts[ihost]))
556 for (icmd = 0; icmd < numcmds; icmd++)
562 #endif /* SYS_WINNT */
568 * openhost - open a socket to a host
576 char temphost[LENHOSTNAME];
578 if (server_entry == NULL) {
579 server_entry = getservbyname("ntp", "udp");
580 if (server_entry == NULL) {
581 #ifdef VMS /* UCX getservbyname() doesn't work [yet], but we do know better */
582 server_entry = (struct servent *)
583 malloc(sizeof(struct servent));
584 server_entry->s_port = htons(NTP_PORT);
586 (void) fprintf(stderr, "%s: ntp/udp: unknown service\n",
589 #endif /* VMS & UCX */
592 printf("Got ntp/udp service entry\n");
595 if (!getnetnum(hname, &netnum, temphost))
599 printf("Opening host %s\n", temphost);
603 printf("Closing old host %s\n", currenthost);
604 (void) closesocket(sockfd);
607 (void) strcpy(currenthost, temphost);
609 hostaddr.sin_family = AF_INET;
611 hostaddr.sin_port = server_entry->s_port;
613 hostaddr.sin_port = htons(SERVER_PORT_NUM);
615 hostaddr.sin_addr.s_addr = netnum;
619 int optionValue = SO_SYNCHRONOUS_NONALERT;
621 err = setsockopt(INVALID_SOCKET, SOL_SOCKET, SO_OPENTYPE, (char *)&optionValue, sizeof(optionValue));
622 if (err != NO_ERROR) {
623 (void) fprintf(stderr, "cannot open nonoverlapped sockets\n");
629 sockfd = socket(AF_INET, SOCK_DGRAM, 0);
630 if (sockfd == INVALID_SOCKET) {
631 error("socket", "", "");
635 sockfd = socket(AF_INET, SOCK_DGRAM, 0);
637 error("socket", "", "");
638 #endif /* SYS_WINNT */
641 #ifdef NEED_RCVBUF_SLOP
643 { int rbufsize = DATASIZE + 2048; /* 2K for slop */
644 if (setsockopt(sockfd, SOL_SOCKET, SO_RCVBUF,
645 &rbufsize, sizeof(int)) == -1)
646 error("setsockopt", "", "");
651 if (connect(sockfd, (struct sockaddr *)&hostaddr,
652 sizeof(hostaddr)) == -1)
653 error("connect", "", "");
660 /* XXX ELIMINATE sendpkt similar in ntpq.c, ntpdc.c, ntp_io.c, ntptrace.c */
662 * sendpkt - send a packet to the remote host
671 printf("Sending %d octets\n", xdatalen);
674 if (send(sockfd, xdata, (size_t)xdatalen, 0) == -1) {
675 warning("write to %s failed", currenthost, "");
681 printf("Packet data:\n");
682 while (xdatalen-- > 0) {
687 printf(" %02x", *xdata++ & 0xff);
697 * getresponse - get a (series of) response packet(s) and return the data
709 struct ntp_control rpkt;
711 u_short offsets[MAXFRAGS+1];
712 u_short counts[MAXFRAGS+1];
721 * This is pretty tricky. We may get between 1 and MAXFRAG packets
722 * back in response to the request. We peel the data out of
723 * each packet and collect it in one long block. When the last
724 * packet in the sequence is received we'll know how much data we
725 * should have had. Note we use one long time out, should reconsider.
730 *rdata = (char *)pktdata;
743 FD_SET(sockfd, &fds);
744 n = select(sockfd+1, &fds, (fd_set *)0, (fd_set *)0, &tvo);
748 printf("select() returns %d\n", n);
752 warning("select fails", "", "");
757 * Timed out. Return what we have
761 (void) fprintf(stderr,
762 "%s: timed out, nothing received\n",
767 (void) fprintf(stderr,
768 "%s: timed out with incomplete data\n",
771 printf("Received fragments:\n");
772 for (n = 0; n < numfrags; n++)
773 printf("%4d %d\n", offsets[n],
776 printf("last fragment received\n");
778 printf("last fragment not received\n");
780 return ERR_INCOMPLETE;
784 n = recv(sockfd, (char *)&rpkt, sizeof(rpkt), 0);
786 warning("read", "", "");
791 int len = n, first = 8;
792 char *data = (char *)&rpkt;
794 printf("Packet data:\n");
800 printf(" %02x", *data++ & 0xff);
806 * Check for format errors. Bug proofing.
808 if (n < CTL_HEADER_LEN) {
810 printf("Short (%d byte) packet received\n", n);
813 if (PKT_VERSION(rpkt.li_vn_mode) > NTP_VERSION
814 || PKT_VERSION(rpkt.li_vn_mode) < NTP_OLDVERSION) {
816 printf("Packet received with version %d\n",
817 PKT_VERSION(rpkt.li_vn_mode));
820 if (PKT_MODE(rpkt.li_vn_mode) != MODE_CONTROL) {
822 printf("Packet received with mode %d\n",
823 PKT_MODE(rpkt.li_vn_mode));
826 if (!CTL_ISRESPONSE(rpkt.r_m_e_op)) {
828 printf("Received request packet, wanted response\n");
833 * Check opcode and sequence number for a match.
834 * Could be old data getting to us.
836 if (ntohs(rpkt.sequence) != sequence) {
839 "Received sequnce number %d, wanted %d\n",
840 ntohs(rpkt.sequence), sequence);
843 if (CTL_OP(rpkt.r_m_e_op) != opcode) {
846 "Received opcode %d, wanted %d (sequence number okay)\n",
847 CTL_OP(rpkt.r_m_e_op), opcode);
852 * Check the error code. If non-zero, return it.
854 if (CTL_ISERROR(rpkt.r_m_e_op)) {
857 errcode = (ntohs(rpkt.status) >> 8) & 0xff;
858 if (debug && CTL_ISMORE(rpkt.r_m_e_op)) {
859 printf("Error code %d received on not-final packet\n",
862 if (errcode == CERR_UNSPEC)
868 * Check the association ID to make sure it matches what
871 if (ntohs(rpkt.associd) != associd) {
873 printf("Association ID %d doesn't match expected %d\n",
874 ntohs(rpkt.associd), associd);
876 * Hack for silly fuzzballs which, at the time of writing,
877 * return an assID of sys.peer when queried for system variables.
885 * Collect offset and count. Make sure they make sense.
887 offset = ntohs(rpkt.offset);
888 count = ntohs(rpkt.count);
897 * Usually we ignore authentication, but for debugging purposes
900 shouldbesize = CTL_HEADER_LEN + count;
902 /* round to 8 octet boundary */
903 shouldbesize = (shouldbesize + 7) & ~7;
906 printf("Packet not padded, size = %d\n", n);
907 } if ((maclen = n - shouldbesize) >= MIN_MAC_LEN) {
909 "Packet shows signs of authentication (total %d, data %d, mac %d)\n",
910 n, shouldbesize, maclen);
911 lpkt = (u_long *)&rpkt;
912 printf("%08lx %08lx %08lx %08lx %08lx %08lx\n",
913 (u_long)ntohl(lpkt[(n - maclen)/sizeof(u_long) - 3]),
914 (u_long)ntohl(lpkt[(n - maclen)/sizeof(u_long) - 2]),
915 (u_long)ntohl(lpkt[(n - maclen)/sizeof(u_long) - 1]),
916 (u_long)ntohl(lpkt[(n - maclen)/sizeof(u_long)]),
917 (u_long)ntohl(lpkt[(n - maclen)/sizeof(u_long) + 1]),
918 (u_long)ntohl(lpkt[(n - maclen)/sizeof(u_long) + 2]));
919 key = ntohl(lpkt[(n - maclen) / sizeof(u_long)]);
920 printf("Authenticated with keyid %lu\n", (u_long)key);
921 if (key != 0 && key != info_auth_keyid) {
922 printf("We don't know that key\n");
924 if (authdecrypt(key, (u_int32 *)&rpkt,
925 n - maclen, maclen)) {
926 printf("Auth okay!\n");
928 printf("Auth failed!\n");
935 printf("Got packet, size = %d\n", n);
936 if (count > (u_short)(n-CTL_HEADER_LEN)) {
939 "Received count of %d octets, data in packet is %d\n",
940 count, n-CTL_HEADER_LEN);
943 if (count == 0 && CTL_ISMORE(rpkt.r_m_e_op)) {
945 printf("Received count of 0 in non-final fragment\n");
948 if (offset + count > sizeof(pktdata)) {
950 printf("Offset %d, count %d, too big for buffer\n",
954 if (seenlastfrag && !CTL_ISMORE(rpkt.r_m_e_op)) {
956 printf("Received second last fragment packet\n");
961 * So far, so good. Record this fragment, making sure it doesn't
965 printf("Packet okay\n");;
967 if (numfrags == MAXFRAGS) {
969 printf("Number of fragments exceeds maximum\n");
973 for (n = 0; n < numfrags; n++) {
974 if (offset == offsets[n])
975 goto again; /* duplicate */
976 if (offset < offsets[n])
980 if ((u_short)(n > 0 && offsets[n-1] + counts[n-1]) > offset)
982 if (n < numfrags && (u_short)(offset + count) > offsets[n])
988 for (i = numfrags; i > n; i--) {
989 offsets[i] = offsets[i-1];
990 counts[i] = counts[i-1];
998 * Got that stuffed in right. Figure out if this was the last.
999 * Record status info out of the last packet.
1001 if (!CTL_ISMORE(rpkt.r_m_e_op)) {
1004 *rstatus = ntohs(rpkt.status);
1008 * Copy the data into the data buffer.
1010 memmove((char *)pktdata + offset, (char *)rpkt.data, count);
1013 * If we've seen the last fragment, look for holes in the sequence.
1014 * If there aren't any, we're done.
1016 if (seenlastfrag && offsets[0] == 0) {
1017 for (n = 1; n < numfrags; n++) {
1018 if (offsets[n-1] + counts[n-1] != offsets[n])
1021 if (n == numfrags) {
1022 *rsize = offsets[numfrags-1] + counts[numfrags-1];
1030 * Print debugging message about overlapping fragments
1033 printf("Overlapping fragments returned in response\n");
1039 * sendrequest - format and send a request packet
1050 struct ntp_control qpkt;
1054 * Check to make sure the data will fit in one packet
1056 if (qsize > CTL_MAX_DATA_LEN) {
1057 (void) fprintf(stderr,
1058 "***Internal error! qsize (%d) too large\n",
1064 * Fill in the packet
1066 qpkt.li_vn_mode = PKT_LI_VN_MODE(0, pktversion, MODE_CONTROL);
1067 qpkt.r_m_e_op = (u_char)opcode & CTL_OP_MASK;
1068 qpkt.sequence = htons(sequence);
1070 qpkt.associd = htons((u_short)associd);
1072 qpkt.count = htons((u_short)qsize);
1075 * If we have data, copy it in and pad it out to a 64
1079 memmove((char *)qpkt.data, qdata, (unsigned)qsize);
1080 pktsize = qsize + CTL_HEADER_LEN;
1081 while (pktsize & (sizeof(u_long) - 1)) {
1082 qpkt.data[qsize++] = 0;
1086 pktsize = CTL_HEADER_LEN;
1090 * If it isn't authenticated we can just send it. Otherwise
1091 * we're going to have to think about it a little.
1093 if (!auth && !always_auth) {
1094 return sendpkt((char *)&qpkt, pktsize);
1096 const char *pass = "\0";
1101 * Pad out packet to a multiple of 8 octets to be sure
1102 * receiver can handle it.
1104 while (pktsize & 7) {
1105 qpkt.data[qsize++] = 0;
1110 * Get the keyid and the password if we don't have one.
1112 if (info_auth_keyid == 0) {
1113 maclen = getkeyid("Keyid: ");
1115 (void) fprintf(stderr,
1116 "Invalid key identifier\n");
1120 if (!authistrusted(info_auth_keyid)) {
1121 pass = getpass((info_auth_keytype == KEY_TYPE_DES)
1122 ? "DES Password: " : "MD5 Password: ");
1123 if (*pass == '\0') {
1124 (void) fprintf(stderr,
1125 "Invalid password\n");
1129 info_auth_keyid = maclen;
1130 authusekey(info_auth_keyid, info_auth_keytype, (const u_char *)pass);
1131 authtrust(info_auth_keyid, 1);
1134 * Stick the keyid in the packet where
1135 * cp currently points. Cp should be aligned
1136 * properly. Then do the encryptions.
1138 my_keyid = htonl(info_auth_keyid);
1139 memcpy(&qpkt.data[qsize], &my_keyid, sizeof my_keyid);
1140 maclen = authencrypt(info_auth_keyid, (u_int32 *)&qpkt,
1143 (void) fprintf(stderr, "Key not found\n");
1146 return sendpkt((char *)&qpkt, pktsize + maclen);
1153 * doquery - send a request and process the response
1171 * Check to make sure host is open
1174 (void) fprintf(stderr, "***No host open, use `host' command\n");
1185 res = sendrequest(opcode, associd, auth, qsize, qdata);
1190 * Get the response. If we got a standard error, print a message
1192 res = getresponse(opcode, associd, rstatus, rsize, rdata, done);
1195 if (!done && (res == ERR_TIMEOUT || res == ERR_INCOMPLETE)) {
1196 if (res == ERR_INCOMPLETE) {
1198 * better bump the sequence so we don't
1199 * get confused about differing fragments.
1208 (void) fprintf(stderr,
1209 "***Server reports a bad format request packet\n");
1211 case CERR_PERMISSION:
1212 (void) fprintf(stderr,
1213 "***Server disallowed request (authentication?)\n");
1216 (void) fprintf(stderr,
1217 "***Server reports a bad opcode in request\n");
1220 (void) fprintf(stderr,
1221 "***Association ID %d unknown to server\n",associd);
1223 case CERR_UNKNOWNVAR:
1224 (void) fprintf(stderr,
1225 "***A request variable unknown to the server\n");
1228 (void) fprintf(stderr,
1229 "***Server indicates a request variable was bad\n");
1232 (void) fprintf(stderr,
1233 "***Server returned an unspecified error\n");
1236 (void) fprintf(stderr, "***Request timed out\n");
1238 case ERR_INCOMPLETE:
1239 (void) fprintf(stderr,
1240 "***Response from server was incomplete\n");
1243 (void) fprintf(stderr,
1244 "***Buffer size exceeded for returned data\n");
1247 (void) fprintf(stderr,
1248 "***Server returns unknown error code %d\n", res);
1257 * getcmds - read commands from the standard input and execute them
1266 #ifdef VMS /* work around a problem with mixing stdout & stderr */
1269 (void) fputs(prompt, stderr);
1270 (void) fflush(stderr);
1273 if (fgets(line, sizeof line, stdin) == NULL)
1282 * abortcmd - catch interrupts and abort the current command
1289 if (current_output == stdout)
1290 (void) fflush(stdout);
1292 (void) fflush(stderr);
1293 if (jump) longjmp(interrupt_buf, 1);
1298 * docmd - decode the command line and execute a command
1305 char *tokens[1+MAXARGS+2];
1312 * Tokenize the command line. If nothing on it, return.
1314 tokenize(cmdline, tokens, &ntok);
1319 * Find the appropriate command description.
1321 i = findcmd(tokens[0], builtins, opcmds, &xcmd);
1323 (void) fprintf(stderr, "***Command `%s' unknown\n",
1326 } else if (i >= 2) {
1327 (void) fprintf(stderr, "***Command `%s' ambiguous\n",
1333 * Save the keyword, then walk through the arguments, interpreting
1336 pcmd.keyword = tokens[0];
1338 for (i = 0; i < MAXARGS && xcmd->arg[i] != NO; i++) {
1339 if ((i+1) >= ntok) {
1340 if (!(xcmd->arg[i] & OPT)) {
1341 printusage(xcmd, stderr);
1346 if ((xcmd->arg[i] & OPT) && (*tokens[i+1] == '>'))
1348 if (!getarg(tokens[i+1], (int)xcmd->arg[i], &pcmd.argval[i]))
1354 if (i < ntok && *tokens[i] == '>') {
1357 if (*(tokens[i]+1) != '\0')
1358 fname = tokens[i]+1;
1359 else if ((i+1) < ntok)
1360 fname = tokens[i+1];
1362 (void) fprintf(stderr, "***No file for redirect\n");
1366 current_output = fopen(fname, "w");
1367 if (current_output == NULL) {
1368 (void) fprintf(stderr, "***Error opening %s: ", fname);
1372 i = 1; /* flag we need a close */
1374 current_output = stdout;
1375 i = 0; /* flag no close */
1378 if (interactive && setjmp(interrupt_buf)) {
1383 (xcmd->handler)(&pcmd, current_output);
1384 jump = 0; /* HMS: 961106: was after fclose() */
1385 if (i) (void) fclose(current_output);
1391 * tokenize - turn a command line into tokens
1400 register const char *cp;
1402 static char tspace[MAXLINE];
1406 for (*ntok = 0; *ntok < MAXTOKENS; (*ntok)++) {
1408 while (ISSPACE(*cp))
1414 } while (!ISSPACE(*cp) && !ISEOL(*cp));
1423 * findcmd - find a command in a command description table
1428 struct xcmd *clist1,
1429 struct xcmd *clist2,
1433 register struct xcmd *cl;
1436 struct xcmd *nearmatch = NULL;
1443 else if (clist2 != 0)
1449 for (cl = clist; cl->keyword != 0; cl++) {
1450 /* do a first character check, for efficiency */
1451 if (*str != *(cl->keyword))
1453 if (strncmp(str, cl->keyword, (unsigned)clen) == 0) {
1455 * Could be extact match, could be approximate.
1456 * Is exact if the length of the keyword is the
1459 if (*((cl->keyword) + clen) == '\0') {
1469 * See if there is more to do. If so, go again. Sorry about the
1470 * goto, too much looking at BSD sources...
1472 if (clist == clist1 && clist2 != 0) {
1478 * If we got extactly 1 near match, use it, else return number
1490 * getarg - interpret an argument token
1501 static const char *digits = "0123456789";
1503 switch (code & ~OPT) {
1508 if (!getnetnum(str, &(argp->netnum), (char *)0)) {
1520 (void) fprintf(stderr,
1521 "***Association value `%s' invalid/undecodable\n", str);
1524 if (isneg > numassoc) {
1525 (void) fprintf(stderr,
1526 "***Association for `%s' unknown (max &%d)\n",
1530 argp->uval = assoc_cache[isneg-1].assid;
1541 cp = strchr(digits, *np);
1543 (void) fprintf(stderr,
1544 "***Illegal integer value %s\n", str);
1548 argp->uval += (cp - digits);
1549 } while (*(++np) != '\0');
1552 if ((code & ~OPT) == UINT) {
1553 (void) fprintf(stderr,
1554 "***Value %s should be unsigned\n", str);
1557 argp->ival = -argp->ival;
1567 * getnetnum - given a host name, return its net number
1568 * and (optional) full name
1579 if (decodenetnum(hname, num)) {
1580 if (fullhost != 0) {
1581 (void) sprintf(fullhost, "%lu.%lu.%lu.%lu",
1582 (u_long)((htonl(*num) >> 24) & 0xff),
1583 (u_long)((htonl(*num) >> 16) & 0xff),
1584 (u_long)((htonl(*num) >> 8) & 0xff),
1585 (u_long)(htonl(*num) & 0xff));
1588 } else if ((hp = gethostbyname(hname)) != 0) {
1589 memmove((char *)num, hp->h_addr, sizeof(u_int32));
1591 (void) strcpy(fullhost, hp->h_name);
1594 (void) fprintf(stderr, "***Can't find host %s\n", hname);
1601 * nntohost - convert network number to host name. This routine enforces
1602 * the showhostnames setting.
1610 return numtoa(netnum);
1611 if ((ntohl(netnum) & REFCLOCK_MASK) == REFCLOCK_ADDR)
1612 return refnumtoa(netnum);
1613 return numtohost(netnum);
1618 * rtdatetolfp - decode an RT-11 date into an l_fp
1628 struct calendar cal;
1630 static const char *months[12] = {
1631 "Jan", "Feb", "Mar", "Apr", "May", "Jun",
1632 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
1638 * An RT-11 date looks like:
1640 * d[d]-Mth-y[y] hh:mm:ss
1642 * (No docs, but assume 4-digit years are also legal...)
1644 * d[d]-Mth-y[y[y[y]]] hh:mm:ss
1647 if (!isdigit((int)*cp)) {
1650 * Catch special case
1658 cal.monthday = *cp++ - '0'; /* ascii dependent */
1659 if (isdigit((int)*cp)) {
1660 cal.monthday = (cal.monthday << 3) + (cal.monthday << 1);
1661 cal.monthday += *cp++ - '0';
1667 for (i = 0; i < 3; i++)
1671 for (i = 0; i < 12; i++)
1672 if (STREQ(buf, months[i]))
1681 if (!isdigit((int)*cp))
1683 cal.year = *cp++ - '0';
1684 if (isdigit((int)*cp)) {
1685 cal.year = (cal.year << 3) + (cal.year << 1);
1686 cal.year += *cp++ - '0';
1688 if (isdigit((int)*cp)) {
1689 cal.year = (cal.year << 3) + (cal.year << 1);
1690 cal.year += *cp++ - '0';
1692 if (isdigit((int)*cp)) {
1693 cal.year = (cal.year << 3) + (cal.year << 1);
1694 cal.year += *cp++ - '0';
1698 * Catch special case. If cal.year == 0 this is a zero timestamp.
1700 if (cal.year == 0) {
1705 if (*cp++ != ' ' || !isdigit((int)*cp))
1707 cal.hour = *cp++ - '0';
1708 if (isdigit((int)*cp)) {
1709 cal.hour = (cal.hour << 3) + (cal.hour << 1);
1710 cal.hour += *cp++ - '0';
1713 if (*cp++ != ':' || !isdigit((int)*cp))
1715 cal.minute = *cp++ - '0';
1716 if (isdigit((int)*cp)) {
1717 cal.minute = (cal.minute << 3) + (cal.minute << 1);
1718 cal.minute += *cp++ - '0';
1721 if (*cp++ != ':' || !isdigit((int)*cp))
1723 cal.second = *cp++ - '0';
1724 if (isdigit((int)*cp)) {
1725 cal.second = (cal.second << 3) + (cal.second << 1);
1726 cal.second += *cp++ - '0';
1730 * For RT-11, 1972 seems to be the pivot year
1737 lfp->l_ui = caltontp(&cal);
1744 * decodets - decode a timestamp into an l_fp format number, with
1745 * consideration of fuzzball formats.
1754 * If it starts with a 0x, decode as hex.
1756 if (*str == '0' && (*(str+1) == 'x' || *(str+1) == 'X'))
1757 return hextolfp(str+2, lfp);
1760 * If it starts with a '"', try it as an RT-11 date.
1763 register char *cp = str+1;
1768 while (*cp != '"' && *cp != '\0' && bp < &buf[29])
1771 return rtdatetolfp(buf, lfp);
1775 * Might still be hex. Check out the first character. Talk
1778 if ((*str >= 'A' && *str <= 'F') || (*str >= 'a' && *str <= 'f'))
1779 return hextolfp(str, lfp);
1782 * Try it as a decimal. If this fails, try as an unquoted
1783 * RT-11 date. This code should go away eventually.
1785 if (atolfp(str, lfp))
1787 return rtdatetolfp(str, lfp);
1792 * decodetime - decode a time value. It should be in milliseconds
1800 return mstolfp(str, lfp);
1805 * decodeint - decode an integer
1814 if (*(str+1) == 'x' || *(str+1) == 'X')
1815 return hextoint(str+2, (u_long *)&val);
1816 return octtoint(str, (u_long *)&val);
1818 return atoint(str, val);
1823 * decodeuint - decode an unsigned integer
1832 if (*(str + 1) == 'x' || *(str + 1) == 'X')
1833 return (hextoint(str + 2, val));
1834 return (octtoint(str, val));
1836 return (atouint(str, val));
1841 * decodearr - decode an array of time values
1850 register char *cp, *bp;
1859 while (isspace((int)*cp))
1865 while (!isspace((int)*cp) && *cp != '\0')
1869 if (!decodetime(buf, lfp))
1879 * Finally, the built in command handlers
1883 * help - tell about commands, or details of a particular command
1895 const char *cmdsort[100];
1899 static const char *spaces = " "; /* 20 spaces */
1901 if (pcmd->nargs == 0) {
1903 for (xcp = builtins; xcp->keyword != 0; xcp++) {
1904 if (*(xcp->keyword) != '?')
1905 cmdsort[n++] = xcp->keyword;
1907 for (xcp = opcmds; xcp->keyword != 0; xcp++)
1908 cmdsort[n++] = xcp->keyword;
1910 #ifdef QSORT_USES_VOID_P
1911 qsort(cmdsort, (size_t)n, sizeof(char *), helpsort);
1913 qsort((char *)cmdsort, (size_t)n, sizeof(char *), helpsort);
1917 for (i = 0; i < n; i++) {
1918 length[i] = strlen(cmdsort[i]);
1919 if (length[i] > maxlength)
1920 maxlength = length[i];
1923 numperline = 76 / maxlength;
1925 (void) fprintf(fp, "Commands available:\n");
1926 for (i = 0; i < n; i++) {
1927 if ((i % numperline) == (numperline-1)
1929 (void) fprintf(fp, "%s\n", cmdsort[i]);
1931 (void) fprintf(fp, "%s%s", cmdsort[i],
1932 spaces+20-maxlength+length[i]);
1935 cmd = pcmd->argval[0].string;
1936 n = findcmd(cmd, builtins, opcmds, &xcp);
1938 (void) fprintf(stderr,
1939 "Command `%s' is unknown\n", cmd);
1941 } else if (n >= 2) {
1942 (void) fprintf(stderr,
1943 "Command `%s' is ambiguous\n", cmd);
1946 (void) fprintf(fp, "function: %s\n", xcp->comment);
1947 printusage(xcp, fp);
1953 * helpsort - do hostname qsort comparisons
1955 #ifdef QSORT_USES_VOID_P
1962 const char **name1 = (const char **)t1;
1963 const char **name2 = (const char **)t2;
1965 return strcmp(*name1, *name2);
1975 return strcmp(*name1, *name2);
1980 * printusage - print usage information for a command
1990 (void) fprintf(fp, "usage: %s", xcp->keyword);
1991 for (i = 0; i < MAXARGS && xcp->arg[i] != NO; i++) {
1992 if (xcp->arg[i] & OPT)
1993 (void) fprintf(fp, " [ %s ]", xcp->desc[i]);
1995 (void) fprintf(fp, " %s", xcp->desc[i]);
1997 (void) fprintf(fp, "\n");
2002 * timeout - set time out time
2012 if (pcmd->nargs == 0) {
2013 val = tvout.tv_sec * 1000 + tvout.tv_usec / 1000;
2014 (void) fprintf(fp, "primary timeout %d ms\n", val);
2016 tvout.tv_sec = pcmd->argval[0].uval / 1000;
2017 tvout.tv_usec = (pcmd->argval[0].uval - (tvout.tv_sec * 1000))
2024 * auth_delay - set delay for auth requests
2035 if (pcmd->nargs == 0) {
2036 val = delay_time.l_ui * 1000 + delay_time.l_uf / 4294967;
2037 (void) fprintf(fp, "delay %lu ms\n", val);
2039 if (pcmd->argval[0].ival < 0) {
2041 val = (u_long)(-pcmd->argval[0].ival);
2044 val = (u_long)pcmd->argval[0].ival;
2047 delay_time.l_ui = val / 1000;
2049 delay_time.l_uf = val * 4294967; /* 2**32/1000 */
2058 * host - set the host we are dealing with.
2066 if (pcmd->nargs == 0) {
2068 (void) fprintf(fp, "current host is %s\n", currenthost);
2070 (void) fprintf(fp, "no current host\n");
2071 } else if (openhost(pcmd->argval[0].string)) {
2072 (void) fprintf(fp, "current host set to %s\n", currenthost);
2077 "current host remains %s\n", currenthost);
2079 (void) fprintf(fp, "still no current host\n");
2085 * poll - do one (or more) polls of the host via NTP
2094 (void) fprintf(fp, "poll not implemented yet\n");
2099 * keyid - get a keyid to use for authenticating requests
2107 if (pcmd->nargs == 0) {
2108 if (info_auth_keyid > NTP_MAXKEY)
2109 (void) fprintf(fp, "no keyid defined\n");
2111 (void) fprintf(fp, "keyid is %lu\n", (u_long)info_auth_keyid);
2113 info_auth_keyid = pcmd->argval[0].uval;
2118 * keytype - get type of key to use for authenticating requests
2126 if (pcmd->nargs == 0)
2127 fprintf(fp, "keytype is %s\n",
2128 (info_auth_keytype == KEY_TYPE_MD5) ? "MD5" : "DES");
2130 switch (*(pcmd->argval[0].string)) {
2133 info_auth_keytype = KEY_TYPE_MD5;
2138 info_auth_keytype = KEY_TYPE_DES;
2142 fprintf(fp, "keytype must be 'md5' or 'des'\n");
2149 * passwd - get an authentication key
2160 if (info_auth_keyid > NTP_MAXKEY) {
2161 info_auth_keyid = getkeyid("Keyid: ");
2162 if (info_auth_keyid > NTP_MAXKEY) {
2163 (void)fprintf(fp, "Keyid must be defined\n");
2167 pass = getpass((info_auth_keytype == KEY_TYPE_DES)
2172 (void) fprintf(fp, "Password unchanged\n");
2174 authusekey(info_auth_keyid, info_auth_keytype, (u_char *)pass);
2179 * hostnames - set the showhostnames flag
2187 if (pcmd->nargs == 0) {
2189 (void) fprintf(fp, "hostnames being shown\n");
2191 (void) fprintf(fp, "hostnames not being shown\n");
2193 if (STREQ(pcmd->argval[0].string, "yes"))
2195 else if (STREQ(pcmd->argval[0].string, "no"))
2198 (void)fprintf(stderr, "What?\n");
2205 * setdebug - set/change debugging level
2213 if (pcmd->nargs == 0) {
2214 (void) fprintf(fp, "debug level is %d\n", debug);
2216 } else if (STREQ(pcmd->argval[0].string, "no")) {
2218 } else if (STREQ(pcmd->argval[0].string, "more")) {
2220 } else if (STREQ(pcmd->argval[0].string, "less")) {
2223 (void) fprintf(fp, "What?\n");
2226 (void) fprintf(fp, "debug level set to %d\n", debug);
2231 * quit - stop this nonsense
2241 closesocket(sockfd); /* cleanliness next to godliness */
2247 * version - print the current version number
2257 (void) fprintf(fp, "%s\n", Version);
2263 * raw - set raw mode output
2273 (void) fprintf(fp, "Output set to raw\n");
2278 * cooked - set cooked mode output
2288 (void) fprintf(fp, "Output set to cooked\n");
2294 * authenticate - always authenticate requests to this host
2302 if (pcmd->nargs == 0) {
2305 "authenticated requests being sent\n");
2308 "unauthenticated requests being sent\n");
2310 if (STREQ(pcmd->argval[0].string, "yes")) {
2312 } else if (STREQ(pcmd->argval[0].string, "no")) {
2315 (void)fprintf(stderr, "What?\n");
2321 * ntpversion - choose the NTP version to use
2329 if (pcmd->nargs == 0) {
2331 "NTP version being claimed is %d\n", pktversion);
2333 if (pcmd->argval[0].uval < NTP_OLDVERSION
2334 || pcmd->argval[0].uval > NTP_VERSION) {
2335 (void) fprintf(stderr, "versions %d to %d, please\n",
2336 NTP_OLDVERSION, NTP_VERSION);
2338 pktversion = (u_char) pcmd->argval[0].uval;
2345 * warning - print a warning message
2354 (void) fprintf(stderr, "%s: ", progname);
2355 (void) fprintf(stderr, fmt, st1, st2);
2356 (void) fprintf(stderr, ": ");
2362 * error - print a message and exit
2371 warning(fmt, st1, st2);
2376 * getkeyid - prompt the user for a keyid to use
2380 const char *keyprompt
2389 if ((fi = fdopen(open("/dev/tty", 2), "r")) == NULL)
2391 if ((fi = _fdopen((int)GetStdHandle(STD_INPUT_HANDLE), "r")) == NULL)
2392 #endif /* SYS_WINNT */
2395 setbuf(fi, (char *)NULL);
2396 fprintf(stderr, "%s", keyprompt); fflush(stderr);
2397 for (p=pbuf; (c = getc(fi))!='\n' && c!=EOF;) {
2404 if (strcmp(pbuf, "0") == 0)
2407 return (u_long) atoi(pbuf);
2412 * atoascii - printable-ize possibly ascii data using the character
2413 * transformations cat -v uses.
2422 register u_char *cp;
2423 register u_char *ocp;
2432 ocp = (u_char *)outdata;
2433 for (cp = (u_char *)data; cp < (u_char *)data + length; cp++) {
2448 } else if (c == 0177) {
2454 if (ocp >= ((u_char *)outdata + length - 4))
2463 * makeascii - print possibly ascii data using the character
2464 * transformations that cat -v uses.
2473 register u_char *cp;
2476 for (cp = (u_char *)data; cp < (u_char *)data + length; cp++) {
2487 } else if (c == 0177) {
2498 * asciize - same thing as makeascii except add a newline
2507 makeascii(length, data, fp);
2513 * Some circular buffer space
2518 char circ_buf[NUMCB][CBLEN];
2522 * nextvar - find the next variable in the buffer
2534 register char *cpend;
2535 register char *npend; /* character after last */
2537 static char name[MAXVARLEN];
2538 static char value[MAXVALLEN];
2541 cpend = cp + *datalen;
2544 * Space past commas and white space
2546 while (cp < cpend && (*cp == ',' || isspace((int)*cp)))
2552 * Copy name until we hit a ',', an '=', a '\r' or a '\n'. Backspace
2553 * over any white space and terminate it.
2556 npend = &name[MAXVARLEN];
2557 while (cp < cpend && np < npend && *cp != ',' && *cp != '='
2558 && *cp != '\r' && *cp != '\n')
2561 * Check if we ran out of name space, without reaching the end or a
2562 * terminating character
2564 if (np == npend && !(cp == cpend || *cp == ',' || *cp == '=' ||
2565 *cp == '\r' || *cp == '\n'))
2567 while (isspace((int)(*(np-1))))
2573 * Check if we hit the end of the buffer or a ','. If so we are done.
2575 if (cp == cpend || *cp == ',' || *cp == '\r' || *cp == '\n') {
2579 *datalen = cpend - cp;
2580 *vvalue = (char *)0;
2585 * So far, so good. Copy out the value
2587 cp++; /* past '=' */
2588 while (cp < cpend && (isspace((int)*cp) && *cp != '\r' && *cp != '\n'))
2591 npend = &value[MAXVALLEN];
2592 while (cp < cpend && np < npend && ((*cp != ',') || quoted))
2594 quoted ^= ((*np++ = *cp++) == '"');
2598 * Check if we overran the value buffer while still in a quoted string
2599 * or without finding a comma
2601 if (np == npend && (quoted || *cp != ','))
2604 * Trim off any trailing whitespace
2606 while (np > value && isspace((int)(*(np-1))))
2611 * Return this. All done.
2616 *datalen = cpend - cp;
2623 * findvar - see if this variable is known to us
2628 struct ctl_var *varlist
2632 register struct ctl_var *vl;
2636 while (vl->fmt != EOV) {
2637 if (vl->fmt != PADDING && STREQ(np, vl->text))
2647 * printvars - print variables returned in response packet
2659 rawprint(sttype, length, data, status, fp);
2661 cookedprint(sttype, length, data, status, fp);
2666 * rawprint - do a printout of the data in raw mode
2678 register char *cpend;
2681 * Essentially print the data as is. We reformat unprintables, though.
2684 cpend = data + length;
2686 (void) fprintf(fp, "status=0x%04x,\n", status);
2688 while (cp < cpend) {
2691 * If this is a \r and the next character is a
2692 * \n, supress this, else pretty print it. Otherwise
2693 * just output the character.
2695 if (cp == (cpend-1) || *(cp+1) != '\n')
2696 makeascii(1, cp, fp);
2697 } else if (isspace((int)*cp) || isprint((int)*cp)) {
2700 makeascii(1, cp, fp);
2708 * Global data used by the cooked output routines
2710 int out_chars; /* number of characters output */
2711 int out_linecount; /* number of characters output on this line */
2715 * startoutput - get ready to do cooked output
2726 * output - output a variable=value combination
2738 lenname = strlen(name);
2739 lenvalue = strlen(value);
2741 if (out_chars != 0) {
2745 if ((out_linecount + lenname + lenvalue + 3) > MAXOUTLINE) {
2759 out_chars += lenname + 1 + lenvalue;
2760 out_linecount += lenname + 1 + lenvalue;
2765 * endoutput - terminate a block of cooked output
2778 * outputarr - output an array of values
2796 * Hack to align delay and offset values
2798 for (i = (int)strlen(name); i < 11; i++)
2801 for (i = narr; i > 0; i--) {
2804 cp = lfptoms(lfp, 2);
2819 output(fp, name, buf);
2827 register char *cb, *s;
2829 register const char *sep;
2833 s = cb = &circ_buf[nextcb][0];
2834 if (++nextcb >= NUMCB)
2837 sprintf(cb, "%02lx", val);
2844 for (i = 0; i < 11; i++) {
2846 sprintf(cb, "%s%s", sep, tstflagnames[i]);
2858 * cookedprint - output variables in cooked mode
2874 struct ctl_var *varlist;
2890 varlist = clock_var;
2893 (void) fprintf(stderr, "Unknown datatype(0x%x) in cookedprint\n", datatype);
2897 (void) fprintf(fp, "status=%04x %s,\n", status,
2898 statustoa(datatype, status));
2901 while (nextvar(&length, &data, &name, &value)) {
2902 varid = findvar(name, varlist);
2907 fmt = varlist[varid].fmt;
2910 if (!decodets(value, &lfp))
2913 output(fp, name, prettydate(&lfp));
2918 if (!decodetime(value, &lfp))
2939 if (!decodeuint(value, &uval))
2942 output(fp, name, uinttoa(uval));
2946 if (!decodeint(value, &ival))
2949 output(fp, name, inttoa(ival));
2954 if (!decodenetnum(value, &hval))
2957 output(fp, name, nntohost(hval));
2959 output(fp, name, numtoa(hval));
2967 if (decodenetnum(value, &hval))
2968 output(fp, name, nntohost(hval));
2969 else if ((int)strlen(value) <= 4)
2970 output(fp, name, value);
2976 if (!decodeuint(value, &uval) || uval > 3)
2986 output(fp, name, b);
2991 if (!decodeuint(value, &uval))
2996 (void) sprintf(b, "%03lo", uval);
2997 output(fp, name, b);
3002 if (!decodeuint(value, &uval))
3005 output(fp, name, uinttoa(uval));
3009 if (!decodearr(value, &narr, lfparr))
3012 outputarr(fp, name, narr, lfparr);
3016 if (!decodeuint(value, &uval))
3019 output(fp, name, tstflags(uval));
3023 (void) fprintf(stderr,
3024 "Internal error in cookedprint, %s=%s, fmt %d\n",
3030 if (output_raw != 0) {
3035 atoascii(400, name, bn);
3036 atoascii(400, value, bv);
3037 if (output_raw != '*') {
3039 bv[len] = output_raw;
3050 * sortassoc - sort associations in the cache into ascending order
3057 #ifdef QSORT_USES_VOID_P
3062 assoc_cache, (size_t)numassoc,
3063 sizeof(struct association), assoccmp);
3068 * assoccmp - compare two associations
3070 #ifdef QSORT_USES_VOID_P
3077 const struct association *ass1 = (const struct association *)t1;
3078 const struct association *ass2 = (const struct association *)t2;
3080 if (ass1->assid < ass2->assid)
3082 if (ass1->assid > ass2->assid)
3089 struct association *ass1,
3090 struct association *ass2
3093 if (ass1->assid < ass2->assid)
3095 if (ass1->assid > ass2->assid)
3099 #endif /* not QSORT_USES_VOID_P */