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