xref: /freebsd/contrib/ntp/ntpq/ntpq.c (revision 2b15cb3d0922bd70ea592f0da9b4a5b167f4d53f)
1 /*
2  * ntpq - query an NTP server using mode 6 commands
3  */
4 #include <config.h>
5 #include <stdio.h>
6 #include <ctype.h>
7 #include <signal.h>
8 #include <setjmp.h>
9 #include <sys/types.h>
10 #include <sys/time.h>
11 #ifdef HAVE_UNISTD_H
12 # include <unistd.h>
13 #endif
14 #ifdef HAVE_FCNTL_H
15 # include <fcntl.h>
16 #endif
17 #ifdef SYS_WINNT
18 # include <mswsock.h>
19 #endif
20 #include <isc/net.h>
21 #include <isc/result.h>
22 
23 #include "ntpq.h"
24 #include "ntp_stdlib.h"
25 #include "ntp_unixtime.h"
26 #include "ntp_calendar.h"
27 #include "ntp_select.h"
28 #include "ntp_assert.h"
29 #include "lib_strbuf.h"
30 #include "ntp_lineedit.h"
31 #include "ntp_debug.h"
32 #ifdef OPENSSL
33 #include "openssl/evp.h"
34 #include "openssl/objects.h"
35 #endif
36 #include <ssl_applink.c>
37 
38 #include "ntp_libopts.h"
39 #include "ntpq-opts.h"
40 
41 
42 #ifdef SYS_VXWORKS		/* vxWorks needs mode flag -casey*/
43 # define open(name, flags)   open(name, flags, 0777)
44 # define SERVER_PORT_NUM     123
45 #endif
46 
47 /* we use COMMAND as an autogen keyword */
48 #ifdef COMMAND
49 # undef COMMAND
50 #endif
51 
52 /*
53  * Because we potentially understand a lot of commands we will run
54  * interactive if connected to a terminal.
55  */
56 int interactive = 0;		/* set to 1 when we should prompt */
57 const char *prompt = "ntpq> ";	/* prompt to ask him about */
58 
59 /*
60  * use old readvars behavior?  --old-rv processing in ntpq resets
61  * this value based on the presence or absence of --old-rv.  It is
62  * initialized to 1 here to maintain backward compatibility with
63  * libntpq clients such as ntpsnmpd, which are free to reset it as
64  * desired.
65  */
66 int	old_rv = 1;
67 
68 
69 /*
70  * for get_systime()
71  */
72 s_char	sys_precision;		/* local clock precision (log2 s) */
73 
74 /*
75  * Keyid used for authenticated requests.  Obtained on the fly.
76  */
77 u_long info_auth_keyid = 0;
78 
79 static	int	info_auth_keytype = NID_md5;	/* MD5 */
80 static	size_t	info_auth_hashlen = 16;		/* MD5 */
81 u_long	current_time;		/* needed by authkeys; not used */
82 
83 /*
84  * Flag which indicates we should always send authenticated requests
85  */
86 int always_auth = 0;
87 
88 /*
89  * Flag which indicates raw mode output.
90  */
91 int rawmode = 0;
92 
93 /*
94  * Packet version number we use
95  */
96 u_char pktversion = NTP_OLDVERSION + 1;
97 
98 /*
99  * Don't jump if no set jmp.
100  */
101 volatile int jump = 0;
102 
103 /*
104  * Format values
105  */
106 #define	PADDING	0
107 #define	HA	1	/* host address */
108 #define	NA	2	/* network address */
109 #define	LP	3	/* leap (print in binary) */
110 #define	RF	4	/* refid (sometimes string, sometimes not) */
111 #define	AR	5	/* array of times */
112 #define FX	6	/* test flags */
113 #define TS	7	/* l_fp timestamp in hex */
114 #define	OC	8	/* integer, print in octal */
115 #define	EOV	255	/* end of table */
116 
117 /*
118  * For the most part ntpq simply displays what ntpd provides in the
119  * mostly plain-text mode 6 responses.  A few variable names are by
120  * default "cooked" to provide more human-friendly output.
121  */
122 const var_format cookedvars[] = {
123 	{ "leap",		LP },
124 	{ "reach",		OC },
125 	{ "refid",		RF },
126 	{ "reftime",		TS },
127 	{ "clock",		TS },
128 	{ "org",		TS },
129 	{ "rec",		TS },
130 	{ "xmt",		TS },
131 	{ "flash",		FX },
132 	{ "srcadr",		HA },
133 	{ "peeradr",		HA },	/* compat with others */
134 	{ "dstadr",		NA },
135 	{ "filtdelay",		AR },
136 	{ "filtoffset",		AR },
137 	{ "filtdisp",		AR },
138 	{ "filterror",		AR },	/* compat with others */
139 };
140 
141 
142 
143 /*
144  * flasher bits
145  */
146 static const char *tstflagnames[] = {
147 	"pkt_dup",		/* TEST1 */
148 	"pkt_bogus",		/* TEST2 */
149 	"pkt_unsync",		/* TEST3 */
150 	"pkt_denied",		/* TEST4 */
151 	"pkt_auth",		/* TEST5 */
152 	"pkt_stratum",		/* TEST6 */
153 	"pkt_header",		/* TEST7 */
154 	"pkt_autokey",		/* TEST8 */
155 	"pkt_crypto",		/* TEST9 */
156 	"peer_stratum",		/* TEST10 */
157 	"peer_dist",		/* TEST11 */
158 	"peer_loop",		/* TEST12 */
159 	"peer_unreach"		/* TEST13 */
160 };
161 
162 
163 int		ntpqmain	(int,	char **);
164 /*
165  * Built in command handler declarations
166  */
167 static	int	openhost	(const char *, int);
168 static	void	dump_hex_printable(const void *, size_t);
169 static	int	sendpkt		(void *, size_t);
170 static	int	getresponse	(int, int, u_short *, int *, const char **, int);
171 static	int	sendrequest	(int, associd_t, int, int, const char *);
172 static	char *	tstflags	(u_long);
173 #ifndef BUILD_AS_LIB
174 static	void	getcmds		(void);
175 #ifndef SYS_WINNT
176 static	RETSIGTYPE abortcmd	(int);
177 #endif	/* SYS_WINNT */
178 static	void	docmd		(const char *);
179 static	void	tokenize	(const char *, char **, int *);
180 static	int	getarg		(const char *, int, arg_v *);
181 #endif	/* BUILD_AS_LIB */
182 static	int	findcmd		(const char *, struct xcmd *,
183 				 struct xcmd *, struct xcmd **);
184 static	int	rtdatetolfp	(char *, l_fp *);
185 static	int	decodearr	(char *, int *, l_fp *);
186 static	void	help		(struct parse *, FILE *);
187 static	int	helpsort	(const void *, const void *);
188 static	void	printusage	(struct xcmd *, FILE *);
189 static	void	timeout		(struct parse *, FILE *);
190 static	void	auth_delay	(struct parse *, FILE *);
191 static	void	host		(struct parse *, FILE *);
192 static	void	ntp_poll	(struct parse *, FILE *);
193 static	void	keyid		(struct parse *, FILE *);
194 static	void	keytype		(struct parse *, FILE *);
195 static	void	passwd		(struct parse *, FILE *);
196 static	void	hostnames	(struct parse *, FILE *);
197 static	void	setdebug	(struct parse *, FILE *);
198 static	void	quit		(struct parse *, FILE *);
199 static	void	version		(struct parse *, FILE *);
200 static	void	raw		(struct parse *, FILE *);
201 static	void	cooked		(struct parse *, FILE *);
202 static	void	authenticate	(struct parse *, FILE *);
203 static	void	ntpversion	(struct parse *, FILE *);
204 static	void	warning		(const char *, ...)
205     __attribute__((__format__(__printf__, 1, 2)));
206 static	void	error		(const char *, ...)
207     __attribute__((__format__(__printf__, 1, 2)));
208 static	u_long	getkeyid	(const char *);
209 static	void	atoascii	(const char *, size_t, char *, size_t);
210 static	void	cookedprint	(int, int, const char *, int, int, FILE *);
211 static	void	rawprint	(int, int, const char *, int, int, FILE *);
212 static	void	startoutput	(void);
213 static	void	output		(FILE *, const char *, const char *);
214 static	void	endoutput	(FILE *);
215 static	void	outputarr	(FILE *, char *, int, l_fp *);
216 static	int	assoccmp	(const void *, const void *);
217 	u_short	varfmt		(const char *);
218 
219 void	ntpq_custom_opt_handler	(tOptions *, tOptDesc *);
220 
221 
222 /*
223  * Built-in commands we understand
224  */
225 struct xcmd builtins[] = {
226 	{ "?",		help,		{  OPT|NTP_STR, NO, NO, NO },
227 	  { "command", "", "", "" },
228 	  "tell the use and syntax of commands" },
229 	{ "help",	help,		{  OPT|NTP_STR, NO, NO, NO },
230 	  { "command", "", "", "" },
231 	  "tell the use and syntax of commands" },
232 	{ "timeout",	timeout,	{ OPT|NTP_UINT, NO, NO, NO },
233 	  { "msec", "", "", "" },
234 	  "set the primary receive time out" },
235 	{ "delay",	auth_delay,	{ OPT|NTP_INT, NO, NO, NO },
236 	  { "msec", "", "", "" },
237 	  "set the delay added to encryption time stamps" },
238 	{ "host",	host,		{ OPT|NTP_STR, OPT|NTP_STR, NO, NO },
239 	  { "-4|-6", "hostname", "", "" },
240 	  "specify the host whose NTP server we talk to" },
241 	{ "poll",	ntp_poll,	{ OPT|NTP_UINT, OPT|NTP_STR, NO, NO },
242 	  { "n", "verbose", "", "" },
243 	  "poll an NTP server in client mode `n' times" },
244 	{ "passwd",	passwd,		{ OPT|NTP_STR, NO, NO, NO },
245 	  { "", "", "", "" },
246 	  "specify a password to use for authenticated requests"},
247 	{ "hostnames",	hostnames,	{ OPT|NTP_STR, NO, NO, NO },
248 	  { "yes|no", "", "", "" },
249 	  "specify whether hostnames or net numbers are printed"},
250 	{ "debug",	setdebug,	{ OPT|NTP_STR, NO, NO, NO },
251 	  { "no|more|less", "", "", "" },
252 	  "set/change debugging level" },
253 	{ "quit",	quit,		{ NO, NO, NO, NO },
254 	  { "", "", "", "" },
255 	  "exit ntpq" },
256 	{ "exit",	quit,		{ NO, NO, NO, NO },
257 	  { "", "", "", "" },
258 	  "exit ntpq" },
259 	{ "keyid",	keyid,		{ OPT|NTP_UINT, NO, NO, NO },
260 	  { "key#", "", "", "" },
261 	  "set keyid to use for authenticated requests" },
262 	{ "version",	version,	{ NO, NO, NO, NO },
263 	  { "", "", "", "" },
264 	  "print version number" },
265 	{ "raw",	raw,		{ NO, NO, NO, NO },
266 	  { "", "", "", "" },
267 	  "do raw mode variable output" },
268 	{ "cooked",	cooked,		{ NO, NO, NO, NO },
269 	  { "", "", "", "" },
270 	  "do cooked mode variable output" },
271 	{ "authenticate", authenticate,	{ OPT|NTP_STR, NO, NO, NO },
272 	  { "yes|no", "", "", "" },
273 	  "always authenticate requests to this server" },
274 	{ "ntpversion",	ntpversion,	{ OPT|NTP_UINT, NO, NO, NO },
275 	  { "version number", "", "", "" },
276 	  "set the NTP version number to use for requests" },
277 	{ "keytype",	keytype,	{ OPT|NTP_STR, NO, NO, NO },
278 	  { "key type (md5|des)", "", "", "" },
279 	  "set key type to use for authenticated requests (des|md5)" },
280 	{ 0,		0,		{ NO, NO, NO, NO },
281 	  { "", "", "", "" }, "" }
282 };
283 
284 
285 /*
286  * Default values we use.
287  */
288 #define	DEFHOST		"localhost"	/* default host name */
289 #define	DEFTIMEOUT	5		/* wait 5 seconds for 1st pkt */
290 #define	DEFSTIMEOUT	3		/* and 3 more for each additional */
291 /*
292  * Requests are automatically retried once, so total timeout with no
293  * response is a bit over 2 * DEFTIMEOUT, or 10 seconds.  At the other
294  * extreme, a request eliciting 32 packets of responses each for some
295  * reason nearly DEFSTIMEOUT seconds after the prior in that series,
296  * with a single packet dropped, would take around 32 * DEFSTIMEOUT, or
297  * 93 seconds to fail each of two times, or 186 seconds.
298  * Some commands involve a series of requests, such as "peers" and
299  * "mrulist", so the cumulative timeouts are even longer for those.
300  */
301 #define	DEFDELAY	0x51EB852	/* 20 milliseconds, l_fp fraction */
302 #define	LENHOSTNAME	256		/* host name is 256 characters long */
303 #define	MAXCMDS		100		/* maximum commands on cmd line */
304 #define	MAXHOSTS	200		/* maximum hosts on cmd line */
305 #define	MAXLINE		512		/* maximum line length */
306 #define	MAXTOKENS	(1+MAXARGS+2)	/* maximum number of usable tokens */
307 #define	MAXVARLEN	256		/* maximum length of a variable name */
308 #define	MAXVALLEN	2048		/* maximum length of a variable value */
309 #define	MAXOUTLINE	72		/* maximum length of an output line */
310 #define SCREENWIDTH	76		/* nominal screen width in columns */
311 
312 /*
313  * Some variables used and manipulated locally
314  */
315 struct sock_timeval tvout = { DEFTIMEOUT, 0 };	/* time out for reads */
316 struct sock_timeval tvsout = { DEFSTIMEOUT, 0 };/* secondary time out */
317 l_fp delay_time;				/* delay time */
318 char currenthost[LENHOSTNAME];			/* current host name */
319 int currenthostisnum;				/* is prior text from IP? */
320 struct sockaddr_in hostaddr;			/* host address */
321 int showhostnames = 1;				/* show host names by default */
322 int wideremote = 0;				/* show wide remote names? */
323 
324 int ai_fam_templ;				/* address family */
325 int ai_fam_default;				/* default address family */
326 SOCKET sockfd;					/* fd socket is opened on */
327 int havehost = 0;				/* set to 1 when host open */
328 int s_port = 0;
329 struct servent *server_entry = NULL;		/* server entry for ntp */
330 
331 
332 /*
333  * Sequence number used for requests.  It is incremented before
334  * it is used.
335  */
336 u_short sequence;
337 
338 /*
339  * Holds data returned from queries.  Declare buffer long to be sure of
340  * alignment.
341  */
342 #define	DATASIZE	(MAXFRAGS*480)	/* maximum amount of data */
343 long pktdata[DATASIZE/sizeof(long)];
344 
345 /*
346  * assoc_cache[] is a dynamic array which allows references to
347  * associations using &1 ... &N for n associations, avoiding manual
348  * lookup of the current association IDs for a given ntpd.  It also
349  * caches the status word for each association, retrieved incidentally.
350  */
351 struct association *	assoc_cache;
352 u_int assoc_cache_slots;/* count of allocated array entries */
353 u_int numassoc;		/* number of cached associations */
354 
355 /*
356  * For commands typed on the command line (with the -c option)
357  */
358 int numcmds = 0;
359 const char *ccmds[MAXCMDS];
360 #define	ADDCMD(cp)	if (numcmds < MAXCMDS) ccmds[numcmds++] = (cp)
361 
362 /*
363  * When multiple hosts are specified.
364  */
365 
366 u_int numhosts;
367 
368 chost chosts[MAXHOSTS];
369 #define	ADDHOST(cp)						\
370 	do {							\
371 		if (numhosts < MAXHOSTS) {			\
372 			chosts[numhosts].name = (cp);		\
373 			chosts[numhosts].fam = ai_fam_templ;	\
374 			numhosts++;				\
375 		}						\
376 	} while (0)
377 
378 /*
379  * Macro definitions we use
380  */
381 #define	ISSPACE(c)	((c) == ' ' || (c) == '\t')
382 #define	ISEOL(c)	((c) == '\n' || (c) == '\r' || (c) == '\0')
383 #define	STREQ(a, b)	(*(a) == *(b) && strcmp((a), (b)) == 0)
384 
385 /*
386  * Jump buffer for longjumping back to the command level
387  */
388 jmp_buf interrupt_buf;
389 
390 /*
391  * Points at file being currently printed into
392  */
393 FILE *current_output;
394 
395 /*
396  * Command table imported from ntpdc_ops.c
397  */
398 extern struct xcmd opcmds[];
399 
400 char *progname;
401 
402 #ifdef NO_MAIN_ALLOWED
403 #ifndef BUILD_AS_LIB
404 CALL(ntpq,"ntpq",ntpqmain);
405 
406 void clear_globals(void)
407 {
408 	extern int ntp_optind;
409 	showhostnames = 0;	/* don'tshow host names by default */
410 	ntp_optind = 0;
411 	server_entry = NULL;	/* server entry for ntp */
412 	havehost = 0;		/* set to 1 when host open */
413 	numassoc = 0;		/* number of cached associations */
414 	numcmds = 0;
415 	numhosts = 0;
416 }
417 #endif /* !BUILD_AS_LIB */
418 #endif /* NO_MAIN_ALLOWED */
419 
420 /*
421  * main - parse arguments and handle options
422  */
423 #ifndef NO_MAIN_ALLOWED
424 int
425 main(
426 	int argc,
427 	char *argv[]
428 	)
429 {
430 	return ntpqmain(argc, argv);
431 }
432 #endif
433 
434 #ifndef BUILD_AS_LIB
435 int
436 ntpqmain(
437 	int argc,
438 	char *argv[]
439 	)
440 {
441 	u_int ihost;
442 	int icmd;
443 
444 
445 #ifdef SYS_VXWORKS
446 	clear_globals();
447 	taskPrioritySet(taskIdSelf(), 100 );
448 #endif
449 
450 	delay_time.l_ui = 0;
451 	delay_time.l_uf = DEFDELAY;
452 
453 	init_lib();	/* sets up ipv4_works, ipv6_works */
454 	ssl_applink();
455 	init_auth();
456 
457 	/* Check to see if we have IPv6. Otherwise default to IPv4 */
458 	if (!ipv6_works)
459 		ai_fam_default = AF_INET;
460 
461 	progname = argv[0];
462 
463 	{
464 		int optct = ntpOptionProcess(&ntpqOptions, argc, argv);
465 		argc -= optct;
466 		argv += optct;
467 	}
468 
469 	/*
470 	 * Process options other than -c and -p, which are specially
471 	 * handled by ntpq_custom_opt_handler().
472 	 */
473 
474 	debug = OPT_VALUE_SET_DEBUG_LEVEL;
475 
476 	if (HAVE_OPT(IPV4))
477 		ai_fam_templ = AF_INET;
478 	else if (HAVE_OPT(IPV6))
479 		ai_fam_templ = AF_INET6;
480 	else
481 		ai_fam_templ = ai_fam_default;
482 
483 	if (HAVE_OPT(INTERACTIVE))
484 		interactive = 1;
485 
486 	if (HAVE_OPT(NUMERIC))
487 		showhostnames = 0;
488 
489 	if (HAVE_OPT(WIDE))
490 		wideremote = 1;
491 
492 	old_rv = HAVE_OPT(OLD_RV);
493 
494 	if (0 == argc) {
495 		ADDHOST(DEFHOST);
496 	} else {
497 		for (ihost = 0; ihost < (u_int)argc; ihost++) {
498 			if ('-' == *argv[ihost]) {
499 				//
500 				// If I really cared I'd also check:
501 				// 0 == argv[ihost][2]
502 				//
503 				// and there are other cases as well...
504 				//
505 				if ('4' == argv[ihost][1]) {
506 					ai_fam_templ = AF_INET;
507 					continue;
508 				} else if ('6' == argv[ihost][1]) {
509 					ai_fam_templ = AF_INET6;
510 					continue;
511 				} else {
512 					// XXX Throw a usage error
513 				}
514 			}
515 			ADDHOST(argv[ihost]);
516 		}
517 	}
518 
519 	if (numcmds == 0 && interactive == 0
520 	    && isatty(fileno(stdin)) && isatty(fileno(stderr))) {
521 		interactive = 1;
522 	}
523 
524 #ifndef SYS_WINNT /* Under NT cannot handle SIGINT, WIN32 spawns a handler */
525 	if (interactive)
526 	    (void) signal_no_reset(SIGINT, abortcmd);
527 #endif /* SYS_WINNT */
528 
529 	if (numcmds == 0) {
530 		(void) openhost(chosts[0].name, chosts[0].fam);
531 		getcmds();
532 	} else {
533 		for (ihost = 0; ihost < numhosts; ihost++) {
534 			if (openhost(chosts[ihost].name, chosts[ihost].fam))
535 				for (icmd = 0; icmd < numcmds; icmd++)
536 					docmd(ccmds[icmd]);
537 		}
538 	}
539 #ifdef SYS_WINNT
540 	WSACleanup();
541 #endif /* SYS_WINNT */
542 	return 0;
543 }
544 #endif /* !BUILD_AS_LIB */
545 
546 /*
547  * openhost - open a socket to a host
548  */
549 static	int
550 openhost(
551 	const char *hname,
552 	int	    fam
553 	)
554 {
555 	const char svc[] = "ntp";
556 	char temphost[LENHOSTNAME];
557 	int a_info, i;
558 	struct addrinfo hints, *ai;
559 	sockaddr_u addr;
560 	size_t octets;
561 	register const char *cp;
562 	char name[LENHOSTNAME];
563 
564 	/*
565 	 * We need to get by the [] if they were entered
566 	 */
567 
568 	cp = hname;
569 
570 	if (*cp == '[') {
571 		cp++;
572 		for (i = 0; *cp && *cp != ']'; cp++, i++)
573 			name[i] = *cp;
574 		if (*cp == ']') {
575 			name[i] = '\0';
576 			hname = name;
577 		} else {
578 			return 0;
579 		}
580 	}
581 
582 	/*
583 	 * First try to resolve it as an ip address and if that fails,
584 	 * do a fullblown (dns) lookup. That way we only use the dns
585 	 * when it is needed and work around some implementations that
586 	 * will return an "IPv4-mapped IPv6 address" address if you
587 	 * give it an IPv4 address to lookup.
588 	 */
589 	ZERO(hints);
590 	hints.ai_family = fam;
591 	hints.ai_protocol = IPPROTO_UDP;
592 	hints.ai_socktype = SOCK_DGRAM;
593 	hints.ai_flags = Z_AI_NUMERICHOST;
594 	ai = NULL;
595 
596 	a_info = getaddrinfo(hname, svc, &hints, &ai);
597 	if (a_info == EAI_NONAME
598 #ifdef EAI_NODATA
599 	    || a_info == EAI_NODATA
600 #endif
601 	   ) {
602 		hints.ai_flags = AI_CANONNAME;
603 #ifdef AI_ADDRCONFIG
604 		hints.ai_flags |= AI_ADDRCONFIG;
605 #endif
606 		a_info = getaddrinfo(hname, svc, &hints, &ai);
607 	}
608 #ifdef AI_ADDRCONFIG
609 	/* Some older implementations don't like AI_ADDRCONFIG. */
610 	if (a_info == EAI_BADFLAGS) {
611 		hints.ai_flags &= ~AI_ADDRCONFIG;
612 		a_info = getaddrinfo(hname, svc, &hints, &ai);
613 	}
614 #endif
615 	if (a_info != 0) {
616 		fprintf(stderr, "%s\n", gai_strerror(a_info));
617 		return 0;
618 	}
619 
620 	INSIST(ai != NULL);
621 	ZERO(addr);
622 	octets = min(sizeof(addr), ai->ai_addrlen);
623 	memcpy(&addr, ai->ai_addr, octets);
624 
625 	if (ai->ai_canonname == NULL) {
626 		strlcpy(temphost, stoa(&addr), sizeof(temphost));
627 		currenthostisnum = TRUE;
628 	} else {
629 		strlcpy(temphost, ai->ai_canonname, sizeof(temphost));
630 		currenthostisnum = FALSE;
631 	}
632 
633 	if (debug > 2)
634 		printf("Opening host %s (%s)\n",
635 			temphost,
636 			(ai->ai_family == AF_INET)
637 			? "AF_INET"
638 			: (ai->ai_family == AF_INET6)
639 			  ? "AF_INET6"
640 			  : "AF-???"
641 			);
642 
643 	if (havehost == 1) {
644 		if (debug > 2)
645 			printf("Closing old host %s\n", currenthost);
646 		closesocket(sockfd);
647 		havehost = 0;
648 	}
649 	strlcpy(currenthost, temphost, sizeof(currenthost));
650 
651 	/* port maps to the same location in both families */
652 	s_port = NSRCPORT(&addr);
653 #ifdef SYS_VXWORKS
654 	((struct sockaddr_in6 *)&hostaddr)->sin6_port = htons(SERVER_PORT_NUM);
655 	if (ai->ai_family == AF_INET)
656 		*(struct sockaddr_in *)&hostaddr=
657 			*((struct sockaddr_in *)ai->ai_addr);
658 	else
659 		*(struct sockaddr_in6 *)&hostaddr=
660 			*((struct sockaddr_in6 *)ai->ai_addr);
661 #endif /* SYS_VXWORKS */
662 
663 #ifdef SYS_WINNT
664 	{
665 		int optionValue = SO_SYNCHRONOUS_NONALERT;
666 		int err;
667 
668 		err = setsockopt(INVALID_SOCKET, SOL_SOCKET, SO_OPENTYPE,
669 				 (char *)&optionValue, sizeof(optionValue));
670 		if (err) {
671 			mfprintf(stderr,
672 				 "setsockopt(SO_SYNCHRONOUS_NONALERT)"
673 				 " error: %m\n");
674 			freeaddrinfo(ai);
675 			exit(1);
676 		}
677 	}
678 #endif /* SYS_WINNT */
679 
680 	sockfd = socket(ai->ai_family, ai->ai_socktype,
681 			ai->ai_protocol);
682 	if (sockfd == INVALID_SOCKET) {
683 		error("socket");
684 		freeaddrinfo(ai);
685 		return 0;
686 	}
687 
688 
689 #ifdef NEED_RCVBUF_SLOP
690 # ifdef SO_RCVBUF
691 	{ int rbufsize = DATASIZE + 2048;	/* 2K for slop */
692 	if (setsockopt(sockfd, SOL_SOCKET, SO_RCVBUF,
693 		       &rbufsize, sizeof(int)) == -1)
694 		error("setsockopt");
695 	}
696 # endif
697 #endif
698 
699 	if
700 #ifdef SYS_VXWORKS
701 	   (connect(sockfd, (struct sockaddr *)&hostaddr,
702 		    sizeof(hostaddr)) == -1)
703 #else
704 	   (connect(sockfd, (struct sockaddr *)ai->ai_addr,
705 		    ai->ai_addrlen) == -1)
706 #endif /* SYS_VXWORKS */
707 	    {
708 		error("connect");
709 		freeaddrinfo(ai);
710 		return 0;
711 	}
712 	freeaddrinfo(ai);
713 	havehost = 1;
714 	numassoc = 0;
715 
716 	return 1;
717 }
718 
719 
720 static void
721 dump_hex_printable(
722 	const void *	data,
723 	size_t		len
724 	)
725 {
726 	const char *	cdata;
727 	const char *	rowstart;
728 	size_t		idx;
729 	size_t		rowlen;
730 	u_char		uch;
731 
732 	cdata = data;
733 	while (len > 0) {
734 		rowstart = cdata;
735 		rowlen = min(16, len);
736 		for (idx = 0; idx < rowlen; idx++) {
737 			uch = *(cdata++);
738 			printf("%02x ", uch);
739 		}
740 		for ( ; idx < 16 ; idx++)
741 			printf("   ");
742 		cdata = rowstart;
743 		for (idx = 0; idx < rowlen; idx++) {
744 			uch = *(cdata++);
745 			printf("%c", (isprint(uch))
746 					 ? uch
747 					 : '.');
748 		}
749 		printf("\n");
750 		len -= rowlen;
751 	}
752 }
753 
754 
755 /* XXX ELIMINATE sendpkt similar in ntpq.c, ntpdc.c, ntp_io.c, ntptrace.c */
756 /*
757  * sendpkt - send a packet to the remote host
758  */
759 static int
760 sendpkt(
761 	void *	xdata,
762 	size_t	xdatalen
763 	)
764 {
765 	if (debug >= 3)
766 		printf("Sending %zu octets\n", xdatalen);
767 
768 	if (send(sockfd, xdata, (size_t)xdatalen, 0) == -1) {
769 		warning("write to %s failed", currenthost);
770 		return -1;
771 	}
772 
773 	if (debug >= 4) {
774 		printf("Request packet:\n");
775 		dump_hex_printable(xdata, xdatalen);
776 	}
777 	return 0;
778 }
779 
780 /*
781  * getresponse - get a (series of) response packet(s) and return the data
782  */
783 static int
784 getresponse(
785 	int opcode,
786 	int associd,
787 	u_short *rstatus,
788 	int *rsize,
789 	const char **rdata,
790 	int timeo
791 	)
792 {
793 	struct ntp_control rpkt;
794 	struct sock_timeval tvo;
795 	u_short offsets[MAXFRAGS+1];
796 	u_short counts[MAXFRAGS+1];
797 	u_short offset;
798 	u_short count;
799 	size_t numfrags;
800 	size_t f;
801 	size_t ff;
802 	int seenlastfrag;
803 	int shouldbesize;
804 	fd_set fds;
805 	int n;
806 	int errcode;
807 
808 	/*
809 	 * This is pretty tricky.  We may get between 1 and MAXFRAG packets
810 	 * back in response to the request.  We peel the data out of
811 	 * each packet and collect it in one long block.  When the last
812 	 * packet in the sequence is received we'll know how much data we
813 	 * should have had.  Note we use one long time out, should reconsider.
814 	 */
815 	*rsize = 0;
816 	if (rstatus)
817 		*rstatus = 0;
818 	*rdata = (char *)pktdata;
819 
820 	numfrags = 0;
821 	seenlastfrag = 0;
822 
823 	FD_ZERO(&fds);
824 
825 	/*
826 	 * Loop until we have an error or a complete response.  Nearly all
827 	 * code paths to loop again use continue.
828 	 */
829 	for (;;) {
830 
831 		if (numfrags == 0)
832 			tvo = tvout;
833 		else
834 			tvo = tvsout;
835 
836 		FD_SET(sockfd, &fds);
837 		n = select(sockfd + 1, &fds, NULL, NULL, &tvo);
838 
839 		if (n == -1) {
840 			warning("select fails");
841 			return -1;
842 		}
843 		if (n == 0) {
844 			/*
845 			 * Timed out.  Return what we have
846 			 */
847 			if (numfrags == 0) {
848 				if (timeo)
849 					fprintf(stderr,
850 						"%s: timed out, nothing received\n",
851 						currenthost);
852 				return ERR_TIMEOUT;
853 			}
854 			if (timeo)
855 				fprintf(stderr,
856 					"%s: timed out with incomplete data\n",
857 					currenthost);
858 			if (debug) {
859 				fprintf(stderr,
860 					"ERR_INCOMPLETE: Received fragments:\n");
861 				for (f = 0; f < numfrags; f++)
862 					fprintf(stderr,
863 						"%2u: %5d %5d\t%3d octets\n",
864 						(u_int)f, offsets[f],
865 						offsets[f] +
866 						counts[f],
867 						counts[f]);
868 				fprintf(stderr,
869 					"last fragment %sreceived\n",
870 					(seenlastfrag)
871 					    ? ""
872 					    : "not ");
873 			}
874 			return ERR_INCOMPLETE;
875 		}
876 
877 		n = recv(sockfd, (char *)&rpkt, sizeof(rpkt), 0);
878 		if (n == -1) {
879 			warning("read");
880 			return -1;
881 		}
882 
883 		if (debug >= 4) {
884 			printf("Response packet:\n");
885 			dump_hex_printable(&rpkt, n);
886 		}
887 
888 		/*
889 		 * Check for format errors.  Bug proofing.
890 		 */
891 		if (n < (int)CTL_HEADER_LEN) {
892 			if (debug)
893 				printf("Short (%d byte) packet received\n", n);
894 			continue;
895 		}
896 		if (PKT_VERSION(rpkt.li_vn_mode) > NTP_VERSION
897 		    || PKT_VERSION(rpkt.li_vn_mode) < NTP_OLDVERSION) {
898 			if (debug)
899 				printf("Packet received with version %d\n",
900 				       PKT_VERSION(rpkt.li_vn_mode));
901 			continue;
902 		}
903 		if (PKT_MODE(rpkt.li_vn_mode) != MODE_CONTROL) {
904 			if (debug)
905 				printf("Packet received with mode %d\n",
906 				       PKT_MODE(rpkt.li_vn_mode));
907 			continue;
908 		}
909 		if (!CTL_ISRESPONSE(rpkt.r_m_e_op)) {
910 			if (debug)
911 				printf("Received request packet, wanted response\n");
912 			continue;
913 		}
914 
915 		/*
916 		 * Check opcode and sequence number for a match.
917 		 * Could be old data getting to us.
918 		 */
919 		if (ntohs(rpkt.sequence) != sequence) {
920 			if (debug)
921 				printf("Received sequnce number %d, wanted %d\n",
922 				       ntohs(rpkt.sequence), sequence);
923 			continue;
924 		}
925 		if (CTL_OP(rpkt.r_m_e_op) != opcode) {
926 			if (debug)
927 			    printf(
928 				    "Received opcode %d, wanted %d (sequence number okay)\n",
929 				    CTL_OP(rpkt.r_m_e_op), opcode);
930 			continue;
931 		}
932 
933 		/*
934 		 * Check the error code.  If non-zero, return it.
935 		 */
936 		if (CTL_ISERROR(rpkt.r_m_e_op)) {
937 			errcode = (ntohs(rpkt.status) >> 8) & 0xff;
938 			if (CTL_ISMORE(rpkt.r_m_e_op))
939 				TRACE(1, ("Error code %d received on not-final packet\n",
940 					  errcode));
941 			if (errcode == CERR_UNSPEC)
942 				return ERR_UNSPEC;
943 			return errcode;
944 		}
945 
946 		/*
947 		 * Check the association ID to make sure it matches what
948 		 * we sent.
949 		 */
950 		if (ntohs(rpkt.associd) != associd) {
951 			TRACE(1, ("Association ID %d doesn't match expected %d\n",
952 				  ntohs(rpkt.associd), associd));
953 			/*
954 			 * Hack for silly fuzzballs which, at the time of writing,
955 			 * return an assID of sys.peer when queried for system variables.
956 			 */
957 #ifdef notdef
958 			continue;
959 #endif
960 		}
961 
962 		/*
963 		 * Collect offset and count.  Make sure they make sense.
964 		 */
965 		offset = ntohs(rpkt.offset);
966 		count = ntohs(rpkt.count);
967 
968 		/*
969 		 * validate received payload size is padded to next 32-bit
970 		 * boundary and no smaller than claimed by rpkt.count
971 		 */
972 		if (n & 0x3) {
973 			TRACE(1, ("Response packet not padded, size = %d\n",
974 				  n));
975 			continue;
976 		}
977 
978 		shouldbesize = (CTL_HEADER_LEN + count + 3) & ~3;
979 
980 		if (n < shouldbesize) {
981 			printf("Response packet claims %u octets payload, above %ld received\n",
982 			       count, (long)n - CTL_HEADER_LEN);
983 			return ERR_INCOMPLETE;
984 		}
985 
986 		if (debug >= 3 && shouldbesize > n) {
987 			u_int32 key;
988 			u_int32 *lpkt;
989 			int maclen;
990 
991 			/*
992 			 * Usually we ignore authentication, but for debugging purposes
993 			 * we watch it here.
994 			 */
995 			/* round to 8 octet boundary */
996 			shouldbesize = (shouldbesize + 7) & ~7;
997 
998 			maclen = n - shouldbesize;
999 			if (maclen >= (int)MIN_MAC_LEN) {
1000 				printf(
1001 					"Packet shows signs of authentication (total %d, data %d, mac %d)\n",
1002 					n, shouldbesize, maclen);
1003 				lpkt = (u_int32 *)&rpkt;
1004 				printf("%08lx %08lx %08lx %08lx %08lx %08lx\n",
1005 				       (u_long)ntohl(lpkt[(n - maclen)/sizeof(u_int32) - 3]),
1006 				       (u_long)ntohl(lpkt[(n - maclen)/sizeof(u_int32) - 2]),
1007 				       (u_long)ntohl(lpkt[(n - maclen)/sizeof(u_int32) - 1]),
1008 				       (u_long)ntohl(lpkt[(n - maclen)/sizeof(u_int32)]),
1009 				       (u_long)ntohl(lpkt[(n - maclen)/sizeof(u_int32) + 1]),
1010 				       (u_long)ntohl(lpkt[(n - maclen)/sizeof(u_int32) + 2]));
1011 				key = ntohl(lpkt[(n - maclen) / sizeof(u_int32)]);
1012 				printf("Authenticated with keyid %lu\n", (u_long)key);
1013 				if (key != 0 && key != info_auth_keyid) {
1014 					printf("We don't know that key\n");
1015 				} else {
1016 					if (authdecrypt(key, (u_int32 *)&rpkt,
1017 					    n - maclen, maclen)) {
1018 						printf("Auth okay!\n");
1019 					} else {
1020 						printf("Auth failed!\n");
1021 					}
1022 				}
1023 			}
1024 		}
1025 
1026 		TRACE(2, ("Got packet, size = %d\n", n));
1027 		if (count > (n - CTL_HEADER_LEN)) {
1028 			TRACE(1, ("Received count of %u octets, data in packet is %ld\n",
1029 				  count, (long)n - CTL_HEADER_LEN));
1030 			continue;
1031 		}
1032 		if (count == 0 && CTL_ISMORE(rpkt.r_m_e_op)) {
1033 			TRACE(1, ("Received count of 0 in non-final fragment\n"));
1034 			continue;
1035 		}
1036 		if (offset + count > sizeof(pktdata)) {
1037 			TRACE(1, ("Offset %u, count %u, too big for buffer\n",
1038 				  offset, count));
1039 			return ERR_TOOMUCH;
1040 		}
1041 		if (seenlastfrag && !CTL_ISMORE(rpkt.r_m_e_op)) {
1042 			TRACE(1, ("Received second last fragment packet\n"));
1043 			continue;
1044 		}
1045 
1046 		/*
1047 		 * So far, so good.  Record this fragment, making sure it doesn't
1048 		 * overlap anything.
1049 		 */
1050 		TRACE(2, ("Packet okay\n"));
1051 
1052 		if (numfrags > (MAXFRAGS - 1)) {
1053 			TRACE(2, ("Number of fragments exceeds maximum %d\n",
1054 				  MAXFRAGS - 1));
1055 			return ERR_TOOMUCH;
1056 		}
1057 
1058 		/*
1059 		 * Find the position for the fragment relative to any
1060 		 * previously received.
1061 		 */
1062 		for (f = 0;
1063 		     f < numfrags && offsets[f] < offset;
1064 		     f++) {
1065 			/* empty body */ ;
1066 		}
1067 
1068 		if (f < numfrags && offset == offsets[f]) {
1069 			TRACE(1, ("duplicate %u octets at %u ignored, prior %u at %u\n",
1070 				  count, offset, counts[f], offsets[f]));
1071 			continue;
1072 		}
1073 
1074 		if (f > 0 && (offsets[f-1] + counts[f-1]) > offset) {
1075 			TRACE(1, ("received frag at %u overlaps with %u octet frag at %u\n",
1076 				  offset, counts[f-1], offsets[f-1]));
1077 			continue;
1078 		}
1079 
1080 		if (f < numfrags && (offset + count) > offsets[f]) {
1081 			TRACE(1, ("received %u octet frag at %u overlaps with frag at %u\n",
1082 				  count, offset, offsets[f]));
1083 			continue;
1084 		}
1085 
1086 		for (ff = numfrags; ff > f; ff--) {
1087 			offsets[ff] = offsets[ff-1];
1088 			counts[ff] = counts[ff-1];
1089 		}
1090 		offsets[f] = offset;
1091 		counts[f] = count;
1092 		numfrags++;
1093 
1094 		/*
1095 		 * Got that stuffed in right.  Figure out if this was the last.
1096 		 * Record status info out of the last packet.
1097 		 */
1098 		if (!CTL_ISMORE(rpkt.r_m_e_op)) {
1099 			seenlastfrag = 1;
1100 			if (rstatus != 0)
1101 				*rstatus = ntohs(rpkt.status);
1102 		}
1103 
1104 		/*
1105 		 * Copy the data into the data buffer.
1106 		 */
1107 		memcpy((char *)pktdata + offset, &rpkt.u, count);
1108 
1109 		/*
1110 		 * If we've seen the last fragment, look for holes in the sequence.
1111 		 * If there aren't any, we're done.
1112 		 */
1113 		if (seenlastfrag && offsets[0] == 0) {
1114 			for (f = 1; f < numfrags; f++)
1115 				if (offsets[f-1] + counts[f-1] !=
1116 				    offsets[f])
1117 					break;
1118 			if (f == numfrags) {
1119 				*rsize = offsets[f-1] + counts[f-1];
1120 				TRACE(1, ("%lu packets reassembled into response\n",
1121 					  (u_long)numfrags));
1122 				return 0;
1123 			}
1124 		}
1125 	}  /* giant for (;;) collecting response packets */
1126 }  /* getresponse() */
1127 
1128 
1129 /*
1130  * sendrequest - format and send a request packet
1131  */
1132 static int
1133 sendrequest(
1134 	int opcode,
1135 	associd_t associd,
1136 	int auth,
1137 	int qsize,
1138 	const char *qdata
1139 	)
1140 {
1141 	struct ntp_control qpkt;
1142 	int	pktsize;
1143 	u_long	key_id;
1144 	char *	pass;
1145 	int	maclen;
1146 
1147 	/*
1148 	 * Check to make sure the data will fit in one packet
1149 	 */
1150 	if (qsize > CTL_MAX_DATA_LEN) {
1151 		fprintf(stderr,
1152 			"***Internal error!  qsize (%d) too large\n",
1153 			qsize);
1154 		return 1;
1155 	}
1156 
1157 	/*
1158 	 * Fill in the packet
1159 	 */
1160 	qpkt.li_vn_mode = PKT_LI_VN_MODE(0, pktversion, MODE_CONTROL);
1161 	qpkt.r_m_e_op = (u_char)(opcode & CTL_OP_MASK);
1162 	qpkt.sequence = htons(sequence);
1163 	qpkt.status = 0;
1164 	qpkt.associd = htons((u_short)associd);
1165 	qpkt.offset = 0;
1166 	qpkt.count = htons((u_short)qsize);
1167 
1168 	pktsize = CTL_HEADER_LEN;
1169 
1170 	/*
1171 	 * If we have data, copy and pad it out to a 32-bit boundary.
1172 	 */
1173 	if (qsize > 0) {
1174 		memcpy(&qpkt.u, qdata, (size_t)qsize);
1175 		pktsize += qsize;
1176 		while (pktsize & (sizeof(u_int32) - 1)) {
1177 			qpkt.u.data[qsize++] = 0;
1178 			pktsize++;
1179 		}
1180 	}
1181 
1182 	/*
1183 	 * If it isn't authenticated we can just send it.  Otherwise
1184 	 * we're going to have to think about it a little.
1185 	 */
1186 	if (!auth && !always_auth) {
1187 		return sendpkt(&qpkt, pktsize);
1188 	}
1189 
1190 	/*
1191 	 * Pad out packet to a multiple of 8 octets to be sure
1192 	 * receiver can handle it.
1193 	 */
1194 	while (pktsize & 7) {
1195 		qpkt.u.data[qsize++] = 0;
1196 		pktsize++;
1197 	}
1198 
1199 	/*
1200 	 * Get the keyid and the password if we don't have one.
1201 	 */
1202 	if (info_auth_keyid == 0) {
1203 		key_id = getkeyid("Keyid: ");
1204 		if (key_id == 0 || key_id > NTP_MAXKEY) {
1205 			fprintf(stderr,
1206 				"Invalid key identifier\n");
1207 			return 1;
1208 		}
1209 		info_auth_keyid = key_id;
1210 	}
1211 	if (!authistrusted(info_auth_keyid)) {
1212 		pass = getpass_keytype(info_auth_keytype);
1213 		if ('\0' == pass[0]) {
1214 			fprintf(stderr, "Invalid password\n");
1215 			return 1;
1216 		}
1217 		authusekey(info_auth_keyid, info_auth_keytype,
1218 			   (u_char *)pass);
1219 		authtrust(info_auth_keyid, 1);
1220 	}
1221 
1222 	/*
1223 	 * Do the encryption.
1224 	 */
1225 	maclen = authencrypt(info_auth_keyid, (void *)&qpkt, pktsize);
1226 	if (!maclen) {
1227 		fprintf(stderr, "Key not found\n");
1228 		return 1;
1229 	} else if ((size_t)maclen != (info_auth_hashlen + sizeof(keyid_t))) {
1230 		fprintf(stderr,
1231 			"%d octet MAC, %zu expected with %zu octet digest\n",
1232 			maclen, (info_auth_hashlen + sizeof(keyid_t)),
1233 			info_auth_hashlen);
1234 		return 1;
1235 	}
1236 
1237 	return sendpkt((char *)&qpkt, pktsize + maclen);
1238 }
1239 
1240 
1241 /*
1242  * show_error_msg - display the error text for a mode 6 error response.
1243  */
1244 void
1245 show_error_msg(
1246 	int		m6resp,
1247 	associd_t	associd
1248 	)
1249 {
1250 	if (numhosts > 1)
1251 		fprintf(stderr, "server=%s ", currenthost);
1252 
1253 	switch(m6resp) {
1254 
1255 	case CERR_BADFMT:
1256 		fprintf(stderr,
1257 		    "***Server reports a bad format request packet\n");
1258 		break;
1259 
1260 	case CERR_PERMISSION:
1261 		fprintf(stderr,
1262 		    "***Server disallowed request (authentication?)\n");
1263 		break;
1264 
1265 	case CERR_BADOP:
1266 		fprintf(stderr,
1267 		    "***Server reports a bad opcode in request\n");
1268 		break;
1269 
1270 	case CERR_BADASSOC:
1271 		fprintf(stderr,
1272 		    "***Association ID %d unknown to server\n",
1273 		    associd);
1274 		break;
1275 
1276 	case CERR_UNKNOWNVAR:
1277 		fprintf(stderr,
1278 		    "***A request variable unknown to the server\n");
1279 		break;
1280 
1281 	case CERR_BADVALUE:
1282 		fprintf(stderr,
1283 		    "***Server indicates a request variable was bad\n");
1284 		break;
1285 
1286 	case ERR_UNSPEC:
1287 		fprintf(stderr,
1288 		    "***Server returned an unspecified error\n");
1289 		break;
1290 
1291 	case ERR_TIMEOUT:
1292 		fprintf(stderr, "***Request timed out\n");
1293 		break;
1294 
1295 	case ERR_INCOMPLETE:
1296 		fprintf(stderr,
1297 		    "***Response from server was incomplete\n");
1298 		break;
1299 
1300 	case ERR_TOOMUCH:
1301 		fprintf(stderr,
1302 		    "***Buffer size exceeded for returned data\n");
1303 		break;
1304 
1305 	default:
1306 		fprintf(stderr,
1307 		    "***Server returns unknown error code %d\n",
1308 		    m6resp);
1309 	}
1310 }
1311 
1312 /*
1313  * doquery - send a request and process the response, displaying
1314  *	     error messages for any error responses.
1315  */
1316 int
1317 doquery(
1318 	int opcode,
1319 	associd_t associd,
1320 	int auth,
1321 	int qsize,
1322 	const char *qdata,
1323 	u_short *rstatus,
1324 	int *rsize,
1325 	const char **rdata
1326 	)
1327 {
1328 	return doqueryex(opcode, associd, auth, qsize, qdata, rstatus,
1329 			 rsize, rdata, FALSE);
1330 }
1331 
1332 
1333 /*
1334  * doqueryex - send a request and process the response, optionally
1335  *	       displaying error messages for any error responses.
1336  */
1337 int
1338 doqueryex(
1339 	int opcode,
1340 	associd_t associd,
1341 	int auth,
1342 	int qsize,
1343 	const char *qdata,
1344 	u_short *rstatus,
1345 	int *rsize,
1346 	const char **rdata,
1347 	int quiet
1348 	)
1349 {
1350 	int res;
1351 	int done;
1352 
1353 	/*
1354 	 * Check to make sure host is open
1355 	 */
1356 	if (!havehost) {
1357 		fprintf(stderr, "***No host open, use `host' command\n");
1358 		return -1;
1359 	}
1360 
1361 	done = 0;
1362 	sequence++;
1363 
1364     again:
1365 	/*
1366 	 * send a request
1367 	 */
1368 	res = sendrequest(opcode, associd, auth, qsize, qdata);
1369 	if (res != 0)
1370 		return res;
1371 
1372 	/*
1373 	 * Get the response.  If we got a standard error, print a message
1374 	 */
1375 	res = getresponse(opcode, associd, rstatus, rsize, rdata, done);
1376 
1377 	if (res > 0) {
1378 		if (!done && (res == ERR_TIMEOUT || res == ERR_INCOMPLETE)) {
1379 			if (res == ERR_INCOMPLETE) {
1380 				/*
1381 				 * better bump the sequence so we don't
1382 				 * get confused about differing fragments.
1383 				 */
1384 				sequence++;
1385 			}
1386 			done = 1;
1387 			goto again;
1388 		}
1389 		if (!quiet)
1390 			show_error_msg(res, associd);
1391 
1392 	}
1393 	return res;
1394 }
1395 
1396 
1397 #ifndef BUILD_AS_LIB
1398 /*
1399  * getcmds - read commands from the standard input and execute them
1400  */
1401 static void
1402 getcmds(void)
1403 {
1404 	char *	line;
1405 	int	count;
1406 
1407 	ntp_readline_init(interactive ? prompt : NULL);
1408 
1409 	for (;;) {
1410 		line = ntp_readline(&count);
1411 		if (NULL == line)
1412 			break;
1413 		docmd(line);
1414 		free(line);
1415 	}
1416 
1417 	ntp_readline_uninit();
1418 }
1419 #endif /* !BUILD_AS_LIB */
1420 
1421 
1422 #if !defined(SYS_WINNT) && !defined(BUILD_AS_LIB)
1423 /*
1424  * abortcmd - catch interrupts and abort the current command
1425  */
1426 static RETSIGTYPE
1427 abortcmd(
1428 	int sig
1429 	)
1430 {
1431 	if (current_output == stdout)
1432 	    (void) fflush(stdout);
1433 	putc('\n', stderr);
1434 	(void) fflush(stderr);
1435 	if (jump) longjmp(interrupt_buf, 1);
1436 }
1437 #endif	/* !SYS_WINNT && !BUILD_AS_LIB */
1438 
1439 
1440 #ifndef	BUILD_AS_LIB
1441 /*
1442  * docmd - decode the command line and execute a command
1443  */
1444 static void
1445 docmd(
1446 	const char *cmdline
1447 	)
1448 {
1449 	char *tokens[1+MAXARGS+2];
1450 	struct parse pcmd;
1451 	int ntok;
1452 	static int i;
1453 	struct xcmd *xcmd;
1454 
1455 	/*
1456 	 * Tokenize the command line.  If nothing on it, return.
1457 	 */
1458 	tokenize(cmdline, tokens, &ntok);
1459 	if (ntok == 0)
1460 	    return;
1461 
1462 	/*
1463 	 * Find the appropriate command description.
1464 	 */
1465 	i = findcmd(tokens[0], builtins, opcmds, &xcmd);
1466 	if (i == 0) {
1467 		(void) fprintf(stderr, "***Command `%s' unknown\n",
1468 			       tokens[0]);
1469 		return;
1470 	} else if (i >= 2) {
1471 		(void) fprintf(stderr, "***Command `%s' ambiguous\n",
1472 			       tokens[0]);
1473 		return;
1474 	}
1475 
1476 	/* Warn about ignored extra args */
1477 	for (i = MAXARGS + 1; i < ntok ; ++i) {
1478 		fprintf(stderr, "***Extra arg `%s' ignored\n", tokens[i]);
1479 	}
1480 
1481 	/*
1482 	 * Save the keyword, then walk through the arguments, interpreting
1483 	 * as we go.
1484 	 */
1485 	pcmd.keyword = tokens[0];
1486 	pcmd.nargs = 0;
1487 	for (i = 0; i < MAXARGS && xcmd->arg[i] != NO; i++) {
1488 		if ((i+1) >= ntok) {
1489 			if (!(xcmd->arg[i] & OPT)) {
1490 				printusage(xcmd, stderr);
1491 				return;
1492 			}
1493 			break;
1494 		}
1495 		if ((xcmd->arg[i] & OPT) && (*tokens[i+1] == '>'))
1496 			break;
1497 		if (!getarg(tokens[i+1], (int)xcmd->arg[i], &pcmd.argval[i]))
1498 			return;
1499 		pcmd.nargs++;
1500 	}
1501 
1502 	i++;
1503 	if (i < ntok && *tokens[i] == '>') {
1504 		char *fname;
1505 
1506 		if (*(tokens[i]+1) != '\0')
1507 			fname = tokens[i]+1;
1508 		else if ((i+1) < ntok)
1509 			fname = tokens[i+1];
1510 		else {
1511 			(void) fprintf(stderr, "***No file for redirect\n");
1512 			return;
1513 		}
1514 
1515 		current_output = fopen(fname, "w");
1516 		if (current_output == NULL) {
1517 			(void) fprintf(stderr, "***Error opening %s: ", fname);
1518 			perror("");
1519 			return;
1520 		}
1521 		i = 1;		/* flag we need a close */
1522 	} else {
1523 		current_output = stdout;
1524 		i = 0;		/* flag no close */
1525 	}
1526 
1527 	if (interactive && setjmp(interrupt_buf)) {
1528 		jump = 0;
1529 		return;
1530 	} else {
1531 		jump++;
1532 		(xcmd->handler)(&pcmd, current_output);
1533 		jump = 0;	/* HMS: 961106: was after fclose() */
1534 		if (i) (void) fclose(current_output);
1535 	}
1536 
1537 	return;
1538 }
1539 
1540 
1541 /*
1542  * tokenize - turn a command line into tokens
1543  *
1544  * SK: Modified to allow a quoted string
1545  *
1546  * HMS: If the first character of the first token is a ':' then (after
1547  * eating inter-token whitespace) the 2nd token is the rest of the line.
1548  */
1549 
1550 static void
1551 tokenize(
1552 	const char *line,
1553 	char **tokens,
1554 	int *ntok
1555 	)
1556 {
1557 	register const char *cp;
1558 	register char *sp;
1559 	static char tspace[MAXLINE];
1560 
1561 	sp = tspace;
1562 	cp = line;
1563 	for (*ntok = 0; *ntok < MAXTOKENS; (*ntok)++) {
1564 		tokens[*ntok] = sp;
1565 
1566 		/* Skip inter-token whitespace */
1567 		while (ISSPACE(*cp))
1568 		    cp++;
1569 
1570 		/* If we're at EOL we're done */
1571 		if (ISEOL(*cp))
1572 		    break;
1573 
1574 		/* If this is the 2nd token and the first token begins
1575 		 * with a ':', then just grab to EOL.
1576 		 */
1577 
1578 		if (*ntok == 1 && tokens[0][0] == ':') {
1579 			do {
1580 				if (sp - tspace >= MAXLINE)
1581 					goto toobig;
1582 				*sp++ = *cp++;
1583 			} while (!ISEOL(*cp));
1584 		}
1585 
1586 		/* Check if this token begins with a double quote.
1587 		 * If yes, continue reading till the next double quote
1588 		 */
1589 		else if (*cp == '\"') {
1590 			++cp;
1591 			do {
1592 				if (sp - tspace >= MAXLINE)
1593 					goto toobig;
1594 				*sp++ = *cp++;
1595 			} while ((*cp != '\"') && !ISEOL(*cp));
1596 			/* HMS: a missing closing " should be an error */
1597 		}
1598 		else {
1599 			do {
1600 				if (sp - tspace >= MAXLINE)
1601 					goto toobig;
1602 				*sp++ = *cp++;
1603 			} while ((*cp != '\"') && !ISSPACE(*cp) && !ISEOL(*cp));
1604 			/* HMS: Why check for a " in the previous line? */
1605 		}
1606 
1607 		if (sp - tspace >= MAXLINE)
1608 			goto toobig;
1609 		*sp++ = '\0';
1610 	}
1611 	return;
1612 
1613   toobig:
1614 	*ntok = 0;
1615 	fprintf(stderr,
1616 		"***Line `%s' is too big\n",
1617 		line);
1618 	return;
1619 }
1620 
1621 
1622 /*
1623  * getarg - interpret an argument token
1624  */
1625 static int
1626 getarg(
1627 	const char *str,
1628 	int code,
1629 	arg_v *argp
1630 	)
1631 {
1632 	u_long ul;
1633 
1634 	switch (code & ~OPT) {
1635 	case NTP_STR:
1636 		argp->string = str;
1637 		break;
1638 
1639 	case NTP_ADD:
1640 		if (!getnetnum(str, &argp->netnum, NULL, 0))
1641 			return 0;
1642 		break;
1643 
1644 	case NTP_UINT:
1645 		if ('&' == str[0]) {
1646 			if (!atouint(&str[1], &ul)) {
1647 				fprintf(stderr,
1648 					"***Association index `%s' invalid/undecodable\n",
1649 					str);
1650 				return 0;
1651 			}
1652 			if (0 == numassoc) {
1653 				dogetassoc(stdout);
1654 				if (0 == numassoc) {
1655 					fprintf(stderr,
1656 						"***No associations found, `%s' unknown\n",
1657 						str);
1658 					return 0;
1659 				}
1660 			}
1661 			ul = min(ul, numassoc);
1662 			argp->uval = assoc_cache[ul - 1].assid;
1663 			break;
1664 		}
1665 		if (!atouint(str, &argp->uval)) {
1666 			fprintf(stderr, "***Illegal unsigned value %s\n",
1667 				str);
1668 			return 0;
1669 		}
1670 		break;
1671 
1672 	case NTP_INT:
1673 		if (!atoint(str, &argp->ival)) {
1674 			fprintf(stderr, "***Illegal integer value %s\n",
1675 				str);
1676 			return 0;
1677 		}
1678 		break;
1679 
1680 	case IP_VERSION:
1681 		if (!strcmp("-6", str)) {
1682 			argp->ival = 6;
1683 		} else if (!strcmp("-4", str)) {
1684 			argp->ival = 4;
1685 		} else {
1686 			fprintf(stderr, "***Version must be either 4 or 6\n");
1687 			return 0;
1688 		}
1689 		break;
1690 	}
1691 
1692 	return 1;
1693 }
1694 #endif	/* !BUILD_AS_LIB */
1695 
1696 
1697 /*
1698  * findcmd - find a command in a command description table
1699  */
1700 static int
1701 findcmd(
1702 	const char *	str,
1703 	struct xcmd *	clist1,
1704 	struct xcmd *	clist2,
1705 	struct xcmd **	cmd
1706 	)
1707 {
1708 	struct xcmd *cl;
1709 	int clen;
1710 	int nmatch;
1711 	struct xcmd *nearmatch = NULL;
1712 	struct xcmd *clist;
1713 
1714 	clen = strlen(str);
1715 	nmatch = 0;
1716 	if (clist1 != 0)
1717 	    clist = clist1;
1718 	else if (clist2 != 0)
1719 	    clist = clist2;
1720 	else
1721 	    return 0;
1722 
1723     again:
1724 	for (cl = clist; cl->keyword != 0; cl++) {
1725 		/* do a first character check, for efficiency */
1726 		if (*str != *(cl->keyword))
1727 		    continue;
1728 		if (strncmp(str, cl->keyword, (unsigned)clen) == 0) {
1729 			/*
1730 			 * Could be extact match, could be approximate.
1731 			 * Is exact if the length of the keyword is the
1732 			 * same as the str.
1733 			 */
1734 			if (*((cl->keyword) + clen) == '\0') {
1735 				*cmd = cl;
1736 				return 1;
1737 			}
1738 			nmatch++;
1739 			nearmatch = cl;
1740 		}
1741 	}
1742 
1743 	/*
1744 	 * See if there is more to do.  If so, go again.  Sorry about the
1745 	 * goto, too much looking at BSD sources...
1746 	 */
1747 	if (clist == clist1 && clist2 != 0) {
1748 		clist = clist2;
1749 		goto again;
1750 	}
1751 
1752 	/*
1753 	 * If we got extactly 1 near match, use it, else return number
1754 	 * of matches.
1755 	 */
1756 	if (nmatch == 1) {
1757 		*cmd = nearmatch;
1758 		return 1;
1759 	}
1760 	return nmatch;
1761 }
1762 
1763 
1764 /*
1765  * getnetnum - given a host name, return its net number
1766  *	       and (optional) full name
1767  */
1768 int
1769 getnetnum(
1770 	const char *hname,
1771 	sockaddr_u *num,
1772 	char *fullhost,
1773 	int af
1774 	)
1775 {
1776 	struct addrinfo hints, *ai = NULL;
1777 
1778 	ZERO(hints);
1779 	hints.ai_flags = AI_CANONNAME;
1780 #ifdef AI_ADDRCONFIG
1781 	hints.ai_flags |= AI_ADDRCONFIG;
1782 #endif
1783 
1784 	/*
1785 	 * decodenetnum only works with addresses, but handles syntax
1786 	 * that getaddrinfo doesn't:  [2001::1]:1234
1787 	 */
1788 	if (decodenetnum(hname, num)) {
1789 		if (fullhost != NULL)
1790 			getnameinfo(&num->sa, SOCKLEN(num), fullhost,
1791 				    LENHOSTNAME, NULL, 0, 0);
1792 		return 1;
1793 	} else if (getaddrinfo(hname, "ntp", &hints, &ai) == 0) {
1794 		INSIST(sizeof(*num) >= ai->ai_addrlen);
1795 		memcpy(num, ai->ai_addr, ai->ai_addrlen);
1796 		if (fullhost != NULL) {
1797 			if (ai->ai_canonname != NULL)
1798 				strlcpy(fullhost, ai->ai_canonname,
1799 					LENHOSTNAME);
1800 			else
1801 				getnameinfo(&num->sa, SOCKLEN(num),
1802 					    fullhost, LENHOSTNAME, NULL,
1803 					    0, 0);
1804 		}
1805 		freeaddrinfo(ai);
1806 		return 1;
1807 	}
1808 	fprintf(stderr, "***Can't find host %s\n", hname);
1809 
1810 	return 0;
1811 }
1812 
1813 
1814 /*
1815  * nntohost - convert network number to host name.  This routine enforces
1816  *	       the showhostnames setting.
1817  */
1818 const char *
1819 nntohost(
1820 	sockaddr_u *netnum
1821 	)
1822 {
1823 	return nntohost_col(netnum, LIB_BUFLENGTH - 1, FALSE);
1824 }
1825 
1826 
1827 /*
1828  * nntohost_col - convert network number to host name in fixed width.
1829  *		  This routine enforces the showhostnames setting.
1830  *		  When displaying hostnames longer than the width,
1831  *		  the first part of the hostname is displayed.  When
1832  *		  displaying numeric addresses longer than the width,
1833  *		  Such as IPv6 addresses, the caller decides whether
1834  *		  the first or last of the numeric address is used.
1835  */
1836 const char *
1837 nntohost_col(
1838 	sockaddr_u *	addr,
1839 	size_t		width,
1840 	int		preserve_lowaddrbits
1841 	)
1842 {
1843 	const char *	out;
1844 
1845 	if (!showhostnames || SOCK_UNSPEC(addr)) {
1846 		if (preserve_lowaddrbits)
1847 			out = trunc_left(stoa(addr), width);
1848 		else
1849 			out = trunc_right(stoa(addr), width);
1850 	} else if (ISREFCLOCKADR(addr)) {
1851 		out = refnumtoa(addr);
1852 	} else {
1853 		out = trunc_right(socktohost(addr), width);
1854 	}
1855 	return out;
1856 }
1857 
1858 
1859 /*
1860  * nntohostp() is the same as nntohost() plus a :port suffix
1861  */
1862 const char *
1863 nntohostp(
1864 	sockaddr_u *netnum
1865 	)
1866 {
1867 	const char *	hostn;
1868 	char *		buf;
1869 
1870 	if (!showhostnames || SOCK_UNSPEC(netnum))
1871 		return sptoa(netnum);
1872 	else if (ISREFCLOCKADR(netnum))
1873 		return refnumtoa(netnum);
1874 
1875 	hostn = socktohost(netnum);
1876 	LIB_GETBUF(buf);
1877 	snprintf(buf, LIB_BUFLENGTH, "%s:%u", hostn, SRCPORT(netnum));
1878 
1879 	return buf;
1880 }
1881 
1882 /*
1883  * rtdatetolfp - decode an RT-11 date into an l_fp
1884  */
1885 static int
1886 rtdatetolfp(
1887 	char *str,
1888 	l_fp *lfp
1889 	)
1890 {
1891 	register char *cp;
1892 	register int i;
1893 	struct calendar cal;
1894 	char buf[4];
1895 
1896 	cal.yearday = 0;
1897 
1898 	/*
1899 	 * An RT-11 date looks like:
1900 	 *
1901 	 * d[d]-Mth-y[y] hh:mm:ss
1902 	 *
1903 	 * (No docs, but assume 4-digit years are also legal...)
1904 	 *
1905 	 * d[d]-Mth-y[y[y[y]]] hh:mm:ss
1906 	 */
1907 	cp = str;
1908 	if (!isdigit((int)*cp)) {
1909 		if (*cp == '-') {
1910 			/*
1911 			 * Catch special case
1912 			 */
1913 			L_CLR(lfp);
1914 			return 1;
1915 		}
1916 		return 0;
1917 	}
1918 
1919 	cal.monthday = (u_char) (*cp++ - '0');	/* ascii dependent */
1920 	if (isdigit((int)*cp)) {
1921 		cal.monthday = (u_char)((cal.monthday << 3) + (cal.monthday << 1));
1922 		cal.monthday = (u_char)(cal.monthday + *cp++ - '0');
1923 	}
1924 
1925 	if (*cp++ != '-')
1926 	    return 0;
1927 
1928 	for (i = 0; i < 3; i++)
1929 	    buf[i] = *cp++;
1930 	buf[3] = '\0';
1931 
1932 	for (i = 0; i < 12; i++)
1933 	    if (STREQ(buf, months[i]))
1934 		break;
1935 	if (i == 12)
1936 	    return 0;
1937 	cal.month = (u_char)(i + 1);
1938 
1939 	if (*cp++ != '-')
1940 	    return 0;
1941 
1942 	if (!isdigit((int)*cp))
1943 	    return 0;
1944 	cal.year = (u_short)(*cp++ - '0');
1945 	if (isdigit((int)*cp)) {
1946 		cal.year = (u_short)((cal.year << 3) + (cal.year << 1));
1947 		cal.year = (u_short)(*cp++ - '0');
1948 	}
1949 	if (isdigit((int)*cp)) {
1950 		cal.year = (u_short)((cal.year << 3) + (cal.year << 1));
1951 		cal.year = (u_short)(cal.year + *cp++ - '0');
1952 	}
1953 	if (isdigit((int)*cp)) {
1954 		cal.year = (u_short)((cal.year << 3) + (cal.year << 1));
1955 		cal.year = (u_short)(cal.year + *cp++ - '0');
1956 	}
1957 
1958 	/*
1959 	 * Catch special case.  If cal.year == 0 this is a zero timestamp.
1960 	 */
1961 	if (cal.year == 0) {
1962 		L_CLR(lfp);
1963 		return 1;
1964 	}
1965 
1966 	if (*cp++ != ' ' || !isdigit((int)*cp))
1967 	    return 0;
1968 	cal.hour = (u_char)(*cp++ - '0');
1969 	if (isdigit((int)*cp)) {
1970 		cal.hour = (u_char)((cal.hour << 3) + (cal.hour << 1));
1971 		cal.hour = (u_char)(cal.hour + *cp++ - '0');
1972 	}
1973 
1974 	if (*cp++ != ':' || !isdigit((int)*cp))
1975 	    return 0;
1976 	cal.minute = (u_char)(*cp++ - '0');
1977 	if (isdigit((int)*cp)) {
1978 		cal.minute = (u_char)((cal.minute << 3) + (cal.minute << 1));
1979 		cal.minute = (u_char)(cal.minute + *cp++ - '0');
1980 	}
1981 
1982 	if (*cp++ != ':' || !isdigit((int)*cp))
1983 	    return 0;
1984 	cal.second = (u_char)(*cp++ - '0');
1985 	if (isdigit((int)*cp)) {
1986 		cal.second = (u_char)((cal.second << 3) + (cal.second << 1));
1987 		cal.second = (u_char)(cal.second + *cp++ - '0');
1988 	}
1989 
1990 	/*
1991 	 * For RT-11, 1972 seems to be the pivot year
1992 	 */
1993 	if (cal.year < 72)
1994 		cal.year += 2000;
1995 	if (cal.year < 100)
1996 		cal.year += 1900;
1997 
1998 	lfp->l_ui = caltontp(&cal);
1999 	lfp->l_uf = 0;
2000 	return 1;
2001 }
2002 
2003 
2004 /*
2005  * decodets - decode a timestamp into an l_fp format number, with
2006  *	      consideration of fuzzball formats.
2007  */
2008 int
2009 decodets(
2010 	char *str,
2011 	l_fp *lfp
2012 	)
2013 {
2014 	char *cp;
2015 	char buf[30];
2016 	size_t b;
2017 
2018 	/*
2019 	 * If it starts with a 0x, decode as hex.
2020 	 */
2021 	if (*str == '0' && (*(str+1) == 'x' || *(str+1) == 'X'))
2022 		return hextolfp(str+2, lfp);
2023 
2024 	/*
2025 	 * If it starts with a '"', try it as an RT-11 date.
2026 	 */
2027 	if (*str == '"') {
2028 		cp = str + 1;
2029 		b = 0;
2030 		while ('"' != *cp && '\0' != *cp &&
2031 		       b < COUNTOF(buf) - 1)
2032 			buf[b++] = *cp++;
2033 		buf[b] = '\0';
2034 		return rtdatetolfp(buf, lfp);
2035 	}
2036 
2037 	/*
2038 	 * Might still be hex.  Check out the first character.  Talk
2039 	 * about heuristics!
2040 	 */
2041 	if ((*str >= 'A' && *str <= 'F') || (*str >= 'a' && *str <= 'f'))
2042 		return hextolfp(str, lfp);
2043 
2044 	/*
2045 	 * Try it as a decimal.  If this fails, try as an unquoted
2046 	 * RT-11 date.  This code should go away eventually.
2047 	 */
2048 	if (atolfp(str, lfp))
2049 		return 1;
2050 
2051 	return rtdatetolfp(str, lfp);
2052 }
2053 
2054 
2055 /*
2056  * decodetime - decode a time value.  It should be in milliseconds
2057  */
2058 int
2059 decodetime(
2060 	char *str,
2061 	l_fp *lfp
2062 	)
2063 {
2064 	return mstolfp(str, lfp);
2065 }
2066 
2067 
2068 /*
2069  * decodeint - decode an integer
2070  */
2071 int
2072 decodeint(
2073 	char *str,
2074 	long *val
2075 	)
2076 {
2077 	if (*str == '0') {
2078 		if (*(str+1) == 'x' || *(str+1) == 'X')
2079 		    return hextoint(str+2, (u_long *)val);
2080 		return octtoint(str, (u_long *)val);
2081 	}
2082 	return atoint(str, val);
2083 }
2084 
2085 
2086 /*
2087  * decodeuint - decode an unsigned integer
2088  */
2089 int
2090 decodeuint(
2091 	char *str,
2092 	u_long *val
2093 	)
2094 {
2095 	if (*str == '0') {
2096 		if (*(str + 1) == 'x' || *(str + 1) == 'X')
2097 			return (hextoint(str + 2, val));
2098 		return (octtoint(str, val));
2099 	}
2100 	return (atouint(str, val));
2101 }
2102 
2103 
2104 /*
2105  * decodearr - decode an array of time values
2106  */
2107 static int
2108 decodearr(
2109 	char *str,
2110 	int *narr,
2111 	l_fp *lfparr
2112 	)
2113 {
2114 	register char *cp, *bp;
2115 	register l_fp *lfp;
2116 	char buf[60];
2117 
2118 	lfp = lfparr;
2119 	cp = str;
2120 	*narr = 0;
2121 
2122 	while (*narr < 8) {
2123 		while (isspace((int)*cp))
2124 		    cp++;
2125 		if (*cp == '\0')
2126 		    break;
2127 
2128 		bp = buf;
2129 		while (!isspace((int)*cp) && *cp != '\0')
2130 		    *bp++ = *cp++;
2131 		*bp++ = '\0';
2132 
2133 		if (!decodetime(buf, lfp))
2134 		    return 0;
2135 		(*narr)++;
2136 		lfp++;
2137 	}
2138 	return 1;
2139 }
2140 
2141 
2142 /*
2143  * Finally, the built in command handlers
2144  */
2145 
2146 /*
2147  * help - tell about commands, or details of a particular command
2148  */
2149 static void
2150 help(
2151 	struct parse *pcmd,
2152 	FILE *fp
2153 	)
2154 {
2155 	struct xcmd *xcp = NULL;	/* quiet warning */
2156 	const char *cmd;
2157 	const char *list[100];
2158 	size_t word, words;
2159 	size_t row, rows;
2160 	size_t col, cols;
2161 	size_t length;
2162 
2163 	if (pcmd->nargs == 0) {
2164 		words = 0;
2165 		for (xcp = builtins; xcp->keyword != NULL; xcp++) {
2166 			if (*(xcp->keyword) != '?' &&
2167 			    words < COUNTOF(list))
2168 				list[words++] = xcp->keyword;
2169 		}
2170 		for (xcp = opcmds; xcp->keyword != NULL; xcp++)
2171 			if (words < COUNTOF(list))
2172 				list[words++] = xcp->keyword;
2173 
2174 		qsort((void *)list, words, sizeof(list[0]), helpsort);
2175 		col = 0;
2176 		for (word = 0; word < words; word++) {
2177 			length = strlen(list[word]);
2178 			col = max(col, length);
2179 		}
2180 
2181 		cols = SCREENWIDTH / ++col;
2182 		rows = (words + cols - 1) / cols;
2183 
2184 		fprintf(fp, "ntpq commands:\n");
2185 
2186 		for (row = 0; row < rows; row++) {
2187 			for (word = row; word < words; word += rows)
2188 				fprintf(fp, "%-*.*s", (int)col,
2189 					(int)col - 1, list[word]);
2190 			fprintf(fp, "\n");
2191 		}
2192 	} else {
2193 		cmd = pcmd->argval[0].string;
2194 		words = findcmd(cmd, builtins, opcmds, &xcp);
2195 		if (words == 0) {
2196 			fprintf(stderr,
2197 				"Command `%s' is unknown\n", cmd);
2198 			return;
2199 		} else if (words >= 2) {
2200 			fprintf(stderr,
2201 				"Command `%s' is ambiguous\n", cmd);
2202 			return;
2203 		}
2204 		fprintf(fp, "function: %s\n", xcp->comment);
2205 		printusage(xcp, fp);
2206 	}
2207 }
2208 
2209 
2210 /*
2211  * helpsort - do hostname qsort comparisons
2212  */
2213 static int
2214 helpsort(
2215 	const void *t1,
2216 	const void *t2
2217 	)
2218 {
2219 	const char * const *	name1 = t1;
2220 	const char * const *	name2 = t2;
2221 
2222 	return strcmp(*name1, *name2);
2223 }
2224 
2225 
2226 /*
2227  * printusage - print usage information for a command
2228  */
2229 static void
2230 printusage(
2231 	struct xcmd *xcp,
2232 	FILE *fp
2233 	)
2234 {
2235 	register int i;
2236 
2237 	/* XXX: Do we need to warn about extra args here too? */
2238 
2239 	(void) fprintf(fp, "usage: %s", xcp->keyword);
2240 	for (i = 0; i < MAXARGS && xcp->arg[i] != NO; i++) {
2241 		if (xcp->arg[i] & OPT)
2242 		    (void) fprintf(fp, " [ %s ]", xcp->desc[i]);
2243 		else
2244 		    (void) fprintf(fp, " %s", xcp->desc[i]);
2245 	}
2246 	(void) fprintf(fp, "\n");
2247 }
2248 
2249 
2250 /*
2251  * timeout - set time out time
2252  */
2253 static void
2254 timeout(
2255 	struct parse *pcmd,
2256 	FILE *fp
2257 	)
2258 {
2259 	int val;
2260 
2261 	if (pcmd->nargs == 0) {
2262 		val = (int)tvout.tv_sec * 1000 + tvout.tv_usec / 1000;
2263 		(void) fprintf(fp, "primary timeout %d ms\n", val);
2264 	} else {
2265 		tvout.tv_sec = pcmd->argval[0].uval / 1000;
2266 		tvout.tv_usec = (pcmd->argval[0].uval - ((long)tvout.tv_sec * 1000))
2267 			* 1000;
2268 	}
2269 }
2270 
2271 
2272 /*
2273  * auth_delay - set delay for auth requests
2274  */
2275 static void
2276 auth_delay(
2277 	struct parse *pcmd,
2278 	FILE *fp
2279 	)
2280 {
2281 	int isneg;
2282 	u_long val;
2283 
2284 	if (pcmd->nargs == 0) {
2285 		val = delay_time.l_ui * 1000 + delay_time.l_uf / 4294967;
2286 		(void) fprintf(fp, "delay %lu ms\n", val);
2287 	} else {
2288 		if (pcmd->argval[0].ival < 0) {
2289 			isneg = 1;
2290 			val = (u_long)(-pcmd->argval[0].ival);
2291 		} else {
2292 			isneg = 0;
2293 			val = (u_long)pcmd->argval[0].ival;
2294 		}
2295 
2296 		delay_time.l_ui = val / 1000;
2297 		val %= 1000;
2298 		delay_time.l_uf = val * 4294967;	/* 2**32/1000 */
2299 
2300 		if (isneg)
2301 		    L_NEG(&delay_time);
2302 	}
2303 }
2304 
2305 
2306 /*
2307  * host - set the host we are dealing with.
2308  */
2309 static void
2310 host(
2311 	struct parse *pcmd,
2312 	FILE *fp
2313 	)
2314 {
2315 	int i;
2316 
2317 	if (pcmd->nargs == 0) {
2318 		if (havehost)
2319 			(void) fprintf(fp, "current host is %s\n",
2320 					   currenthost);
2321 		else
2322 			(void) fprintf(fp, "no current host\n");
2323 		return;
2324 	}
2325 
2326 	i = 0;
2327 	ai_fam_templ = ai_fam_default;
2328 	if (pcmd->nargs == 2) {
2329 		if (!strcmp("-4", pcmd->argval[i].string))
2330 			ai_fam_templ = AF_INET;
2331 		else if (!strcmp("-6", pcmd->argval[i].string))
2332 			ai_fam_templ = AF_INET6;
2333 		else
2334 			goto no_change;
2335 		i = 1;
2336 	}
2337 	if (openhost(pcmd->argval[i].string, ai_fam_templ)) {
2338 		fprintf(fp, "current host set to %s\n", currenthost);
2339 	} else {
2340     no_change:
2341 		if (havehost)
2342 			fprintf(fp, "current host remains %s\n",
2343 				currenthost);
2344 		else
2345 			fprintf(fp, "still no current host\n");
2346 	}
2347 }
2348 
2349 
2350 /*
2351  * poll - do one (or more) polls of the host via NTP
2352  */
2353 /*ARGSUSED*/
2354 static void
2355 ntp_poll(
2356 	struct parse *pcmd,
2357 	FILE *fp
2358 	)
2359 {
2360 	(void) fprintf(fp, "poll not implemented yet\n");
2361 }
2362 
2363 
2364 /*
2365  * keyid - get a keyid to use for authenticating requests
2366  */
2367 static void
2368 keyid(
2369 	struct parse *pcmd,
2370 	FILE *fp
2371 	)
2372 {
2373 	if (pcmd->nargs == 0) {
2374 		if (info_auth_keyid == 0)
2375 		    (void) fprintf(fp, "no keyid defined\n");
2376 		else
2377 		    (void) fprintf(fp, "keyid is %lu\n", (u_long)info_auth_keyid);
2378 	} else {
2379 		/* allow zero so that keyid can be cleared. */
2380 		if(pcmd->argval[0].uval > NTP_MAXKEY)
2381 		    (void) fprintf(fp, "Invalid key identifier\n");
2382 		info_auth_keyid = pcmd->argval[0].uval;
2383 	}
2384 }
2385 
2386 /*
2387  * keytype - get type of key to use for authenticating requests
2388  */
2389 static void
2390 keytype(
2391 	struct parse *pcmd,
2392 	FILE *fp
2393 	)
2394 {
2395 	const char *	digest_name;
2396 	size_t		digest_len;
2397 	int		key_type;
2398 
2399 	if (!pcmd->nargs) {
2400 		fprintf(fp, "keytype is %s with %lu octet digests\n",
2401 			keytype_name(info_auth_keytype),
2402 			(u_long)info_auth_hashlen);
2403 		return;
2404 	}
2405 
2406 	digest_name = pcmd->argval[0].string;
2407 	digest_len = 0;
2408 	key_type = keytype_from_text(digest_name, &digest_len);
2409 
2410 	if (!key_type) {
2411 		fprintf(fp, "keytype must be 'md5'%s\n",
2412 #ifdef OPENSSL
2413 			" or a digest type provided by OpenSSL");
2414 #else
2415 			"");
2416 #endif
2417 		return;
2418 	}
2419 
2420 	info_auth_keytype = key_type;
2421 	info_auth_hashlen = digest_len;
2422 }
2423 
2424 
2425 /*
2426  * passwd - get an authentication key
2427  */
2428 /*ARGSUSED*/
2429 static void
2430 passwd(
2431 	struct parse *pcmd,
2432 	FILE *fp
2433 	)
2434 {
2435 	const char *pass;
2436 
2437 	if (info_auth_keyid == 0) {
2438 		info_auth_keyid = getkeyid("Keyid: ");
2439 		if (info_auth_keyid == 0) {
2440 			(void)fprintf(fp, "Keyid must be defined\n");
2441 			return;
2442 		}
2443 	}
2444 	if (pcmd->nargs >= 1)
2445 		pass = pcmd->argval[0].string;
2446 	else {
2447 		pass = getpass_keytype(info_auth_keytype);
2448 		if ('\0' == pass[0]) {
2449 			fprintf(fp, "Password unchanged\n");
2450 			return;
2451 		}
2452 	}
2453 	authusekey(info_auth_keyid, info_auth_keytype,
2454 		   (const u_char *)pass);
2455 	authtrust(info_auth_keyid, 1);
2456 }
2457 
2458 
2459 /*
2460  * hostnames - set the showhostnames flag
2461  */
2462 static void
2463 hostnames(
2464 	struct parse *pcmd,
2465 	FILE *fp
2466 	)
2467 {
2468 	if (pcmd->nargs == 0) {
2469 		if (showhostnames)
2470 		    (void) fprintf(fp, "hostnames being shown\n");
2471 		else
2472 		    (void) fprintf(fp, "hostnames not being shown\n");
2473 	} else {
2474 		if (STREQ(pcmd->argval[0].string, "yes"))
2475 		    showhostnames = 1;
2476 		else if (STREQ(pcmd->argval[0].string, "no"))
2477 		    showhostnames = 0;
2478 		else
2479 		    (void)fprintf(stderr, "What?\n");
2480 	}
2481 }
2482 
2483 
2484 
2485 /*
2486  * setdebug - set/change debugging level
2487  */
2488 static void
2489 setdebug(
2490 	struct parse *pcmd,
2491 	FILE *fp
2492 	)
2493 {
2494 	if (pcmd->nargs == 0) {
2495 		(void) fprintf(fp, "debug level is %d\n", debug);
2496 		return;
2497 	} else if (STREQ(pcmd->argval[0].string, "no")) {
2498 		debug = 0;
2499 	} else if (STREQ(pcmd->argval[0].string, "more")) {
2500 		debug++;
2501 	} else if (STREQ(pcmd->argval[0].string, "less")) {
2502 		debug--;
2503 	} else {
2504 		(void) fprintf(fp, "What?\n");
2505 		return;
2506 	}
2507 	(void) fprintf(fp, "debug level set to %d\n", debug);
2508 }
2509 
2510 
2511 /*
2512  * quit - stop this nonsense
2513  */
2514 /*ARGSUSED*/
2515 static void
2516 quit(
2517 	struct parse *pcmd,
2518 	FILE *fp
2519 	)
2520 {
2521 	if (havehost)
2522 	    closesocket(sockfd);	/* cleanliness next to godliness */
2523 	exit(0);
2524 }
2525 
2526 
2527 /*
2528  * version - print the current version number
2529  */
2530 /*ARGSUSED*/
2531 static void
2532 version(
2533 	struct parse *pcmd,
2534 	FILE *fp
2535 	)
2536 {
2537 
2538 	(void) fprintf(fp, "%s\n", Version);
2539 	return;
2540 }
2541 
2542 
2543 /*
2544  * raw - set raw mode output
2545  */
2546 /*ARGSUSED*/
2547 static void
2548 raw(
2549 	struct parse *pcmd,
2550 	FILE *fp
2551 	)
2552 {
2553 	rawmode = 1;
2554 	(void) fprintf(fp, "Output set to raw\n");
2555 }
2556 
2557 
2558 /*
2559  * cooked - set cooked mode output
2560  */
2561 /*ARGSUSED*/
2562 static void
2563 cooked(
2564 	struct parse *pcmd,
2565 	FILE *fp
2566 	)
2567 {
2568 	rawmode = 0;
2569 	(void) fprintf(fp, "Output set to cooked\n");
2570 	return;
2571 }
2572 
2573 
2574 /*
2575  * authenticate - always authenticate requests to this host
2576  */
2577 static void
2578 authenticate(
2579 	struct parse *pcmd,
2580 	FILE *fp
2581 	)
2582 {
2583 	if (pcmd->nargs == 0) {
2584 		if (always_auth) {
2585 			(void) fprintf(fp,
2586 				       "authenticated requests being sent\n");
2587 		} else
2588 		    (void) fprintf(fp,
2589 				   "unauthenticated requests being sent\n");
2590 	} else {
2591 		if (STREQ(pcmd->argval[0].string, "yes")) {
2592 			always_auth = 1;
2593 		} else if (STREQ(pcmd->argval[0].string, "no")) {
2594 			always_auth = 0;
2595 		} else
2596 		    (void)fprintf(stderr, "What?\n");
2597 	}
2598 }
2599 
2600 
2601 /*
2602  * ntpversion - choose the NTP version to use
2603  */
2604 static void
2605 ntpversion(
2606 	struct parse *pcmd,
2607 	FILE *fp
2608 	)
2609 {
2610 	if (pcmd->nargs == 0) {
2611 		(void) fprintf(fp,
2612 			       "NTP version being claimed is %d\n", pktversion);
2613 	} else {
2614 		if (pcmd->argval[0].uval < NTP_OLDVERSION
2615 		    || pcmd->argval[0].uval > NTP_VERSION) {
2616 			(void) fprintf(stderr, "versions %d to %d, please\n",
2617 				       NTP_OLDVERSION, NTP_VERSION);
2618 		} else {
2619 			pktversion = (u_char) pcmd->argval[0].uval;
2620 		}
2621 	}
2622 }
2623 
2624 
2625 static void __attribute__((__format__(__printf__, 1, 0)))
2626 vwarning(const char *fmt, va_list ap)
2627 {
2628 	int serrno = errno;
2629 	(void) fprintf(stderr, "%s: ", progname);
2630 	vfprintf(stderr, fmt, ap);
2631 	(void) fprintf(stderr, ": %s", strerror(serrno));
2632 }
2633 
2634 /*
2635  * warning - print a warning message
2636  */
2637 static void __attribute__((__format__(__printf__, 1, 2)))
2638 warning(
2639 	const char *fmt,
2640 	...
2641 	)
2642 {
2643 	va_list ap;
2644 	va_start(ap, fmt);
2645 	vwarning(fmt, ap);
2646 	va_end(ap);
2647 }
2648 
2649 
2650 /*
2651  * error - print a message and exit
2652  */
2653 static void __attribute__((__format__(__printf__, 1, 2)))
2654 error(
2655 	const char *fmt,
2656 	...
2657 	)
2658 {
2659 	va_list ap;
2660 	va_start(ap, fmt);
2661 	vwarning(fmt, ap);
2662 	va_end(ap);
2663 	exit(1);
2664 }
2665 /*
2666  * getkeyid - prompt the user for a keyid to use
2667  */
2668 static u_long
2669 getkeyid(
2670 	const char *keyprompt
2671 	)
2672 {
2673 	int c;
2674 	FILE *fi;
2675 	char pbuf[20];
2676 	size_t i;
2677 	size_t ilim;
2678 
2679 #ifndef SYS_WINNT
2680 	if ((fi = fdopen(open("/dev/tty", 2), "r")) == NULL)
2681 #else
2682 	if ((fi = _fdopen(open("CONIN$", _O_TEXT), "r")) == NULL)
2683 #endif /* SYS_WINNT */
2684 		fi = stdin;
2685 	else
2686 		setbuf(fi, (char *)NULL);
2687 	fprintf(stderr, "%s", keyprompt); fflush(stderr);
2688 	for (i = 0, ilim = COUNTOF(pbuf) - 1;
2689 	     i < ilim && (c = getc(fi)) != '\n' && c != EOF;
2690 	     )
2691 		pbuf[i++] = (char)c;
2692 	pbuf[i] = '\0';
2693 	if (fi != stdin)
2694 		fclose(fi);
2695 
2696 	return (u_long) atoi(pbuf);
2697 }
2698 
2699 
2700 /*
2701  * atoascii - printable-ize possibly ascii data using the character
2702  *	      transformations cat -v uses.
2703  */
2704 static void
2705 atoascii(
2706 	const char *in,
2707 	size_t in_octets,
2708 	char *out,
2709 	size_t out_octets
2710 	)
2711 {
2712 	const u_char *	pchIn;
2713 	const u_char *	pchInLimit;
2714 	u_char *	pchOut;
2715 	u_char		c;
2716 
2717 	pchIn = (const u_char *)in;
2718 	pchInLimit = pchIn + in_octets;
2719 	pchOut = (u_char *)out;
2720 
2721 	if (NULL == pchIn) {
2722 		if (0 < out_octets)
2723 			*pchOut = '\0';
2724 		return;
2725 	}
2726 
2727 #define	ONEOUT(c)					\
2728 do {							\
2729 	if (0 == --out_octets) {			\
2730 		*pchOut = '\0';				\
2731 		return;					\
2732 	}						\
2733 	*pchOut++ = (c);				\
2734 } while (0)
2735 
2736 	for (	; pchIn < pchInLimit; pchIn++) {
2737 		c = *pchIn;
2738 		if ('\0' == c)
2739 			break;
2740 		if (c & 0x80) {
2741 			ONEOUT('M');
2742 			ONEOUT('-');
2743 			c &= 0x7f;
2744 		}
2745 		if (c < ' ') {
2746 			ONEOUT('^');
2747 			ONEOUT((u_char)(c + '@'));
2748 		} else if (0x7f == c) {
2749 			ONEOUT('^');
2750 			ONEOUT('?');
2751 		} else
2752 			ONEOUT(c);
2753 	}
2754 	ONEOUT('\0');
2755 
2756 #undef ONEOUT
2757 }
2758 
2759 
2760 /*
2761  * makeascii - print possibly ascii data using the character
2762  *	       transformations that cat -v uses.
2763  */
2764 void
2765 makeascii(
2766 	int length,
2767 	const char *data,
2768 	FILE *fp
2769 	)
2770 {
2771 	const u_char *data_u_char;
2772 	const u_char *cp;
2773 	int c;
2774 
2775 	data_u_char = (const u_char *)data;
2776 
2777 	for (cp = data_u_char; cp < data_u_char + length; cp++) {
2778 		c = (int)*cp;
2779 		if (c & 0x80) {
2780 			putc('M', fp);
2781 			putc('-', fp);
2782 			c &= 0x7f;
2783 		}
2784 
2785 		if (c < ' ') {
2786 			putc('^', fp);
2787 			putc(c + '@', fp);
2788 		} else if (0x7f == c) {
2789 			putc('^', fp);
2790 			putc('?', fp);
2791 		} else
2792 			putc(c, fp);
2793 	}
2794 }
2795 
2796 
2797 /*
2798  * asciize - same thing as makeascii except add a newline
2799  */
2800 void
2801 asciize(
2802 	int length,
2803 	char *data,
2804 	FILE *fp
2805 	)
2806 {
2807 	makeascii(length, data, fp);
2808 	putc('\n', fp);
2809 }
2810 
2811 
2812 /*
2813  * truncate string to fit clipping excess at end.
2814  *	"too long"	->	"too l"
2815  * Used for hostnames.
2816  */
2817 const char *
2818 trunc_right(
2819 	const char *	src,
2820 	size_t		width
2821 	)
2822 {
2823 	size_t	sl;
2824 	char *	out;
2825 
2826 
2827 	sl = strlen(src);
2828 	if (sl > width && LIB_BUFLENGTH - 1 > width && width > 0) {
2829 		LIB_GETBUF(out);
2830 		memcpy(out, src, width);
2831 		out[width] = '\0';
2832 
2833 		return out;
2834 	}
2835 
2836 	return src;
2837 }
2838 
2839 
2840 /*
2841  * truncate string to fit by preserving right side and using '_' to hint
2842  *	"too long"	->	"_long"
2843  * Used for local IPv6 addresses, where low bits differentiate.
2844  */
2845 const char *
2846 trunc_left(
2847 	const char *	src,
2848 	size_t		width
2849 	)
2850 {
2851 	size_t	sl;
2852 	char *	out;
2853 
2854 
2855 	sl = strlen(src);
2856 	if (sl > width && LIB_BUFLENGTH - 1 > width && width > 1) {
2857 		LIB_GETBUF(out);
2858 		out[0] = '_';
2859 		memcpy(&out[1], &src[sl + 1 - width], width);
2860 
2861 		return out;
2862 	}
2863 
2864 	return src;
2865 }
2866 
2867 
2868 /*
2869  * Some circular buffer space
2870  */
2871 #define	CBLEN	80
2872 #define	NUMCB	6
2873 
2874 char circ_buf[NUMCB][CBLEN];
2875 int nextcb = 0;
2876 
2877 /*
2878  * nextvar - find the next variable in the buffer
2879  */
2880 int
2881 nextvar(
2882 	int *datalen,
2883 	const char **datap,
2884 	char **vname,
2885 	char **vvalue
2886 	)
2887 {
2888 	const char *cp;
2889 	const char *np;
2890 	const char *cpend;
2891 	size_t srclen;
2892 	size_t len;
2893 	static char name[MAXVARLEN];
2894 	static char value[MAXVALLEN];
2895 
2896 	cp = *datap;
2897 	cpend = cp + *datalen;
2898 
2899 	/*
2900 	 * Space past commas and white space
2901 	 */
2902 	while (cp < cpend && (*cp == ',' || isspace((int)*cp)))
2903 		cp++;
2904 	if (cp >= cpend)
2905 		return 0;
2906 
2907 	/*
2908 	 * Copy name until we hit a ',', an '=', a '\r' or a '\n'.  Backspace
2909 	 * over any white space and terminate it.
2910 	 */
2911 	srclen = strcspn(cp, ",=\r\n");
2912 	srclen = min(srclen, (size_t)(cpend - cp));
2913 	len = srclen;
2914 	while (len > 0 && isspace((unsigned char)cp[len - 1]))
2915 		len--;
2916 	if (len > 0)
2917 		memcpy(name, cp, len);
2918 	name[len] = '\0';
2919 	*vname = name;
2920 	cp += srclen;
2921 
2922 	/*
2923 	 * Check if we hit the end of the buffer or a ','.  If so we are done.
2924 	 */
2925 	if (cp >= cpend || *cp == ',' || *cp == '\r' || *cp == '\n') {
2926 		if (cp < cpend)
2927 			cp++;
2928 		*datap = cp;
2929 		*datalen = cpend - cp;
2930 		*vvalue = NULL;
2931 		return 1;
2932 	}
2933 
2934 	/*
2935 	 * So far, so good.  Copy out the value
2936 	 */
2937 	cp++;	/* past '=' */
2938 	while (cp < cpend && (isspace((unsigned char)*cp) && *cp != '\r' && *cp != '\n'))
2939 		cp++;
2940 	np = cp;
2941 	if ('"' == *np) {
2942 		do {
2943 			np++;
2944 		} while (np < cpend && '"' != *np);
2945 		if (np < cpend && '"' == *np)
2946 			np++;
2947 	} else {
2948 		while (np < cpend && ',' != *np && '\r' != *np)
2949 			np++;
2950 	}
2951 	len = np - cp;
2952 	if (np > cpend || len >= sizeof(value) ||
2953 	    (np < cpend && ',' != *np && '\r' != *np))
2954 		return 0;
2955 	memcpy(value, cp, len);
2956 	/*
2957 	 * Trim off any trailing whitespace
2958 	 */
2959 	while (len > 0 && isspace((unsigned char)value[len - 1]))
2960 		len--;
2961 	value[len] = '\0';
2962 
2963 	/*
2964 	 * Return this.  All done.
2965 	 */
2966 	if (np < cpend && ',' == *np)
2967 		np++;
2968 	*datap = np;
2969 	*datalen = cpend - np;
2970 	*vvalue = value;
2971 	return 1;
2972 }
2973 
2974 
2975 u_short
2976 varfmt(const char * varname)
2977 {
2978 	u_int n;
2979 
2980 	for (n = 0; n < COUNTOF(cookedvars); n++)
2981 		if (!strcmp(varname, cookedvars[n].varname))
2982 			return cookedvars[n].fmt;
2983 
2984 	return PADDING;
2985 }
2986 
2987 
2988 /*
2989  * printvars - print variables returned in response packet
2990  */
2991 void
2992 printvars(
2993 	int length,
2994 	const char *data,
2995 	int status,
2996 	int sttype,
2997 	int quiet,
2998 	FILE *fp
2999 	)
3000 {
3001 	if (rawmode)
3002 	    rawprint(sttype, length, data, status, quiet, fp);
3003 	else
3004 	    cookedprint(sttype, length, data, status, quiet, fp);
3005 }
3006 
3007 
3008 /*
3009  * rawprint - do a printout of the data in raw mode
3010  */
3011 static void
3012 rawprint(
3013 	int datatype,
3014 	int length,
3015 	const char *data,
3016 	int status,
3017 	int quiet,
3018 	FILE *fp
3019 	)
3020 {
3021 	const char *cp;
3022 	const char *cpend;
3023 
3024 	/*
3025 	 * Essentially print the data as is.  We reformat unprintables, though.
3026 	 */
3027 	cp = data;
3028 	cpend = data + length;
3029 
3030 	if (!quiet)
3031 		(void) fprintf(fp, "status=0x%04x,\n", status);
3032 
3033 	while (cp < cpend) {
3034 		if (*cp == '\r') {
3035 			/*
3036 			 * If this is a \r and the next character is a
3037 			 * \n, supress this, else pretty print it.  Otherwise
3038 			 * just output the character.
3039 			 */
3040 			if (cp == (cpend - 1) || *(cp + 1) != '\n')
3041 			    makeascii(1, cp, fp);
3042 		} else if (isspace((unsigned char)*cp) || isprint((unsigned char)*cp))
3043 			putc(*cp, fp);
3044 		else
3045 			makeascii(1, cp, fp);
3046 		cp++;
3047 	}
3048 }
3049 
3050 
3051 /*
3052  * Global data used by the cooked output routines
3053  */
3054 int out_chars;		/* number of characters output */
3055 int out_linecount;	/* number of characters output on this line */
3056 
3057 
3058 /*
3059  * startoutput - get ready to do cooked output
3060  */
3061 static void
3062 startoutput(void)
3063 {
3064 	out_chars = 0;
3065 	out_linecount = 0;
3066 }
3067 
3068 
3069 /*
3070  * output - output a variable=value combination
3071  */
3072 static void
3073 output(
3074 	FILE *fp,
3075 	const char *name,
3076 	const char *value
3077 	)
3078 {
3079 	size_t len;
3080 
3081 	/* strlen of "name=value" */
3082 	len = strlen(name) + 1 + strlen(value);
3083 
3084 	if (out_chars != 0) {
3085 		out_chars += 2;
3086 		if ((out_linecount + len + 2) > MAXOUTLINE) {
3087 			fputs(",\n", fp);
3088 			out_linecount = 0;
3089 		} else {
3090 			fputs(", ", fp);
3091 			out_linecount += 2;
3092 		}
3093 	}
3094 
3095 	fputs(name, fp);
3096 	putc('=', fp);
3097 	fputs(value, fp);
3098 	out_chars += len;
3099 	out_linecount += len;
3100 }
3101 
3102 
3103 /*
3104  * endoutput - terminate a block of cooked output
3105  */
3106 static void
3107 endoutput(
3108 	FILE *fp
3109 	)
3110 {
3111 	if (out_chars != 0)
3112 		putc('\n', fp);
3113 }
3114 
3115 
3116 /*
3117  * outputarr - output an array of values
3118  */
3119 static void
3120 outputarr(
3121 	FILE *fp,
3122 	char *name,
3123 	int narr,
3124 	l_fp *lfp
3125 	)
3126 {
3127 	register char *bp;
3128 	register char *cp;
3129 	register int i;
3130 	register int len;
3131 	char buf[256];
3132 
3133 	bp = buf;
3134 	/*
3135 	 * Hack to align delay and offset values
3136 	 */
3137 	for (i = (int)strlen(name); i < 11; i++)
3138 	    *bp++ = ' ';
3139 
3140 	for (i = narr; i > 0; i--) {
3141 		if (i != narr)
3142 		    *bp++ = ' ';
3143 		cp = lfptoms(lfp, 2);
3144 		len = strlen(cp);
3145 		if (len > 7) {
3146 			cp[7] = '\0';
3147 			len = 7;
3148 		}
3149 		while (len < 7) {
3150 			*bp++ = ' ';
3151 			len++;
3152 		}
3153 		while (*cp != '\0')
3154 		    *bp++ = *cp++;
3155 		lfp++;
3156 	}
3157 	*bp = '\0';
3158 	output(fp, name, buf);
3159 }
3160 
3161 static char *
3162 tstflags(
3163 	u_long val
3164 	)
3165 {
3166 	register char *cp, *s;
3167 	size_t cb;
3168 	register int i;
3169 	register const char *sep;
3170 
3171 	sep = "";
3172 	i = 0;
3173 	s = cp = circ_buf[nextcb];
3174 	if (++nextcb >= NUMCB)
3175 		nextcb = 0;
3176 	cb = sizeof(circ_buf[0]);
3177 
3178 	snprintf(cp, cb, "%02lx", val);
3179 	cp += strlen(cp);
3180 	cb -= strlen(cp);
3181 	if (!val) {
3182 		strlcat(cp, " ok", cb);
3183 		cp += strlen(cp);
3184 		cb -= strlen(cp);
3185 	} else {
3186 		if (cb) {
3187 			*cp++ = ' ';
3188 			cb--;
3189 		}
3190 		for (i = 0; i < (int)COUNTOF(tstflagnames); i++) {
3191 			if (val & 0x1) {
3192 				snprintf(cp, cb, "%s%s", sep,
3193 					 tstflagnames[i]);
3194 				sep = ", ";
3195 				cp += strlen(cp);
3196 				cb -= strlen(cp);
3197 			}
3198 			val >>= 1;
3199 		}
3200 	}
3201 	if (cb)
3202 		*cp = '\0';
3203 
3204 	return s;
3205 }
3206 
3207 /*
3208  * cookedprint - output variables in cooked mode
3209  */
3210 static void
3211 cookedprint(
3212 	int datatype,
3213 	int length,
3214 	const char *data,
3215 	int status,
3216 	int quiet,
3217 	FILE *fp
3218 	)
3219 {
3220 	char *name;
3221 	char *value;
3222 	char output_raw;
3223 	int fmt;
3224 	l_fp lfp;
3225 	sockaddr_u hval;
3226 	u_long uval;
3227 	int narr;
3228 	size_t len;
3229 	l_fp lfparr[8];
3230 	char b[12];
3231 	char bn[2 * MAXVARLEN];
3232 	char bv[2 * MAXVALLEN];
3233 
3234 	UNUSED_ARG(datatype);
3235 
3236 	if (!quiet)
3237 		fprintf(fp, "status=%04x %s,\n", status,
3238 			statustoa(datatype, status));
3239 
3240 	startoutput();
3241 	while (nextvar(&length, &data, &name, &value)) {
3242 		fmt = varfmt(name);
3243 		output_raw = 0;
3244 		switch (fmt) {
3245 
3246 		case PADDING:
3247 			output_raw = '*';
3248 			break;
3249 
3250 		case TS:
3251 			if (!decodets(value, &lfp))
3252 				output_raw = '?';
3253 			else
3254 				output(fp, name, prettydate(&lfp));
3255 			break;
3256 
3257 		case HA:	/* fallthru */
3258 		case NA:
3259 			if (!decodenetnum(value, &hval)) {
3260 				output_raw = '?';
3261 			} else if (fmt == HA){
3262 				output(fp, name, nntohost(&hval));
3263 			} else {
3264 				output(fp, name, stoa(&hval));
3265 			}
3266 			break;
3267 
3268 		case RF:
3269 			if (decodenetnum(value, &hval)) {
3270 				if (ISREFCLOCKADR(&hval))
3271 					output(fp, name,
3272 					       refnumtoa(&hval));
3273 				else
3274 					output(fp, name, stoa(&hval));
3275 			} else if (strlen(value) <= 4) {
3276 				output(fp, name, value);
3277 			} else {
3278 				output_raw = '?';
3279 			}
3280 			break;
3281 
3282 		case LP:
3283 			if (!decodeuint(value, &uval) || uval > 3) {
3284 				output_raw = '?';
3285 			} else {
3286 				b[0] = (0x2 & uval)
3287 					   ? '1'
3288 					   : '0';
3289 				b[1] = (0x1 & uval)
3290 					   ? '1'
3291 					   : '0';
3292 				b[2] = '\0';
3293 				output(fp, name, b);
3294 			}
3295 			break;
3296 
3297 		case OC:
3298 			if (!decodeuint(value, &uval)) {
3299 				output_raw = '?';
3300 			} else {
3301 				snprintf(b, sizeof(b), "%03lo", uval);
3302 				output(fp, name, b);
3303 			}
3304 			break;
3305 
3306 		case AR:
3307 			if (!decodearr(value, &narr, lfparr))
3308 				output_raw = '?';
3309 			else
3310 				outputarr(fp, name, narr, lfparr);
3311 			break;
3312 
3313 		case FX:
3314 			if (!decodeuint(value, &uval))
3315 				output_raw = '?';
3316 			else
3317 				output(fp, name, tstflags(uval));
3318 			break;
3319 
3320 		default:
3321 			fprintf(stderr, "Internal error in cookedprint, %s=%s, fmt %d\n",
3322 				name, value, fmt);
3323 			output_raw = '?';
3324 			break;
3325 		}
3326 
3327 		if (output_raw != 0) {
3328 			atoascii(name, MAXVARLEN, bn, sizeof(bn));
3329 			atoascii(value, MAXVALLEN, bv, sizeof(bv));
3330 			if (output_raw != '*') {
3331 				len = strlen(bv);
3332 				bv[len] = output_raw;
3333 				bv[len+1] = '\0';
3334 			}
3335 			output(fp, bn, bv);
3336 		}
3337 	}
3338 	endoutput(fp);
3339 }
3340 
3341 
3342 /*
3343  * sortassoc - sort associations in the cache into ascending order
3344  */
3345 void
3346 sortassoc(void)
3347 {
3348 	if (numassoc > 1)
3349 		qsort(assoc_cache, (size_t)numassoc,
3350 		      sizeof(assoc_cache[0]), &assoccmp);
3351 }
3352 
3353 
3354 /*
3355  * assoccmp - compare two associations
3356  */
3357 static int
3358 assoccmp(
3359 	const void *t1,
3360 	const void *t2
3361 	)
3362 {
3363 	const struct association *ass1 = t1;
3364 	const struct association *ass2 = t2;
3365 
3366 	if (ass1->assid < ass2->assid)
3367 		return -1;
3368 	if (ass1->assid > ass2->assid)
3369 		return 1;
3370 	return 0;
3371 }
3372 
3373 
3374 /*
3375  * grow_assoc_cache() - enlarge dynamic assoc_cache array
3376  *
3377  * The strategy is to add an assumed 4k page size at a time, leaving
3378  * room for malloc() bookkeeping overhead equivalent to 4 pointers.
3379  */
3380 void
3381 grow_assoc_cache(void)
3382 {
3383 	static size_t	prior_sz;
3384 	size_t		new_sz;
3385 
3386 	new_sz = prior_sz + 4 * 1024;
3387 	if (0 == prior_sz) {
3388 		new_sz -= 4 * sizeof(void *);
3389 	}
3390 	assoc_cache = erealloc_zero(assoc_cache, new_sz, prior_sz);
3391 	prior_sz = new_sz;
3392 	assoc_cache_slots = new_sz / sizeof(assoc_cache[0]);
3393 }
3394 
3395 
3396 /*
3397  * ntpq_custom_opt_handler - autoopts handler for -c and -p
3398  *
3399  * By default, autoopts loses the relative order of -c and -p options
3400  * on the command line.  This routine replaces the default handler for
3401  * those routines and builds a list of commands to execute preserving
3402  * the order.
3403  */
3404 void
3405 ntpq_custom_opt_handler(
3406 	tOptions *pOptions,
3407 	tOptDesc *pOptDesc
3408 	)
3409 {
3410 	switch (pOptDesc->optValue) {
3411 
3412 	default:
3413 		fprintf(stderr,
3414 			"ntpq_custom_opt_handler unexpected option '%c' (%d)\n",
3415 			pOptDesc->optValue, pOptDesc->optValue);
3416 		exit(1);
3417 
3418 	case 'c':
3419 		ADDCMD(pOptDesc->pzLastArg);
3420 		break;
3421 
3422 	case 'p':
3423 		ADDCMD("peers");
3424 		break;
3425 	}
3426 }
3427