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