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 13 extern char * chosts[]; 14 extern char currenthost[]; 15 extern int numhosts; 16 int maxhostlen; 17 18 /* 19 * Declarations for command handlers in here 20 */ 21 static int checkassocid P((u_int32)); 22 static char * strsave P((char *)); 23 static struct varlist *findlistvar P((struct varlist *, char *)); 24 static void doaddvlist P((struct varlist *, char *)); 25 static void dormvlist P((struct varlist *, char *)); 26 static void doclearvlist P((struct varlist *)); 27 static void makequerydata P((struct varlist *, int *, char *)); 28 static int doquerylist P((struct varlist *, int, int, int, u_short *, int *, char **)); 29 static void doprintvlist P((struct varlist *, FILE *)); 30 static void addvars P((struct parse *, FILE *)); 31 static void rmvars P((struct parse *, FILE *)); 32 static void clearvars P((struct parse *, FILE *)); 33 static void showvars P((struct parse *, FILE *)); 34 static int dolist P((struct varlist *, int, int, int, FILE *)); 35 static void readlist P((struct parse *, FILE *)); 36 static void writelist P((struct parse *, FILE *)); 37 static void readvar P((struct parse *, FILE *)); 38 static void writevar P((struct parse *, FILE *)); 39 static void clocklist P((struct parse *, FILE *)); 40 static void clockvar P((struct parse *, FILE *)); 41 static int findassidrange P((u_int32, u_int32, int *, int *)); 42 static void mreadlist P((struct parse *, FILE *)); 43 static void mreadvar P((struct parse *, FILE *)); 44 static int dogetassoc P((FILE *)); 45 static void printassoc P((int, FILE *)); 46 static void associations P((struct parse *, FILE *)); 47 static void lassociations P((struct parse *, FILE *)); 48 static void passociations P((struct parse *, FILE *)); 49 static void lpassociations P((struct parse *, FILE *)); 50 51 #ifdef UNUSED 52 static void radiostatus P((struct parse *, FILE *)); 53 #endif /* UNUSED */ 54 55 static void pstatus P((struct parse *, FILE *)); 56 static long when P((l_fp *, l_fp *, l_fp *)); 57 static char * prettyinterval P((char *, long)); 58 static int doprintpeers P((struct varlist *, int, int, int, char *, FILE *, int)); 59 static int dogetpeers P((struct varlist *, int, FILE *, int)); 60 static void dopeers P((int, FILE *, int)); 61 static void peers P((struct parse *, FILE *)); 62 static void lpeers P((struct parse *, FILE *)); 63 static void doopeers P((int, FILE *, int)); 64 static void opeers P((struct parse *, FILE *)); 65 static void lopeers P((struct parse *, FILE *)); 66 67 68 /* 69 * Commands we understand. Ntpdc imports this. 70 */ 71 struct 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 178 char flash2[] = " .+* "; /* flash decode for version 2 */ 179 char flash3[] = " x.-+#*o"; /* flash decode for peer status version 3 */ 180 181 struct varlist { 182 char *name; 183 char *value; 184 } varlist[MAXLIST] = { { 0, 0 } }; 185 186 /* 187 * Imported from ntpq.c 188 */ 189 extern int showhostnames; 190 extern int rawmode; 191 extern struct servent *server_entry; 192 extern struct association assoc_cache[]; 193 extern int numassoc; 194 extern u_char pktversion; 195 extern 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 */ 206 static int 207 checkassocid( 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 */ 223 static char * 224 strsave( 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 */ 245 static struct varlist * 246 findlistvar( 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 */ 265 static void 266 doaddvlist( 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 */ 300 static void 301 dormvlist( 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 */ 335 static void 336 doclearvlist( 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 */ 356 static void 357 makequerydata( 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 */ 398 static int 399 doquerylist( 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 */ 423 static void 424 doprintvlist( 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*/ 450 static void 451 addvars( 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*/ 464 static void 465 rmvars( 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*/ 478 static void 479 clearvars( 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*/ 492 static void 493 showvars( 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 */ 505 static int 506 dolist( 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 */ 546 static void 547 readlist( 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 */ 572 static void 573 writelist( 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 */ 616 static void 617 readvar( 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 */ 645 static void 646 writevar( 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 */ 691 static void 692 clocklist( 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 */ 716 static void 717 clockvar( 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 */ 744 static int 745 findassidrange( 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 */ 803 static void 804 mreadlist( 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 */ 832 static void 833 mreadvar( 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 */ 867 static int 868 dogetassoc( 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 */ 917 static void 918 printassoc( 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*/ 1068 static void 1069 associations( 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*/ 1083 static void 1084 lassociations( 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*/ 1098 static void 1099 passociations( 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*/ 1112 static void 1113 lpassociations( 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*/ 1127 static void 1128 radiostatus( 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 */ 1158 static void 1159 pstatus( 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 */ 1197 static long 1198 when( 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 */ 1220 static char * 1221 prettyinterval( 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 1254 static char 1255 decodeaddrtype( 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 */ 1290 struct 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 1307 struct 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 */ 1343 static int 1344 doprintpeers( 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 */ 1553 static int 1554 dogetpeers( 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 */ 1596 static void 1597 dopeers( 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*/ 1642 static void 1643 peers( 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*/ 1664 static void 1665 lpeers( 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 */ 1685 static void 1686 doopeers( 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*/ 1731 static void 1732 opeers( 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*/ 1753 static void 1754 lopeers( 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 } 1769