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