PageRenderTime 107ms CodeModel.GetById 2ms app.highlight 95ms RepoModel.GetById 1ms app.codeStats 0ms

/contrib/ntp/ntpq/ntpq-subs.c

https://bitbucket.org/freebsd/freebsd-head/
C | 1768 lines | 1381 code | 202 blank | 185 comment | 307 complexity | 7c8e2ff6e32af5485776a9dff2cc41b2 MD5 | raw file
   1/*
   2 * ntpq_ops.c - subroutines which are called to perform operations by ntpq
   3 */
   4
   5#include <stdio.h>
   6#include <ctype.h>
   7#include <sys/types.h>
   8#include <sys/time.h>
   9
  10#include "ntpq.h"
  11#include "ntp_stdlib.h"
  12
  13extern char *	chosts[];
  14extern char currenthost[];
  15extern int	numhosts;
  16int 	maxhostlen;
  17
  18/*
  19 * Declarations for command handlers in here
  20 */
  21static	int checkassocid	P((u_int32));
  22static	char *	strsave 	P((char *));
  23static	struct varlist *findlistvar P((struct varlist *, char *));
  24static	void	doaddvlist	P((struct varlist *, char *));
  25static	void	dormvlist	P((struct varlist *, char *));
  26static	void	doclearvlist	P((struct varlist *));
  27static	void	makequerydata	P((struct varlist *, int *, char *));
  28static	int doquerylist P((struct varlist *, int, int, int, u_short *, int *, char **));
  29static	void	doprintvlist	P((struct varlist *, FILE *));
  30static	void	addvars 	P((struct parse *, FILE *));
  31static	void	rmvars		P((struct parse *, FILE *));
  32static	void	clearvars	P((struct parse *, FILE *));
  33static	void	showvars	P((struct parse *, FILE *));
  34static	int dolist		P((struct varlist *, int, int, int, FILE *));
  35static	void	readlist	P((struct parse *, FILE *));
  36static	void	writelist	P((struct parse *, FILE *));
  37static	void	readvar 	P((struct parse *, FILE *));
  38static	void	writevar	P((struct parse *, FILE *));
  39static	void	clocklist	P((struct parse *, FILE *));
  40static	void	clockvar	P((struct parse *, FILE *));
  41static	int findassidrange	P((u_int32, u_int32, int *, int *));
  42static	void	mreadlist	P((struct parse *, FILE *));
  43static	void	mreadvar	P((struct parse *, FILE *));
  44static	int dogetassoc	P((FILE *));
  45static	void	printassoc	P((int, FILE *));
  46static	void	associations	P((struct parse *, FILE *));
  47static	void	lassociations	P((struct parse *, FILE *));
  48static	void	passociations	P((struct parse *, FILE *));
  49static	void	lpassociations	P((struct parse *, FILE *));
  50
  51#ifdef	UNUSED
  52static	void	radiostatus P((struct parse *, FILE *));
  53#endif	/* UNUSED */
  54
  55static	void	pstatus 	P((struct parse *, FILE *));
  56static	long	when		P((l_fp *, l_fp *, l_fp *));
  57static	char *	prettyinterval	P((char *, long));
  58static	int doprintpeers	P((struct varlist *, int, int, int, char *, FILE *, int));
  59static	int dogetpeers	P((struct varlist *, int, FILE *, int));
  60static	void	dopeers 	P((int, FILE *, int));
  61static	void	peers		P((struct parse *, FILE *));
  62static	void	lpeers		P((struct parse *, FILE *));
  63static	void	doopeers	P((int, FILE *, int));
  64static	void	opeers		P((struct parse *, FILE *));
  65static	void	lopeers 	P((struct parse *, FILE *));
  66
  67
  68/*
  69 * Commands we understand.	Ntpdc imports this.
  70 */
  71struct xcmd opcmds[] = {
  72	{ "associations", associations, {  NO, NO, NO, NO },
  73	  { "", "", "", "" },
  74	  "print list of association ID's and statuses for the server's peers" },
  75	{ "passociations", passociations,   {  NO, NO, NO, NO },
  76	  { "", "", "", "" },
  77	  "print list of associations returned by last associations command" },
  78	{ "lassociations", lassociations,   {  NO, NO, NO, NO },
  79	  { "", "", "", "" },
  80	  "print list of associations including all client information" },
  81	{ "lpassociations", lpassociations, {  NO, NO, NO, NO },
  82	  { "", "", "", "" },
  83	  "print last obtained list of associations, including client information" },
  84	{ "addvars",    addvars,    { NTP_STR, NO, NO, NO },
  85	  { "name[=value][,...]", "", "", "" },
  86	  "add variables to the variable list or change their values" },
  87	{ "rmvars", rmvars,     { NTP_STR, NO, NO, NO },
  88	  { "name[,...]", "", "", "" },
  89	  "remove variables from the variable list" },
  90	{ "clearvars",  clearvars,  { NO, NO, NO, NO },
  91	  { "", "", "", "" },
  92	  "remove all variables from the variable list" },
  93	{ "showvars",   showvars,   { NO, NO, NO, NO },
  94	  { "", "", "", "" },
  95	  "print variables on the variable list" },
  96	{ "readlist",   readlist,   { OPT|NTP_UINT, NO, NO, NO },
  97	  { "assocID", "", "", "" },
  98	  "read the system or peer variables included in the variable list" },
  99	{ "rl",     readlist,   { OPT|NTP_UINT, NO, NO, NO },
 100	  { "assocID", "", "", "" },
 101	  "read the system or peer variables included in the variable list" },
 102	{ "writelist",  writelist,  { OPT|NTP_UINT, NO, NO, NO },
 103	  { "assocID", "", "", "" },
 104	  "write the system or peer variables included in the variable list" },
 105	{ "readvar",    readvar,    { OPT|NTP_UINT, OPT|NTP_STR, NO, NO },
 106	  { "assocID", "name=value[,...]", "", "" },
 107	  "read system or peer variables" },
 108	{ "rv",     readvar,    { OPT|NTP_UINT, OPT|NTP_STR, NO, NO },
 109	  { "assocID", "name=value[,...]", "", "" },
 110	  "read system or peer variables" },
 111	{ "writevar",   writevar,   { NTP_UINT, NTP_STR, NO, NO },
 112	  { "assocID", "name=value,[...]", "", "" },
 113	  "write system or peer variables" },
 114	{ "mreadlist",  mreadlist,  { NTP_UINT, NTP_UINT, NO, NO },
 115	  { "assocID", "assocID", "", "" },
 116	  "read the peer variables in the variable list for multiple peers" },
 117	{ "mrl",    mreadlist,  { NTP_UINT, NTP_UINT, NO, NO },
 118	  { "assocID", "assocID", "", "" },
 119	  "read the peer variables in the variable list for multiple peers" },
 120	{ "mreadvar",   mreadvar,   { NTP_UINT, NTP_UINT, OPT|NTP_STR, NO },
 121	  { "assocID", "assocID", "name=value[,...]", "" },
 122	  "read peer variables from multiple peers" },
 123	{ "mrv",    mreadvar,   { NTP_UINT, NTP_UINT, OPT|NTP_STR, NO },
 124	  { "assocID", "assocID", "name=value[,...]", "" },
 125	  "read peer variables from multiple peers" },
 126	{ "clocklist",  clocklist,  { OPT|NTP_UINT, NO, NO, NO },
 127	  { "assocID", "", "", "" },
 128	  "read the clock variables included in the variable list" },
 129	{ "cl",     clocklist,  { OPT|NTP_UINT, NO, NO, NO },
 130	  { "assocID", "", "", "" },
 131	  "read the clock variables included in the variable list" },
 132	{ "clockvar",   clockvar,   { OPT|NTP_UINT, OPT|NTP_STR, NO, NO },
 133	  { "assocID", "name=value[,...]", "", "" },
 134	  "read clock variables" },
 135	{ "cv",     clockvar,   { OPT|NTP_UINT, OPT|NTP_STR, NO, NO },
 136	  { "assocID", "name=value[,...]", "", "" },
 137	  "read clock variables" },
 138	{ "pstatus",    pstatus,    { NTP_UINT, NO, NO, NO },
 139	  { "assocID", "", "", "" },
 140	  "print status information returned for a peer" },
 141	{ "peers",  peers,      { OPT|IP_VERSION, NO, NO, NO },
 142	  { "-4|-6", "", "", "" },
 143	  "obtain and print a list of the server's peers [IP version]" },
 144	{ "lpeers", lpeers,     { OPT|IP_VERSION, NO, NO, NO },
 145	  { "-4|-6", "", "", "" },
 146	  "obtain and print a list of all peers and clients [IP version]" },
 147	{ "opeers", opeers,     { OPT|IP_VERSION, NO, NO, NO },
 148	  { "-4|-6", "", "", "" },
 149	  "print peer list the old way, with dstadr shown rather than refid [IP version]" },
 150	{ "lopeers", lopeers,   { OPT|IP_VERSION, NO, NO, NO },
 151	  { "-4|-6", "", "", "" },
 152	  "obtain and print a list of all peers and clients showing dstadr [IP version]" },
 153	{ 0,		0,		{ NO, NO, NO, NO },
 154	  { "-4|-6", "", "", "" }, "" }
 155};
 156
 157
 158/*
 159 * Variable list data space
 160 */
 161#define MAXLIST 	64	/* maximum number of variables in list */
 162#define LENHOSTNAME 256 /* host name is 256 characters long */
 163/*
 164 * Old CTL_PST defines for version 2.
 165 */
 166#define OLD_CTL_PST_CONFIG			0x80
 167#define OLD_CTL_PST_AUTHENABLE		0x40
 168#define OLD_CTL_PST_AUTHENTIC		0x20
 169#define OLD_CTL_PST_REACH			0x10
 170#define OLD_CTL_PST_SANE			0x08
 171#define OLD_CTL_PST_DISP			0x04
 172#define OLD_CTL_PST_SEL_REJECT		0
 173#define OLD_CTL_PST_SEL_SELCAND 	1
 174#define OLD_CTL_PST_SEL_SYNCCAND	2
 175#define OLD_CTL_PST_SEL_SYSPEER 	3
 176
 177
 178char flash2[] = " .+*    "; /* flash decode for version 2 */
 179char flash3[] = " x.-+#*o"; /* flash decode for peer status version 3 */
 180
 181struct varlist {
 182	char *name;
 183	char *value;
 184} varlist[MAXLIST] = { { 0, 0 } };
 185
 186/*
 187 * Imported from ntpq.c
 188 */
 189extern int showhostnames;
 190extern int rawmode;
 191extern struct servent *server_entry;
 192extern struct association assoc_cache[];
 193extern int numassoc;
 194extern u_char pktversion;
 195extern struct ctl_var peer_var[];
 196
 197/*
 198 * For quick string comparisons
 199 */
 200#define STREQ(a, b) (*(a) == *(b) && strcmp((a), (b)) == 0)
 201
 202
 203/*
 204 * checkassocid - return the association ID, checking to see if it is valid
 205 */
 206static int
 207checkassocid(
 208	u_int32 value
 209	)
 210{
 211	if (value == 0 || value >= 65536) {
 212		(void) fprintf(stderr, "***Invalid association ID specified\n");
 213		return 0;
 214	}
 215	return (int)value;
 216}
 217
 218
 219/*
 220 * strsave - save a string
 221 * XXX - should be in libntp.a
 222 */
 223static char *
 224strsave(
 225	char *str
 226	)
 227{
 228	char *cp;
 229	u_int len;
 230
 231	len = strlen(str) + 1;
 232	if ((cp = (char *)malloc(len)) == NULL) {
 233		(void) fprintf(stderr, "Malloc failed!!\n");
 234		exit(1);
 235	}
 236
 237	memmove(cp, str, len);
 238	return (cp);
 239}
 240
 241
 242/*
 243 * findlistvar - look for the named variable in a list and return if found
 244 */
 245static struct varlist *
 246findlistvar(
 247	struct varlist *list,
 248	char *name
 249	)
 250{
 251	register struct varlist *vl;
 252
 253	for (vl = list; vl < list + MAXLIST && vl->name != 0; vl++)
 254		if (STREQ(name, vl->name))
 255		return vl;
 256	if (vl < list + MAXLIST)
 257		return vl;
 258	return (struct varlist *)0;
 259}
 260
 261
 262/*
 263 * doaddvlist - add variable(s) to the variable list
 264 */
 265static void
 266doaddvlist(
 267	struct varlist *vlist,
 268	char *vars
 269	)
 270{
 271	register struct varlist *vl;
 272	int len;
 273	char *name;
 274	char *value;
 275
 276	len = strlen(vars);
 277	while (nextvar(&len, &vars, &name, &value)) {
 278		vl = findlistvar(vlist, name);
 279		if (vl == 0) {
 280			(void) fprintf(stderr, "Variable list full\n");
 281			return;
 282		}
 283
 284		if (vl->name == 0) {
 285			vl->name = strsave(name);
 286		} else if (vl->value != 0) {
 287			free(vl->value);
 288			vl->value = 0;
 289		}
 290
 291		if (value != 0)
 292			vl->value = strsave(value);
 293	}
 294}
 295
 296
 297/*
 298 * dormvlist - remove variable(s) from the variable list
 299 */
 300static void
 301dormvlist(
 302	struct varlist *vlist,
 303	char *vars
 304	)
 305{
 306	register struct varlist *vl;
 307	int len;
 308	char *name;
 309	char *value;
 310
 311	len = strlen(vars);
 312	while (nextvar(&len, &vars, &name, &value)) {
 313		vl = findlistvar(vlist, name);
 314		if (vl == 0 || vl->name == 0) {
 315			(void) fprintf(stderr, "Variable `%s' not found\n",
 316				       name);
 317		} else {
 318			free((void *)vl->name);
 319			if (vl->value != 0)
 320			    free(vl->value);
 321			for ( ; (vl+1) < (varlist+MAXLIST)
 322				      && (vl+1)->name != 0; vl++) {
 323				vl->name = (vl+1)->name;
 324				vl->value = (vl+1)->value;
 325			}
 326			vl->name = vl->value = 0;
 327		}
 328	}
 329}
 330
 331
 332/*
 333 * doclearvlist - clear a variable list
 334 */
 335static void
 336doclearvlist(
 337	struct varlist *vlist
 338	)
 339{
 340	register struct varlist *vl;
 341
 342	for (vl = vlist; vl < vlist + MAXLIST && vl->name != 0; vl++) {
 343		free((void *)vl->name);
 344		vl->name = 0;
 345		if (vl->value != 0) {
 346			free(vl->value);
 347			vl->value = 0;
 348		}
 349	}
 350}
 351
 352
 353/*
 354 * makequerydata - form a data buffer to be included with a query
 355 */
 356static void
 357makequerydata(
 358	struct varlist *vlist,
 359	int *datalen,
 360	char *data
 361	)
 362{
 363	register struct varlist *vl;
 364	register char *cp, *cpend;
 365	register int namelen, valuelen;
 366	register int totallen;
 367
 368	cp = data;
 369	cpend = data + *datalen;
 370
 371	for (vl = vlist; vl < vlist + MAXLIST && vl->name != 0; vl++) {
 372		namelen = strlen(vl->name);
 373		if (vl->value == 0)
 374			valuelen = 0;
 375		else
 376			valuelen = strlen(vl->value);
 377		totallen = namelen + valuelen + (valuelen != 0) + (cp != data);
 378		if (cp + totallen > cpend)
 379			break;
 380
 381		if (cp != data)
 382			*cp++ = ',';
 383		memmove(cp, vl->name, (unsigned)namelen);
 384		cp += namelen;
 385		if (valuelen != 0) {
 386			*cp++ = '=';
 387			memmove(cp, vl->value, (unsigned)valuelen);
 388			cp += valuelen;
 389		}
 390	}
 391	*datalen = cp - data;
 392}
 393
 394
 395/*
 396 * doquerylist - send a message including variables in a list
 397 */
 398static int
 399doquerylist(
 400	struct varlist *vlist,
 401	int op,
 402	int associd,
 403	int auth,
 404	u_short *rstatus,
 405	int *dsize,
 406	char **datap
 407	)
 408{
 409	char data[CTL_MAX_DATA_LEN];
 410	int datalen;
 411
 412	datalen = sizeof(data);
 413	makequerydata(vlist, &datalen, data);
 414
 415	return doquery(op, associd, auth, datalen, data, rstatus,
 416			   dsize, datap);
 417}
 418
 419
 420/*
 421 * doprintvlist - print the variables on a list
 422 */
 423static void
 424doprintvlist(
 425	struct varlist *vlist,
 426	FILE *fp
 427	)
 428{
 429	register struct varlist *vl;
 430
 431	if (vlist->name == 0) {
 432		(void) fprintf(fp, "No variables on list\n");
 433	} else {
 434		for (vl = vlist; vl < vlist + MAXLIST && vl->name != 0; vl++) {
 435			if (vl->value == 0) {
 436				(void) fprintf(fp, "%s\n", vl->name);
 437			} else {
 438				(void) fprintf(fp, "%s=%s\n",
 439						   vl->name, vl->value);
 440			}
 441		}
 442	}
 443}
 444
 445
 446/*
 447 * addvars - add variables to the variable list
 448 */
 449/*ARGSUSED*/
 450static void
 451addvars(
 452	struct parse *pcmd,
 453	FILE *fp
 454	)
 455{
 456	doaddvlist(varlist, pcmd->argval[0].string);
 457}
 458
 459
 460/*
 461 * rmvars - remove variables from the variable list
 462 */
 463/*ARGSUSED*/
 464static void
 465rmvars(
 466	struct parse *pcmd,
 467	FILE *fp
 468	)
 469{
 470	dormvlist(varlist, pcmd->argval[0].string);
 471}
 472
 473
 474/*
 475 * clearvars - clear the variable list
 476 */
 477/*ARGSUSED*/
 478static void
 479clearvars(
 480	struct parse *pcmd,
 481	FILE *fp
 482	)
 483{
 484	doclearvlist(varlist);
 485}
 486
 487
 488/*
 489 * showvars - show variables on the variable list
 490 */
 491/*ARGSUSED*/
 492static void
 493showvars(
 494	struct parse *pcmd,
 495	FILE *fp
 496	)
 497{
 498	doprintvlist(varlist, fp);
 499}
 500
 501
 502/*
 503 * dolist - send a request with the given list of variables
 504 */
 505static int
 506dolist(
 507	struct varlist *vlist,
 508	int associd,
 509	int op,
 510	int type,
 511	FILE *fp
 512	)
 513{
 514	char *datap;
 515	int res;
 516	int dsize;
 517	u_short rstatus;
 518
 519	res = doquerylist(vlist, op, associd, 0, &rstatus, &dsize, &datap);
 520
 521	if (res != 0)
 522		return 0;
 523
 524	if (numhosts > 1)
 525		(void) fprintf(fp, "server=%s ", currenthost);
 526	if (dsize == 0) {
 527		if (associd == 0)
 528			(void) fprintf(fp, "No system%s variables returned\n",
 529				   (type == TYPE_CLOCK) ? " clock" : "");
 530		else
 531			(void) fprintf(fp,
 532				   "No information returned for%s association %u\n",
 533				   (type == TYPE_CLOCK) ? " clock" : "", associd);
 534		return 1;
 535	}
 536
 537	(void) fprintf(fp,"assID=%d ",associd);
 538	printvars(dsize, datap, (int)rstatus, type, fp);
 539	return 1;
 540}
 541
 542
 543/*
 544 * readlist - send a read variables request with the variables on the list
 545 */
 546static void
 547readlist(
 548	struct parse *pcmd,
 549	FILE *fp
 550	)
 551{
 552	int associd;
 553
 554	if (pcmd->nargs == 0) {
 555		associd = 0;
 556	} else {
 557	  /* HMS: I think we want the u_int32 target here, not the u_long */
 558		if (pcmd->argval[0].uval == 0)
 559			associd = 0;
 560		else if ((associd = checkassocid(pcmd->argval[0].uval)) == 0)
 561			return;
 562	}
 563
 564	(void) dolist(varlist, associd, CTL_OP_READVAR,
 565			  (associd == 0) ? TYPE_SYS : TYPE_PEER, fp);
 566}
 567
 568
 569/*
 570 * writelist - send a write variables request with the variables on the list
 571 */
 572static void
 573writelist(
 574	struct parse *pcmd,
 575	FILE *fp
 576	)
 577{
 578	char *datap;
 579	int res;
 580	int associd;
 581	int dsize;
 582	u_short rstatus;
 583
 584	if (pcmd->nargs == 0) {
 585		associd = 0;
 586	} else {
 587		/* HMS: Do we really want uval here? */
 588		if (pcmd->argval[0].uval == 0)
 589			associd = 0;
 590		else if ((associd = checkassocid(pcmd->argval[0].uval)) == 0)
 591			return;
 592	}
 593
 594	res = doquerylist(varlist, CTL_OP_WRITEVAR, associd, 1, &rstatus,
 595			  &dsize, &datap);
 596
 597	if (res != 0)
 598		return;
 599
 600	if (numhosts > 1)
 601		(void) fprintf(fp, "server=%s ", currenthost);
 602	if (dsize == 0)
 603		(void) fprintf(fp, "done! (no data returned)\n");
 604	else {
 605		(void) fprintf(fp,"assID=%d ",associd);
 606		printvars(dsize, datap, (int)rstatus,
 607			  (associd != 0) ? TYPE_PEER : TYPE_SYS, fp);
 608	}
 609	return;
 610}
 611
 612
 613/*
 614 * readvar - send a read variables request with the specified variables
 615 */
 616static void
 617readvar(
 618	struct parse *pcmd,
 619	FILE *fp
 620	)
 621{
 622	int associd;
 623	struct varlist tmplist[MAXLIST];
 624
 625	/* HMS: uval? */
 626	if (pcmd->nargs == 0 || pcmd->argval[0].uval == 0)
 627		associd = 0;
 628	else if ((associd = checkassocid(pcmd->argval[0].uval)) == 0)
 629		return;
 630
 631	memset((char *)tmplist, 0, sizeof(tmplist));
 632	if (pcmd->nargs >= 2)
 633		doaddvlist(tmplist, pcmd->argval[1].string);
 634
 635	(void) dolist(tmplist, associd, CTL_OP_READVAR,
 636			  (associd == 0) ? TYPE_SYS : TYPE_PEER, fp);
 637
 638	doclearvlist(tmplist);
 639}
 640
 641
 642/*
 643 * writevar - send a write variables request with the specified variables
 644 */
 645static void
 646writevar(
 647	struct parse *pcmd,
 648	FILE *fp
 649	)
 650{
 651	char *datap;
 652	int res;
 653	int associd;
 654	int dsize;
 655	u_short rstatus;
 656	struct varlist tmplist[MAXLIST];
 657
 658	/* HMS: uval? */
 659	if (pcmd->argval[0].uval == 0)
 660		associd = 0;
 661	else if ((associd = checkassocid(pcmd->argval[0].uval)) == 0)
 662		return;
 663
 664	memset((char *)tmplist, 0, sizeof(tmplist));
 665	doaddvlist(tmplist, pcmd->argval[1].string);
 666
 667	res = doquerylist(tmplist, CTL_OP_WRITEVAR, associd, 1, &rstatus,
 668			  &dsize, &datap);
 669
 670	doclearvlist(tmplist);
 671
 672	if (res != 0)
 673		return;
 674
 675	if (numhosts > 1)
 676		(void) fprintf(fp, "server=%s ", currenthost);
 677	if (dsize == 0)
 678		(void) fprintf(fp, "done! (no data returned)\n");
 679	else {
 680		(void) fprintf(fp,"assID=%d ",associd);
 681		printvars(dsize, datap, (int)rstatus,
 682			  (associd != 0) ? TYPE_PEER : TYPE_SYS, fp);
 683	}
 684	return;
 685}
 686
 687
 688/*
 689 * clocklist - send a clock variables request with the variables on the list
 690 */
 691static void
 692clocklist(
 693	struct parse *pcmd,
 694	FILE *fp
 695	)
 696{
 697	int associd;
 698
 699	/* HMS: uval? */
 700	if (pcmd->nargs == 0) {
 701		associd = 0;
 702	} else {
 703		if (pcmd->argval[0].uval == 0)
 704			associd = 0;
 705		else if ((associd = checkassocid(pcmd->argval[0].uval)) == 0)
 706			return;
 707	}
 708
 709	(void) dolist(varlist, associd, CTL_OP_READCLOCK, TYPE_CLOCK, fp);
 710}
 711
 712
 713/*
 714 * clockvar - send a clock variables request with the specified variables
 715 */
 716static void
 717clockvar(
 718	struct parse *pcmd,
 719	FILE *fp
 720	)
 721{
 722	int associd;
 723	struct varlist tmplist[MAXLIST];
 724
 725	/* HMS: uval? */
 726	if (pcmd->nargs == 0 || pcmd->argval[0].uval == 0)
 727		associd = 0;
 728	else if ((associd = checkassocid(pcmd->argval[0].uval)) == 0)
 729		return;
 730
 731	memset((char *)tmplist, 0, sizeof(tmplist));
 732	if (pcmd->nargs >= 2)
 733		doaddvlist(tmplist, pcmd->argval[1].string);
 734
 735	(void) dolist(tmplist, associd, CTL_OP_READCLOCK, TYPE_CLOCK, fp);
 736
 737	doclearvlist(tmplist);
 738}
 739
 740
 741/*
 742 * findassidrange - verify a range of association ID's
 743 */
 744static int
 745findassidrange(
 746	u_int32 assid1,
 747	u_int32 assid2,
 748	int *from,
 749	int *to
 750	)
 751{
 752	register int i;
 753	int f, t;
 754
 755	if (assid1 == 0 || assid1 > 65535) {
 756		(void) fprintf(stderr,
 757				   "***Invalid association ID %lu specified\n", (u_long)assid1);
 758		return 0;
 759	}
 760
 761	if (assid2 == 0 || assid2 > 65535) {
 762		(void) fprintf(stderr,
 763				   "***Invalid association ID %lu specified\n", (u_long)assid2);
 764		return 0;
 765	}
 766
 767	f = t = -1;
 768	for (i = 0; i < numassoc; i++) {
 769		if (assoc_cache[i].assid == assid1) {
 770			f = i;
 771			if (t != -1)
 772				break;
 773		}
 774		if (assoc_cache[i].assid == assid2) {
 775			t = i;
 776			if (f != -1)
 777				break;
 778		}
 779	}
 780
 781	if (f == -1 || t == -1) {
 782		(void) fprintf(stderr,
 783				   "***Association ID %lu not found in list\n",
 784				   (f == -1) ? (u_long)assid1 : (u_long)assid2);
 785		return 0;
 786	}
 787
 788	if (f < t) {
 789		*from = f;
 790		*to = t;
 791	} else {
 792		*from = t;
 793		*to = f;
 794	}
 795	return 1;
 796}
 797
 798
 799
 800/*
 801 * mreadlist - send a read variables request for multiple associations
 802 */
 803static void
 804mreadlist(
 805	struct parse *pcmd,
 806	FILE *fp
 807	)
 808{
 809	int i;
 810	int from;
 811	int to;
 812
 813	/* HMS: uval? */
 814	if (!findassidrange(pcmd->argval[0].uval, pcmd->argval[1].uval,
 815				&from, &to))
 816		return;
 817
 818	for (i = from; i <= to; i++) {
 819		if (i != from)
 820			(void) fprintf(fp, "\n");
 821		if (!dolist(varlist, (int)assoc_cache[i].assid,
 822				CTL_OP_READVAR, TYPE_PEER, fp))
 823			return;
 824	}
 825	return;
 826}
 827
 828
 829/*
 830 * mreadvar - send a read variables request for multiple associations
 831 */
 832static void
 833mreadvar(
 834	struct parse *pcmd,
 835	FILE *fp
 836	)
 837{
 838	int i;
 839	int from;
 840	int to;
 841	struct varlist tmplist[MAXLIST];
 842
 843	/* HMS: uval? */
 844	if (!findassidrange(pcmd->argval[0].uval, pcmd->argval[1].uval,
 845				&from, &to))
 846		return;
 847
 848	memset((char *)tmplist, 0, sizeof(tmplist));
 849	if (pcmd->nargs >= 3)
 850		doaddvlist(tmplist, pcmd->argval[2].string);
 851
 852	for (i = from; i <= to; i++) {
 853		if (i != from)
 854			(void) fprintf(fp, "\n");
 855		if (!dolist(varlist, (int)assoc_cache[i].assid,
 856				CTL_OP_READVAR, TYPE_PEER, fp))
 857			break;
 858	}
 859	doclearvlist(tmplist);
 860	return;
 861}
 862
 863
 864/*
 865 * dogetassoc - query the host for its list of associations
 866 */
 867static int
 868dogetassoc(
 869	FILE *fp
 870	)
 871{
 872	char *datap;
 873	int res;
 874	int dsize;
 875	u_short rstatus;
 876
 877	res = doquery(CTL_OP_READSTAT, 0, 0, 0, (char *)0, &rstatus,
 878			  &dsize, &datap);
 879
 880	if (res != 0)
 881		return 0;
 882
 883	if (dsize == 0) {
 884		if (numhosts > 1)
 885			(void) fprintf(fp, "server=%s ", currenthost);
 886		(void) fprintf(fp, "No association ID's returned\n");
 887		return 0;
 888	}
 889
 890	if (dsize & 0x3) {
 891		if (numhosts > 1)
 892			(void) fprintf(stderr, "server=%s ", currenthost);
 893		(void) fprintf(stderr,
 894				   "***Server returned %d octets, should be multiple of 4\n",
 895				   dsize);
 896		return 0;
 897	}
 898
 899	numassoc = 0;
 900	while (dsize > 0) {
 901		assoc_cache[numassoc].assid = ntohs(*((u_short *)datap));
 902		datap += sizeof(u_short);
 903		assoc_cache[numassoc].status = ntohs(*((u_short *)datap));
 904		datap += sizeof(u_short);
 905		if (++numassoc >= MAXASSOC)
 906			break;
 907		dsize -= sizeof(u_short) + sizeof(u_short);
 908	}
 909	sortassoc();
 910	return 1;
 911}
 912
 913
 914/*
 915 * printassoc - print the current list of associations
 916 */
 917static void
 918printassoc(
 919	int showall,
 920	FILE *fp
 921	)
 922{
 923	register char *bp;
 924	int i;
 925	u_char statval;
 926	int event;
 927	u_long event_count;
 928	const char *conf;
 929	const char *reach;
 930	const char *auth;
 931	const char *condition = "";
 932	const char *last_event;
 933	const char *cnt;
 934	char buf[128];
 935
 936	if (numassoc == 0) {
 937		(void) fprintf(fp, "No association ID's in list\n");
 938		return;
 939	}
 940
 941	/*
 942	 * Output a header
 943	 */
 944	(void) fprintf(fp,
 945			   "\nind assID status  conf reach auth condition  last_event cnt\n");
 946	(void) fprintf(fp,
 947			   "===========================================================\n");
 948	for (i = 0; i < numassoc; i++) {
 949		statval = (u_char) CTL_PEER_STATVAL(assoc_cache[i].status);
 950		if (!showall && !(statval & (CTL_PST_CONFIG|CTL_PST_REACH)))
 951			continue;
 952		event = CTL_PEER_EVENT(assoc_cache[i].status);
 953		event_count = CTL_PEER_NEVNT(assoc_cache[i].status);
 954		if (statval & CTL_PST_CONFIG)
 955			conf = "yes";
 956		else
 957			conf = "no";
 958		if (statval & CTL_PST_REACH || 1) {
 959			reach = "yes";
 960			if (statval & CTL_PST_AUTHENABLE) {
 961				if (statval & CTL_PST_AUTHENTIC)
 962					auth = "ok ";
 963				else
 964					auth = "bad";
 965			} else
 966				auth = "none";
 967
 968			if (pktversion > NTP_OLDVERSION)
 969				switch (statval & 0x7) {
 970				case CTL_PST_SEL_REJECT:
 971					condition = "reject";
 972					break;
 973				case CTL_PST_SEL_SANE:
 974					condition = "falsetick";
 975					break;
 976				case CTL_PST_SEL_CORRECT:
 977					condition = "excess";
 978					break;
 979				case CTL_PST_SEL_SELCAND:
 980					condition = "outlyer";
 981					break;
 982				case CTL_PST_SEL_SYNCCAND:
 983					condition = "candidat";
 984					break;
 985				case CTL_PST_SEL_DISTSYSPEER:
 986					condition = "selected";
 987					break;
 988				case CTL_PST_SEL_SYSPEER:
 989					condition = "sys.peer";
 990					break;
 991				case CTL_PST_SEL_PPS:
 992					condition = "pps.peer";
 993					break;
 994				}
 995			else
 996				switch (statval & 0x3) {
 997				case OLD_CTL_PST_SEL_REJECT:
 998					if (!(statval & OLD_CTL_PST_SANE))
 999					condition = "insane";
1000					else if (!(statval & OLD_CTL_PST_DISP))
1001					condition = "hi_disp";
1002					else
1003					condition = "";
1004					break;
1005				case OLD_CTL_PST_SEL_SELCAND:
1006					condition = "sel_cand";
1007					break;
1008				case OLD_CTL_PST_SEL_SYNCCAND:
1009					condition = "sync_cand";
1010					break;
1011				case OLD_CTL_PST_SEL_SYSPEER:
1012					condition = "sys_peer";
1013					break;
1014				}
1015
1016		} else {
1017			reach = "no";
1018			auth = condition = "";
1019		}
1020
1021		switch (PEER_EVENT|event) {
1022			case EVNT_PEERIPERR:
1023			last_event = "IP error";
1024			break;
1025			case EVNT_PEERAUTH:
1026			last_event = "auth fail";
1027			break;
1028			case EVNT_UNREACH:
1029			last_event = "lost reach";
1030			break;
1031			case EVNT_REACH:
1032			last_event = "reachable";
1033			break;
1034			case EVNT_PEERCLOCK:
1035			last_event = "clock expt";
1036			break;
1037#if 0
1038			case EVNT_PEERSTRAT:
1039			last_event = "stratum chg";
1040			break;
1041#endif
1042			default:
1043			last_event = "";
1044			break;
1045		}
1046
1047		if (event_count != 0)
1048			cnt = uinttoa(event_count);
1049		else
1050			cnt = "";
1051		(void) sprintf(buf,
1052				   "%3d %5u  %04x   %3.3s  %4s  %4.4s %9.9s %11s %2s",
1053				   i+1, assoc_cache[i].assid, assoc_cache[i].status,
1054				   conf, reach, auth, condition, last_event, cnt);
1055		bp = &buf[strlen(buf)];
1056		while (bp > buf && *(bp-1) == ' ')
1057			*(--bp) = '\0';
1058		(void) fprintf(fp, "%s\n", buf);
1059	}
1060}
1061
1062
1063
1064/*
1065 * associations - get, record and print a list of associations
1066 */
1067/*ARGSUSED*/
1068static void
1069associations(
1070	struct parse *pcmd,
1071	FILE *fp
1072	)
1073{
1074	if (dogetassoc(fp))
1075		printassoc(0, fp);
1076}
1077
1078
1079/*
1080 * lassociations - get, record and print a long list of associations
1081 */
1082/*ARGSUSED*/
1083static void
1084lassociations(
1085	struct parse *pcmd,
1086	FILE *fp
1087	)
1088{
1089	if (dogetassoc(fp))
1090		printassoc(1, fp);
1091}
1092
1093
1094/*
1095 * passociations - print the association list
1096 */
1097/*ARGSUSED*/
1098static void
1099passociations(
1100	struct parse *pcmd,
1101	FILE *fp
1102	)
1103{
1104	printassoc(0, fp);
1105}
1106
1107
1108/*
1109 * lpassociations - print the long association list
1110 */
1111/*ARGSUSED*/
1112static void
1113lpassociations(
1114	struct parse *pcmd,
1115	FILE *fp
1116	)
1117{
1118	printassoc(1, fp);
1119}
1120
1121
1122#ifdef	UNUSED
1123/*
1124 * radiostatus - print the radio status returned by the server
1125 */
1126/*ARGSUSED*/
1127static void
1128radiostatus(
1129	struct parse *pcmd,
1130	FILE *fp
1131	)
1132{
1133	char *datap;
1134	int res;
1135	int dsize;
1136	u_short rstatus;
1137
1138	res = doquery(CTL_OP_READCLOCK, 0, 0, 0, (char *)0, &rstatus,
1139			  &dsize, &datap);
1140
1141	if (res != 0)
1142		return;
1143
1144	if (numhosts > 1)
1145		(void) fprintf(fp, "server=%s ", currenthost);
1146	if (dsize == 0) {
1147		(void) fprintf(fp, "No radio status string returned\n");
1148		return;
1149	}
1150
1151	asciize(dsize, datap, fp);
1152}
1153#endif	/* UNUSED */
1154
1155/*
1156 * pstatus - print peer status returned by the server
1157 */
1158static void
1159pstatus(
1160	struct parse *pcmd,
1161	FILE *fp
1162	)
1163{
1164	char *datap;
1165	int res;
1166	int associd;
1167	int dsize;
1168	u_short rstatus;
1169
1170	/* HMS: uval? */
1171	if ((associd = checkassocid(pcmd->argval[0].uval)) == 0)
1172		return;
1173
1174	res = doquery(CTL_OP_READSTAT, associd, 0, 0, (char *)0, &rstatus,
1175			  &dsize, &datap);
1176
1177	if (res != 0)
1178		return;
1179
1180	if (numhosts > 1)
1181		(void) fprintf(fp, "server=%s ", currenthost);
1182	if (dsize == 0) {
1183		(void) fprintf(fp,
1184				   "No information returned for association %u\n",
1185				   associd);
1186		return;
1187	}
1188
1189	(void) fprintf(fp,"assID=%d ",associd);
1190	printvars(dsize, datap, (int)rstatus, TYPE_PEER, fp);
1191}
1192
1193
1194/*
1195 * when - print how long its been since his last packet arrived
1196 */
1197static long
1198when(
1199	l_fp *ts,
1200	l_fp *rec,
1201	l_fp *reftime
1202	)
1203{
1204	l_fp *lasttime;
1205
1206	if (rec->l_ui != 0)
1207		lasttime = rec;
1208	else if (reftime->l_ui != 0)
1209		lasttime = reftime;
1210	else
1211		return 0;
1212
1213	return (ts->l_ui - lasttime->l_ui);
1214}
1215
1216
1217/*
1218 * Pretty-print an interval into the given buffer, in a human-friendly format.
1219 */
1220static char *
1221prettyinterval(
1222	char *buf,
1223	long diff
1224	)
1225{
1226	if (diff <= 0) {
1227		buf[0] = '-';
1228		buf[1] = 0;
1229		return buf;
1230	}
1231
1232	if (diff <= 2048) {
1233		(void) sprintf(buf, "%ld", (long int)diff);
1234		return buf;
1235	}
1236
1237	diff = (diff + 29) / 60;
1238	if (diff <= 300) {
1239		(void) sprintf(buf, "%ldm", (long int)diff);
1240		return buf;
1241	}
1242
1243	diff = (diff + 29) / 60;
1244	if (diff <= 96) {
1245		(void) sprintf(buf, "%ldh", (long int)diff);
1246		return buf;
1247	}
1248
1249	diff = (diff + 11) / 24;
1250	(void) sprintf(buf, "%ldd", (long int)diff);
1251	return buf;
1252}
1253
1254static char
1255decodeaddrtype(
1256	struct sockaddr_storage *sock
1257	)
1258{
1259	char ch = '-';
1260	u_int32 dummy;
1261	struct sockaddr_in6 *sin6;
1262
1263	switch(sock->ss_family) {
1264	case AF_INET:
1265		dummy = ((struct sockaddr_in *)sock)->sin_addr.s_addr;
1266		dummy = ntohl(dummy);
1267		ch = (char)(((dummy&0xf0000000)==0xe0000000) ? 'm' :
1268			((dummy&0x000000ff)==0x000000ff) ? 'b' :
1269			((dummy&0xffffffff)==0x7f000001) ? 'l' :
1270			((dummy&0xffffffe0)==0x00000000) ? '-' :
1271			'u');
1272		break;
1273	case AF_INET6:
1274		sin6 = (struct sockaddr_in6 *)sock;
1275		if (IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr))
1276			ch = 'm';
1277		else
1278			ch = 'u';
1279		break;
1280	default:
1281		ch = '-';
1282		break;
1283	}
1284	return ch;
1285}
1286
1287/*
1288 * A list of variables required by the peers command
1289 */
1290struct varlist opeervarlist[] = {
1291	{ "srcadr", 0 },    /* 0 */
1292	{ "dstadr", 0 },    /* 1 */
1293	{ "stratum",    0 },    /* 2 */
1294	{ "hpoll",  0 },    /* 3 */
1295	{ "ppoll",  0 },    /* 4 */
1296	{ "reach",  0 },    /* 5 */
1297	{ "delay",  0 },    /* 6 */
1298	{ "offset", 0 },    /* 7 */
1299	{ "jitter", 0 },    /* 8 */
1300	{ "dispersion", 0 },    /* 9 */
1301	{ "rec",    0 },    /* 10 */
1302	{ "reftime",    0 },    /* 11 */
1303	{ "srcport",    0 },    /* 12 */
1304	{ 0,		0 }
1305};
1306
1307struct varlist peervarlist[] = {
1308	{ "srcadr", 0 },    /* 0 */
1309	{ "refid",  0 },    /* 1 */
1310	{ "stratum",    0 },    /* 2 */
1311	{ "hpoll",  0 },    /* 3 */
1312	{ "ppoll",  0 },    /* 4 */
1313	{ "reach",  0 },    /* 5 */
1314	{ "delay",  0 },    /* 6 */
1315	{ "offset", 0 },    /* 7 */
1316	{ "jitter", 0 },    /* 8 */
1317	{ "dispersion", 0 },    /* 9 */
1318	{ "rec",    0 },    /* 10 */
1319	{ "reftime",    0 },    /* 11 */
1320	{ "srcport",    0 },    /* 12 */
1321	{ 0,		0 }
1322};
1323
1324#define HAVE_SRCADR 0
1325#define HAVE_DSTADR 1
1326#define HAVE_REFID	1
1327#define HAVE_STRATUM	2
1328#define HAVE_HPOLL	3
1329#define HAVE_PPOLL	4
1330#define HAVE_REACH	5
1331#define HAVE_DELAY	6
1332#define HAVE_OFFSET 7
1333#define HAVE_JITTER 8
1334#define HAVE_DISPERSION 9
1335#define HAVE_REC	10
1336#define HAVE_REFTIME	11
1337#define HAVE_SRCPORT	12
1338#define MAXHAVE 	13
1339
1340/*
1341 * Decode an incoming data buffer and print a line in the peer list
1342 */
1343static int
1344doprintpeers(
1345	struct varlist *pvl,
1346	int associd,
1347	int rstatus,
1348	int datalen,
1349	char *data,
1350	FILE *fp,
1351	int af
1352	)
1353{
1354	char *name;
1355	char *value = NULL;
1356	int i;
1357	int c;
1358
1359	struct sockaddr_storage srcadr;
1360	struct sockaddr_storage dstadr;
1361	u_long srcport = 0;
1362	char *dstadr_refid = "0.0.0.0";
1363	u_long stratum = 0;
1364	long ppoll = 0;
1365	long hpoll = 0;
1366	u_long reach = 0;
1367	l_fp estoffset;
1368	l_fp estdelay;
1369	l_fp estjitter;
1370	l_fp estdisp;
1371	l_fp reftime;
1372	l_fp rec;
1373	l_fp ts;
1374	u_char havevar[MAXHAVE];
1375	u_long poll_sec;
1376	char type = '?';
1377	char refid_string[10];
1378	char whenbuf[8], pollbuf[8];
1379	char clock_name[LENHOSTNAME];
1380
1381	memset((char *)havevar, 0, sizeof(havevar));
1382	get_systime(&ts);
1383	
1384	memset((char *)&srcadr, 0, sizeof(struct sockaddr_storage));
1385	memset((char *)&dstadr, 0, sizeof(struct sockaddr_storage));
1386
1387	/* Initialize by zeroing out estimate variables */
1388	memset((char *)&estoffset, 0, sizeof(l_fp));
1389	memset((char *)&estdelay, 0, sizeof(l_fp));
1390	memset((char *)&estjitter, 0, sizeof(l_fp));
1391	memset((char *)&estdisp, 0, sizeof(l_fp));
1392
1393	while (nextvar(&datalen, &data, &name, &value)) {
1394		struct sockaddr_storage dum_store;
1395
1396		i = findvar(name, peer_var, 1);
1397		if (i == 0)
1398			continue;	/* don't know this one */
1399		switch (i) {
1400			case CP_SRCADR:
1401			if (decodenetnum(value, &srcadr))
1402				havevar[HAVE_SRCADR] = 1;
1403			break;
1404			case CP_DSTADR:
1405			if (decodenetnum(value, &dum_store))
1406				type = decodeaddrtype(&dum_store);
1407			if (pvl == opeervarlist) {
1408				if (decodenetnum(value, &dstadr)) {
1409					havevar[HAVE_DSTADR] = 1;
1410					dstadr_refid = stoa(&dstadr);
1411				}
1412			}
1413			break;
1414			case CP_REFID:
1415			if (pvl == peervarlist) {
1416				havevar[HAVE_REFID] = 1;
1417				if (*value == '\0') {
1418					dstadr_refid = "0.0.0.0";
1419				} else if ((int)strlen(value) <= 4) {
1420					refid_string[0] = '.';
1421					(void) strcpy(&refid_string[1], value);
1422					i = strlen(refid_string);
1423					refid_string[i] = '.';
1424					refid_string[i+1] = '\0';
1425					dstadr_refid = refid_string;
1426				} else if (decodenetnum(value, &dstadr)) {
1427					if (SOCKNUL(&dstadr))
1428						dstadr_refid = "0.0.0.0";
1429					else if ((dstadr.ss_family == AF_INET)
1430					    && ISREFCLOCKADR(&dstadr))
1431    						dstadr_refid =
1432						    refnumtoa(&dstadr);
1433					else
1434						dstadr_refid =
1435						    stoa(&dstadr);
1436				} else {
1437					havevar[HAVE_REFID] = 0;
1438				}
1439			}
1440			break;
1441			case CP_STRATUM:
1442			if (decodeuint(value, &stratum))
1443				havevar[HAVE_STRATUM] = 1;
1444			break;
1445			case CP_HPOLL:
1446			if (decodeint(value, &hpoll)) {
1447				havevar[HAVE_HPOLL] = 1;
1448				if (hpoll < 0)
1449					hpoll = NTP_MINPOLL;
1450			}
1451			break;
1452			case CP_PPOLL:
1453			if (decodeint(value, &ppoll)) {
1454				havevar[HAVE_PPOLL] = 1;
1455				if (ppoll < 0)
1456					ppoll = NTP_MINPOLL;
1457			}
1458			break;
1459			case CP_REACH:
1460			if (decodeuint(value, &reach))
1461				havevar[HAVE_REACH] = 1;
1462			break;
1463			case CP_DELAY:
1464			if (decodetime(value, &estdelay))
1465				havevar[HAVE_DELAY] = 1;
1466			break;
1467			case CP_OFFSET:
1468			if (decodetime(value, &estoffset))
1469				havevar[HAVE_OFFSET] = 1;
1470			break;
1471			case CP_JITTER:
1472			if (pvl == peervarlist)
1473				if (decodetime(value, &estjitter))
1474					havevar[HAVE_JITTER] = 1;
1475			break;
1476			case CP_DISPERSION:
1477			if (decodetime(value, &estdisp))
1478				havevar[HAVE_DISPERSION] = 1;
1479			break;
1480			case CP_REC:
1481			if (decodets(value, &rec))
1482				havevar[HAVE_REC] = 1;
1483			break;
1484			case CP_SRCPORT:
1485			if (decodeuint(value, &srcport))
1486				havevar[HAVE_SRCPORT] = 1;
1487			break;
1488			case CP_REFTIME:
1489			havevar[HAVE_REFTIME] = 1;
1490			if (!decodets(value, &reftime))
1491				L_CLR(&reftime);
1492			break;
1493			default:
1494			break;
1495		}
1496	}
1497
1498	/*
1499	 * Check to see if the srcport is NTP's port.  If not this probably
1500	 * isn't a valid peer association.
1501	 */
1502	if (havevar[HAVE_SRCPORT] && srcport != NTP_PORT)
1503		return (1);
1504
1505	/*
1506	 * Got everything, format the line
1507	 */
1508	poll_sec = 1<<max(min3(ppoll, hpoll, NTP_MAXPOLL), NTP_MINPOLL);
1509	if (pktversion > NTP_OLDVERSION)
1510		c = flash3[CTL_PEER_STATVAL(rstatus) & 0x7];
1511	else
1512		c = flash2[CTL_PEER_STATVAL(rstatus) & 0x3];
1513	if (numhosts > 1)
1514		(void) fprintf(fp, "%-*s ", maxhostlen, currenthost);
1515	if (af == 0 || srcadr.ss_family == af){
1516		strcpy(clock_name, nntohost(&srcadr));
1517		
1518		(void) fprintf(fp,
1519			"%c%-15.15s %-15.15s %2ld %c %4.4s %4.4s  %3lo  %7.7s %8.7s %7.7s\n",
1520			c, clock_name, dstadr_refid, stratum, type,
1521			prettyinterval(whenbuf, when(&ts, &rec, &reftime)),
1522			prettyinterval(pollbuf, (int)poll_sec), reach,
1523			lfptoms(&estdelay, 3), lfptoms(&estoffset, 3),
1524			havevar[HAVE_JITTER] ? lfptoms(&estjitter, 3) :
1525			lfptoms(&estdisp, 3));
1526		return (1);
1527	}
1528	else
1529		return(1);
1530}
1531
1532#undef	HAVE_SRCADR
1533#undef	HAVE_DSTADR
1534#undef	HAVE_STRATUM
1535#undef	HAVE_PPOLL
1536#undef	HAVE_HPOLL
1537#undef	HAVE_REACH
1538#undef	HAVE_ESTDELAY
1539#undef	HAVE_ESTOFFSET
1540#undef	HAVE_JITTER
1541#undef	HAVE_ESTDISP
1542#undef	HAVE_REFID
1543#undef	HAVE_REC
1544#undef	HAVE_SRCPORT
1545#undef	HAVE_REFTIME
1546#undef	MAXHAVE
1547
1548
1549/*
1550 * dogetpeers - given an association ID, read and print the spreadsheet
1551 *		peer variables.
1552 */
1553static int
1554dogetpeers(
1555	struct varlist *pvl,
1556	int associd,
1557	FILE *fp,
1558	int af
1559	)
1560{
1561	char *datap;
1562	int res;
1563	int dsize;
1564	u_short rstatus;
1565
1566#ifdef notdef
1567	res = doquerylist(pvl, CTL_OP_READVAR, associd, 0, &rstatus,
1568			  &dsize, &datap);
1569#else
1570	/*
1571	 * Damn fuzzballs
1572	 */
1573	res = doquery(CTL_OP_READVAR, associd, 0, 0, (char *)0, &rstatus,
1574			  &dsize, &datap);
1575#endif
1576
1577	if (res != 0)
1578		return 0;
1579
1580	if (dsize == 0) {
1581		if (numhosts > 1)
1582			(void) fprintf(stderr, "server=%s ", currenthost);
1583		(void) fprintf(stderr,
1584				   "***No information returned for association %d\n",
1585				   associd);
1586		return 0;
1587	}
1588
1589	return doprintpeers(pvl, associd, (int)rstatus, dsize, datap, fp, af);
1590}
1591
1592
1593/*
1594 * peers - print a peer spreadsheet
1595 */
1596static void
1597dopeers(
1598	int showall,
1599	FILE *fp,
1600	int af
1601	)
1602{
1603	register int i;
1604	char fullname[LENHOSTNAME];
1605	struct sockaddr_storage netnum;
1606
1607	if (!dogetassoc(fp))
1608		return;
1609
1610	for (i = 0; i < numhosts; ++i) {
1611		if (getnetnum(chosts[i], &netnum, fullname, af))
1612			if ((int)strlen(fullname) > maxhostlen)
1613				maxhostlen = strlen(fullname);
1614	}
1615	if (numhosts > 1)
1616		(void) fprintf(fp, "%-*.*s ", maxhostlen, maxhostlen, "server");
1617	(void) fprintf(fp,
1618			   "     remote           refid      st t when poll reach   delay   offset  jitter\n");
1619	if (numhosts > 1)
1620		for (i = 0; i <= maxhostlen; ++i)
1621		(void) fprintf(fp, "=");
1622	(void) fprintf(fp,
1623			   "==============================================================================\n");
1624
1625	for (i = 0; i < numassoc; i++) {
1626		if (!showall &&
1627			!(CTL_PEER_STATVAL(assoc_cache[i].status)
1628			  & (CTL_PST_CONFIG|CTL_PST_REACH)))
1629			continue;
1630		if (!dogetpeers(peervarlist, (int)assoc_cache[i].assid, fp, af)) {
1631			return;
1632		}
1633	}
1634	return;
1635}
1636
1637
1638/*
1639 * peers - print a peer spreadsheet
1640 */
1641/*ARGSUSED*/
1642static void
1643peers(
1644	struct parse *pcmd,
1645	FILE *fp
1646	)
1647{
1648	int af = 0;
1649
1650	if (pcmd->nargs == 1) {
1651		if (pcmd->argval->ival == 6)
1652			af = AF_INET6;
1653		else
1654			af = AF_INET;
1655	}
1656	dopeers(0, fp, af);
1657}
1658
1659
1660/*
1661 * lpeers - print a peer spreadsheet including all fuzzball peers
1662 */
1663/*ARGSUSED*/
1664static void
1665lpeers(
1666	struct parse *pcmd,
1667	FILE *fp
1668	)
1669{
1670	int af = 0;
1671
1672	if (pcmd->nargs == 1) {
1673		if (pcmd->argval->ival == 6)
1674			af = AF_INET6;
1675		else
1676			af = AF_INET;
1677	}
1678	dopeers(1, fp, af);
1679}
1680
1681
1682/*
1683 * opeers - print a peer spreadsheet
1684 */
1685static void
1686doopeers(
1687	int showall,
1688	FILE *fp,
1689	int af
1690	)
1691{
1692	register int i;
1693	char fullname[LENHOSTNAME];
1694	struct sockaddr_storage netnum;
1695
1696	if (!dogetassoc(fp))
1697		return;
1698
1699	for (i = 0; i < numhosts; ++i) {
1700		if (getnetnum(chosts[i], &netnum, fullname, af))
1701			if ((int)strlen(fullname) > maxhostlen)
1702				maxhostlen = strlen(fullname);
1703	}
1704	if (numhosts > 1)
1705		(void) fprintf(fp, "%-*.*s ", maxhostlen, maxhostlen, "server");
1706	(void) fprintf(fp,
1707			   "     remote           local      st t when poll reach   delay   offset    disp\n");
1708	if (numhosts > 1)
1709		for (i = 0; i <= maxhostlen; ++i)
1710		(void) fprintf(fp, "=");
1711	(void) fprintf(fp,
1712			   "==============================================================================\n");
1713
1714	for (i = 0; i < numassoc; i++) {
1715		if (!showall &&
1716			!(CTL_PEER_STATVAL(assoc_cache[i].status)
1717			  & (CTL_PST_CONFIG|CTL_PST_REACH)))
1718			continue;
1719		if (!dogetpeers(opeervarlist, (int)assoc_cache[i].assid, fp, af)) {
1720			return;
1721		}
1722	}
1723	return;
1724}
1725
1726
1727/*
1728 * opeers - print a peer spreadsheet the old way
1729 */
1730/*ARGSUSED*/
1731static void
1732opeers(
1733	struct parse *pcmd,
1734	FILE *fp
1735	)
1736{
1737	int af = 0;
1738
1739	if (pcmd->nargs == 1) {
1740		if (pcmd->argval->ival == 6)
1741			af = AF_INET6;
1742		else
1743			af = AF_INET;
1744	}
1745	doopeers(0, fp, af);
1746}
1747
1748
1749/*
1750 * lopeers - print a peer spreadsheet including all fuzzball peers
1751 */
1752/*ARGSUSED*/
1753static void
1754lopeers(
1755	struct parse *pcmd,
1756	FILE *fp
1757	)
1758{
1759	int af = 0;
1760
1761	if (pcmd->nargs == 1) {
1762		if (pcmd->argval->ival == 6)
1763			af = AF_INET6;
1764		else
1765			af = AF_INET;
1766	}
1767	doopeers(1, fp, af);
1768}