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