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