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