xref: /freebsd/contrib/ntp/ntpdc/ntpdc_ops.c (revision b52b9d56d4e96089873a75f9e29062eec19fabba)
1 /*
2  * ntpdc_ops.c - subroutines which are called to perform operations by ntpdc
3  */
4 
5 #ifdef HAVE_CONFIG_H
6 # include <config.h>
7 #endif
8 
9 #include <stdio.h>
10 
11 #include "ntpdc.h"
12 #include "ntp_control.h"
13 #include "ntp_refclock.h"
14 #include "ntp_stdlib.h"
15 
16 #include <ctype.h>
17 #ifdef HAVE_SYS_TIMEX_H
18 # include <sys/timex.h>
19 #endif
20 #include <netdb.h>
21 #if !defined(__bsdi__) && !defined(apollo)
22 #include <netinet/in.h>
23 #endif
24 
25 #include <arpa/inet.h>
26 
27 /*
28  * Declarations for command handlers in here
29  */
30 static	int	checkitems	P((int, FILE *));
31 static	int	checkitemsize	P((int, int));
32 static	int	check1item	P((int, FILE *));
33 static	void	peerlist	P((struct parse *, FILE *));
34 static	void	peers		P((struct parse *, FILE *));
35 static void	doconfig	P((struct parse *pcmd, FILE *fp, int mode, int refc));
36 static	void	dmpeers		P((struct parse *, FILE *));
37 static	void	dopeers		P((struct parse *, FILE *, int));
38 static	void	printpeer	P((struct info_peer *, FILE *));
39 static	void	showpeer	P((struct parse *, FILE *));
40 static	void	peerstats	P((struct parse *, FILE *));
41 static	void	loopinfo	P((struct parse *, FILE *));
42 static	void	sysinfo		P((struct parse *, FILE *));
43 static	void	sysstats	P((struct parse *, FILE *));
44 static	void	iostats		P((struct parse *, FILE *));
45 static	void	memstats	P((struct parse *, FILE *));
46 static	void	timerstats	P((struct parse *, FILE *));
47 static	void	addpeer		P((struct parse *, FILE *));
48 static	void	addserver	P((struct parse *, FILE *));
49 static	void	addrefclock	P((struct parse *, FILE *));
50 static	void	broadcast	P((struct parse *, FILE *));
51 static	void	doconfig	P((struct parse *, FILE *, int, int));
52 static	void	unconfig	P((struct parse *, FILE *));
53 static	void	set		P((struct parse *, FILE *));
54 static	void	sys_clear	P((struct parse *, FILE *));
55 static	void	doset		P((struct parse *, FILE *, int));
56 static	void	reslist		P((struct parse *, FILE *));
57 static	void	new_restrict	P((struct parse *, FILE *));
58 static	void	unrestrict	P((struct parse *, FILE *));
59 static	void	delrestrict	P((struct parse *, FILE *));
60 static	void	do_restrict	P((struct parse *, FILE *, int));
61 static	void	monlist		P((struct parse *, FILE *));
62 static	void	reset		P((struct parse *, FILE *));
63 static	void	preset		P((struct parse *, FILE *));
64 static	void	readkeys	P((struct parse *, FILE *));
65 static	void	trustkey	P((struct parse *, FILE *));
66 static	void	untrustkey	P((struct parse *, FILE *));
67 static	void	do_trustkey	P((struct parse *, FILE *, int));
68 static	void	authinfo	P((struct parse *, FILE *));
69 static	void	traps		P((struct parse *, FILE *));
70 static	void	addtrap		P((struct parse *, FILE *));
71 static	void	clrtrap		P((struct parse *, FILE *));
72 static	void	do_addclr_trap	P((struct parse *, FILE *, int));
73 static	void	requestkey	P((struct parse *, FILE *));
74 static	void	controlkey	P((struct parse *, FILE *));
75 static	void	do_changekey	P((struct parse *, FILE *, int));
76 static	void	ctlstats	P((struct parse *, FILE *));
77 static	void	clockstat	P((struct parse *, FILE *));
78 static	void	fudge		P((struct parse *, FILE *));
79 static	void	clkbug		P((struct parse *, FILE *));
80 static	void	kerninfo	P((struct parse *, FILE *));
81 
82 /*
83  * Commands we understand.  Ntpdc imports this.
84  */
85 struct xcmd opcmds[] = {
86 	{ "listpeers",	peerlist,	{  NO, NO, NO, NO },
87 	  { "", "", "", "" },
88 	  "display list of peers the server knows about" },
89 	{ "peers",	peers,		{ NO, NO, NO, NO },
90 	  { "", "", "", "" },
91 	  "display peer summary information" },
92 	{ "dmpeers",	dmpeers,	{ NO, NO, NO, NO },
93 	  { "", "", "", "" },
94 	  "display peer summary info the way Dave Mills likes it" },
95 	{ "showpeer",	showpeer,	{ ADD, OPT|ADD, OPT|ADD, OPT|ADD },
96 	  { "peer_address", "peer2_addr", "peer3_addr", "peer4_addr" },
97 	  "display detailed information for one or more peers" },
98 	{ "pstats",	peerstats,	{ ADD, OPT|ADD, OPT|ADD, OPT|ADD },
99 	  { "peer_address", "peer2_addr", "peer3_addr", "peer4_addr" },
100 	  "display statistical information for one or more peers" },
101 	{ "loopinfo",	loopinfo,	{ OPT|NTP_STR, NO, NO, NO },
102 	  { "oneline|multiline", "", "", "" },
103 	  "display loop filter information" },
104 	{ "sysinfo",	sysinfo,	{ NO, NO, NO, NO },
105 	  { "", "", "", "" },
106 	  "display local server information" },
107 	{ "sysstats",	sysstats,	{ NO, NO, NO, NO },
108 	  { "", "", "", "" },
109 	  "display local server statistics" },
110 	{ "memstats",	memstats,	{ NO, NO, NO, NO },
111 	  { "", "", "", "" },
112 	  "display peer memory usage statistics" },
113 	{ "iostats",	iostats,	{ NO, NO, NO, NO },
114 	  { "", "", "", "" },
115 	  "display I/O subsystem statistics" },
116 	{ "timerstats",	timerstats,	{ NO, NO, NO, NO },
117 	  { "", "", "", "" },
118 	  "display event timer subsystem statistics" },
119 	{ "addpeer",	addpeer,	{ ADD, OPT|UINT, OPT|UINT, OPT|NTP_STR },
120 	  { "addr", "keyid", "version", "minpoll|prefer" },
121 	  "configure a new peer association" },
122 	{ "addserver",	addserver,	{ ADD, OPT|UINT, OPT|UINT, OPT|NTP_STR },
123 	  { "addr", "keyid", "version", "minpoll|prefer" },
124 	  "configure a new server" },
125 	{ "addrefclock",addrefclock,	{ ADD, OPT|UINT, OPT|NTP_STR, OPT|NTP_STR },
126 	  { "addr", "mode", "minpoll|prefer", "minpoll|prefer" },
127 	  "configure a new server" },
128 	{ "broadcast",	broadcast,	{ ADD, OPT|UINT, OPT|UINT, OPT|NTP_STR },
129 	  { "addr", "keyid", "version", "minpoll" },
130 	  "configure broadcasting time service" },
131 	{ "unconfig",	unconfig,	{ ADD, OPT|ADD, OPT|ADD, OPT|ADD },
132 	  { "peer_address", "peer2_addr", "peer3_addr", "peer4_addr" },
133 	  "unconfigure existing peer assocations" },
134 	{ "enable",	set,		{ NTP_STR, OPT|NTP_STR, OPT|NTP_STR, OPT|NTP_STR },
135 	  { "auth|bclient|monitor|pll|kernel|stats", "...", "...", "..." },
136 	  "set a system flag (auth, bclient, monitor, pll, kernel, stats)" },
137         { "disable",	sys_clear,      { NTP_STR, OPT|NTP_STR, OPT|NTP_STR, OPT|NTP_STR },
138 	  { "auth|bclient|monitor|pll|kernel|stats", "...", "...", "..." },
139 	  "clear a system flag (auth, bclient, monitor, pll, kernel, stats)" },
140 	{ "reslist",	reslist,	{ NO, NO, NO, NO },
141 	  { "", "", "", "" },
142 	  "display the server's restrict list" },
143 	{ "restrict",	new_restrict,	{ ADD, ADD, NTP_STR, OPT|NTP_STR },
144 	  { "address", "mask",
145 	    "ntpport|ignore|noserve|notrust|noquery|nomodify|nopeer|version|kod",
146 	    "..." },
147 	  "create restrict entry/add flags to entry" },
148 	{ "unrestrict", unrestrict,	{ ADD, ADD, NTP_STR, OPT|NTP_STR },
149 	  { "address", "mask",
150 	    "ntpport|ignore|noserve|notrust|noquery|nomodify|nopeer|version|kod",
151 	    "..." },
152 	  "remove flags from a restrict entry" },
153 	{ "delrestrict", delrestrict,	{ ADD, ADD, OPT|NTP_STR, NO },
154 	  { "address", "mask", "ntpport", "" },
155 	  "delete a restrict entry" },
156 	{ "monlist",	monlist,	{ OPT|INT, NO, NO, NO },
157 	  { "version", "", "", "" },
158 	  "display data the server's monitor routines have collected" },
159 	{ "reset",	reset,		{ NTP_STR, OPT|NTP_STR, OPT|NTP_STR, OPT|NTP_STR },
160 	  { "io|sys|mem|timer|auth|allpeers", "...", "...", "..." },
161 	  "reset various subsystem statistics counters" },
162 	{ "preset",	preset,		{ ADD, OPT|ADD, OPT|ADD, OPT|ADD },
163 	  { "peer_address", "peer2_addr", "peer3_addr", "peer4_addr" },
164 	  "reset stat counters associated with particular peer(s)" },
165 	{ "readkeys",	readkeys,	{ NO, NO, NO, NO },
166 	  { "", "", "", "" },
167 	  "request a reread of the keys file and re-init of system keys" },
168 	{ "trustedkey",	trustkey,	{ UINT, OPT|UINT, OPT|UINT, OPT|UINT },
169 	  { "keyid", "keyid", "keyid", "keyid" },
170 	  "add one or more key ID's to the trusted list" },
171 	{ "untrustedkey", untrustkey,	{ UINT, OPT|UINT, OPT|UINT, OPT|UINT },
172 	  { "keyid", "keyid", "keyid", "keyid" },
173 	  "remove one or more key ID's from the trusted list" },
174 	{ "authinfo",	authinfo,	{ NO, NO, NO, NO },
175 	  { "", "", "", "" },
176 	  "display the state of the authentication code" },
177 	{ "traps",	traps,		{ NO, NO, NO, NO },
178 	  { "", "", "", "" },
179 	  "display the traps set in the server" },
180 	{ "addtrap",	addtrap,	{ ADD, OPT|UINT, OPT|ADD, NO },
181 	  { "address", "port", "interface", "" },
182 	  "configure a trap in the server" },
183 	{ "clrtrap",	clrtrap,	{ ADD, OPT|UINT, OPT|ADD, NO },
184 	  { "address", "port", "interface", "" },
185 	  "remove a trap (configured or otherwise) from the server" },
186 	{ "requestkey",	requestkey,	{ UINT, NO, NO, NO },
187 	  { "keyid", "", "", "" },
188 	  "change the keyid the server uses to authenticate requests" },
189 	{ "controlkey",	controlkey,	{ UINT, NO, NO, NO },
190 	  { "keyid", "", "", "" },
191 	  "change the keyid the server uses to authenticate control messages" },
192 	{ "ctlstats",	ctlstats,	{ NO, NO, NO, NO },
193 	  { "", "", "", "" },
194 	  "display packet count statistics from the control module" },
195 	{ "clockstat",	clockstat,	{ ADD, OPT|ADD, OPT|ADD, OPT|ADD },
196 	  { "address", "address", "address", "address" },
197 	  "display clock status information" },
198 	{ "fudge",	fudge,		{ ADD, NTP_STR, NTP_STR, NO },
199 	  { "address", "time1|time2|val1|val2|flags", "value", "" },
200 	  "set/change one of a clock's fudge factors" },
201 	{ "clkbug",	clkbug,		{ ADD, OPT|ADD, OPT|ADD, OPT|ADD },
202 	  { "address", "address", "address", "address" },
203 	  "display clock debugging information" },
204 	{ "kerninfo",	kerninfo,	{ NO, NO, NO, NO },
205 	  { "", "", "", "" },
206 	  "display the kernel pll/pps variables" },
207 
208 	{ 0,		0,		{ NO, NO, NO, NO },
209 	  { "", "", "", "" }, "" }
210 };
211 
212 
213 /*
214  * Imported from ntpdc.c
215  */
216 extern int showhostnames;
217 extern struct servent *server_entry;
218 
219 /*
220  * For quick string comparisons
221  */
222 #define	STREQ(a, b)	(*(a) == *(b) && strcmp((a), (b)) == 0)
223 
224 
225 /*
226  * checkitems - utility to print a message if no items were returned
227  */
228 static int
229 checkitems(
230 	int items,
231 	FILE *fp
232 	)
233 {
234 	if (items == 0) {
235 		(void) fprintf(fp, "No data returned in response to query\n");
236 		return 0;
237 	}
238 	return 1;
239 }
240 
241 
242 /*
243  * checkitemsize - utility to print a message if the item size is wrong
244  */
245 static int
246 checkitemsize(
247 	int itemsize,
248 	int expected
249 	)
250 {
251 	if (itemsize != expected) {
252 		(void) fprintf(stderr,
253 			       "***Incorrect item size returned by remote host (%d should be %d)\n",
254 			       itemsize, expected);
255 		return 0;
256 	}
257 	return 1;
258 }
259 
260 
261 /*
262  * check1item - check to make sure we have exactly one item
263  */
264 static int
265 check1item(
266 	int items,
267 	FILE *fp
268 	)
269 {
270 	if (items == 0) {
271 		(void) fprintf(fp, "No data returned in response to query\n");
272 		return 0;
273 	}
274 	if (items > 1) {
275 		(void) fprintf(fp, "Expected one item in response, got %d\n",
276 			       items);
277 		return 0;
278 	}
279 	return 1;
280 }
281 
282 
283 
284 /*
285  * peerlist - get a short list of peers
286  */
287 /*ARGSUSED*/
288 static void
289 peerlist(
290 	struct parse *pcmd,
291 	FILE *fp
292 	)
293 {
294 	struct info_peer_list *plist;
295 	int items;
296 	int itemsize;
297 	int res;
298 
299 	res = doquery(IMPL_XNTPD, REQ_PEER_LIST, 0, 0, 0, (char *)NULL, &items,
300 		      &itemsize, (char **)&plist, 0);
301 
302 	if (res != 0 && items == 0)
303 	    return;
304 
305 	if (!checkitems(items, fp))
306 	    return;
307 
308 	if (!checkitemsize(itemsize, sizeof(struct info_peer_list)))
309 	    return;
310 
311 	while (items > 0) {
312 		(void) fprintf(fp, "%-9s %s\n", modetoa(plist->hmode),
313 			       nntohost(plist->address));
314 		plist++;
315 		items--;
316 	}
317 }
318 
319 
320 /*
321  * peers - show peer summary
322  */
323 static void
324 peers(
325 	struct parse *pcmd,
326 	FILE *fp
327 	)
328 {
329 	dopeers(pcmd, fp, 0);
330 }
331 
332 /*
333  * dmpeers - show peer summary, Dave Mills style
334  */
335 static void
336 dmpeers(
337 	struct parse *pcmd,
338 	FILE *fp
339 	)
340 {
341 	dopeers(pcmd, fp, 1);
342 }
343 
344 
345 /*
346  * peers - show peer summary
347  */
348 /*ARGSUSED*/
349 static void
350 dopeers(
351 	struct parse *pcmd,
352 	FILE *fp,
353 	int dmstyle
354 	)
355 {
356 	struct info_peer_summary *plist;
357 	int items;
358 	int itemsize;
359 	int ntp_poll;
360 	int res;
361 	int c;
362 	l_fp tempts;
363 
364 	res = doquery(IMPL_XNTPD, REQ_PEER_LIST_SUM, 0, 0, 0, (char *)NULL,
365 		      &items, &itemsize, (char **)&plist, 0);
366 
367 	if (res != 0 && items == 0)
368 	    return;
369 
370 	if (!checkitems(items, fp))
371 	    return;
372 
373 	if (!checkitemsize(itemsize, sizeof(struct info_peer_summary)))
374 	    return;
375 
376 	(void) fprintf(fp,
377 		       "     remote           local      st poll reach  delay   offset    disp\n");
378 	(void) fprintf(fp,
379 		       "=======================================================================\n");
380 	while (items > 0) {
381 		if (!dmstyle) {
382 			if (plist->flags & INFO_FLAG_SYSPEER)
383 			    c = '*';
384 			else if (plist->hmode == MODE_ACTIVE)
385 			    c = '+';
386 			else if (plist->hmode == MODE_PASSIVE)
387 			    c = '-';
388 			else if (plist->hmode == MODE_CLIENT)
389 			    c = '=';
390 			else if (plist->hmode == MODE_BROADCAST)
391 			    c = '^';
392 			else if (plist->hmode == MODE_BCLIENT)
393 			    c = '~';
394 			else
395 			    c = ' ';
396 		} else {
397 			if (plist->flags & INFO_FLAG_SYSPEER)
398 			    c = '*';
399 			else if (plist->flags & INFO_FLAG_SHORTLIST)
400 			    c = '+';
401 			else if (plist->flags & INFO_FLAG_SEL_CANDIDATE)
402 			    c = '.';
403 			else
404 			    c = ' ';
405 		}
406 		NTOHL_FP(&(plist->offset), &tempts);
407 		ntp_poll = 1<<max(min3(plist->ppoll, plist->hpoll, NTP_MAXPOLL),
408 				  NTP_MINPOLL);
409 		(void) fprintf(fp,
410 			       "%c%-15.15s %-15.15s %2d %4d  %3o %7.7s %9.9s %7.7s\n",
411 			       c, nntohost(plist->srcadr),
412 			       numtoa(plist->dstadr),
413 			       plist->stratum, ntp_poll, plist->reach,
414 			       fptoa(NTOHS_FP(plist->delay), 5),
415 			       lfptoa(&tempts, 6),
416 			       ufptoa(NTOHS_FP(plist->dispersion), 5));
417 
418 		plist++;
419 		items--;
420 	}
421 }
422 
423 /* Convert a refid & stratum (in host order) to a string */
424 static char*
425 refid_string(
426 	u_int32 refid,
427 	int stratum
428 	)
429 {
430 	if (stratum <= 1) {
431 		static char junk[5];
432 		junk[4] = 0;
433 		memmove(junk, (char *)&refid, 4);
434 		return junk;
435 	}
436 
437 	return numtoa(refid);
438 }
439 
440 /*
441  * printpeer - print detail information for a peer
442  */
443 static void
444 printpeer(
445 	register struct info_peer *pp,
446 	FILE *fp
447 	)
448 {
449 	register int i;
450 	const char *str;
451 	l_fp tempts;
452 
453 	(void) fprintf(fp, "remote %s, local %s\n",
454 		       numtoa(pp->srcadr), numtoa(pp->dstadr));
455 
456 	(void) fprintf(fp, "hmode %s, pmode %s, stratum %d, precision %d\n",
457 		       modetoa(pp->hmode), modetoa(pp->pmode),
458 		       pp->stratum, pp->precision);
459 
460 	(void) fprintf(fp,
461 		       "leap %c%c, refid [%s], rootdistance %s, rootdispersion %s\n",
462 		       pp->leap & 0x2 ? '1' : '0',
463 		       pp->leap & 0x1 ? '1' : '0',
464 		       refid_string(pp->refid, pp->stratum), fptoa(NTOHS_FP(pp->rootdelay), 5),
465 		       ufptoa(NTOHS_FP(pp->rootdispersion), 5));
466 
467 	(void) fprintf(fp,
468 		       "ppoll %d, hpoll %d, keyid %lu, version %d, association %u\n",
469 		       pp->ppoll, pp->hpoll, (u_long)pp->keyid, pp->version, ntohs(pp->associd));
470 
471 	(void) fprintf(fp,
472 		       "reach %03o, unreach %d, flash 0x%04x, ",
473 		       pp->reach, pp->unreach, pp->flash2);
474 
475 	(void) fprintf(fp, "boffset %s, ttl/mode %d\n",
476 		       fptoa(NTOHS_FP(pp->estbdelay), 5), pp->ttl);
477 
478 	(void) fprintf(fp, "timer %lds, flags", (long)ntohl(pp->timer));
479 	if (pp->flags == 0) {
480 		(void) fprintf(fp, " none\n");
481 	} else {
482 		str = "";
483 		if (pp->flags & INFO_FLAG_SYSPEER) {
484 			(void) fprintf(fp, " system_peer");
485 			str = ",";
486 		}
487 		if (pp->flags & INFO_FLAG_CONFIG) {
488 			(void) fprintf(fp, "%s config", str);
489 			str = ",";
490 		}
491 		if (pp->flags & INFO_FLAG_REFCLOCK) {
492 			(void) fprintf(fp, "%s refclock", str);
493 			str = ",";
494 		}
495 		if (pp->flags & INFO_FLAG_AUTHENABLE) {
496 			(void) fprintf(fp, "%s auth", str);
497 			str = ",";
498 		}
499 		if (pp->flags & INFO_FLAG_BCLIENT) {
500 			(void) fprintf(fp, "%s bclient", str);
501 			str = ",";
502 		}
503 		if (pp->flags & INFO_FLAG_PREFER) {
504 			(void) fprintf(fp, "%s prefer", str);
505 			str = ",";
506 		}
507 		if (pp->flags & INFO_FLAG_BURST) {
508 			(void) fprintf(fp, "%s burst", str);
509 		}
510 		(void) fprintf(fp, "\n");
511 	}
512 
513 	NTOHL_FP(&pp->reftime, &tempts);
514 	(void) fprintf(fp, "reference time:      %s\n",
515 		       prettydate(&tempts));
516 	NTOHL_FP(&pp->org, &tempts);
517 	(void) fprintf(fp, "originate timestamp: %s\n",
518 		       prettydate(&tempts));
519 	NTOHL_FP(&pp->rec, &tempts);
520 	(void) fprintf(fp, "receive timestamp:   %s\n",
521 		       prettydate(&tempts));
522 	NTOHL_FP(&pp->xmt, &tempts);
523 	(void) fprintf(fp, "transmit timestamp:  %s\n",
524 		       prettydate(&tempts));
525 
526 	(void) fprintf(fp, "filter delay: ");
527 	for (i = 0; i < NTP_SHIFT; i++) {
528 		(void) fprintf(fp, " %-8.8s",
529 			       fptoa(NTOHS_FP(pp->filtdelay[i]), 5));
530 		if (i == (NTP_SHIFT>>1)-1)
531 		    (void) fprintf(fp, "\n              ");
532 	}
533 	(void) fprintf(fp, "\n");
534 
535 	(void) fprintf(fp, "filter offset:");
536 	for (i = 0; i < NTP_SHIFT; i++) {
537 		NTOHL_FP(&pp->filtoffset[i], &tempts);
538 		(void) fprintf(fp, " %-8.8s", lfptoa(&tempts, 6));
539 		if (i == (NTP_SHIFT>>1)-1)
540 		    (void) fprintf(fp, "\n              ");
541 	}
542 	(void) fprintf(fp, "\n");
543 
544 	(void) fprintf(fp, "filter order: ");
545 	for (i = 0; i < NTP_SHIFT; i++) {
546 		(void) fprintf(fp, " %-8d", pp->order[i]);
547 		if (i == (NTP_SHIFT>>1)-1)
548 		    (void) fprintf(fp, "\n              ");
549 	}
550 	(void) fprintf(fp, "\n");
551 
552 
553 	NTOHL_FP(&pp->offset, &tempts);
554 	(void) fprintf(fp,
555 		       "offset %s, delay %s, error bound %s, filter error %s\n",
556 		       lfptoa(&tempts, 6), fptoa(NTOHS_FP(pp->delay), 5),
557 		       ufptoa(NTOHS_FP(pp->dispersion), 5),
558 		       ufptoa(NTOHS_FP(pp->selectdisp), 5));
559 }
560 
561 
562 /*
563  * showpeer - show detailed information for a peer
564  */
565 static void
566 showpeer(
567 	struct parse *pcmd,
568 	FILE *fp
569 	)
570 {
571 	struct info_peer *pp;
572 	/* 4 is the maximum number of peers which will fit in a packet */
573 	struct info_peer_list plist[min(MAXARGS, 4)];
574 	int qitems;
575 	int items;
576 	int itemsize;
577 	int res;
578 
579 	for (qitems = 0; qitems < min(pcmd->nargs, 4); qitems++) {
580 		plist[qitems].address = pcmd->argval[qitems].netnum;
581 		plist[qitems].port = server_entry->s_port;
582 		plist[qitems].hmode = plist[qitems].flags = 0;
583 	}
584 
585 	res = doquery(IMPL_XNTPD, REQ_PEER_INFO, 0, qitems,
586 		      sizeof(struct info_peer_list), (char *)plist, &items,
587 		      &itemsize, (char **)&pp, 0);
588 
589 	if (res != 0 && items == 0)
590 	    return;
591 
592 	if (!checkitems(items, fp))
593 	    return;
594 
595 	if (!checkitemsize(itemsize, sizeof(struct info_peer)))
596 	    return;
597 
598 	while (items-- > 0) {
599 		printpeer(pp, fp);
600 		if (items > 0)
601 		    (void) fprintf(fp, "\n");
602 		pp++;
603 	}
604 }
605 
606 
607 /*
608  * peerstats - return statistics for a peer
609  */
610 static void
611 peerstats(
612 	struct parse *pcmd,
613 	FILE *fp
614 	)
615 {
616 	struct info_peer_stats *pp;
617 	/* 4 is the maximum number of peers which will fit in a packet */
618 	struct info_peer_list plist[min(MAXARGS, 4)];
619 	int qitems;
620 	int items;
621 	int itemsize;
622 	int res;
623 
624 	for (qitems = 0; qitems < min(pcmd->nargs, 4); qitems++) {
625 		plist[qitems].address = pcmd->argval[qitems].netnum;
626 		plist[qitems].port = server_entry->s_port;
627 		plist[qitems].hmode = plist[qitems].flags = 0;
628 	}
629 
630 	res = doquery(IMPL_XNTPD, REQ_PEER_STATS, 0, qitems,
631 		      sizeof(struct info_peer_list), (char *)plist, &items,
632 		      &itemsize, (char **)&pp, 0);
633 
634 	if (res != 0 && items == 0)
635 	    return;
636 
637 	if (!checkitems(items, fp))
638 	    return;
639 
640 	if (!checkitemsize(itemsize, sizeof(struct info_peer_stats)))
641 	    return;
642 
643 	while (items-- > 0) {
644 		(void) fprintf(fp, "remote host:          %s\n",
645 			       nntohost(pp->srcadr));
646 		(void) fprintf(fp, "local interface:      %s\n",
647 			       numtoa(pp->dstadr));
648 		(void) fprintf(fp, "time last received:   %lds\n",
649 			       (long)ntohl(pp->timereceived));
650 		(void) fprintf(fp, "time until next send: %lds\n",
651 			       (long)ntohl(pp->timetosend));
652 		(void) fprintf(fp, "reachability change:  %lds\n",
653 			       (long)ntohl(pp->timereachable));
654 		(void) fprintf(fp, "packets sent:         %ld\n",
655 			       (long)ntohl(pp->sent));
656 		(void) fprintf(fp, "packets received:     %ld\n",
657 			       (long)ntohl(pp->processed));
658 		(void) fprintf(fp, "bad authentication:   %ld\n",
659 			       (long)ntohl(pp->badauth));
660 		(void) fprintf(fp, "bogus origin:         %ld\n",
661 			       (long)ntohl(pp->bogusorg));
662 		(void) fprintf(fp, "duplicate:            %ld\n",
663 			       (long)ntohl(pp->oldpkt));
664 		(void) fprintf(fp, "bad dispersion:       %ld\n",
665 			       (long)ntohl(pp->seldisp));
666 		(void) fprintf(fp, "bad reference time:   %ld\n",
667 			       (long)ntohl(pp->selbroken));
668 		(void) fprintf(fp, "candidate order:      %d\n",
669 			       (int)pp->candidate);
670 		if (items > 0)
671 		    (void) fprintf(fp, "\n");
672 		pp++;
673 	}
674 }
675 
676 
677 /*
678  * loopinfo - show loop filter information
679  */
680 static void
681 loopinfo(
682 	struct parse *pcmd,
683 	FILE *fp
684 	)
685 {
686 	struct info_loop *il;
687 	int items;
688 	int itemsize;
689 	int oneline = 0;
690 	int res;
691 	l_fp tempts;
692 
693 	if (pcmd->nargs > 0) {
694 		if (STREQ(pcmd->argval[0].string, "oneline"))
695 		    oneline = 1;
696 		else if (STREQ(pcmd->argval[0].string, "multiline"))
697 		    oneline = 0;
698 		else {
699 			(void) fprintf(stderr, "How many lines?\n");
700 			return;
701 		}
702 	}
703 
704 	res = doquery(IMPL_XNTPD, REQ_LOOP_INFO, 0, 0, 0, (char *)NULL,
705 		      &items, &itemsize, (char **)&il, 0);
706 
707 	if (res != 0 && items == 0)
708 	    return;
709 
710 	if (!check1item(items, fp))
711 	    return;
712 
713 	if (!checkitemsize(itemsize, sizeof(struct info_loop)))
714 	    return;
715 
716 	if (oneline) {
717 		l_fp temp2ts;
718 
719 		NTOHL_FP(&il->last_offset, &tempts);
720 		NTOHL_FP(&il->drift_comp, &temp2ts);
721 
722 		(void) fprintf(fp,
723 			       "offset %s, frequency %s, time_const %ld, watchdog %ld\n",
724 			       lfptoa(&tempts, 6),
725 			       lfptoa(&temp2ts, 3),
726 			       (u_long)ntohl(il->compliance),
727 			       (u_long)ntohl(il->watchdog_timer));
728 	} else {
729 		NTOHL_FP(&il->last_offset, &tempts);
730 		(void) fprintf(fp, "offset:               %s s\n",
731 			       lfptoa(&tempts, 6));
732 		NTOHL_FP(&il->drift_comp, &tempts);
733 		(void) fprintf(fp, "frequency:            %s ppm\n",
734 			       lfptoa(&tempts, 3));
735 		(void) fprintf(fp, "poll adjust:          %ld\n",
736 			       (u_long)ntohl(il->compliance));
737 		(void) fprintf(fp, "watchdog timer:       %ld s\n",
738 			       (u_long)ntohl(il->watchdog_timer));
739 	}
740 }
741 
742 
743 /*
744  * sysinfo - show current system state
745  */
746 /*ARGSUSED*/
747 static void
748 sysinfo(
749 	struct parse *pcmd,
750 	FILE *fp
751 	)
752 {
753 	struct info_sys *is;
754 	int items;
755 	int itemsize;
756 	int res;
757 	l_fp tempts;
758 
759 	res = doquery(IMPL_XNTPD, REQ_SYS_INFO, 0, 0, 0, (char *)NULL,
760 		      &items, &itemsize, (char **)&is, 0);
761 
762 	if (res != 0 && items == 0)
763 	    return;
764 
765 	if (!check1item(items, fp))
766 	    return;
767 
768 	if (!checkitemsize(itemsize, sizeof(struct info_sys)))
769 	    return;
770 
771 	(void) fprintf(fp, "system peer:          %s\n", nntohost(is->peer));
772 	(void) fprintf(fp, "system peer mode:     %s\n", modetoa(is->peer_mode));
773 	(void) fprintf(fp, "leap indicator:       %c%c\n",
774 		       is->leap & 0x2 ? '1' : '0',
775 		       is->leap & 0x1 ? '1' : '0');
776 	(void) fprintf(fp, "stratum:              %d\n", (int)is->stratum);
777 	(void) fprintf(fp, "precision:            %d\n", (int)is->precision);
778 	(void) fprintf(fp, "root distance:        %s s\n",
779 		       fptoa(NTOHS_FP(is->rootdelay), 5));
780 	(void) fprintf(fp, "root dispersion:      %s s\n",
781 		       ufptoa(NTOHS_FP(is->rootdispersion), 5));
782 	(void) fprintf(fp, "reference ID:         [%s]\n",
783 		       refid_string(is->refid, is->stratum));
784 	NTOHL_FP(&is->reftime, &tempts);
785 	(void) fprintf(fp, "reference time:       %s\n", prettydate(&tempts));
786 
787 	(void) fprintf(fp, "system flags:         ");
788 	if ((is->flags & (INFO_FLAG_BCLIENT | INFO_FLAG_AUTHENABLE |
789 	    INFO_FLAG_NTP | INFO_FLAG_KERNEL| INFO_FLAG_PLL_SYNC |
790 	    INFO_FLAG_PPS_SYNC | INFO_FLAG_MONITOR | INFO_FLAG_FILEGEN)) == 0) {
791 		(void) fprintf(fp, "none\n");
792 	} else {
793 		if (is->flags & INFO_FLAG_BCLIENT)
794 		    (void) fprintf(fp, "bclient ");
795 		if (is->flags & INFO_FLAG_AUTHENTICATE)
796 		    (void) fprintf(fp, "auth ");
797 		if (is->flags & INFO_FLAG_MONITOR)
798 		    (void) fprintf(fp, "monitor ");
799 		if (is->flags & INFO_FLAG_NTP)
800 		    (void) fprintf(fp, "ntp ");
801 		if (is->flags & INFO_FLAG_KERNEL)
802 		    (void) fprintf(fp, "kernel ");
803 		if (is->flags & INFO_FLAG_FILEGEN)
804 		    (void) fprintf(fp, "stats ");
805 		if (is->flags & INFO_FLAG_PLL_SYNC)
806 		    (void) fprintf(fp, "kernel_sync ");
807 		if (is->flags & INFO_FLAG_PPS_SYNC)
808 		    (void) fprintf(fp, "pps_sync ");
809 		(void) fprintf(fp, "\n");
810 	}
811 	(void) fprintf(fp, "jitter:               %s s\n",
812 		       fptoa(ntohl(is->frequency), 6));
813 	(void) fprintf(fp, "stability:            %s ppm\n",
814 		       ufptoa(ntohl(is->stability), 3));
815 	(void) fprintf(fp, "broadcastdelay:       %s s\n",
816 		       fptoa(NTOHS_FP(is->bdelay), 6));
817 	NTOHL_FP(&is->authdelay, &tempts);
818 	(void) fprintf(fp, "authdelay:            %s s\n", lfptoa(&tempts, 6));
819 }
820 
821 
822 /*
823  * sysstats - print system statistics
824  */
825 /*ARGSUSED*/
826 static void
827 sysstats(
828 	struct parse *pcmd,
829 	FILE *fp
830 	)
831 {
832 	struct info_sys_stats *ss;
833 	int items;
834 	int itemsize;
835 	int res;
836 
837 	res = doquery(IMPL_XNTPD, REQ_SYS_STATS, 0, 0, 0, (char *)NULL,
838 		      &items, &itemsize, (char **)&ss, 0);
839 
840 	if (res != 0 && items == 0)
841 	    return;
842 
843 	if (!check1item(items, fp))
844 	    return;
845 
846 	if (itemsize != sizeof(struct info_sys_stats) &&
847 	    itemsize != sizeof(struct old_info_sys_stats)) {
848 		/* issue warning according to new structure size */
849 		checkitemsize(itemsize, sizeof(struct info_sys_stats));
850 		return;
851 	}
852 
853 	(void) fprintf(fp, "system uptime:          %ld\n",
854 		       (u_long)ntohl(ss->timeup));
855 	(void) fprintf(fp, "time since reset:       %ld\n",
856 		       (u_long)ntohl(ss->timereset));
857 	(void) fprintf(fp, "bad stratum in packet:  %ld\n",
858 		       (u_long)ntohl(ss->badstratum));
859 	(void) fprintf(fp, "old version packets:    %ld\n",
860 		       (u_long)ntohl(ss->oldversionpkt));
861 	(void) fprintf(fp, "new version packets:    %ld\n",
862 		       (u_long)ntohl(ss->newversionpkt));
863 	(void) fprintf(fp, "unknown version number: %ld\n",
864 		       (u_long)ntohl(ss->unknownversion));
865 	(void) fprintf(fp, "bad packet format:      %ld\n",
866 		       (u_long)ntohl(ss->badlength));
867 	(void) fprintf(fp, "packets processed:      %ld\n",
868 		       (u_long)ntohl(ss->processed));
869 	(void) fprintf(fp, "bad authentication:     %ld\n",
870 		       (u_long)ntohl(ss->badauth));
871 	if (itemsize != sizeof(struct info_sys_stats))
872 	    return;
873 
874 	(void) fprintf(fp, "packets rejected:       %ld\n",
875 		       (u_long)ntohl(ss->limitrejected));
876 }
877 
878 
879 
880 /*
881  * iostats - print I/O statistics
882  */
883 /*ARGSUSED*/
884 static void
885 iostats(
886 	struct parse *pcmd,
887 	FILE *fp
888 	)
889 {
890 	struct info_io_stats *io;
891 	int items;
892 	int itemsize;
893 	int res;
894 
895 	res = doquery(IMPL_XNTPD, REQ_IO_STATS, 0, 0, 0, (char *)NULL,
896 		      &items, &itemsize, (char **)&io, 0);
897 
898 	if (res != 0 && items == 0)
899 	    return;
900 
901 	if (!check1item(items, fp))
902 	    return;
903 
904 	if (!checkitemsize(itemsize, sizeof(struct info_io_stats)))
905 	    return;
906 
907 	(void) fprintf(fp, "time since reset:     %ld\n",
908 		       (u_long)ntohl(io->timereset));
909 	(void) fprintf(fp, "receive buffers:      %d\n",
910 		       ntohs(io->totalrecvbufs));
911 	(void) fprintf(fp, "free receive buffers: %d\n",
912 		       ntohs(io->freerecvbufs));
913 	(void) fprintf(fp, "used receive buffers: %d\n",
914 		       ntohs(io->fullrecvbufs));
915 	(void) fprintf(fp, "low water refills:    %d\n",
916 		       ntohs(io->lowwater));
917 	(void) fprintf(fp, "dropped packets:      %ld\n",
918 		       (u_long)ntohl(io->dropped));
919 	(void) fprintf(fp, "ignored packets:      %ld\n",
920 		       (u_long)ntohl(io->ignored));
921 	(void) fprintf(fp, "received packets:     %ld\n",
922 		       (u_long)ntohl(io->received));
923 	(void) fprintf(fp, "packets sent:         %ld\n",
924 		       (u_long)ntohl(io->sent));
925 	(void) fprintf(fp, "packets not sent:     %ld\n",
926 		       (u_long)ntohl(io->notsent));
927 	(void) fprintf(fp, "interrupts handled:   %ld\n",
928 		       (u_long)ntohl(io->interrupts));
929 	(void) fprintf(fp, "received by int:      %ld\n",
930 		       (u_long)ntohl(io->int_received));
931 }
932 
933 
934 /*
935  * memstats - print peer memory statistics
936  */
937 /*ARGSUSED*/
938 static void
939 memstats(
940 	struct parse *pcmd,
941 	FILE *fp
942 	)
943 {
944 	struct info_mem_stats *mem;
945 	int i;
946 	int items;
947 	int itemsize;
948 	int res;
949 
950 	res = doquery(IMPL_XNTPD, REQ_MEM_STATS, 0, 0, 0, (char *)NULL,
951 		      &items, &itemsize, (char **)&mem, 0);
952 
953 	if (res != 0 && items == 0)
954 	    return;
955 
956 	if (!check1item(items, fp))
957 	    return;
958 
959 	if (!checkitemsize(itemsize, sizeof(struct info_mem_stats)))
960 	    return;
961 
962 	(void) fprintf(fp, "time since reset:     %ld\n",
963 		       (u_long)ntohl(mem->timereset));
964 	(void) fprintf(fp, "total peer memory:    %d\n",
965 		       ntohs(mem->totalpeermem));
966 	(void) fprintf(fp, "free peer memory:     %d\n",
967 		       ntohs(mem->freepeermem));
968 	(void) fprintf(fp, "calls to findpeer:    %ld\n",
969 		       (u_long)ntohl(mem->findpeer_calls));
970 	(void) fprintf(fp, "new peer allocations: %ld\n",
971 		       (u_long)ntohl(mem->allocations));
972 	(void) fprintf(fp, "peer demobilizations: %ld\n",
973 		       (u_long)ntohl(mem->demobilizations));
974 
975 	(void) fprintf(fp, "hash table counts:   ");
976 	for (i = 0; i < HASH_SIZE; i++) {
977 		(void) fprintf(fp, "%4d", (int)mem->hashcount[i]);
978 		if ((i % 8) == 7 && i != (HASH_SIZE-1)) {
979 			(void) fprintf(fp, "\n                     ");
980 		}
981 	}
982 	(void) fprintf(fp, "\n");
983 }
984 
985 
986 
987 /*
988  * timerstats - print timer statistics
989  */
990 /*ARGSUSED*/
991 static void
992 timerstats(
993 	struct parse *pcmd,
994 	FILE *fp
995 	)
996 {
997 	struct info_timer_stats *tim;
998 	int items;
999 	int itemsize;
1000 	int res;
1001 
1002 	res = doquery(IMPL_XNTPD, REQ_TIMER_STATS, 0, 0, 0, (char *)NULL,
1003 		      &items, &itemsize, (char **)&tim, 0);
1004 
1005 	if (res != 0 && items == 0)
1006 	    return;
1007 
1008 	if (!check1item(items, fp))
1009 	    return;
1010 
1011 	if (!checkitemsize(itemsize, sizeof(struct info_timer_stats)))
1012 	    return;
1013 
1014 	(void) fprintf(fp, "time since reset:  %ld\n",
1015 		       (u_long)ntohl(tim->timereset));
1016 	(void) fprintf(fp, "alarms handled:    %ld\n",
1017 		       (u_long)ntohl(tim->alarms));
1018 	(void) fprintf(fp, "alarm overruns:    %ld\n",
1019 		       (u_long)ntohl(tim->overflows));
1020 	(void) fprintf(fp, "calls to transmit: %ld\n",
1021 		       (u_long)ntohl(tim->xmtcalls));
1022 }
1023 
1024 
1025 /*
1026  * addpeer - configure an active mode association
1027  */
1028 static void
1029 addpeer(
1030 	struct parse *pcmd,
1031 	FILE *fp
1032 	)
1033 {
1034 	doconfig(pcmd, fp, MODE_ACTIVE, 0);
1035 }
1036 
1037 
1038 /*
1039  * addserver - configure a client mode association
1040  */
1041 static void
1042 addserver(
1043 	struct parse *pcmd,
1044 	FILE *fp
1045 	)
1046 {
1047 	doconfig(pcmd, fp, MODE_CLIENT, 0);
1048 }
1049 
1050 /*
1051  * addrefclock - configure a reference clock association
1052  */
1053 static void
1054 addrefclock(
1055 	struct parse *pcmd,
1056 	FILE *fp
1057 	)
1058 {
1059 	doconfig(pcmd, fp, MODE_CLIENT, 1);
1060 }
1061 
1062 /*
1063  * broadcast - configure a broadcast mode association
1064  */
1065 static void
1066 broadcast(
1067 	struct parse *pcmd,
1068 	FILE *fp
1069 	)
1070 {
1071 	doconfig(pcmd, fp, MODE_BROADCAST, 0);
1072 }
1073 
1074 
1075 /*
1076  * config - configure a new peer association
1077  */
1078 static void
1079 doconfig(
1080 	struct parse *pcmd,
1081 	FILE *fp,
1082 	int mode,
1083         int refc
1084 	)
1085 {
1086 	struct conf_peer cpeer;
1087 	int items;
1088 	int itemsize;
1089 	char *dummy;
1090 	u_long keyid;
1091 	u_int version;
1092 	u_char minpoll;
1093 	u_int flags;
1094 	u_char cmode;
1095 	int res;
1096 
1097 	keyid = 0;
1098 	version = NTP_OLDVERSION + 1;
1099 	flags = 0;
1100 	res = 0;
1101 	cmode = 0;
1102 	minpoll = NTP_MINDPOLL;
1103 
1104 	items = pcmd->nargs;
1105 
1106 	if (refc) {
1107 		if (pcmd->nargs > 1) {
1108 			cmode = (u_char) pcmd->argval[1].uval;
1109 			items = 2;
1110 		}
1111 	} else {
1112 		if (pcmd->nargs > 1) {
1113 			keyid = pcmd->argval[1].uval;
1114 			if (keyid > 0) {
1115 				flags |= CONF_FLAG_AUTHENABLE;
1116 			}
1117 			if (pcmd->nargs > 2) {
1118 				version = (u_int)pcmd->argval[2].uval;
1119 				if (version > NTP_VERSION ||
1120 				    version < NTP_OLDVERSION) {
1121 					(void)fprintf(fp,
1122 					"invalid version number %u\n",
1123 					    version);
1124 					res++;
1125 				}
1126 				items = 3;
1127 			}
1128 		}
1129 	}
1130 
1131 	while (pcmd->nargs > items) {
1132 		if (STREQ(pcmd->argval[items].string, "prefer"))
1133 		    flags |= CONF_FLAG_PREFER;
1134 		else if (STREQ(pcmd->argval[items].string, "burst"))
1135 		    flags |= CONF_FLAG_BURST;
1136 		else {
1137 		        long val;
1138 			if (!atoint(pcmd->argval[items].string, &val)) {
1139 				(void) fprintf(fp,
1140 				    "%s not understood\n",
1141 				    pcmd->argval[items].string);
1142 				res++;
1143 				break;
1144 			} else {
1145 				if (val >= NTP_MINPOLL && val <= NTP_MAXPOLL) {
1146 					minpoll = (u_char)val;
1147 				} else {
1148 					(void) fprintf(fp,
1149 						       "minpol must be within %d..%d\n",
1150 						       NTP_MINPOLL, NTP_MAXPOLL);
1151 					res++;
1152 					break;
1153 				}
1154 			}
1155 		}
1156 		items++;
1157 	}
1158 
1159 	if (res)
1160 	    return;
1161 
1162 	memset((void *)&cpeer, 0, sizeof cpeer);
1163 
1164 	cpeer.peeraddr = pcmd->argval[0].netnum;
1165 	cpeer.hmode = (u_char) mode;
1166 	cpeer.keyid = keyid;
1167 	cpeer.version = (u_char) version;
1168 	cpeer.minpoll = minpoll;
1169 	cpeer.maxpoll = NTP_MAXDPOLL;
1170 	cpeer.flags = (u_char)flags;
1171 	cpeer.ttl = cmode;
1172 
1173 	res = doquery(IMPL_XNTPD, REQ_CONFIG, 1, 1,
1174 		      sizeof(struct conf_peer), (char *)&cpeer, &items,
1175 		      &itemsize, &dummy, 0);
1176 
1177 	if (res == 0)
1178 	    (void) fprintf(fp, "done!\n");
1179 	return;
1180 }
1181 
1182 
1183 /*
1184  * unconfig - unconfigure some associations
1185  */
1186 static void
1187 unconfig(
1188 	struct parse *pcmd,
1189 	FILE *fp
1190 	)
1191 {
1192 	/* 8 is the maximum number of peers which will fit in a packet */
1193 	struct conf_unpeer plist[min(MAXARGS, 8)];
1194 	int qitems;
1195 	int items;
1196 	int itemsize;
1197 	char *dummy;
1198 	int res;
1199 
1200 	for (qitems = 0; qitems < min(pcmd->nargs, 8); qitems++) {
1201 		plist[qitems].peeraddr = pcmd->argval[qitems].netnum;
1202 	}
1203 
1204 	res = doquery(IMPL_XNTPD, REQ_UNCONFIG, 1, qitems,
1205 		      sizeof(struct conf_unpeer), (char *)plist, &items,
1206 		      &itemsize, &dummy, 0);
1207 
1208 	if (res == 0)
1209 	    (void) fprintf(fp, "done!\n");
1210 }
1211 
1212 
1213 /*
1214  * set - set some system flags
1215  */
1216 static void
1217 set(
1218 	struct parse *pcmd,
1219 	FILE *fp
1220 	)
1221 {
1222 	doset(pcmd, fp, REQ_SET_SYS_FLAG);
1223 }
1224 
1225 
1226 /*
1227  * clear - clear some system flags
1228  */
1229 static void
1230 sys_clear(
1231 	struct parse *pcmd,
1232 	FILE *fp
1233 	)
1234 {
1235 	doset(pcmd, fp, REQ_CLR_SYS_FLAG);
1236 }
1237 
1238 
1239 /*
1240  * doset - set/clear system flags
1241  */
1242 static void
1243 doset(
1244 	struct parse *pcmd,
1245 	FILE *fp,
1246 	int req
1247 	)
1248 {
1249 	/* 8 is the maximum number of peers which will fit in a packet */
1250 	struct conf_sys_flags sys;
1251 	int items;
1252 	int itemsize;
1253 	char *dummy;
1254 	int res;
1255 
1256 	sys.flags = 0;
1257 	res = 0;
1258 	for (items = 0; items < pcmd->nargs; items++) {
1259 		if (STREQ(pcmd->argval[items].string, "pps"))
1260 		    sys.flags |= SYS_FLAG_PPS;
1261 		else if (STREQ(pcmd->argval[items].string, "bclient"))
1262 		    sys.flags |= SYS_FLAG_BCLIENT;
1263 		else if (STREQ(pcmd->argval[items].string, "monitor"))
1264 		    sys.flags |= SYS_FLAG_MONITOR;
1265 		else if (STREQ(pcmd->argval[items].string, "ntp"))
1266 		    sys.flags |= SYS_FLAG_NTP;
1267 		else if (STREQ(pcmd->argval[items].string, "kernel"))
1268 		    sys.flags |= SYS_FLAG_KERNEL;
1269 		else if (STREQ(pcmd->argval[items].string, "stats"))
1270 		    sys.flags |= SYS_FLAG_FILEGEN;
1271 		else {
1272 			(void) fprintf(fp, "Unknown flag %s\n",
1273 				       pcmd->argval[items].string);
1274 			res = 1;
1275 		}
1276 	}
1277 
1278 	if (res || sys.flags == 0)
1279 	    return;
1280 
1281 	res = doquery(IMPL_XNTPD, req, 1, 1,
1282 		      sizeof(struct conf_sys_flags), (char *)&sys, &items,
1283 		      &itemsize, &dummy, 0);
1284 
1285 	if (res == 0)
1286 	    (void) fprintf(fp, "done!\n");
1287 }
1288 
1289 
1290 /*
1291  * data for printing/interrpreting the restrict flags
1292  */
1293 struct resflags {
1294   const char *str;
1295 	int bit;
1296 };
1297 
1298 static struct resflags resflags[] = {
1299 	{ "ignore",	RES_IGNORE },
1300 	{ "noserve",	RES_DONTSERVE },
1301 	{ "notrust",	RES_DONTTRUST },
1302 	{ "noquery",	RES_NOQUERY },
1303 	{ "nomodify",	RES_NOMODIFY },
1304 	{ "nopeer",	RES_NOPEER },
1305 	{ "notrap",	RES_NOTRAP },
1306 	{ "lptrap",	RES_LPTRAP },
1307 	{ "limited",	RES_LIMITED },
1308 	{ "version",	RES_VERSION },
1309 	{ "kod",	RES_DEMOBILIZE },
1310 
1311 	{ "",		0 }
1312 };
1313 
1314 static struct resflags resmflags[] = {
1315 	{ "ntpport",	RESM_NTPONLY },
1316 	{ "interface",	RESM_INTERFACE },
1317 	{ "",		0 }
1318 };
1319 
1320 
1321 /*
1322  * reslist - obtain and print the server's restrict list
1323  */
1324 /*ARGSUSED*/
1325 static void
1326 reslist(
1327 	struct parse *pcmd,
1328 	FILE *fp
1329 	)
1330 {
1331 	struct info_restrict *rl;
1332 	int items;
1333 	int itemsize;
1334 	int res;
1335 	char *addr;
1336 	char *mask;
1337 	struct resflags *rf;
1338 	u_int32 count;
1339 	u_short flags;
1340 	u_short mflags;
1341 	char flagstr[300];
1342 	static const char *comma = ", ";
1343 
1344 	res = doquery(IMPL_XNTPD, REQ_GET_RESTRICT, 0, 0, 0, (char *)NULL,
1345 		      &items, &itemsize, (char **)&rl, 0);
1346 
1347 	if (res != 0 && items == 0)
1348 	    return;
1349 
1350 	if (!checkitems(items, fp))
1351 	    return;
1352 
1353 	if (!checkitemsize(itemsize, sizeof(struct info_restrict)))
1354 	    return;
1355 
1356 	(void) fprintf(fp,
1357 		       "   address          mask            count        flags\n");
1358 	(void) fprintf(fp,
1359 		       "=====================================================================\n");
1360 	while (items > 0) {
1361 		if ((rl->mask == (u_int32)0xffffffff))
1362 		    addr = nntohost(rl->addr);
1363 		else
1364 		    addr = numtoa( rl->addr );
1365 		mask = numtoa(rl->mask);
1366 		count = ntohl(rl->count);
1367 		flags = ntohs(rl->flags);
1368 		mflags = ntohs(rl->mflags);
1369 		flagstr[0] = '\0';
1370 
1371 		res = 1;
1372 		rf = &resmflags[0];
1373 		while (rf->bit != 0) {
1374 			if (mflags & rf->bit) {
1375 				if (!res)
1376 				    (void) strcat(flagstr, comma);
1377 				res = 0;
1378 				(void) strcat(flagstr, rf->str);
1379 			}
1380 			rf++;
1381 		}
1382 
1383 		rf = &resflags[0];
1384 		while (rf->bit != 0) {
1385 			if (flags & rf->bit) {
1386 				if (!res)
1387 				    (void) strcat(flagstr, comma);
1388 				res = 0;
1389 				(void) strcat(flagstr, rf->str);
1390 			}
1391 			rf++;
1392 		}
1393 
1394 		if (flagstr[0] == '\0')
1395 		    (void) strcpy(flagstr, "none");
1396 
1397 		(void) fprintf(fp, "%-15.15s %-15.15s %9ld  %s\n",
1398 			       addr, mask, (u_long)count, flagstr);
1399 		rl++;
1400 		items--;
1401 	}
1402 }
1403 
1404 
1405 
1406 /*
1407  * new_restrict - create/add a set of restrictions
1408  */
1409 static void
1410 new_restrict(
1411 	struct parse *pcmd,
1412 	FILE *fp
1413 	)
1414 {
1415 	do_restrict(pcmd, fp, REQ_RESADDFLAGS);
1416 }
1417 
1418 
1419 /*
1420  * unrestrict - remove restriction flags from existing entry
1421  */
1422 static void
1423 unrestrict(
1424 	struct parse *pcmd,
1425 	FILE *fp
1426 	)
1427 {
1428 	do_restrict(pcmd, fp, REQ_RESSUBFLAGS);
1429 }
1430 
1431 
1432 /*
1433  * delrestrict - delete an existing restriction
1434  */
1435 static void
1436 delrestrict(
1437 	struct parse *pcmd,
1438 	FILE *fp
1439 	)
1440 {
1441 	do_restrict(pcmd, fp, REQ_UNRESTRICT);
1442 }
1443 
1444 
1445 /*
1446  * do_restrict - decode commandline restrictions and make the request
1447  */
1448 static void
1449 do_restrict(
1450 	struct parse *pcmd,
1451 	FILE *fp,
1452 	int req_code
1453 	)
1454 {
1455 	struct conf_restrict cres;
1456 	int items;
1457 	int itemsize;
1458 	char *dummy;
1459 	u_int32 num;
1460 	u_long bit;
1461 	int i;
1462 	int res;
1463 	int err;
1464 
1465 	cres.addr = pcmd->argval[0].netnum;
1466 	cres.mask = pcmd->argval[1].netnum;
1467 	cres.flags = 0;
1468 	cres.mflags = 0;
1469 	err = 0;
1470 	for (res = 2; res < pcmd->nargs; res++) {
1471 		if (STREQ(pcmd->argval[res].string, "ntpport")) {
1472 			cres.mflags |= RESM_NTPONLY;
1473 		} else {
1474 			for (i = 0; resflags[i].bit != 0; i++) {
1475 				if (STREQ(pcmd->argval[res].string,
1476 					  resflags[i].str))
1477 				    break;
1478 			}
1479 			if (resflags[i].bit != 0) {
1480 				cres.flags |= resflags[i].bit;
1481 				if (req_code == REQ_UNRESTRICT) {
1482 					(void) fprintf(fp,
1483 						       "Flag %s inappropriate\n",
1484 						       resflags[i].str);
1485 					err++;
1486 				}
1487 			} else {
1488 				(void) fprintf(fp, "Unknown flag %s\n",
1489 					       pcmd->argval[res].string);
1490 				err++;
1491 			}
1492 		}
1493 	}
1494 
1495 	/*
1496 	 * Make sure mask for default address is zero.  Otherwise,
1497 	 * make sure mask bits are contiguous.
1498 	 */
1499 	if (cres.addr == 0) {
1500 		cres.mask = 0;
1501 	} else {
1502 		num = ntohl(cres.mask);
1503 		for (bit = 0x80000000; bit != 0; bit >>= 1)
1504 		    if ((num & bit) == 0)
1505 			break;
1506 		for ( ; bit != 0; bit >>= 1)
1507 		    if ((num & bit) != 0)
1508 			break;
1509 		if (bit != 0) {
1510 			(void) fprintf(fp, "Invalid mask %s\n",
1511 				       numtoa(cres.mask));
1512 			err++;
1513 		}
1514 	}
1515 
1516 	if (err)
1517 	    return;
1518 
1519 	res = doquery(IMPL_XNTPD, req_code, 1, 1,
1520 		      sizeof(struct conf_restrict), (char *)&cres, &items,
1521 		      &itemsize, &dummy, 0);
1522 
1523 	if (res == 0)
1524 	    (void) fprintf(fp, "done!\n");
1525 	return;
1526 }
1527 
1528 
1529 /*
1530  * monlist - obtain and print the server's monitor data
1531  */
1532 /*ARGSUSED*/
1533 static void
1534 monlist(
1535 	struct parse *pcmd,
1536 	FILE *fp
1537 	)
1538 {
1539 	char *struct_star;
1540 	struct in_addr addr;
1541 	int items;
1542 	int itemsize;
1543 	int res;
1544 	int version = -1;
1545 
1546 	if (pcmd->nargs > 0) {
1547 		version = pcmd->argval[0].ival;
1548 	}
1549 
1550 	res = doquery(IMPL_XNTPD,
1551 		      (version == 1 || version == -1) ? REQ_MON_GETLIST_1 :
1552 		      REQ_MON_GETLIST, 0, 0, 0, (char *)NULL,
1553 		      &items, &itemsize, &struct_star,
1554 		      (version < 0) ? (1 << INFO_ERR_REQ) : 0);
1555 
1556 	if (res == INFO_ERR_REQ && version < 0)
1557 	    res = doquery(IMPL_XNTPD, REQ_MON_GETLIST, 0, 0, 0, (char *)NULL,
1558 			  &items, &itemsize, &struct_star, 0);
1559 
1560 	if (res != 0 && items == 0)
1561 	    return;
1562 
1563 	if (!checkitems(items, fp))
1564 	    return;
1565 
1566 	if (itemsize == sizeof(struct info_monitor_1)) {
1567 		struct info_monitor_1 *ml = (struct info_monitor_1 *) struct_star;
1568 
1569 		(void) fprintf(fp,
1570 			       "remote address          port local address      count m ver drop   last   first\n");
1571 		(void) fprintf(fp,
1572 			       "===============================================================================\n");
1573 		while (items > 0) {
1574 			addr.s_addr = ml->daddr;
1575 			(void) fprintf(fp,
1576 				       "%-22.22s %5d %-15s %8ld %1d %1d %6lu %6lu %7lu\n",
1577 				       nntohost(ml->addr),
1578 				       ntohs(ml->port),
1579 				       inet_ntoa(addr),
1580 				       (u_long)ntohl(ml->count),
1581 				       ml->mode,
1582 				       ml->version,
1583 				       (u_long)ntohl(ml->lastdrop),
1584 				       (u_long)ntohl(ml->lasttime),
1585 				       (u_long)ntohl(ml->firsttime));
1586 			ml++;
1587 			items--;
1588 		}
1589 	} else if (itemsize == sizeof(struct info_monitor)) {
1590 		struct info_monitor *ml = (struct info_monitor *) struct_star;
1591 
1592 		(void) fprintf(fp,
1593 			       "     address               port     count mode ver lastdrop  lasttime firsttime\n");
1594 		(void) fprintf(fp,
1595 			       "===============================================================================\n");
1596 		while (items > 0) {
1597 			addr.s_addr = ml->lastdrop;
1598 			(void) fprintf(fp,
1599 				       "%-25.25s %5d %9ld %4d %2d %9lu %9lu %9lu\n",
1600 				       nntohost(ml->addr),
1601 				       ntohs(ml->port),
1602 				       (u_long)ntohl(ml->count),
1603 				       ml->mode,
1604 				       ml->version,
1605 				       (u_long)ntohl(ml->lastdrop),
1606 				       (u_long)ntohl(ml->lasttime),
1607 				       (u_long)ntohl(ml->firsttime));
1608 			ml++;
1609 			items--;
1610 		}
1611 	} else if (itemsize == sizeof(struct old_info_monitor)) {
1612 		struct old_info_monitor *oml = (struct old_info_monitor *)struct_star;
1613 		(void) fprintf(fp,
1614 			       "     address          port     count  mode version  lasttime firsttime\n");
1615 		(void) fprintf(fp,
1616 			       "======================================================================\n");
1617 		while (items > 0) {
1618 			(void) fprintf(fp, "%-20.20s %5d %9ld %4d   %3d %9lu %9lu\n",
1619 				       nntohost(oml->addr),
1620 				       ntohs(oml->port),
1621 				       (u_long)ntohl(oml->count),
1622 				       oml->mode,
1623 				       oml->version,
1624 				       (u_long)ntohl(oml->lasttime),
1625 				       (u_long)ntohl(oml->firsttime));
1626 			oml++;
1627 			items--;
1628 		}
1629 	} else {
1630 		/* issue warning according to new info_monitor size */
1631 		checkitemsize(itemsize, sizeof(struct info_monitor));
1632 	}
1633 }
1634 
1635 
1636 /*
1637  * Mapping between command line strings and stat reset flags
1638  */
1639 struct statreset {
1640   const char *str;
1641 	int flag;
1642 } sreset[] = {
1643 	{ "io",		RESET_FLAG_IO },
1644 	{ "sys",	RESET_FLAG_SYS },
1645 	{ "mem",	RESET_FLAG_MEM },
1646 	{ "timer",	RESET_FLAG_TIMER },
1647 	{ "auth",	RESET_FLAG_AUTH },
1648 	{ "allpeers",	RESET_FLAG_ALLPEERS },
1649 	{ "",		0 }
1650 };
1651 
1652 /*
1653  * reset - reset statistic counters
1654  */
1655 static void
1656 reset(
1657 	struct parse *pcmd,
1658 	FILE *fp
1659 	)
1660 {
1661 	struct reset_flags rflags;
1662 	int items;
1663 	int itemsize;
1664 	char *dummy;
1665 	int i;
1666 	int res;
1667 	int err;
1668 
1669 	err = 0;
1670 	rflags.flags = 0;
1671 	for (res = 0; res < pcmd->nargs; res++) {
1672 		for (i = 0; sreset[i].flag != 0; i++) {
1673 			if (STREQ(pcmd->argval[res].string, sreset[i].str))
1674 			    break;
1675 		}
1676 		if (sreset[i].flag == 0) {
1677 			(void) fprintf(fp, "Flag %s unknown\n",
1678 				       pcmd->argval[res].string);
1679 			err++;
1680 		} else {
1681 			rflags.flags |= sreset[i].flag;
1682 		}
1683 	}
1684 
1685 	if (err) {
1686 		(void) fprintf(fp, "Not done due to errors\n");
1687 		return;
1688 	}
1689 
1690 	res = doquery(IMPL_XNTPD, REQ_RESET_STATS, 1, 1,
1691 		      sizeof(struct reset_flags), (char *)&rflags, &items,
1692 		      &itemsize, &dummy, 0);
1693 
1694 	if (res == 0)
1695 	    (void) fprintf(fp, "done!\n");
1696 	return;
1697 }
1698 
1699 
1700 
1701 /*
1702  * preset - reset stat counters for particular peers
1703  */
1704 static void
1705 preset(
1706 	struct parse *pcmd,
1707 	FILE *fp
1708 	)
1709 {
1710 	/* 8 is the maximum number of peers which will fit in a packet */
1711 	struct conf_unpeer plist[min(MAXARGS, 8)];
1712 	int qitems;
1713 	int items;
1714 	int itemsize;
1715 	char *dummy;
1716 	int res;
1717 
1718 	for (qitems = 0; qitems < min(pcmd->nargs, 8); qitems++) {
1719 		plist[qitems].peeraddr = pcmd->argval[qitems].netnum;
1720 	}
1721 
1722 	res = doquery(IMPL_XNTPD, REQ_RESET_PEER, 1, qitems,
1723 		      sizeof(struct conf_unpeer), (char *)plist, &items,
1724 		      &itemsize, &dummy, 0);
1725 
1726 	if (res == 0)
1727 	    (void) fprintf(fp, "done!\n");
1728 }
1729 
1730 
1731 /*
1732  * readkeys - request the server to reread the keys file
1733  */
1734 /*ARGSUSED*/
1735 static void
1736 readkeys(
1737 	struct parse *pcmd,
1738 	FILE *fp
1739 	)
1740 {
1741 	int items;
1742 	int itemsize;
1743 	char *dummy;
1744 	int res;
1745 
1746 	res = doquery(IMPL_XNTPD, REQ_REREAD_KEYS, 1, 0, 0, (char *)0,
1747 		      &items, &itemsize, &dummy, 0);
1748 
1749 	if (res == 0)
1750 	    (void) fprintf(fp, "done!\n");
1751 	return;
1752 }
1753 
1754 
1755 /*
1756  * trustkey - add some keys to the trusted key list
1757  */
1758 static void
1759 trustkey(
1760 	struct parse *pcmd,
1761 	FILE *fp
1762 	)
1763 {
1764 	do_trustkey(pcmd, fp, REQ_TRUSTKEY);
1765 }
1766 
1767 
1768 /*
1769  * untrustkey - remove some keys from the trusted key list
1770  */
1771 static void
1772 untrustkey(
1773 	struct parse *pcmd,
1774 	FILE *fp
1775 	)
1776 {
1777 	do_trustkey(pcmd, fp, REQ_UNTRUSTKEY);
1778 }
1779 
1780 
1781 /*
1782  * do_trustkey - do grunge work of adding/deleting keys
1783  */
1784 static void
1785 do_trustkey(
1786 	struct parse *pcmd,
1787 	FILE *fp,
1788 	int req
1789 	)
1790 {
1791 	u_long keyids[MAXARGS];
1792 	int i;
1793 	int items;
1794 	int itemsize;
1795 	char *dummy;
1796 	int ritems;
1797 	int res;
1798 
1799 	ritems = 0;
1800 	for (i = 0; i < pcmd->nargs; i++) {
1801 		keyids[ritems++] = pcmd->argval[i].uval;
1802 	}
1803 
1804 	res = doquery(IMPL_XNTPD, req, 1, ritems, sizeof(u_long),
1805 		      (char *)keyids, &items, &itemsize, &dummy, 0);
1806 
1807 	if (res == 0)
1808 	    (void) fprintf(fp, "done!\n");
1809 	return;
1810 }
1811 
1812 
1813 
1814 /*
1815  * authinfo - obtain and print info about authentication
1816  */
1817 /*ARGSUSED*/
1818 static void
1819 authinfo(
1820 	struct parse *pcmd,
1821 	FILE *fp
1822 	)
1823 {
1824 	struct info_auth *ia;
1825 	int items;
1826 	int itemsize;
1827 	int res;
1828 
1829 	res = doquery(IMPL_XNTPD, REQ_AUTHINFO, 0, 0, 0, (char *)NULL,
1830 		      &items, &itemsize, (char **)&ia, 0);
1831 
1832 	if (res != 0 && items == 0)
1833 	    return;
1834 
1835 	if (!check1item(items, fp))
1836 	    return;
1837 
1838 	if (!checkitemsize(itemsize, sizeof(struct info_auth)))
1839 	    return;
1840 
1841 	(void) fprintf(fp, "time since reset:     %ld\n",
1842 	    (u_long)ntohl(ia->timereset));
1843 	(void) fprintf(fp, "stored keys:          %ld\n",
1844 	    (u_long)ntohl(ia->numkeys));
1845 	(void) fprintf(fp, "free keys:            %ld\n",
1846 	    (u_long)ntohl(ia->numfreekeys));
1847 	(void) fprintf(fp, "key lookups:          %ld\n",
1848 	    (u_long)ntohl(ia->keylookups));
1849 	(void) fprintf(fp, "keys not found:       %ld\n",
1850 	    (u_long)ntohl(ia->keynotfound));
1851 	(void) fprintf(fp, "uncached keys:        %ld\n",
1852 	    (u_long)ntohl(ia->keyuncached));
1853 	(void) fprintf(fp, "encryptions:          %ld\n",
1854 	    (u_long)ntohl(ia->encryptions));
1855 	(void) fprintf(fp, "decryptions:          %ld\n",
1856 	    (u_long)ntohl(ia->decryptions));
1857 	(void) fprintf(fp, "expired keys:         %ld\n",
1858 	    (u_long)ntohl(ia->expired));
1859 }
1860 
1861 
1862 
1863 /*
1864  * traps - obtain and print a list of traps
1865  */
1866 /*ARGSUSED*/
1867 static void
1868 traps(
1869 	struct parse *pcmd,
1870 	FILE *fp
1871 	)
1872 {
1873 	int i;
1874 	struct info_trap *it;
1875 	int items;
1876 	int itemsize;
1877 	int res;
1878 
1879 	res = doquery(IMPL_XNTPD, REQ_TRAPS, 0, 0, 0, (char *)NULL,
1880 		      &items, &itemsize, (char **)&it, 0);
1881 
1882 	if (res != 0 && items == 0)
1883 	    return;
1884 
1885 	if (!checkitems(items, fp))
1886 	    return;
1887 
1888 	if (!checkitemsize(itemsize, sizeof(struct info_trap)))
1889 	    return;
1890 
1891 	for (i = 0; i < items; i++ ) {
1892 		if (i != 0)
1893 		    (void) fprintf(fp, "\n");
1894 		(void) fprintf(fp, "address %s, port %d\n",
1895 			       numtoa(it->trap_address), ntohs(it->trap_port));
1896 		(void) fprintf(fp, "interface: %s, ",
1897 			       (it->local_address == 0)
1898 			       ? "wildcard"
1899 			       : numtoa(it->local_address));
1900 
1901 		if (ntohl(it->flags) & TRAP_CONFIGURED)
1902 		    (void) fprintf(fp, "configured\n");
1903 		else if (ntohl(it->flags) & TRAP_NONPRIO)
1904 		    (void) fprintf(fp, "low priority\n");
1905 		else
1906 		    (void) fprintf(fp, "normal priority\n");
1907 
1908 		(void) fprintf(fp, "set for %ld secs, last set %ld secs ago\n",
1909 			       (long)ntohl(it->origtime),
1910 			       (long)ntohl(it->settime));
1911 		(void) fprintf(fp, "sequence %d, number of resets %ld\n",
1912 			       ntohs(it->sequence),
1913 			       (long)ntohl(it->resets));
1914 	}
1915 }
1916 
1917 
1918 /*
1919  * addtrap - configure a trap
1920  */
1921 static void
1922 addtrap(
1923 	struct parse *pcmd,
1924 	FILE *fp
1925 	)
1926 {
1927 	do_addclr_trap(pcmd, fp, REQ_ADD_TRAP);
1928 }
1929 
1930 
1931 /*
1932  * clrtrap - clear a trap from the server
1933  */
1934 static void
1935 clrtrap(
1936 	struct parse *pcmd,
1937 	FILE *fp
1938 	)
1939 {
1940 	do_addclr_trap(pcmd, fp, REQ_CLR_TRAP);
1941 }
1942 
1943 
1944 /*
1945  * do_addclr_trap - do grunge work of adding/deleting traps
1946  */
1947 static void
1948 do_addclr_trap(
1949 	struct parse *pcmd,
1950 	FILE *fp,
1951 	int req
1952 	)
1953 {
1954 	struct conf_trap ctrap;
1955 	int items;
1956 	int itemsize;
1957 	char *dummy;
1958 	int res;
1959 
1960 	ctrap.trap_address = pcmd->argval[0].netnum;
1961 	ctrap.local_address = 0;
1962 	ctrap.trap_port = htons(TRAPPORT);
1963 	ctrap.unused = 0;
1964 
1965 	if (pcmd->nargs > 1) {
1966 		ctrap.trap_port
1967 			= htons((u_short)(pcmd->argval[1].uval & 0xffff));
1968 		if (pcmd->nargs > 2)
1969 		    ctrap.local_address = pcmd->argval[2].netnum;
1970 	}
1971 
1972 	res = doquery(IMPL_XNTPD, req, 1, 1, sizeof(struct conf_trap),
1973 		      (char *)&ctrap, &items, &itemsize, &dummy, 0);
1974 
1975 	if (res == 0)
1976 	    (void) fprintf(fp, "done!\n");
1977 	return;
1978 }
1979 
1980 
1981 
1982 /*
1983  * requestkey - change the server's request key (a dangerous request)
1984  */
1985 static void
1986 requestkey(
1987 	struct parse *pcmd,
1988 	FILE *fp
1989 	)
1990 {
1991 	do_changekey(pcmd, fp, REQ_REQUEST_KEY);
1992 }
1993 
1994 
1995 /*
1996  * controlkey - change the server's control key
1997  */
1998 static void
1999 controlkey(
2000 	struct parse *pcmd,
2001 	FILE *fp
2002 	)
2003 {
2004 	do_changekey(pcmd, fp, REQ_CONTROL_KEY);
2005 }
2006 
2007 
2008 
2009 /*
2010  * do_changekey - do grunge work of changing keys
2011  */
2012 static void
2013 do_changekey(
2014 	struct parse *pcmd,
2015 	FILE *fp,
2016 	int req
2017 	)
2018 {
2019 	u_long key;
2020 	int items;
2021 	int itemsize;
2022 	char *dummy;
2023 	int res;
2024 
2025 
2026 	key = htonl((u_int32)pcmd->argval[0].uval);
2027 
2028 	res = doquery(IMPL_XNTPD, req, 1, 1, sizeof(u_int32),
2029 		      (char *)&key, &items, &itemsize, &dummy, 0);
2030 
2031 	if (res == 0)
2032 	    (void) fprintf(fp, "done!\n");
2033 	return;
2034 }
2035 
2036 
2037 
2038 /*
2039  * ctlstats - obtain and print info about authentication
2040  */
2041 /*ARGSUSED*/
2042 static void
2043 ctlstats(
2044 	struct parse *pcmd,
2045 	FILE *fp
2046 	)
2047 {
2048 	struct info_control *ic;
2049 	int items;
2050 	int itemsize;
2051 	int res;
2052 
2053 	res = doquery(IMPL_XNTPD, REQ_GET_CTLSTATS, 0, 0, 0, (char *)NULL,
2054 		      &items, &itemsize, (char **)&ic, 0);
2055 
2056 	if (res != 0 && items == 0)
2057 	    return;
2058 
2059 	if (!check1item(items, fp))
2060 	    return;
2061 
2062 	if (!checkitemsize(itemsize, sizeof(struct info_control)))
2063 	    return;
2064 
2065 	(void) fprintf(fp, "time since reset:       %ld\n",
2066 		       (u_long)ntohl(ic->ctltimereset));
2067 	(void) fprintf(fp, "requests received:      %ld\n",
2068 		       (u_long)ntohl(ic->numctlreq));
2069 	(void) fprintf(fp, "responses sent:         %ld\n",
2070 		       (u_long)ntohl(ic->numctlresponses));
2071 	(void) fprintf(fp, "fragments sent:         %ld\n",
2072 		       (u_long)ntohl(ic->numctlfrags));
2073 	(void) fprintf(fp, "async messages sent:    %ld\n",
2074 		       (u_long)ntohl(ic->numasyncmsgs));
2075 	(void) fprintf(fp, "error msgs sent:        %ld\n",
2076 		       (u_long)ntohl(ic->numctlerrors));
2077 	(void) fprintf(fp, "total bad pkts:         %ld\n",
2078 		       (u_long)ntohl(ic->numctlbadpkts));
2079 	(void) fprintf(fp, "packet too short:       %ld\n",
2080 		       (u_long)ntohl(ic->numctltooshort));
2081 	(void) fprintf(fp, "response on input:      %ld\n",
2082 		       (u_long)ntohl(ic->numctlinputresp));
2083 	(void) fprintf(fp, "fragment on input:      %ld\n",
2084 		       (u_long)ntohl(ic->numctlinputfrag));
2085 	(void) fprintf(fp, "error set on input:     %ld\n",
2086 		       (u_long)ntohl(ic->numctlinputerr));
2087 	(void) fprintf(fp, "bad offset on input:    %ld\n",
2088 		       (u_long)ntohl(ic->numctlbadoffset));
2089 	(void) fprintf(fp, "bad version packets:    %ld\n",
2090 		       (u_long)ntohl(ic->numctlbadversion));
2091 	(void) fprintf(fp, "data in pkt too short:  %ld\n",
2092 		       (u_long)ntohl(ic->numctldatatooshort));
2093 	(void) fprintf(fp, "unknown op codes:       %ld\n",
2094 		       (u_long)ntohl(ic->numctlbadop));
2095 }
2096 
2097 
2098 /*
2099  * clockstat - get and print clock status information
2100  */
2101 static void
2102 clockstat(
2103 	struct parse *pcmd,
2104 	FILE *fp
2105 	)
2106 {
2107 	struct info_clock *cl;
2108 	/* 8 is the maximum number of clocks which will fit in a packet */
2109 	u_long clist[min(MAXARGS, 8)];
2110 	int qitems;
2111 	int items;
2112 	int itemsize;
2113 	int res;
2114 	l_fp ts;
2115 	struct clktype *clk;
2116 	u_long ltemp;
2117 
2118 	for (qitems = 0; qitems < min(pcmd->nargs, 8); qitems++)
2119 	    clist[qitems] = pcmd->argval[qitems].netnum;
2120 
2121 	res = doquery(IMPL_XNTPD, REQ_GET_CLOCKINFO, 0, qitems,
2122 		      sizeof(u_int32), (char *)clist, &items,
2123 		      &itemsize, (char **)&cl, 0);
2124 
2125 	if (res != 0 && items == 0)
2126 	    return;
2127 
2128 	if (!checkitems(items, fp))
2129 	    return;
2130 
2131 	if (!checkitemsize(itemsize, sizeof(struct info_clock)))
2132 	    return;
2133 
2134 	while (items-- > 0) {
2135 		(void) fprintf(fp, "clock address:        %s\n",
2136 			       numtoa(cl->clockadr));
2137 		for (clk = clktypes; clk->code >= 0; clk++)
2138 		    if (clk->code == cl->type)
2139 			break;
2140 		if (clk->code >= 0)
2141 		    (void) fprintf(fp, "clock type:           %s\n",
2142 				   clk->clocktype);
2143 		else
2144 		    (void) fprintf(fp, "clock type:           unknown type (%d)\n",
2145 				   cl->type);
2146 		(void) fprintf(fp, "last event:           %d\n",
2147 			       cl->lastevent);
2148 		(void) fprintf(fp, "current status:       %d\n",
2149 			       cl->currentstatus);
2150 		(void) fprintf(fp, "number of polls:      %lu\n",
2151 			       (u_long)ntohl(cl->polls));
2152 		(void) fprintf(fp, "no response to poll:  %lu\n",
2153 			       (u_long)ntohl(cl->noresponse));
2154 		(void) fprintf(fp, "bad format responses: %lu\n",
2155 			       (u_long)ntohl(cl->badformat));
2156 		(void) fprintf(fp, "bad data responses:   %lu\n",
2157 			       (u_long)ntohl(cl->baddata));
2158 		(void) fprintf(fp, "running time:         %lu\n",
2159 			       (u_long)ntohl(cl->timestarted));
2160 		NTOHL_FP(&cl->fudgetime1, &ts);
2161 		(void) fprintf(fp, "fudge time 1:         %s\n",
2162 			       lfptoa(&ts, 6));
2163 		NTOHL_FP(&cl->fudgetime2, &ts);
2164 		(void) fprintf(fp, "fudge time 2:         %s\n",
2165 			       lfptoa(&ts, 6));
2166 		(void) fprintf(fp, "stratum:              %ld\n",
2167 			       (u_long)ntohl(cl->fudgeval1));
2168 		ltemp = ntohl(cl->fudgeval2);
2169 		(void) fprintf(fp, "reference ID:         %s\n",
2170 			       (char *)&ltemp);
2171 		(void) fprintf(fp, "fudge flags:          0x%x\n",
2172 			       cl->flags);
2173 
2174 		if (items > 0)
2175 		    (void) fprintf(fp, "\n");
2176 		cl++;
2177 	}
2178 }
2179 
2180 
2181 /*
2182  * fudge - set clock fudge factors
2183  */
2184 static void
2185 fudge(
2186 	struct parse *pcmd,
2187 	FILE *fp
2188 	)
2189 {
2190 	struct conf_fudge fudgedata;
2191 	int items;
2192 	int itemsize;
2193 	char *dummy;
2194 	l_fp ts;
2195 	int res;
2196 	long val;
2197 	u_long u_val;
2198 	int err;
2199 
2200 
2201 	err = 0;
2202 	memset((char *)&fudgedata, 0, sizeof fudgedata);
2203 	fudgedata.clockadr = pcmd->argval[0].netnum;
2204 
2205 	if (STREQ(pcmd->argval[1].string, "time1")) {
2206 		fudgedata.which = htonl(FUDGE_TIME1);
2207 		if (!atolfp(pcmd->argval[2].string, &ts))
2208 		    err = 1;
2209 		else
2210 		    NTOHL_FP(&ts, &fudgedata.fudgetime);
2211 	} else if (STREQ(pcmd->argval[1].string, "time2")) {
2212 		fudgedata.which = htonl(FUDGE_TIME2);
2213 		if (!atolfp(pcmd->argval[2].string, &ts))
2214 		    err = 1;
2215 		else
2216 		    NTOHL_FP(&ts, &fudgedata.fudgetime);
2217 	} else if (STREQ(pcmd->argval[1].string, "val1")) {
2218 		fudgedata.which = htonl(FUDGE_VAL1);
2219 		if (!atoint(pcmd->argval[2].string, &val))
2220 		    err = 1;
2221 		else
2222 		    fudgedata.fudgeval_flags = htonl(val);
2223 	} else if (STREQ(pcmd->argval[1].string, "val2")) {
2224 		fudgedata.which = htonl(FUDGE_VAL2);
2225 		if (!atoint(pcmd->argval[2].string, &val))
2226 		    err = 1;
2227 		else
2228 		    fudgedata.fudgeval_flags = htonl((u_int32)val);
2229 	} else if (STREQ(pcmd->argval[1].string, "flags")) {
2230 		fudgedata.which = htonl(FUDGE_FLAGS);
2231 		if (!hextoint(pcmd->argval[2].string, &u_val))
2232 		    err = 1;
2233 		else
2234 		    fudgedata.fudgeval_flags = htonl((u_int32)(u_val & 0xf));
2235 	} else {
2236 		(void) fprintf(stderr, "What fudge is %s?\n",
2237 			       pcmd->argval[1].string);
2238 		return;
2239 	}
2240 
2241 	if (err) {
2242 		(void) fprintf(stderr, "Unknown fudge parameter %s\n",
2243 			       pcmd->argval[2].string);
2244 		return;
2245 	}
2246 
2247 
2248 	res = doquery(IMPL_XNTPD, REQ_SET_CLKFUDGE, 1, 1,
2249 		      sizeof(struct conf_fudge), (char *)&fudgedata, &items,
2250 		      &itemsize, &dummy, 0);
2251 
2252 	if (res == 0)
2253 	    (void) fprintf(fp, "done!\n");
2254 	return;
2255 }
2256 
2257 /*
2258  * clkbug - get and print clock debugging information
2259  */
2260 static void
2261 clkbug(
2262 	struct parse *pcmd,
2263 	FILE *fp
2264 	)
2265 {
2266 	register int i;
2267 	register int n;
2268 	register u_int32 s;
2269 	struct info_clkbug *cl;
2270 	/* 8 is the maximum number of clocks which will fit in a packet */
2271 	u_long clist[min(MAXARGS, 8)];
2272 	u_int32 ltemp;
2273 	int qitems;
2274 	int items;
2275 	int itemsize;
2276 	int res;
2277 	int needsp;
2278 	l_fp ts;
2279 
2280 	for (qitems = 0; qitems < min(pcmd->nargs, 8); qitems++)
2281 	    clist[qitems] = pcmd->argval[qitems].netnum;
2282 
2283 	res = doquery(IMPL_XNTPD, REQ_GET_CLKBUGINFO, 0, qitems,
2284 		      sizeof(u_int32), (char *)clist, &items,
2285 		      &itemsize, (char **)&cl, 0);
2286 
2287 	if (res != 0 && items == 0)
2288 	    return;
2289 
2290 	if (!checkitems(items, fp))
2291 	    return;
2292 
2293 	if (!checkitemsize(itemsize, sizeof(struct info_clkbug)))
2294 	    return;
2295 
2296 	while (items-- > 0) {
2297 		(void) fprintf(fp, "clock address:        %s\n",
2298 			       numtoa(cl->clockadr));
2299 		n = (int)cl->nvalues;
2300 		(void) fprintf(fp, "values: %d", n);
2301 		s = ntohs(cl->svalues);
2302 		if (n > NUMCBUGVALUES)
2303 		    n = NUMCBUGVALUES;
2304 		for (i = 0; i < n; i++) {
2305 			ltemp = ntohl(cl->values[i]);
2306 			ltemp &= 0xffffffff;	/* HMS: This does nothing now */
2307 			if ((i & 0x3) == 0)
2308 			    (void) fprintf(fp, "\n");
2309 			if (s & (1 << i))
2310 			    (void) fprintf(fp, "%12ld", (u_long)ltemp);
2311 			else
2312 			    (void) fprintf(fp, "%12lu", (u_long)ltemp);
2313 		}
2314 		(void) fprintf(fp, "\n");
2315 
2316 		n = (int)cl->ntimes;
2317 		(void) fprintf(fp, "times: %d", n);
2318 		s = ntohl(cl->stimes);
2319 		if (n > NUMCBUGTIMES)
2320 		    n = NUMCBUGTIMES;
2321 		needsp = 0;
2322 		for (i = 0; i < n; i++) {
2323 			if ((i & 0x1) == 0) {
2324 			    (void) fprintf(fp, "\n");
2325 			} else {
2326 				for (;needsp > 0; needsp--)
2327 				    putc(' ', fp);
2328 			}
2329 			NTOHL_FP(&cl->times[i], &ts);
2330 			if (s & (1 << i)) {
2331 				(void) fprintf(fp, "%17s",
2332 					       lfptoa(&ts, 6));
2333 				needsp = 22;
2334 			} else {
2335 				(void) fprintf(fp, "%37s",
2336 					       uglydate(&ts));
2337 				needsp = 2;
2338 			}
2339 		}
2340 		(void) fprintf(fp, "\n");
2341 		if (items > 0) {
2342 			cl++;
2343 			(void) fprintf(fp, "\n");
2344 		}
2345 	}
2346 }
2347 
2348 
2349 /*
2350  * kerninfo - display the kernel pll/pps variables
2351  */
2352 static void
2353 kerninfo(
2354 	struct parse *pcmd,
2355 	FILE *fp
2356 	)
2357 {
2358 	struct info_kernel *ik;
2359 	int items;
2360 	int itemsize;
2361 	int res;
2362 	unsigned status;
2363 	double tscale = 1e-6;
2364 
2365 	res = doquery(IMPL_XNTPD, REQ_GET_KERNEL, 0, 0, 0, (char *)NULL,
2366 		      &items, &itemsize, (char **)&ik, 0);
2367 	if (res != 0 && items == 0)
2368 	    return;
2369 	if (!check1item(items, fp))
2370 	    return;
2371 	if (!checkitemsize(itemsize, sizeof(struct info_kernel)))
2372 	    return;
2373 
2374 	status = ntohs(ik->status) & 0xffff;
2375 	/*
2376 	 * pll variables. We know more than we should about the NANO bit.
2377 	 */
2378 #ifdef STA_NANO
2379 	if (status & STA_NANO)
2380 		tscale = 1e-9;
2381 #endif
2382 	(void)fprintf(fp, "pll offset:           %g s\n",
2383 	    (long)ntohl(ik->offset) * tscale);
2384 	(void)fprintf(fp, "pll frequency:        %s ppm\n",
2385 	    fptoa((s_fp)ntohl(ik->freq), 3));
2386 	(void)fprintf(fp, "maximum error:        %g s\n",
2387 	    (u_long)ntohl(ik->maxerror) * 1e-6);
2388 	(void)fprintf(fp, "estimated error:      %g s\n",
2389 	    (u_long)ntohl(ik->esterror) * 1e-6);
2390 	(void)fprintf(fp, "status:               %04x ", status);
2391 #ifdef STA_PLL
2392 	if (status & STA_PLL) (void)fprintf(fp, " pll");
2393 #endif
2394 #ifdef STA_PPSFREQ
2395 	if (status & STA_PPSFREQ) (void)fprintf(fp, " ppsfreq");
2396 #endif
2397 #ifdef STA_PPSTIME
2398 	if (status & STA_PPSTIME) (void)fprintf(fp, " ppstime");
2399 #endif
2400 #ifdef STA_FLL
2401 	if (status & STA_FLL) (void)fprintf(fp, " fll");
2402 #endif
2403 #ifdef STA_INS
2404 	if (status & STA_INS) (void)fprintf(fp, " ins");
2405 #endif
2406 #ifdef STA_DEL
2407 	if (status & STA_DEL) (void)fprintf(fp, " del");
2408 #endif
2409 #ifdef STA_UNSYNC
2410 	if (status & STA_UNSYNC) (void)fprintf(fp, " unsync");
2411 #endif
2412 #ifdef STA_FREQHOLD
2413 	if (status & STA_FREQHOLD) (void)fprintf(fp, " freqhold");
2414 #endif
2415 #ifdef STA_PPSSIGNAL
2416 	if (status & STA_PPSSIGNAL) (void)fprintf(fp, " ppssignal");
2417 #endif
2418 #ifdef STA_PPSJITTER
2419 	if (status & STA_PPSJITTER) (void)fprintf(fp, " ppsjitter");
2420 #endif
2421 #ifdef STA_PPSWANDER
2422 	if (status & STA_PPSWANDER) (void)fprintf(fp, " ppswander");
2423 #endif
2424 #ifdef STA_PPSERROR
2425 	if (status & STA_PPSERROR) (void)fprintf(fp, " ppserror");
2426 #endif
2427 #ifdef STA_CLOCKERR
2428 	if (status & STA_CLOCKERR) (void)fprintf(fp, " clockerr");
2429 #endif
2430 #ifdef STA_NANO
2431 	if (status & STA_NANO) (void)fprintf(fp, " nano");
2432 #endif
2433 #ifdef STA_MODE
2434 	if (status & STA_MODE) (void)fprintf(fp, " mode=fll");
2435 #endif
2436 #ifdef STA_CLK
2437 	if (status & STA_CLK) (void)fprintf(fp, " src=B");
2438 #endif
2439 	(void)fprintf(fp, "\n");
2440 	(void)fprintf(fp, "pll time constant:    %ld\n",
2441 	    (u_long)ntohl(ik->constant));
2442 	(void)fprintf(fp, "precision:            %g s\n",
2443 	    (u_long)ntohl(ik->precision) * tscale);
2444 	(void)fprintf(fp, "frequency tolerance:  %s ppm\n",
2445 	    fptoa((s_fp)ntohl(ik->tolerance), 0));
2446 
2447 	/*
2448 	 * For backwards compatibility (ugh), we find the pps variables
2449 	 * only if the shift member is nonzero.
2450 	 */
2451 	if (!ik->shift)
2452 	    return;
2453 
2454 	/*
2455 	 * pps variables
2456 	 */
2457 	(void)fprintf(fp, "pps frequency:        %s ppm\n",
2458 	    fptoa((s_fp)ntohl(ik->ppsfreq), 3));
2459 	(void)fprintf(fp, "pps stability:        %s ppm\n",
2460 	    fptoa((s_fp)ntohl(ik->stabil), 3));
2461 	(void)fprintf(fp, "pps jitter:           %g s\n",
2462 	    (u_long)ntohl(ik->jitter) * tscale);
2463 	(void)fprintf(fp, "calibration interval: %d s\n",
2464 		      1 << ntohs(ik->shift));
2465 	(void)fprintf(fp, "calibration cycles:   %ld\n",
2466 		      (u_long)ntohl(ik->calcnt));
2467 	(void)fprintf(fp, "jitter exceeded:      %ld\n",
2468 		      (u_long)ntohl(ik->jitcnt));
2469 	(void)fprintf(fp, "stability exceeded:   %ld\n",
2470 		      (u_long)ntohl(ik->stbcnt));
2471 	(void)fprintf(fp, "calibration errors:   %ld\n",
2472 		      (u_long)ntohl(ik->errcnt));
2473 }
2474