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