Expand PMF_FN_* macros.
[netbsd-mini2440.git] / dist / ntp / ntpq / ntpq-subs.c
blob2ea898f3ce7124588596f6bf2d251059d6adccb0
1 /* $NetBSD: ntpq-subs.c,v 1.1.1.2 2007/06/24 15:50:25 kardel Exp $ */
3 /*
4 * ntpq_ops.c - subroutines which are called to perform operations by ntpq
5 */
7 #include <stdio.h>
8 #include <ctype.h>
9 #include <sys/types.h>
10 #include <sys/time.h>
12 #include "ntpq.h"
13 #include "ntp_stdlib.h"
15 extern const char * chosts[];
16 extern char currenthost[];
17 extern int numhosts;
18 int maxhostlen;
21 * Declarations for command handlers in here
23 static int checkassocid P((u_int32));
24 static char * strsave P((char *));
25 static struct varlist *findlistvar P((struct varlist *, char *));
26 static void doaddvlist P((struct varlist *, char *));
27 static void dormvlist P((struct varlist *, char *));
28 static void doclearvlist P((struct varlist *));
29 static void makequerydata P((struct varlist *, int *, char *));
30 static int doquerylist P((struct varlist *, int, int, int, u_short *, int *, char **));
31 static void doprintvlist P((struct varlist *, FILE *));
32 static void addvars P((struct parse *, FILE *));
33 static void rmvars P((struct parse *, FILE *));
34 static void clearvars P((struct parse *, FILE *));
35 static void showvars P((struct parse *, FILE *));
36 static int dolist P((struct varlist *, int, int, int, FILE *));
37 static void readlist P((struct parse *, FILE *));
38 static void writelist P((struct parse *, FILE *));
39 static void readvar P((struct parse *, FILE *));
40 static void writevar P((struct parse *, FILE *));
41 static void clocklist P((struct parse *, FILE *));
42 static void clockvar P((struct parse *, FILE *));
43 static int findassidrange P((u_int32, u_int32, int *, int *));
44 static void mreadlist P((struct parse *, FILE *));
45 static void mreadvar P((struct parse *, FILE *));
46 static int dogetassoc P((FILE *));
47 static void printassoc P((int, FILE *));
48 static void associations P((struct parse *, FILE *));
49 static void lassociations P((struct parse *, FILE *));
50 static void passociations P((struct parse *, FILE *));
51 static void lpassociations P((struct parse *, FILE *));
53 #ifdef UNUSED
54 static void radiostatus P((struct parse *, FILE *));
55 #endif /* UNUSED */
57 static void pstatus P((struct parse *, FILE *));
58 static long when P((l_fp *, l_fp *, l_fp *));
59 static char * prettyinterval P((char *, long));
60 static int doprintpeers P((struct varlist *, int, int, int, char *, FILE *, int));
61 static int dogetpeers P((struct varlist *, int, FILE *, int));
62 static void dopeers P((int, FILE *, int));
63 static void peers P((struct parse *, FILE *));
64 static void lpeers P((struct parse *, FILE *));
65 static void doopeers P((int, FILE *, int));
66 static void opeers P((struct parse *, FILE *));
67 static void lopeers P((struct parse *, FILE *));
71 * Commands we understand. Ntpdc imports this.
73 struct xcmd opcmds[] = {
74 { "associations", associations, { NO, NO, NO, NO },
75 { "", "", "", "" },
76 "print list of association ID's and statuses for the server's peers" },
77 { "passociations", passociations, { NO, NO, NO, NO },
78 { "", "", "", "" },
79 "print list of associations returned by last associations command" },
80 { "lassociations", lassociations, { NO, NO, NO, NO },
81 { "", "", "", "" },
82 "print list of associations including all client information" },
83 { "lpassociations", lpassociations, { NO, NO, NO, NO },
84 { "", "", "", "" },
85 "print last obtained list of associations, including client information" },
86 { "addvars", addvars, { NTP_STR, NO, NO, NO },
87 { "name[=value][,...]", "", "", "" },
88 "add variables to the variable list or change their values" },
89 { "rmvars", rmvars, { NTP_STR, NO, NO, NO },
90 { "name[,...]", "", "", "" },
91 "remove variables from the variable list" },
92 { "clearvars", clearvars, { NO, NO, NO, NO },
93 { "", "", "", "" },
94 "remove all variables from the variable list" },
95 { "showvars", showvars, { NO, NO, NO, NO },
96 { "", "", "", "" },
97 "print variables on the variable list" },
98 { "readlist", readlist, { OPT|NTP_UINT, NO, NO, NO },
99 { "assocID", "", "", "" },
100 "read the system or peer variables included in the variable list" },
101 { "rl", readlist, { OPT|NTP_UINT, NO, NO, NO },
102 { "assocID", "", "", "" },
103 "read the system or peer variables included in the variable list" },
104 { "writelist", writelist, { OPT|NTP_UINT, NO, NO, NO },
105 { "assocID", "", "", "" },
106 "write the system or peer variables included in the variable list" },
107 { "readvar", readvar, { OPT|NTP_UINT, OPT|NTP_STR, NO, NO },
108 { "assocID", "name=value[,...]", "", "" },
109 "read system or peer variables" },
110 { "rv", readvar, { OPT|NTP_UINT, OPT|NTP_STR, NO, NO },
111 { "assocID", "name=value[,...]", "", "" },
112 "read system or peer variables" },
113 { "writevar", writevar, { NTP_UINT, NTP_STR, NO, NO },
114 { "assocID", "name=value,[...]", "", "" },
115 "write system or peer variables" },
116 { "mreadlist", mreadlist, { NTP_UINT, NTP_UINT, NO, NO },
117 { "assocID", "assocID", "", "" },
118 "read the peer variables in the variable list for multiple peers" },
119 { "mrl", mreadlist, { NTP_UINT, NTP_UINT, NO, NO },
120 { "assocID", "assocID", "", "" },
121 "read the peer variables in the variable list for multiple peers" },
122 { "mreadvar", mreadvar, { NTP_UINT, NTP_UINT, OPT|NTP_STR, NO },
123 { "assocID", "assocID", "name=value[,...]", "" },
124 "read peer variables from multiple peers" },
125 { "mrv", mreadvar, { NTP_UINT, NTP_UINT, OPT|NTP_STR, NO },
126 { "assocID", "assocID", "name=value[,...]", "" },
127 "read peer variables from multiple peers" },
128 { "clocklist", clocklist, { OPT|NTP_UINT, NO, NO, NO },
129 { "assocID", "", "", "" },
130 "read the clock variables included in the variable list" },
131 { "cl", clocklist, { OPT|NTP_UINT, NO, NO, NO },
132 { "assocID", "", "", "" },
133 "read the clock variables included in the variable list" },
134 { "clockvar", clockvar, { OPT|NTP_UINT, OPT|NTP_STR, NO, NO },
135 { "assocID", "name=value[,...]", "", "" },
136 "read clock variables" },
137 { "cv", clockvar, { OPT|NTP_UINT, OPT|NTP_STR, NO, NO },
138 { "assocID", "name=value[,...]", "", "" },
139 "read clock variables" },
140 { "pstatus", pstatus, { NTP_UINT, NO, NO, NO },
141 { "assocID", "", "", "" },
142 "print status information returned for a peer" },
143 { "peers", peers, { OPT|IP_VERSION, NO, NO, NO },
144 { "-4|-6", "", "", "" },
145 "obtain and print a list of the server's peers [IP version]" },
146 { "lpeers", lpeers, { OPT|IP_VERSION, NO, NO, NO },
147 { "-4|-6", "", "", "" },
148 "obtain and print a list of all peers and clients [IP version]" },
149 { "opeers", opeers, { OPT|IP_VERSION, NO, NO, NO },
150 { "-4|-6", "", "", "" },
151 "print peer list the old way, with dstadr shown rather than refid [IP version]" },
152 { "lopeers", lopeers, { OPT|IP_VERSION, NO, NO, NO },
153 { "-4|-6", "", "", "" },
154 "obtain and print a list of all peers and clients showing dstadr [IP version]" },
155 { 0, 0, { NO, NO, NO, NO },
156 { "-4|-6", "", "", "" }, "" }
161 * Variable list data space
163 #define MAXLIST 64 /* maximum number of variables in list */
164 #define LENHOSTNAME 256 /* host name is 256 characters long */
166 * Old CTL_PST defines for version 2.
168 #define OLD_CTL_PST_CONFIG 0x80
169 #define OLD_CTL_PST_AUTHENABLE 0x40
170 #define OLD_CTL_PST_AUTHENTIC 0x20
171 #define OLD_CTL_PST_REACH 0x10
172 #define OLD_CTL_PST_SANE 0x08
173 #define OLD_CTL_PST_DISP 0x04
174 #define OLD_CTL_PST_SEL_REJECT 0
175 #define OLD_CTL_PST_SEL_SELCAND 1
176 #define OLD_CTL_PST_SEL_SYNCCAND 2
177 #define OLD_CTL_PST_SEL_SYSPEER 3
180 char flash2[] = " .+* "; /* flash decode for version 2 */
181 char flash3[] = " x.-+#*o"; /* flash decode for peer status version 3 */
183 struct varlist {
184 char *name;
185 char *value;
186 } varlist[MAXLIST] = { { 0, 0 } };
189 * Imported from ntpq.c
191 extern int showhostnames;
192 extern int rawmode;
193 extern struct servent *server_entry;
194 extern struct association assoc_cache[];
195 extern int numassoc;
196 extern u_char pktversion;
197 extern struct ctl_var peer_var[];
200 * For quick string comparisons
202 #define STREQ(a, b) (*(a) == *(b) && strcmp((a), (b)) == 0)
206 * checkassocid - return the association ID, checking to see if it is valid
208 static int
209 checkassocid(
210 u_int32 value
213 if (value == 0 || value >= 65536) {
214 (void) fprintf(stderr, "***Invalid association ID specified\n");
215 return 0;
217 return (int)value;
222 * strsave - save a string
223 * XXX - should be in libntp.a
225 static char *
226 strsave(
227 char *str
230 char *cp;
231 u_int len;
233 len = strlen(str) + 1;
234 if ((cp = (char *)malloc(len)) == NULL) {
235 (void) fprintf(stderr, "Malloc failed!!\n");
236 exit(1);
239 memmove(cp, str, len);
240 return (cp);
245 * findlistvar - look for the named variable in a list and return if found
247 static struct varlist *
248 findlistvar(
249 struct varlist *list,
250 char *name
253 register struct varlist *vl;
255 for (vl = list; vl < list + MAXLIST && vl->name != 0; vl++)
256 if (STREQ(name, vl->name))
257 return vl;
258 if (vl < list + MAXLIST)
259 return vl;
260 return (struct varlist *)0;
265 * doaddvlist - add variable(s) to the variable list
267 static void
268 doaddvlist(
269 struct varlist *vlist,
270 char *vars
273 register struct varlist *vl;
274 int len;
275 char *name;
276 char *value;
278 len = strlen(vars);
279 while (nextvar(&len, &vars, &name, &value)) {
280 vl = findlistvar(vlist, name);
281 if (vl == 0) {
282 (void) fprintf(stderr, "Variable list full\n");
283 return;
286 if (vl->name == 0) {
287 vl->name = strsave(name);
288 } else if (vl->value != 0) {
289 free(vl->value);
290 vl->value = 0;
293 if (value != 0)
294 vl->value = strsave(value);
300 * dormvlist - remove variable(s) from the variable list
302 static void
303 dormvlist(
304 struct varlist *vlist,
305 char *vars
308 register struct varlist *vl;
309 int len;
310 char *name;
311 char *value;
313 len = strlen(vars);
314 while (nextvar(&len, &vars, &name, &value)) {
315 vl = findlistvar(vlist, name);
316 if (vl == 0 || vl->name == 0) {
317 (void) fprintf(stderr, "Variable `%s' not found\n",
318 name);
319 } else {
320 free((void *)vl->name);
321 if (vl->value != 0)
322 free(vl->value);
323 for ( ; (vl+1) < (varlist+MAXLIST)
324 && (vl+1)->name != 0; vl++) {
325 vl->name = (vl+1)->name;
326 vl->value = (vl+1)->value;
328 vl->name = vl->value = 0;
335 * doclearvlist - clear a variable list
337 static void
338 doclearvlist(
339 struct varlist *vlist
342 register struct varlist *vl;
344 for (vl = vlist; vl < vlist + MAXLIST && vl->name != 0; vl++) {
345 free((void *)vl->name);
346 vl->name = 0;
347 if (vl->value != 0) {
348 free(vl->value);
349 vl->value = 0;
356 * makequerydata - form a data buffer to be included with a query
358 static void
359 makequerydata(
360 struct varlist *vlist,
361 int *datalen,
362 char *data
365 register struct varlist *vl;
366 register char *cp, *cpend;
367 register int namelen, valuelen;
368 register int totallen;
370 cp = data;
371 cpend = data + *datalen;
373 for (vl = vlist; vl < vlist + MAXLIST && vl->name != 0; vl++) {
374 namelen = strlen(vl->name);
375 if (vl->value == 0)
376 valuelen = 0;
377 else
378 valuelen = strlen(vl->value);
379 totallen = namelen + valuelen + (valuelen != 0) + (cp != data);
380 if (cp + totallen > cpend)
381 break;
383 if (cp != data)
384 *cp++ = ',';
385 memmove(cp, vl->name, (unsigned)namelen);
386 cp += namelen;
387 if (valuelen != 0) {
388 *cp++ = '=';
389 memmove(cp, vl->value, (unsigned)valuelen);
390 cp += valuelen;
393 *datalen = cp - data;
398 * doquerylist - send a message including variables in a list
400 static int
401 doquerylist(
402 struct varlist *vlist,
403 int op,
404 int associd,
405 int auth,
406 u_short *rstatus,
407 int *dsize,
408 char **datap
411 char data[CTL_MAX_DATA_LEN];
412 int datalen;
414 datalen = sizeof(data);
415 makequerydata(vlist, &datalen, data);
417 return doquery(op, associd, auth, datalen, data, rstatus,
418 dsize, datap);
423 * doprintvlist - print the variables on a list
425 static void
426 doprintvlist(
427 struct varlist *vlist,
428 FILE *fp
431 register struct varlist *vl;
433 if (vlist->name == 0) {
434 (void) fprintf(fp, "No variables on list\n");
435 } else {
436 for (vl = vlist; vl < vlist + MAXLIST && vl->name != 0; vl++) {
437 if (vl->value == 0) {
438 (void) fprintf(fp, "%s\n", vl->name);
439 } else {
440 (void) fprintf(fp, "%s=%s\n",
441 vl->name, vl->value);
449 * addvars - add variables to the variable list
451 /*ARGSUSED*/
452 static void
453 addvars(
454 struct parse *pcmd,
455 FILE *fp
458 doaddvlist(varlist, pcmd->argval[0].string);
463 * rmvars - remove variables from the variable list
465 /*ARGSUSED*/
466 static void
467 rmvars(
468 struct parse *pcmd,
469 FILE *fp
472 dormvlist(varlist, pcmd->argval[0].string);
477 * clearvars - clear the variable list
479 /*ARGSUSED*/
480 static void
481 clearvars(
482 struct parse *pcmd,
483 FILE *fp
486 doclearvlist(varlist);
491 * showvars - show variables on the variable list
493 /*ARGSUSED*/
494 static void
495 showvars(
496 struct parse *pcmd,
497 FILE *fp
500 doprintvlist(varlist, fp);
505 * dolist - send a request with the given list of variables
507 static int
508 dolist(
509 struct varlist *vlist,
510 int associd,
511 int op,
512 int type,
513 FILE *fp
516 char *datap;
517 int res;
518 int dsize;
519 u_short rstatus;
521 res = doquerylist(vlist, op, associd, 0, &rstatus, &dsize, &datap);
523 if (res != 0)
524 return 0;
526 if (numhosts > 1)
527 (void) fprintf(fp, "server=%s ", currenthost);
528 if (dsize == 0) {
529 if (associd == 0)
530 (void) fprintf(fp, "No system%s variables returned\n",
531 (type == TYPE_CLOCK) ? " clock" : "");
532 else
533 (void) fprintf(fp,
534 "No information returned for%s association %u\n",
535 (type == TYPE_CLOCK) ? " clock" : "", associd);
536 return 1;
539 (void) fprintf(fp,"assID=%d ",associd);
540 printvars(dsize, datap, (int)rstatus, type, fp);
541 return 1;
546 * readlist - send a read variables request with the variables on the list
548 static void
549 readlist(
550 struct parse *pcmd,
551 FILE *fp
554 int associd;
556 if (pcmd->nargs == 0) {
557 associd = 0;
558 } else {
559 /* HMS: I think we want the u_int32 target here, not the u_long */
560 if (pcmd->argval[0].uval == 0)
561 associd = 0;
562 else if ((associd = checkassocid(pcmd->argval[0].uval)) == 0)
563 return;
566 (void) dolist(varlist, associd, CTL_OP_READVAR,
567 (associd == 0) ? TYPE_SYS : TYPE_PEER, fp);
572 * writelist - send a write variables request with the variables on the list
574 static void
575 writelist(
576 struct parse *pcmd,
577 FILE *fp
580 char *datap;
581 int res;
582 int associd;
583 int dsize;
584 u_short rstatus;
586 if (pcmd->nargs == 0) {
587 associd = 0;
588 } else {
589 /* HMS: Do we really want uval here? */
590 if (pcmd->argval[0].uval == 0)
591 associd = 0;
592 else if ((associd = checkassocid(pcmd->argval[0].uval)) == 0)
593 return;
596 res = doquerylist(varlist, CTL_OP_WRITEVAR, associd, 1, &rstatus,
597 &dsize, &datap);
599 if (res != 0)
600 return;
602 if (numhosts > 1)
603 (void) fprintf(fp, "server=%s ", currenthost);
604 if (dsize == 0)
605 (void) fprintf(fp, "done! (no data returned)\n");
606 else {
607 (void) fprintf(fp,"assID=%d ",associd);
608 printvars(dsize, datap, (int)rstatus,
609 (associd != 0) ? TYPE_PEER : TYPE_SYS, fp);
611 return;
616 * readvar - send a read variables request with the specified variables
618 static void
619 readvar(
620 struct parse *pcmd,
621 FILE *fp
624 int associd;
625 struct varlist tmplist[MAXLIST];
627 /* HMS: uval? */
628 if (pcmd->nargs == 0 || pcmd->argval[0].uval == 0)
629 associd = 0;
630 else if ((associd = checkassocid(pcmd->argval[0].uval)) == 0)
631 return;
633 memset((char *)tmplist, 0, sizeof(tmplist));
634 if (pcmd->nargs >= 2)
635 doaddvlist(tmplist, pcmd->argval[1].string);
637 (void) dolist(tmplist, associd, CTL_OP_READVAR,
638 (associd == 0) ? TYPE_SYS : TYPE_PEER, fp);
640 doclearvlist(tmplist);
645 * writevar - send a write variables request with the specified variables
647 static void
648 writevar(
649 struct parse *pcmd,
650 FILE *fp
653 char *datap;
654 int res;
655 int associd;
656 int dsize;
657 u_short rstatus;
658 struct varlist tmplist[MAXLIST];
660 /* HMS: uval? */
661 if (pcmd->argval[0].uval == 0)
662 associd = 0;
663 else if ((associd = checkassocid(pcmd->argval[0].uval)) == 0)
664 return;
666 memset((char *)tmplist, 0, sizeof(tmplist));
667 doaddvlist(tmplist, pcmd->argval[1].string);
669 res = doquerylist(tmplist, CTL_OP_WRITEVAR, associd, 1, &rstatus,
670 &dsize, &datap);
672 doclearvlist(tmplist);
674 if (res != 0)
675 return;
677 if (numhosts > 1)
678 (void) fprintf(fp, "server=%s ", currenthost);
679 if (dsize == 0)
680 (void) fprintf(fp, "done! (no data returned)\n");
681 else {
682 (void) fprintf(fp,"assID=%d ",associd);
683 printvars(dsize, datap, (int)rstatus,
684 (associd != 0) ? TYPE_PEER : TYPE_SYS, fp);
686 return;
691 * clocklist - send a clock variables request with the variables on the list
693 static void
694 clocklist(
695 struct parse *pcmd,
696 FILE *fp
699 int associd;
701 /* HMS: uval? */
702 if (pcmd->nargs == 0) {
703 associd = 0;
704 } else {
705 if (pcmd->argval[0].uval == 0)
706 associd = 0;
707 else if ((associd = checkassocid(pcmd->argval[0].uval)) == 0)
708 return;
711 (void) dolist(varlist, associd, CTL_OP_READCLOCK, TYPE_CLOCK, fp);
716 * clockvar - send a clock variables request with the specified variables
718 static void
719 clockvar(
720 struct parse *pcmd,
721 FILE *fp
724 int associd;
725 struct varlist tmplist[MAXLIST];
727 /* HMS: uval? */
728 if (pcmd->nargs == 0 || pcmd->argval[0].uval == 0)
729 associd = 0;
730 else if ((associd = checkassocid(pcmd->argval[0].uval)) == 0)
731 return;
733 memset((char *)tmplist, 0, sizeof(tmplist));
734 if (pcmd->nargs >= 2)
735 doaddvlist(tmplist, pcmd->argval[1].string);
737 (void) dolist(tmplist, associd, CTL_OP_READCLOCK, TYPE_CLOCK, fp);
739 doclearvlist(tmplist);
744 * findassidrange - verify a range of association ID's
746 static int
747 findassidrange(
748 u_int32 assid1,
749 u_int32 assid2,
750 int *from,
751 int *to
754 register int i;
755 int f, t;
757 if (assid1 == 0 || assid1 > 65535) {
758 (void) fprintf(stderr,
759 "***Invalid association ID %lu specified\n", (u_long)assid1);
760 return 0;
763 if (assid2 == 0 || assid2 > 65535) {
764 (void) fprintf(stderr,
765 "***Invalid association ID %lu specified\n", (u_long)assid2);
766 return 0;
769 f = t = -1;
770 for (i = 0; i < numassoc; i++) {
771 if (assoc_cache[i].assid == assid1) {
772 f = i;
773 if (t != -1)
774 break;
776 if (assoc_cache[i].assid == assid2) {
777 t = i;
778 if (f != -1)
779 break;
783 if (f == -1 || t == -1) {
784 (void) fprintf(stderr,
785 "***Association ID %lu not found in list\n",
786 (f == -1) ? (u_long)assid1 : (u_long)assid2);
787 return 0;
790 if (f < t) {
791 *from = f;
792 *to = t;
793 } else {
794 *from = t;
795 *to = f;
797 return 1;
803 * mreadlist - send a read variables request for multiple associations
805 static void
806 mreadlist(
807 struct parse *pcmd,
808 FILE *fp
811 int i;
812 int from;
813 int to;
815 /* HMS: uval? */
816 if (!findassidrange(pcmd->argval[0].uval, pcmd->argval[1].uval,
817 &from, &to))
818 return;
820 for (i = from; i <= to; i++) {
821 if (i != from)
822 (void) fprintf(fp, "\n");
823 if (!dolist(varlist, (int)assoc_cache[i].assid,
824 CTL_OP_READVAR, TYPE_PEER, fp))
825 return;
827 return;
832 * mreadvar - send a read variables request for multiple associations
834 static void
835 mreadvar(
836 struct parse *pcmd,
837 FILE *fp
840 int i;
841 int from;
842 int to;
843 struct varlist tmplist[MAXLIST];
845 /* HMS: uval? */
846 if (!findassidrange(pcmd->argval[0].uval, pcmd->argval[1].uval,
847 &from, &to))
848 return;
850 memset((char *)tmplist, 0, sizeof(tmplist));
851 if (pcmd->nargs >= 3)
852 doaddvlist(tmplist, pcmd->argval[2].string);
854 for (i = from; i <= to; i++) {
855 if (i != from)
856 (void) fprintf(fp, "\n");
857 if (!dolist(varlist, (int)assoc_cache[i].assid,
858 CTL_OP_READVAR, TYPE_PEER, fp))
859 break;
861 doclearvlist(tmplist);
862 return;
867 * dogetassoc - query the host for its list of associations
869 static int
870 dogetassoc(
871 FILE *fp
874 char *datap;
875 int res;
876 int dsize;
877 u_short rstatus;
879 res = doquery(CTL_OP_READSTAT, 0, 0, 0, (char *)0, &rstatus,
880 &dsize, &datap);
882 if (res != 0)
883 return 0;
885 if (dsize == 0) {
886 if (numhosts > 1)
887 (void) fprintf(fp, "server=%s ", currenthost);
888 (void) fprintf(fp, "No association ID's returned\n");
889 return 0;
892 if (dsize & 0x3) {
893 if (numhosts > 1)
894 (void) fprintf(stderr, "server=%s ", currenthost);
895 (void) fprintf(stderr,
896 "***Server returned %d octets, should be multiple of 4\n",
897 dsize);
898 return 0;
901 numassoc = 0;
902 while (dsize > 0) {
903 assoc_cache[numassoc].assid = ntohs(*((u_short *)datap));
904 datap += sizeof(u_short);
905 assoc_cache[numassoc].status = ntohs(*((u_short *)datap));
906 datap += sizeof(u_short);
907 if (++numassoc >= MAXASSOC)
908 break;
909 dsize -= sizeof(u_short) + sizeof(u_short);
911 sortassoc();
912 return 1;
917 * printassoc - print the current list of associations
919 static void
920 printassoc(
921 int showall,
922 FILE *fp
925 register char *bp;
926 int i;
927 u_char statval;
928 int event;
929 u_long event_count;
930 const char *conf;
931 const char *reach;
932 const char *auth;
933 const char *condition = "";
934 const char *last_event;
935 const char *cnt;
936 char buf[128];
938 if (numassoc == 0) {
939 (void) fprintf(fp, "No association ID's in list\n");
940 return;
944 * Output a header
946 (void) fprintf(fp,
947 "\nind assID status conf reach auth condition last_event cnt\n");
948 (void) fprintf(fp,
949 "===========================================================\n");
950 for (i = 0; i < numassoc; i++) {
951 statval = (u_char) CTL_PEER_STATVAL(assoc_cache[i].status);
952 if (!showall && !(statval & (CTL_PST_CONFIG|CTL_PST_REACH)))
953 continue;
954 event = CTL_PEER_EVENT(assoc_cache[i].status);
955 event_count = CTL_PEER_NEVNT(assoc_cache[i].status);
956 if (statval & CTL_PST_CONFIG)
957 conf = "yes";
958 else
959 conf = "no";
960 if (statval & CTL_PST_REACH || 1) {
961 reach = "yes";
962 if (statval & CTL_PST_AUTHENABLE) {
963 if (statval & CTL_PST_AUTHENTIC)
964 auth = "ok ";
965 else
966 auth = "bad";
967 } else
968 auth = "none";
970 if (pktversion > NTP_OLDVERSION)
971 switch (statval & 0x7) {
972 case CTL_PST_SEL_REJECT:
973 condition = "reject";
974 break;
975 case CTL_PST_SEL_SANE:
976 condition = "falsetick";
977 break;
978 case CTL_PST_SEL_CORRECT:
979 condition = "excess";
980 break;
981 case CTL_PST_SEL_SELCAND:
982 condition = "outlyer";
983 break;
984 case CTL_PST_SEL_SYNCCAND:
985 condition = "candidat";
986 break;
987 case CTL_PST_SEL_DISTSYSPEER:
988 condition = "selected";
989 break;
990 case CTL_PST_SEL_SYSPEER:
991 condition = "sys.peer";
992 break;
993 case CTL_PST_SEL_PPS:
994 condition = "pps.peer";
995 break;
997 else
998 switch (statval & 0x3) {
999 case OLD_CTL_PST_SEL_REJECT:
1000 if (!(statval & OLD_CTL_PST_SANE))
1001 condition = "insane";
1002 else if (!(statval & OLD_CTL_PST_DISP))
1003 condition = "hi_disp";
1004 else
1005 condition = "";
1006 break;
1007 case OLD_CTL_PST_SEL_SELCAND:
1008 condition = "sel_cand";
1009 break;
1010 case OLD_CTL_PST_SEL_SYNCCAND:
1011 condition = "sync_cand";
1012 break;
1013 case OLD_CTL_PST_SEL_SYSPEER:
1014 condition = "sys_peer";
1015 break;
1018 } else {
1019 reach = "no";
1020 auth = condition = "";
1023 switch (PEER_EVENT|event) {
1024 case EVNT_PEERIPERR:
1025 last_event = "IP error";
1026 break;
1027 case EVNT_PEERAUTH:
1028 last_event = "auth fail";
1029 break;
1030 case EVNT_UNREACH:
1031 last_event = "lost reach";
1032 break;
1033 case EVNT_REACH:
1034 last_event = "reachable";
1035 break;
1036 case EVNT_PEERCLOCK:
1037 last_event = "clock expt";
1038 break;
1039 #if 0
1040 case EVNT_PEERSTRAT:
1041 last_event = "stratum chg";
1042 break;
1043 #endif
1044 default:
1045 last_event = "";
1046 break;
1049 if (event_count != 0)
1050 cnt = uinttoa(event_count);
1051 else
1052 cnt = "";
1053 (void) sprintf(buf,
1054 "%3d %5u %04x %3.3s %4s %4.4s %9.9s %11s %2s",
1055 i+1, assoc_cache[i].assid, assoc_cache[i].status,
1056 conf, reach, auth, condition, last_event, cnt);
1057 bp = &buf[strlen(buf)];
1058 while (bp > buf && *(bp-1) == ' ')
1059 *(--bp) = '\0';
1060 (void) fprintf(fp, "%s\n", buf);
1067 * associations - get, record and print a list of associations
1069 /*ARGSUSED*/
1070 static void
1071 associations(
1072 struct parse *pcmd,
1073 FILE *fp
1076 if (dogetassoc(fp))
1077 printassoc(0, fp);
1082 * lassociations - get, record and print a long list of associations
1084 /*ARGSUSED*/
1085 static void
1086 lassociations(
1087 struct parse *pcmd,
1088 FILE *fp
1091 if (dogetassoc(fp))
1092 printassoc(1, fp);
1097 * passociations - print the association list
1099 /*ARGSUSED*/
1100 static void
1101 passociations(
1102 struct parse *pcmd,
1103 FILE *fp
1106 printassoc(0, fp);
1111 * lpassociations - print the long association list
1113 /*ARGSUSED*/
1114 static void
1115 lpassociations(
1116 struct parse *pcmd,
1117 FILE *fp
1120 printassoc(1, fp);
1124 #ifdef UNUSED
1126 * radiostatus - print the radio status returned by the server
1128 /*ARGSUSED*/
1129 static void
1130 radiostatus(
1131 struct parse *pcmd,
1132 FILE *fp
1135 char *datap;
1136 int res;
1137 int dsize;
1138 u_short rstatus;
1140 res = doquery(CTL_OP_READCLOCK, 0, 0, 0, (char *)0, &rstatus,
1141 &dsize, &datap);
1143 if (res != 0)
1144 return;
1146 if (numhosts > 1)
1147 (void) fprintf(fp, "server=%s ", currenthost);
1148 if (dsize == 0) {
1149 (void) fprintf(fp, "No radio status string returned\n");
1150 return;
1153 asciize(dsize, datap, fp);
1155 #endif /* UNUSED */
1158 * pstatus - print peer status returned by the server
1160 static void
1161 pstatus(
1162 struct parse *pcmd,
1163 FILE *fp
1166 char *datap;
1167 int res;
1168 int associd;
1169 int dsize;
1170 u_short rstatus;
1172 /* HMS: uval? */
1173 if ((associd = checkassocid(pcmd->argval[0].uval)) == 0)
1174 return;
1176 res = doquery(CTL_OP_READSTAT, associd, 0, 0, (char *)0, &rstatus,
1177 &dsize, &datap);
1179 if (res != 0)
1180 return;
1182 if (numhosts > 1)
1183 (void) fprintf(fp, "server=%s ", currenthost);
1184 if (dsize == 0) {
1185 (void) fprintf(fp,
1186 "No information returned for association %u\n",
1187 associd);
1188 return;
1191 (void) fprintf(fp,"assID=%d ",associd);
1192 printvars(dsize, datap, (int)rstatus, TYPE_PEER, fp);
1197 * when - print how long its been since his last packet arrived
1199 static long
1200 when(
1201 l_fp *ts,
1202 l_fp *rec,
1203 l_fp *reftime
1206 l_fp *lasttime;
1208 if (rec->l_ui != 0)
1209 lasttime = rec;
1210 else if (reftime->l_ui != 0)
1211 lasttime = reftime;
1212 else
1213 return 0;
1215 return (ts->l_ui - lasttime->l_ui);
1220 * Pretty-print an interval into the given buffer, in a human-friendly format.
1222 static char *
1223 prettyinterval(
1224 char *buf,
1225 long diff
1228 if (diff <= 0) {
1229 buf[0] = '-';
1230 buf[1] = 0;
1231 return buf;
1234 if (diff <= 2048) {
1235 (void) sprintf(buf, "%ld", (long int)diff);
1236 return buf;
1239 diff = (diff + 29) / 60;
1240 if (diff <= 300) {
1241 (void) sprintf(buf, "%ldm", (long int)diff);
1242 return buf;
1245 diff = (diff + 29) / 60;
1246 if (diff <= 96) {
1247 (void) sprintf(buf, "%ldh", (long int)diff);
1248 return buf;
1251 diff = (diff + 11) / 24;
1252 (void) sprintf(buf, "%ldd", (long int)diff);
1253 return buf;
1256 static char
1257 decodeaddrtype(
1258 struct sockaddr_storage *sock
1261 char ch = '-';
1262 u_int32 dummy;
1263 struct sockaddr_in6 *sin6;
1265 switch(sock->ss_family) {
1266 case AF_INET:
1267 dummy = ((struct sockaddr_in *)sock)->sin_addr.s_addr;
1268 dummy = ntohl(dummy);
1269 ch = (char)(((dummy&0xf0000000)==0xe0000000) ? 'm' :
1270 ((dummy&0x000000ff)==0x000000ff) ? 'b' :
1271 ((dummy&0xffffffff)==0x7f000001) ? 'l' :
1272 ((dummy&0xffffffe0)==0x00000000) ? '-' :
1273 'u');
1274 break;
1275 case AF_INET6:
1276 sin6 = (struct sockaddr_in6 *)sock;
1277 if (IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr))
1278 ch = 'm';
1279 else
1280 ch = 'u';
1281 break;
1282 default:
1283 ch = '-';
1284 break;
1286 return ch;
1290 * A list of variables required by the peers command
1292 struct varlist opeervarlist[] = {
1293 { "srcadr", 0 }, /* 0 */
1294 { "dstadr", 0 }, /* 1 */
1295 { "stratum", 0 }, /* 2 */
1296 { "hpoll", 0 }, /* 3 */
1297 { "ppoll", 0 }, /* 4 */
1298 { "reach", 0 }, /* 5 */
1299 { "delay", 0 }, /* 6 */
1300 { "offset", 0 }, /* 7 */
1301 { "jitter", 0 }, /* 8 */
1302 { "dispersion", 0 }, /* 9 */
1303 { "rec", 0 }, /* 10 */
1304 { "reftime", 0 }, /* 11 */
1305 { "srcport", 0 }, /* 12 */
1306 { 0, 0 }
1309 struct varlist peervarlist[] = {
1310 { "srcadr", 0 }, /* 0 */
1311 { "refid", 0 }, /* 1 */
1312 { "stratum", 0 }, /* 2 */
1313 { "hpoll", 0 }, /* 3 */
1314 { "ppoll", 0 }, /* 4 */
1315 { "reach", 0 }, /* 5 */
1316 { "delay", 0 }, /* 6 */
1317 { "offset", 0 }, /* 7 */
1318 { "jitter", 0 }, /* 8 */
1319 { "dispersion", 0 }, /* 9 */
1320 { "rec", 0 }, /* 10 */
1321 { "reftime", 0 }, /* 11 */
1322 { "srcport", 0 }, /* 12 */
1323 { 0, 0 }
1326 #define HAVE_SRCADR 0
1327 #define HAVE_DSTADR 1
1328 #define HAVE_REFID 1
1329 #define HAVE_STRATUM 2
1330 #define HAVE_HPOLL 3
1331 #define HAVE_PPOLL 4
1332 #define HAVE_REACH 5
1333 #define HAVE_DELAY 6
1334 #define HAVE_OFFSET 7
1335 #define HAVE_JITTER 8
1336 #define HAVE_DISPERSION 9
1337 #define HAVE_REC 10
1338 #define HAVE_REFTIME 11
1339 #define HAVE_SRCPORT 12
1340 #define MAXHAVE 13
1343 * Decode an incoming data buffer and print a line in the peer list
1345 static int
1346 doprintpeers(
1347 struct varlist *pvl,
1348 int associd,
1349 int rstatus,
1350 int datalen,
1351 char *data,
1352 FILE *fp,
1353 int af
1356 char *name;
1357 char *value = NULL;
1358 int i;
1359 int c;
1361 struct sockaddr_storage srcadr;
1362 struct sockaddr_storage dstadr;
1363 u_long srcport = 0;
1364 char *dstadr_refid = "0.0.0.0";
1365 u_long stratum = 0;
1366 long ppoll = 0;
1367 long hpoll = 0;
1368 u_long reach = 0;
1369 l_fp estoffset;
1370 l_fp estdelay;
1371 l_fp estjitter;
1372 l_fp estdisp;
1373 l_fp reftime;
1374 l_fp rec;
1375 l_fp ts;
1376 u_char havevar[MAXHAVE];
1377 u_long poll_sec;
1378 char type = '?';
1379 char refid_string[10];
1380 char whenbuf[8], pollbuf[8];
1381 char clock_name[LENHOSTNAME];
1383 memset((char *)havevar, 0, sizeof(havevar));
1384 get_systime(&ts);
1386 memset((char *)&srcadr, 0, sizeof(struct sockaddr_storage));
1387 memset((char *)&dstadr, 0, sizeof(struct sockaddr_storage));
1389 /* Initialize by zeroing out estimate variables */
1390 memset((char *)&estoffset, 0, sizeof(l_fp));
1391 memset((char *)&estdelay, 0, sizeof(l_fp));
1392 memset((char *)&estjitter, 0, sizeof(l_fp));
1393 memset((char *)&estdisp, 0, sizeof(l_fp));
1395 while (nextvar(&datalen, &data, &name, &value)) {
1396 struct sockaddr_storage dum_store;
1398 i = findvar(name, peer_var, 1);
1399 if (i == 0)
1400 continue; /* don't know this one */
1401 switch (i) {
1402 case CP_SRCADR:
1403 if (decodenetnum(value, &srcadr))
1404 havevar[HAVE_SRCADR] = 1;
1405 break;
1406 case CP_DSTADR:
1407 if (decodenetnum(value, &dum_store))
1408 type = decodeaddrtype(&dum_store);
1409 if (pvl == opeervarlist) {
1410 if (decodenetnum(value, &dstadr)) {
1411 havevar[HAVE_DSTADR] = 1;
1412 dstadr_refid = stoa(&dstadr);
1415 break;
1416 case CP_REFID:
1417 if (pvl == peervarlist) {
1418 havevar[HAVE_REFID] = 1;
1419 if (*value == '\0') {
1420 dstadr_refid = "0.0.0.0";
1421 } else if ((int)strlen(value) <= 4) {
1422 refid_string[0] = '.';
1423 (void) strcpy(&refid_string[1], value);
1424 i = strlen(refid_string);
1425 refid_string[i] = '.';
1426 refid_string[i+1] = '\0';
1427 dstadr_refid = refid_string;
1428 } else if (decodenetnum(value, &dstadr)) {
1429 if (SOCKNUL(&dstadr))
1430 dstadr_refid = "0.0.0.0";
1431 else if ((dstadr.ss_family == AF_INET)
1432 && ISREFCLOCKADR(&dstadr))
1433 dstadr_refid =
1434 refnumtoa(&dstadr);
1435 else
1436 dstadr_refid =
1437 stoa(&dstadr);
1438 } else {
1439 havevar[HAVE_REFID] = 0;
1442 break;
1443 case CP_STRATUM:
1444 if (decodeuint(value, &stratum))
1445 havevar[HAVE_STRATUM] = 1;
1446 break;
1447 case CP_HPOLL:
1448 if (decodeint(value, &hpoll)) {
1449 havevar[HAVE_HPOLL] = 1;
1450 if (hpoll < 0)
1451 hpoll = NTP_MINPOLL;
1453 break;
1454 case CP_PPOLL:
1455 if (decodeint(value, &ppoll)) {
1456 havevar[HAVE_PPOLL] = 1;
1457 if (ppoll < 0)
1458 ppoll = NTP_MINPOLL;
1460 break;
1461 case CP_REACH:
1462 if (decodeuint(value, &reach))
1463 havevar[HAVE_REACH] = 1;
1464 break;
1465 case CP_DELAY:
1466 if (decodetime(value, &estdelay))
1467 havevar[HAVE_DELAY] = 1;
1468 break;
1469 case CP_OFFSET:
1470 if (decodetime(value, &estoffset))
1471 havevar[HAVE_OFFSET] = 1;
1472 break;
1473 case CP_JITTER:
1474 if (pvl == peervarlist)
1475 if (decodetime(value, &estjitter))
1476 havevar[HAVE_JITTER] = 1;
1477 break;
1478 case CP_DISPERSION:
1479 if (decodetime(value, &estdisp))
1480 havevar[HAVE_DISPERSION] = 1;
1481 break;
1482 case CP_REC:
1483 if (decodets(value, &rec))
1484 havevar[HAVE_REC] = 1;
1485 break;
1486 case CP_SRCPORT:
1487 if (decodeuint(value, &srcport))
1488 havevar[HAVE_SRCPORT] = 1;
1489 break;
1490 case CP_REFTIME:
1491 havevar[HAVE_REFTIME] = 1;
1492 if (!decodets(value, &reftime))
1493 L_CLR(&reftime);
1494 break;
1495 default:
1496 break;
1501 * Check to see if the srcport is NTP's port. If not this probably
1502 * isn't a valid peer association.
1504 if (havevar[HAVE_SRCPORT] && srcport != NTP_PORT)
1505 return (1);
1508 * Got everything, format the line
1510 poll_sec = 1<<max(min3(ppoll, hpoll, NTP_MAXPOLL), NTP_MINPOLL);
1511 if (pktversion > NTP_OLDVERSION)
1512 c = flash3[CTL_PEER_STATVAL(rstatus) & 0x7];
1513 else
1514 c = flash2[CTL_PEER_STATVAL(rstatus) & 0x3];
1515 if (numhosts > 1)
1516 (void) fprintf(fp, "%-*s ", maxhostlen, currenthost);
1517 if (af == 0 || srcadr.ss_family == af){
1518 strcpy(clock_name, nntohost(&srcadr));
1520 (void) fprintf(fp,
1521 "%c%-15.15s %-15.15s %2ld %c %4.4s %4.4s %3lo %7.7s %8.7s %7.7s\n",
1522 c, clock_name, dstadr_refid, stratum, type,
1523 prettyinterval(whenbuf, when(&ts, &rec, &reftime)),
1524 prettyinterval(pollbuf, (int)poll_sec), reach,
1525 lfptoms(&estdelay, 3), lfptoms(&estoffset, 3),
1526 havevar[HAVE_JITTER] ? lfptoms(&estjitter, 3) :
1527 lfptoms(&estdisp, 3));
1528 return (1);
1530 else
1531 return(1);
1534 #undef HAVE_SRCADR
1535 #undef HAVE_DSTADR
1536 #undef HAVE_STRATUM
1537 #undef HAVE_PPOLL
1538 #undef HAVE_HPOLL
1539 #undef HAVE_REACH
1540 #undef HAVE_ESTDELAY
1541 #undef HAVE_ESTOFFSET
1542 #undef HAVE_JITTER
1543 #undef HAVE_ESTDISP
1544 #undef HAVE_REFID
1545 #undef HAVE_REC
1546 #undef HAVE_SRCPORT
1547 #undef HAVE_REFTIME
1548 #undef MAXHAVE
1552 * dogetpeers - given an association ID, read and print the spreadsheet
1553 * peer variables.
1555 static int
1556 dogetpeers(
1557 struct varlist *pvl,
1558 int associd,
1559 FILE *fp,
1560 int af
1563 char *datap;
1564 int res;
1565 int dsize;
1566 u_short rstatus;
1568 #ifdef notdef
1569 res = doquerylist(pvl, CTL_OP_READVAR, associd, 0, &rstatus,
1570 &dsize, &datap);
1571 #else
1573 * Damn fuzzballs
1575 res = doquery(CTL_OP_READVAR, associd, 0, 0, (char *)0, &rstatus,
1576 &dsize, &datap);
1577 #endif
1579 if (res != 0)
1580 return 0;
1582 if (dsize == 0) {
1583 if (numhosts > 1)
1584 (void) fprintf(stderr, "server=%s ", currenthost);
1585 (void) fprintf(stderr,
1586 "***No information returned for association %d\n",
1587 associd);
1588 return 0;
1591 return doprintpeers(pvl, associd, (int)rstatus, dsize, datap, fp, af);
1596 * peers - print a peer spreadsheet
1598 static void
1599 dopeers(
1600 int showall,
1601 FILE *fp,
1602 int af
1605 register int i;
1606 char fullname[LENHOSTNAME];
1607 struct sockaddr_storage netnum;
1609 if (!dogetassoc(fp))
1610 return;
1612 for (i = 0; i < numhosts; ++i) {
1613 if (getnetnum(chosts[i], &netnum, fullname, af))
1614 if ((int)strlen(fullname) > maxhostlen)
1615 maxhostlen = strlen(fullname);
1617 if (numhosts > 1)
1618 (void) fprintf(fp, "%-*.*s ", maxhostlen, maxhostlen, "server");
1619 (void) fprintf(fp,
1620 " remote refid st t when poll reach delay offset jitter\n");
1621 if (numhosts > 1)
1622 for (i = 0; i <= maxhostlen; ++i)
1623 (void) fprintf(fp, "=");
1624 (void) fprintf(fp,
1625 "==============================================================================\n");
1627 for (i = 0; i < numassoc; i++) {
1628 if (!showall &&
1629 !(CTL_PEER_STATVAL(assoc_cache[i].status)
1630 & (CTL_PST_CONFIG|CTL_PST_REACH)))
1631 continue;
1632 if (!dogetpeers(peervarlist, (int)assoc_cache[i].assid, fp, af)) {
1633 return;
1636 return;
1641 * peers - print a peer spreadsheet
1643 /*ARGSUSED*/
1644 static void
1645 peers(
1646 struct parse *pcmd,
1647 FILE *fp
1650 int af = 0;
1652 if (pcmd->nargs == 1) {
1653 if (pcmd->argval->ival == 6)
1654 af = AF_INET6;
1655 else
1656 af = AF_INET;
1658 dopeers(0, fp, af);
1663 * lpeers - print a peer spreadsheet including all fuzzball peers
1665 /*ARGSUSED*/
1666 static void
1667 lpeers(
1668 struct parse *pcmd,
1669 FILE *fp
1672 int af = 0;
1674 if (pcmd->nargs == 1) {
1675 if (pcmd->argval->ival == 6)
1676 af = AF_INET6;
1677 else
1678 af = AF_INET;
1680 dopeers(1, fp, af);
1685 * opeers - print a peer spreadsheet
1687 static void
1688 doopeers(
1689 int showall,
1690 FILE *fp,
1691 int af
1694 register int i;
1695 char fullname[LENHOSTNAME];
1696 struct sockaddr_storage netnum;
1698 if (!dogetassoc(fp))
1699 return;
1701 for (i = 0; i < numhosts; ++i) {
1702 if (getnetnum(chosts[i], &netnum, fullname, af))
1703 if ((int)strlen(fullname) > maxhostlen)
1704 maxhostlen = strlen(fullname);
1706 if (numhosts > 1)
1707 (void) fprintf(fp, "%-*.*s ", maxhostlen, maxhostlen, "server");
1708 (void) fprintf(fp,
1709 " remote local st t when poll reach delay offset disp\n");
1710 if (numhosts > 1)
1711 for (i = 0; i <= maxhostlen; ++i)
1712 (void) fprintf(fp, "=");
1713 (void) fprintf(fp,
1714 "==============================================================================\n");
1716 for (i = 0; i < numassoc; i++) {
1717 if (!showall &&
1718 !(CTL_PEER_STATVAL(assoc_cache[i].status)
1719 & (CTL_PST_CONFIG|CTL_PST_REACH)))
1720 continue;
1721 if (!dogetpeers(opeervarlist, (int)assoc_cache[i].assid, fp, af)) {
1722 return;
1725 return;
1730 * opeers - print a peer spreadsheet the old way
1732 /*ARGSUSED*/
1733 static void
1734 opeers(
1735 struct parse *pcmd,
1736 FILE *fp
1739 int af = 0;
1741 if (pcmd->nargs == 1) {
1742 if (pcmd->argval->ival == 6)
1743 af = AF_INET6;
1744 else
1745 af = AF_INET;
1747 doopeers(0, fp, af);
1752 * lopeers - print a peer spreadsheet including all fuzzball peers
1754 /*ARGSUSED*/
1755 static void
1756 lopeers(
1757 struct parse *pcmd,
1758 FILE *fp
1761 int af = 0;
1763 if (pcmd->nargs == 1) {
1764 if (pcmd->argval->ival == 6)
1765 af = AF_INET6;
1766 else
1767 af = AF_INET;
1769 doopeers(1, fp, af);