]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/ntp/ntpdc/ntpdc_ops.c
This commit was generated by cvs2svn to compensate for changes in r169942,
[FreeBSD/FreeBSD.git] / contrib / ntp / ntpdc / ntpdc_ops.c
1 /*
2  * ntpdc_ops.c - subroutines which are called to perform operations by xntpdc
3  */
4
5 #ifdef HAVE_CONFIG_H
6 # include <config.h>
7 #endif
8
9 #include <stdio.h>
10 #include <stddef.h>
11
12 #include "ntpdc.h"
13 #include "ntp_control.h"
14 #include "ntp_refclock.h"
15 #include "ntp_stdlib.h"
16
17 #include <ctype.h>
18 #ifdef HAVE_SYS_TIMEX_H
19 # include <sys/timex.h>
20 #endif
21 #include <netdb.h>
22 #if !defined(__bsdi__) && !defined(apollo)
23 #include <netinet/in.h>
24 #endif
25
26 #include <arpa/inet.h>
27
28 /*
29  * Declarations for command handlers in here
30  */
31 static  int     checkitems      P((int, FILE *));
32 static  int     checkitemsize   P((int, int));
33 static  int     check1item      P((int, FILE *));
34 static  void    peerlist        P((struct parse *, FILE *));
35 static  void    peers           P((struct parse *, FILE *));
36 static void     doconfig        P((struct parse *pcmd, FILE *fp, int mode, int refc));
37 static  void    dmpeers         P((struct parse *, FILE *));
38 static  void    dopeers         P((struct parse *, FILE *, int));
39 static  void    printpeer       P((struct info_peer *, FILE *));
40 static  void    showpeer        P((struct parse *, FILE *));
41 static  void    peerstats       P((struct parse *, FILE *));
42 static  void    loopinfo        P((struct parse *, FILE *));
43 static  void    sysinfo         P((struct parse *, FILE *));
44 static  void    sysstats        P((struct parse *, FILE *));
45 static  void    iostats         P((struct parse *, FILE *));
46 static  void    memstats        P((struct parse *, FILE *));
47 static  void    timerstats      P((struct parse *, FILE *));
48 static  void    addpeer         P((struct parse *, FILE *));
49 static  void    addserver       P((struct parse *, FILE *));
50 static  void    addrefclock     P((struct parse *, FILE *));
51 static  void    broadcast       P((struct parse *, FILE *));
52 static  void    doconfig        P((struct parse *, FILE *, int, int));
53 static  void    unconfig        P((struct parse *, FILE *));
54 static  void    set             P((struct parse *, FILE *));
55 static  void    sys_clear       P((struct parse *, FILE *));
56 static  void    doset           P((struct parse *, FILE *, int));
57 static  void    reslist         P((struct parse *, FILE *));
58 static  void    new_restrict    P((struct parse *, FILE *));
59 static  void    unrestrict      P((struct parse *, FILE *));
60 static  void    delrestrict     P((struct parse *, FILE *));
61 static  void    do_restrict     P((struct parse *, FILE *, int));
62 static  void    monlist         P((struct parse *, FILE *));
63 static  void    reset           P((struct parse *, FILE *));
64 static  void    preset          P((struct parse *, FILE *));
65 static  void    readkeys        P((struct parse *, FILE *));
66 static  void    trustkey        P((struct parse *, FILE *));
67 static  void    untrustkey      P((struct parse *, FILE *));
68 static  void    do_trustkey     P((struct parse *, FILE *, int));
69 static  void    authinfo        P((struct parse *, FILE *));
70 static  void    traps           P((struct parse *, FILE *));
71 static  void    addtrap         P((struct parse *, FILE *));
72 static  void    clrtrap         P((struct parse *, FILE *));
73 static  void    do_addclr_trap  P((struct parse *, FILE *, int));
74 static  void    requestkey      P((struct parse *, FILE *));
75 static  void    controlkey      P((struct parse *, FILE *));
76 static  void    do_changekey    P((struct parse *, FILE *, int));
77 static  void    ctlstats        P((struct parse *, FILE *));
78 static  void    clockstat       P((struct parse *, FILE *));
79 static  void    fudge           P((struct parse *, FILE *));
80 static  void    clkbug          P((struct parse *, FILE *));
81 static  void    kerninfo        P((struct parse *, FILE *));
82
83 /*
84  * Commands we understand.  Ntpdc imports this.
85  */
86 struct xcmd opcmds[] = {
87         { "listpeers",  peerlist,       { OPT|IP_VERSION, NO, NO, NO },
88           { "-4|-6", "", "", "" },
89           "display list of peers the server knows about [IP Version]" },
90         { "peers",      peers,  { OPT|IP_VERSION, NO, NO, NO },
91           { "-4|-6", "", "", "" },
92           "display peer summary information [IP Version]" },
93         { "dmpeers",    dmpeers,        { OPT|IP_VERSION, NO, NO, NO },
94           { "-4|-6", "", "", "" },
95           "display peer summary info the way Dave Mills likes it (IP Version)" },
96         { "showpeer",   showpeer,       { ADD, OPT|ADD, OPT|ADD, OPT|ADD},
97           { "peer_address", "peer2_addr", "peer3_addr", "peer4_addr" },
98           "display detailed information for one or more peers" },
99         { "pstats",     peerstats,      { ADD, OPT|ADD, OPT|ADD, OPT|ADD },
100           { "peer_address", "peer2_addr", "peer3_addr", "peer4_addr" },
101           "display statistical information for one or more peers" },
102         { "loopinfo",   loopinfo,       { OPT|NTP_STR, NO, NO, NO },
103           { "oneline|multiline", "", "", "" },
104           "display loop filter information" },
105         { "sysinfo",    sysinfo,        { NO, NO, NO, NO },
106           { "", "", "", "" },
107           "display local server information" },
108         { "sysstats",   sysstats,       { NO, NO, NO, NO },
109           { "", "", "", "" },
110           "display local server statistics" },
111         { "memstats",   memstats,       { NO, NO, NO, NO },
112           { "", "", "", "" },
113           "display peer memory usage statistics" },
114         { "iostats",    iostats,        { NO, NO, NO, NO },
115           { "", "", "", "" },
116           "display I/O subsystem statistics" },
117         { "timerstats", timerstats,     { NO, NO, NO, NO },
118           { "", "", "", "" },
119           "display event timer subsystem statistics" },
120         { "addpeer",    addpeer,        { ADD, OPT|UINT, OPT|UINT, OPT|NTP_STR },
121           { "addr", "keyid", "version", "minpoll|prefer" },
122           "configure a new peer association" },
123         { "addserver",  addserver,      { ADD, OPT|UINT, OPT|UINT, OPT|NTP_STR },
124           { "addr", "keyid", "version", "minpoll|prefer" },
125           "configure a new server" },
126         { "addrefclock",addrefclock,    { ADD, OPT|UINT, OPT|NTP_STR, OPT|NTP_STR },
127           { "addr", "mode", "minpoll|prefer", "minpoll|prefer" },
128           "configure a new server" },
129         { "broadcast",  broadcast,      { ADD, OPT|UINT, OPT|UINT, OPT|NTP_STR },
130           { "addr", "keyid", "version", "minpoll" },
131           "configure broadcasting time service" },
132         { "unconfig",   unconfig,       { ADD, OPT|ADD, OPT|ADD, OPT|ADD },
133           { "peer_address", "peer2_addr", "peer3_addr", "peer4_addr" },
134           "unconfigure existing peer assocations" },
135         { "enable",     set,            { NTP_STR, OPT|NTP_STR, OPT|NTP_STR, OPT|NTP_STR },
136           { "auth|bclient|monitor|pll|kernel|stats", "...", "...", "..." },
137           "set a system flag (auth, bclient, monitor, pll, kernel, stats)" },
138         { "disable",    sys_clear,      { NTP_STR, OPT|NTP_STR, OPT|NTP_STR, OPT|NTP_STR },
139           { "auth|bclient|monitor|pll|kernel|stats", "...", "...", "..." },
140           "clear a system flag (auth, bclient, monitor, pll, kernel, stats)" },
141         { "reslist",    reslist,        {OPT|IP_VERSION, NO, NO, NO },
142           { "-4|-6", "", "", "" },
143           "display the server's restrict list" },
144         { "restrict",   new_restrict,   { ADD, ADD, NTP_STR, OPT|NTP_STR },
145           { "address", "mask",
146             "ntpport|ignore|noserve|notrust|noquery|nomodify|nopeer|version|kod",
147             "..." },
148           "create restrict entry/add flags to entry" },
149         { "unrestrict", unrestrict,     { ADD, ADD, NTP_STR, OPT|NTP_STR },
150           { "address", "mask",
151             "ntpport|ignore|noserve|notrust|noquery|nomodify|nopeer|version|kod",
152             "..." },
153           "remove flags from a restrict entry" },
154         { "delrestrict", delrestrict,   { ADD, ADD, OPT|NTP_STR, NO },
155           { "address", "mask", "ntpport", "" },
156           "delete a restrict entry" },
157         { "monlist",    monlist,        { OPT|INT, NO, NO, NO },
158           { "version", "", "", "" },
159           "display data the server's monitor routines have collected" },
160         { "reset",      reset,          { NTP_STR, OPT|NTP_STR, OPT|NTP_STR, OPT|NTP_STR },
161           { "io|sys|mem|timer|auth|allpeers", "...", "...", "..." },
162           "reset various subsystem statistics counters" },
163         { "preset",     preset,         { ADD, OPT|ADD, OPT|ADD, OPT|ADD },
164           { "peer_address", "peer2_addr", "peer3_addr", "peer4_addr" },
165           "reset stat counters associated with particular peer(s)" },
166         { "readkeys",   readkeys,       { NO, NO, NO, NO },
167           { "", "", "", "" },
168           "request a reread of the keys file and re-init of system keys" },
169         { "trustedkey", trustkey,       { UINT, OPT|UINT, OPT|UINT, OPT|UINT },
170           { "keyid", "keyid", "keyid", "keyid" },
171           "add one or more key ID's to the trusted list" },
172         { "untrustedkey", untrustkey,   { UINT, OPT|UINT, OPT|UINT, OPT|UINT },
173           { "keyid", "keyid", "keyid", "keyid" },
174           "remove one or more key ID's from the trusted list" },
175         { "authinfo",   authinfo,       { NO, NO, NO, NO },
176           { "", "", "", "" },
177           "display the state of the authentication code" },
178         { "traps",      traps,          { NO, NO, NO, NO },
179           { "", "", "", "" },
180           "display the traps set in the server" },
181         { "addtrap",    addtrap,        { ADD, OPT|UINT, OPT|ADD, NO },
182           { "address", "port", "interface", "" },
183           "configure a trap in the server" },
184         { "clrtrap",    clrtrap,        { ADD, OPT|UINT, OPT|ADD, NO },
185           { "address", "port", "interface", "" },
186           "remove a trap (configured or otherwise) from the server" },
187         { "requestkey", requestkey,     { UINT, NO, NO, NO },
188           { "keyid", "", "", "" },
189           "change the keyid the server uses to authenticate requests" },
190         { "controlkey", controlkey,     { UINT, NO, NO, NO },
191           { "keyid", "", "", "" },
192           "change the keyid the server uses to authenticate control messages" },
193         { "ctlstats",   ctlstats,       { NO, NO, NO, NO },
194           { "", "", "", "" },
195           "display packet count statistics from the control module" },
196         { "clockstat",  clockstat,      { ADD, OPT|ADD, OPT|ADD, OPT|ADD },
197           { "address", "address", "address", "address" },
198           "display clock status information" },
199         { "fudge",      fudge,          { ADD, NTP_STR, NTP_STR, NO },
200           { "address", "time1|time2|val1|val2|flags", "value", "" },
201           "set/change one of a clock's fudge factors" },
202         { "clkbug",     clkbug,         { ADD, OPT|ADD, OPT|ADD, OPT|ADD },
203           { "address", "address", "address", "address" },
204           "display clock debugging information" },
205         { "kerninfo",   kerninfo,       { NO, NO, NO, NO },
206           { "", "", "", "" },
207           "display the kernel pll/pps variables" },
208
209         { 0,            0,              { NO, NO, NO, NO },
210           { "", "", "", "" }, "" }
211 };
212
213 /*
214  * For quick string comparisons
215  */
216 #define STREQ(a, b)     (*(a) == *(b) && strcmp((a), (b)) == 0)
217
218
219 /*
220  * checkitems - utility to print a message if no items were returned
221  */
222 static int
223 checkitems(
224         int items,
225         FILE *fp
226         )
227 {
228         if (items == 0) {
229                 (void) fprintf(fp, "No data returned in response to query\n");
230                 return 0;
231         }
232         return 1;
233 }
234
235
236 /*
237  * checkitemsize - utility to print a message if the item size is wrong
238  */
239 static int
240 checkitemsize(
241         int itemsize,
242         int expected
243         )
244 {
245         if (itemsize != expected) {
246                 (void) fprintf(stderr,
247                                "***Incorrect item size returned by remote host (%d should be %d)\n",
248                                itemsize, expected);
249                 return 0;
250         }
251         return 1;
252 }
253
254
255 /*
256  * check1item - check to make sure we have exactly one item
257  */
258 static int
259 check1item(
260         int items,
261         FILE *fp
262         )
263 {
264         if (items == 0) {
265                 (void) fprintf(fp, "No data returned in response to query\n");
266                 return 0;
267         }
268         if (items > 1) {
269                 (void) fprintf(fp, "Expected one item in response, got %d\n",
270                                items);
271                 return 0;
272         }
273         return 1;
274 }
275
276
277
278 /*
279  * peerlist - get a short list of peers
280  */
281 /*ARGSUSED*/
282 static void
283 peerlist(
284         struct parse *pcmd,
285         FILE *fp
286         )
287 {
288         struct info_peer_list *plist;
289         struct sockaddr_storage paddr;
290         int items;
291         int itemsize;
292         int res;
293
294 again:
295         res = doquery(impl_ver, REQ_PEER_LIST, 0, 0, 0, (char *)NULL, &items,
296                       &itemsize, (void *)&plist, 0, 
297                       sizeof(struct info_peer_list));
298         
299         if (res == INFO_ERR_IMPL && impl_ver == IMPL_XNTPD) {
300                 impl_ver = IMPL_XNTPD_OLD;
301                 goto again;
302         }
303
304         if (res != 0 && items == 0)
305             return;
306
307         if (!checkitems(items, fp))
308             return;
309
310         if (!checkitemsize(itemsize, sizeof(struct info_peer_list)) &&
311             !checkitemsize(itemsize, v4sizeof(struct info_peer_list)))
312             return;
313
314         while (items > 0) {
315                 memset((char *)&paddr, 0, sizeof(paddr));
316                 if (plist->v6_flag != 0) {
317                         GET_INADDR6(paddr) = plist->addr6;
318                         paddr.ss_family = AF_INET6;
319                 } else {
320                         GET_INADDR(paddr) = plist->addr;
321                         paddr.ss_family = AF_INET;
322                 }
323 #ifdef HAVE_SA_LEN_IN_STRUCT_SOCKADDR
324                 paddr.ss_len = SOCKLEN(&paddr);
325 #endif
326                 if ((pcmd->nargs == 0) ||
327                     ((pcmd->argval->ival == 6) && (plist->v6_flag != 0)) ||
328                     ((pcmd->argval->ival == 4) && (plist->v6_flag == 0)))
329                         (void) fprintf(fp, "%-9s %s\n",
330                                 modetoa(plist->hmode),
331                                 nntohost(&paddr));
332                 plist++;
333                 items--;
334         }
335 }
336
337
338 /*
339  * peers - show peer summary
340  */
341 static void
342 peers(
343         struct parse *pcmd,
344         FILE *fp
345         )
346 {
347         dopeers(pcmd, fp, 0);
348 }
349
350 /*
351  * dmpeers - show peer summary, Dave Mills style
352  */
353 static void
354 dmpeers(
355         struct parse *pcmd,
356         FILE *fp
357         )
358 {
359         dopeers(pcmd, fp, 1);
360 }
361
362
363 /*
364  * peers - show peer summary
365  */
366 /*ARGSUSED*/
367 static void
368 dopeers(
369         struct parse *pcmd,
370         FILE *fp,
371         int dmstyle
372         )
373 {
374         struct info_peer_summary *plist;
375         struct sockaddr_storage dstadr;
376         struct sockaddr_storage srcadr;
377         int items;
378         int itemsize;
379         int ntp_poll;
380         int res;
381         int c;
382         l_fp tempts;
383
384 again:
385         res = doquery(impl_ver, REQ_PEER_LIST_SUM, 0, 0, 0, (char *)NULL,
386                       &items, &itemsize, (void *)&plist, 0, 
387                       sizeof(struct info_peer_summary));
388         
389         if (res == INFO_ERR_IMPL && impl_ver == IMPL_XNTPD) {
390                 impl_ver = IMPL_XNTPD_OLD;
391                 goto again;
392         }
393
394         if (res != 0 && items == 0)
395             return;
396
397         if (!checkitems(items, fp))
398             return;
399
400         if (!checkitemsize(itemsize, sizeof(struct info_peer_summary)) &&
401             !checkitemsize(itemsize, v4sizeof(struct info_peer_summary)))
402                 return;
403
404         (void) fprintf(fp,
405                        "     remote           local      st poll reach  delay   offset    disp\n");
406         (void) fprintf(fp,
407                        "=======================================================================\n");
408         while (items > 0) {
409                 if (!dmstyle) {
410                         if (plist->flags & INFO_FLAG_SYSPEER)
411                             c = '*';
412                         else if (plist->hmode == MODE_ACTIVE)
413                             c = '+';
414                         else if (plist->hmode == MODE_PASSIVE)
415                             c = '-';
416                         else if (plist->hmode == MODE_CLIENT)
417                             c = '=';
418                         else if (plist->hmode == MODE_BROADCAST)
419                             c = '^';
420                         else if (plist->hmode == MODE_BCLIENT)
421                             c = '~';
422                         else
423                             c = ' ';
424                 } else {
425                         if (plist->flags & INFO_FLAG_SYSPEER)
426                             c = '*';
427                         else if (plist->flags & INFO_FLAG_SHORTLIST)
428                             c = '+';
429                         else if (plist->flags & INFO_FLAG_SEL_CANDIDATE)
430                             c = '.';
431                         else
432                             c = ' ';
433                 }
434                 NTOHL_FP(&(plist->offset), &tempts);
435                 ntp_poll = 1<<max(min3(plist->ppoll, plist->hpoll, NTP_MAXPOLL),
436                                   NTP_MINPOLL);
437                 memset((char *)&dstadr, 0, sizeof(dstadr));
438                 memset((char *)&srcadr, 0, sizeof(srcadr));
439                 if (plist->v6_flag != 0) {
440                         GET_INADDR6(dstadr) = plist->dstadr6;
441                         GET_INADDR6(srcadr) = plist->srcadr6;
442                         srcadr.ss_family = AF_INET6;
443                         dstadr.ss_family = AF_INET6;
444                 } else {
445                         GET_INADDR(dstadr) = plist->dstadr;
446                         GET_INADDR(srcadr) = plist->srcadr;
447                         srcadr.ss_family = AF_INET;
448                         dstadr.ss_family = AF_INET;
449                 }
450 #ifdef HAVE_SA_LEN_IN_STRUCT_SOCKADDR
451                 srcadr.ss_len = SOCKLEN(&srcadr);
452                 dstadr.ss_len = SOCKLEN(&dstadr);
453 #endif
454                 if ((pcmd->nargs == 0) ||
455                     ((pcmd->argval->ival == 6) && (plist->v6_flag != 0)) ||
456                     ((pcmd->argval->ival == 4) && (plist->v6_flag == 0)))
457                         (void) fprintf(fp,
458                             "%c%-15.15s %-15.15s %2d %4d  %3o %7.7s %9.9s %7.7s\n",
459                             c, nntohost(&srcadr), stoa(&dstadr),
460                             plist->stratum, ntp_poll, plist->reach,
461                             fptoa(NTOHS_FP(plist->delay), 5),
462                             lfptoa(&tempts, 6),
463                             ufptoa(NTOHS_FP(plist->dispersion), 5));
464                 plist++;
465                 items--;
466         }
467 }
468
469 /* Convert a refid & stratum (in host order) to a string */
470 static char*
471 refid_string(
472         u_int32 refid,
473         int stratum
474         )
475 {
476         if (stratum <= 1) {
477                 static char junk[5];
478                 junk[4] = 0;
479                 memmove(junk, (char *)&refid, 4);
480                 return junk;
481         }
482
483         return numtoa(refid);
484 }
485
486 /*
487  * printpeer - print detail information for a peer
488  */
489 static void
490 printpeer(
491         register struct info_peer *pp,
492         FILE *fp
493         )
494 {
495         register int i;
496         const char *str;
497         l_fp tempts;
498         struct sockaddr_storage srcadr, dstadr;
499         
500         memset((char *)&srcadr, 0, sizeof(srcadr));
501         memset((char *)&dstadr, 0, sizeof(dstadr));
502         if (pp->v6_flag != 0) {
503                 srcadr.ss_family = AF_INET6;
504                 dstadr.ss_family = AF_INET6;
505                 GET_INADDR6(srcadr) = pp->srcadr6;
506                 GET_INADDR6(dstadr) = pp->dstadr6;
507         } else {
508                 srcadr.ss_family = AF_INET;
509                 dstadr.ss_family = AF_INET;
510                 GET_INADDR(srcadr) = pp->srcadr;
511                 GET_INADDR(dstadr) = pp->dstadr;
512         }
513 #ifdef HAVE_SA_LEN_IN_STRUCT_SOCKADDR
514         srcadr.ss_len = SOCKLEN(&srcadr);
515         dstadr.ss_len = SOCKLEN(&dstadr);
516 #endif
517         (void) fprintf(fp, "remote %s, local %s\n",
518                        stoa(&srcadr), stoa(&dstadr));
519         (void) fprintf(fp, "hmode %s, pmode %s, stratum %d, precision %d\n",
520                        modetoa(pp->hmode), modetoa(pp->pmode),
521                        pp->stratum, pp->precision);
522         
523         (void) fprintf(fp,
524                        "leap %c%c, refid [%s], rootdistance %s, rootdispersion %s\n",
525                        pp->leap & 0x2 ? '1' : '0',
526                        pp->leap & 0x1 ? '1' : '0',
527                        refid_string(pp->refid, pp->stratum), fptoa(NTOHS_FP(pp->rootdelay), 5),
528                        ufptoa(NTOHS_FP(pp->rootdispersion), 5));
529         
530         (void) fprintf(fp,
531                        "ppoll %d, hpoll %d, keyid %lu, version %d, association %u\n",
532                        pp->ppoll, pp->hpoll, (u_long)pp->keyid, pp->version, ntohs(pp->associd));
533
534         (void) fprintf(fp,
535                        "reach %03o, unreach %d, flash 0x%04x, ",
536                        pp->reach, pp->unreach, pp->flash2);
537
538         (void) fprintf(fp, "boffset %s, ttl/mode %d\n",
539                        fptoa(NTOHS_FP(pp->estbdelay), 5), pp->ttl);
540         
541         (void) fprintf(fp, "timer %lds, flags", (long)ntohl(pp->timer));
542         if (pp->flags == 0) {
543                 (void) fprintf(fp, " none\n");
544         } else {
545                 str = "";
546                 if (pp->flags & INFO_FLAG_SYSPEER) {
547                         (void) fprintf(fp, " system_peer");
548                         str = ",";
549                 }
550                 if (pp->flags & INFO_FLAG_CONFIG) {
551                         (void) fprintf(fp, "%s config", str);
552                         str = ",";
553                 }
554                 if (pp->flags & INFO_FLAG_REFCLOCK) {
555                         (void) fprintf(fp, "%s refclock", str);
556                         str = ",";
557                 }
558                 if (pp->flags & INFO_FLAG_AUTHENABLE) {
559                         (void) fprintf(fp, "%s auth", str);
560                         str = ",";
561                 }
562                 if (pp->flags & INFO_FLAG_BCLIENT) {
563                         (void) fprintf(fp, "%s bclient", str);
564                         str = ",";
565                 }
566                 if (pp->flags & INFO_FLAG_PREFER) {
567                         (void) fprintf(fp, "%s prefer", str);
568                         str = ",";
569                 }
570                 if (pp->flags & INFO_FLAG_BURST) {
571                         (void) fprintf(fp, "%s burst", str);
572                 }
573                 (void) fprintf(fp, "\n");
574         }
575
576         NTOHL_FP(&pp->reftime, &tempts);
577         (void) fprintf(fp, "reference time:      %s\n",
578                        prettydate(&tempts));
579         NTOHL_FP(&pp->org, &tempts);
580         (void) fprintf(fp, "originate timestamp: %s\n",
581                        prettydate(&tempts));
582         NTOHL_FP(&pp->rec, &tempts);
583         (void) fprintf(fp, "receive timestamp:   %s\n",
584                        prettydate(&tempts));
585         NTOHL_FP(&pp->xmt, &tempts);
586         (void) fprintf(fp, "transmit timestamp:  %s\n",
587                        prettydate(&tempts));
588         
589         (void) fprintf(fp, "filter delay: ");
590         for (i = 0; i < NTP_SHIFT; i++) {
591                 (void) fprintf(fp, " %-8.8s",
592                                fptoa(NTOHS_FP(pp->filtdelay[i]), 5));
593                 if (i == (NTP_SHIFT>>1)-1)
594                     (void) fprintf(fp, "\n              ");
595         }
596         (void) fprintf(fp, "\n");
597
598         (void) fprintf(fp, "filter offset:");
599         for (i = 0; i < NTP_SHIFT; i++) {
600                 NTOHL_FP(&pp->filtoffset[i], &tempts);
601                 (void) fprintf(fp, " %-8.8s", lfptoa(&tempts, 6));
602                 if (i == (NTP_SHIFT>>1)-1)
603                     (void) fprintf(fp, "\n              ");
604         }
605         (void) fprintf(fp, "\n");
606
607         (void) fprintf(fp, "filter order: ");
608         for (i = 0; i < NTP_SHIFT; i++) {
609                 (void) fprintf(fp, " %-8d", pp->order[i]);
610                 if (i == (NTP_SHIFT>>1)-1)
611                     (void) fprintf(fp, "\n              ");
612         }
613         (void) fprintf(fp, "\n");
614         
615
616         NTOHL_FP(&pp->offset, &tempts);
617         (void) fprintf(fp,
618                        "offset %s, delay %s, error bound %s, filter error %s\n",
619                        lfptoa(&tempts, 6), fptoa(NTOHS_FP(pp->delay), 5),
620                        ufptoa(NTOHS_FP(pp->dispersion), 5),
621                        ufptoa(NTOHS_FP(pp->selectdisp), 5));
622 }
623
624
625 /*
626  * showpeer - show detailed information for a peer
627  */
628 static void
629 showpeer(
630         struct parse *pcmd,
631         FILE *fp
632         )
633 {
634         struct info_peer *pp;
635         /* 4 is the maximum number of peers which will fit in a packet */
636         struct info_peer_list *pl, plist[min(MAXARGS, 4)];
637         int qitems;
638         int items;
639         int itemsize;
640         int res;
641         int sendsize;
642
643 again:
644         if (impl_ver == IMPL_XNTPD)
645                 sendsize = sizeof(struct info_peer_list);
646         else
647                 sendsize = v4sizeof(struct info_peer_list);
648
649         for (qitems = 0, pl = plist; qitems < min(pcmd->nargs, 4); qitems++) {
650                 if (pcmd->argval[qitems].netnum.ss_family == AF_INET) {
651                         pl->addr = GET_INADDR(pcmd->argval[qitems].netnum);
652                         if (impl_ver == IMPL_XNTPD)
653                                 pl->v6_flag = 0;
654                 } else {
655                         if (impl_ver == IMPL_XNTPD_OLD) {
656                                 fprintf(stderr,
657                                     "***Server doesn't understand IPv6 addresses\n");
658                                 return;
659                         }
660                         pl->addr6 = GET_INADDR6(pcmd->argval[qitems].netnum);
661                         pl->v6_flag = 1;
662                 }
663                 pl->port = (u_short)s_port;
664                 pl->hmode = pl->flags = 0;
665                 pl = (struct info_peer_list *)((char *)pl + sendsize);
666         }
667
668         res = doquery(impl_ver, REQ_PEER_INFO, 0, qitems,
669                       sendsize, (char *)plist, &items,
670                       &itemsize, (void *)&pp, 0, sizeof(struct info_peer));
671         
672         if (res == INFO_ERR_IMPL && impl_ver == IMPL_XNTPD) {
673                 impl_ver = IMPL_XNTPD_OLD;
674                 goto again;
675         }
676
677         if (res != 0 && items == 0)
678             return;
679
680         if (!checkitems(items, fp))
681             return;
682
683         if (!checkitemsize(itemsize, sizeof(struct info_peer)) &&
684             !checkitemsize(itemsize, v4sizeof(struct info_peer)))
685             return;
686
687         while (items-- > 0) {
688                 printpeer(pp, fp);
689                 if (items > 0)
690                     (void) fprintf(fp, "\n");
691                 pp++;
692         }
693 }
694
695
696 /*
697  * peerstats - return statistics for a peer
698  */
699 static void
700 peerstats(
701         struct parse *pcmd,
702         FILE *fp
703         )
704 {
705         struct info_peer_stats *pp;
706         /* 4 is the maximum number of peers which will fit in a packet */
707         struct info_peer_list *pl, plist[min(MAXARGS, 4)];
708         struct sockaddr_storage src, dst;
709         int qitems;
710         int items;
711         int itemsize;
712         int res;
713         int sendsize;
714
715 again:
716         if (impl_ver == IMPL_XNTPD)
717                 sendsize = sizeof(struct info_peer_list);
718         else
719                 sendsize = v4sizeof(struct info_peer_list);
720
721         memset((char *)plist, 0, sizeof(struct info_peer_list) * min(MAXARGS, 4));
722         for (qitems = 0, pl = plist; qitems < min(pcmd->nargs, 4); qitems++) {
723                 if (pcmd->argval[qitems].netnum.ss_family == AF_INET) {
724                         pl->addr = GET_INADDR(pcmd->argval[qitems].netnum);
725                         if (impl_ver == IMPL_XNTPD)
726                                 pl->v6_flag = 0;
727                 } else {
728                         if (impl_ver == IMPL_XNTPD_OLD) {
729                                 fprintf(stderr,
730                                     "***Server doesn't understand IPv6 addresses\n");
731                                 return;
732                         }
733                         pl->addr6 = GET_INADDR6(pcmd->argval[qitems].netnum);
734                         pl->v6_flag = 1;
735                 }
736                 pl->port = (u_short)s_port;
737                 pl->hmode = plist[qitems].flags = 0;
738                 pl = (struct info_peer_list *)((char *)pl + sendsize);
739         }
740
741         res = doquery(impl_ver, REQ_PEER_STATS, 0, qitems,
742                       sendsize, (char *)plist, &items,
743                       &itemsize, (void *)&pp, 0, 
744                       sizeof(struct info_peer_stats));
745         
746         if (res == INFO_ERR_IMPL && impl_ver == IMPL_XNTPD) {
747                 impl_ver = IMPL_XNTPD_OLD;
748                 goto again;
749         }
750
751         if (res != 0 && items == 0)
752             return;
753
754         if (!checkitems(items, fp))
755             return;
756
757         if (!checkitemsize(itemsize, sizeof(struct info_peer_stats)) &&
758             !checkitemsize(itemsize, v4sizeof(struct info_peer_stats)))
759             return;
760
761         while (items-- > 0) {
762                 memset((char *)&src, 0, sizeof(src));
763                 memset((char *)&dst, 0, sizeof(dst));
764                 if (pp->v6_flag != 0) {
765                         GET_INADDR6(src) = pp->srcadr6;
766                         GET_INADDR6(dst) = pp->dstadr6;
767                         src.ss_family = AF_INET6;
768                         dst.ss_family = AF_INET6;
769                 } else {
770                         GET_INADDR(src) = pp->srcadr;
771                         GET_INADDR(dst) = pp->dstadr;
772                         src.ss_family = AF_INET;
773                         dst.ss_family = AF_INET;
774                 }
775 #ifdef HAVE_SA_LEN_IN_STRUCT_SOCKADDR
776                 src.ss_len = SOCKLEN(&src);
777                 dst.ss_len = SOCKLEN(&dst);
778 #endif
779                 (void) fprintf(fp, "remote host:          %s\n",
780                                nntohost(&src));
781                 (void) fprintf(fp, "local interface:      %s\n",
782                                stoa(&dst));
783                 (void) fprintf(fp, "time last received:   %lds\n",
784                                (long)ntohl(pp->timereceived));
785                 (void) fprintf(fp, "time until next send: %lds\n",
786                                (long)ntohl(pp->timetosend));
787                 (void) fprintf(fp, "reachability change:  %lds\n",
788                                (long)ntohl(pp->timereachable));
789                 (void) fprintf(fp, "packets sent:         %ld\n",
790                                (long)ntohl(pp->sent));
791                 (void) fprintf(fp, "packets received:     %ld\n",
792                                (long)ntohl(pp->processed));
793                 (void) fprintf(fp, "bad authentication:   %ld\n",
794                                (long)ntohl(pp->badauth));
795                 (void) fprintf(fp, "bogus origin:         %ld\n",
796                                (long)ntohl(pp->bogusorg));
797                 (void) fprintf(fp, "duplicate:            %ld\n",
798                                (long)ntohl(pp->oldpkt));
799                 (void) fprintf(fp, "bad dispersion:       %ld\n",
800                                (long)ntohl(pp->seldisp));
801                 (void) fprintf(fp, "bad reference time:   %ld\n",
802                                (long)ntohl(pp->selbroken));
803                 (void) fprintf(fp, "candidate order:      %d\n",
804                                (int)pp->candidate);
805                 if (items > 0)
806                     (void) fprintf(fp, "\n");
807                 pp++;
808         }
809 }
810
811
812 /*
813  * loopinfo - show loop filter information
814  */
815 static void
816 loopinfo(
817         struct parse *pcmd,
818         FILE *fp
819         )
820 {
821         struct info_loop *il;
822         int items;
823         int itemsize;
824         int oneline = 0;
825         int res;
826         l_fp tempts;
827
828         if (pcmd->nargs > 0) {
829                 if (STREQ(pcmd->argval[0].string, "oneline"))
830                     oneline = 1;
831                 else if (STREQ(pcmd->argval[0].string, "multiline"))
832                     oneline = 0;
833                 else {
834                         (void) fprintf(stderr, "How many lines?\n");
835                         return;
836                 }
837         }
838
839 again:
840         res = doquery(impl_ver, REQ_LOOP_INFO, 0, 0, 0, (char *)NULL,
841                       &items, &itemsize, (void *)&il, 0, 
842                       sizeof(struct info_loop));
843         
844         if (res == INFO_ERR_IMPL && impl_ver == IMPL_XNTPD) {
845                 impl_ver = IMPL_XNTPD_OLD;
846                 goto again;
847         }
848
849         if (res != 0 && items == 0)
850             return;
851
852         if (!check1item(items, fp))
853             return;
854
855         if (!checkitemsize(itemsize, sizeof(struct info_loop)))
856             return;
857
858         if (oneline) {
859                 l_fp temp2ts;
860
861                 NTOHL_FP(&il->last_offset, &tempts);
862                 NTOHL_FP(&il->drift_comp, &temp2ts);
863
864                 (void) fprintf(fp,
865                                "offset %s, frequency %s, time_const %ld, watchdog %ld\n",
866                                lfptoa(&tempts, 6),
867                                lfptoa(&temp2ts, 3),
868                                (u_long)ntohl(il->compliance),
869                                (u_long)ntohl(il->watchdog_timer));
870         } else {
871                 NTOHL_FP(&il->last_offset, &tempts);
872                 (void) fprintf(fp, "offset:               %s s\n",
873                                lfptoa(&tempts, 6));
874                 NTOHL_FP(&il->drift_comp, &tempts);
875                 (void) fprintf(fp, "frequency:            %s ppm\n",
876                                lfptoa(&tempts, 3));
877                 (void) fprintf(fp, "poll adjust:          %ld\n",
878                                (u_long)ntohl(il->compliance));
879                 (void) fprintf(fp, "watchdog timer:       %ld s\n",
880                                (u_long)ntohl(il->watchdog_timer));
881         }
882 }
883
884
885 /*
886  * sysinfo - show current system state
887  */
888 /*ARGSUSED*/
889 static void
890 sysinfo(
891         struct parse *pcmd,
892         FILE *fp
893         )
894 {
895         struct info_sys *is;
896         struct sockaddr_storage peeraddr;
897         int items;
898         int itemsize;
899         int res;
900         l_fp tempts;
901
902 again:
903         res = doquery(impl_ver, REQ_SYS_INFO, 0, 0, 0, (char *)NULL,
904                       &items, &itemsize, (void *)&is, 0,
905                       sizeof(struct info_sys));
906         
907         if (res == INFO_ERR_IMPL && impl_ver == IMPL_XNTPD) {
908                 impl_ver = IMPL_XNTPD_OLD;
909                 goto again;
910         }
911
912         if (res != 0 && items == 0)
913             return;
914
915         if (!check1item(items, fp))
916             return;
917
918         if (!checkitemsize(itemsize, sizeof(struct info_sys)) &&
919             !checkitemsize(itemsize, v4sizeof(struct info_sys)))
920             return;
921
922         memset((char *)&peeraddr, 0, sizeof(peeraddr));
923         if (is->v6_flag != 0) {
924                 GET_INADDR6(peeraddr) = is->peer6;
925                 peeraddr.ss_family = AF_INET6;
926         } else {
927                 GET_INADDR(peeraddr) = is->peer;
928                 peeraddr.ss_family = AF_INET;
929         }
930 #ifdef HAVE_SA_LEN_IN_STRUCT_SOCKADDR
931         peeraddr.ss_len = SOCKLEN(&peeraddr);
932 #endif
933         (void) fprintf(fp, "system peer:          %s\n", nntohost(&peeraddr));
934         (void) fprintf(fp, "system peer mode:     %s\n", modetoa(is->peer_mode));
935         (void) fprintf(fp, "leap indicator:       %c%c\n",
936                        is->leap & 0x2 ? '1' : '0',
937                        is->leap & 0x1 ? '1' : '0');
938         (void) fprintf(fp, "stratum:              %d\n", (int)is->stratum);
939         (void) fprintf(fp, "precision:            %d\n", (int)is->precision);
940         (void) fprintf(fp, "root distance:        %s s\n",
941                        fptoa(NTOHS_FP(is->rootdelay), 5));
942         (void) fprintf(fp, "root dispersion:      %s s\n",
943                        ufptoa(NTOHS_FP(is->rootdispersion), 5));
944         (void) fprintf(fp, "reference ID:         [%s]\n",
945                        refid_string(is->refid, is->stratum));
946         NTOHL_FP(&is->reftime, &tempts);
947         (void) fprintf(fp, "reference time:       %s\n", prettydate(&tempts));
948
949         (void) fprintf(fp, "system flags:         ");
950         if ((is->flags & (INFO_FLAG_BCLIENT | INFO_FLAG_AUTHENABLE |
951             INFO_FLAG_NTP | INFO_FLAG_KERNEL| INFO_FLAG_CAL |
952             INFO_FLAG_PPS_SYNC | INFO_FLAG_MONITOR | INFO_FLAG_FILEGEN)) == 0) {
953                 (void) fprintf(fp, "none\n");
954         } else {
955                 if (is->flags & INFO_FLAG_BCLIENT)
956                     (void) fprintf(fp, "bclient ");
957                 if (is->flags & INFO_FLAG_AUTHENTICATE)
958                     (void) fprintf(fp, "auth ");
959                 if (is->flags & INFO_FLAG_MONITOR)
960                     (void) fprintf(fp, "monitor ");
961                 if (is->flags & INFO_FLAG_NTP)
962                     (void) fprintf(fp, "ntp ");
963                 if (is->flags & INFO_FLAG_KERNEL)
964                     (void) fprintf(fp, "kernel ");
965                 if (is->flags & INFO_FLAG_FILEGEN)
966                     (void) fprintf(fp, "stats ");
967                 if (is->flags & INFO_FLAG_CAL)
968                     (void) fprintf(fp, "calibrate ");
969                 if (is->flags & INFO_FLAG_PPS_SYNC)
970                     (void) fprintf(fp, "pps ");
971                 (void) fprintf(fp, "\n");
972         }
973         (void) fprintf(fp, "jitter:               %s s\n",
974                        fptoa(ntohl(is->frequency), 6));
975         (void) fprintf(fp, "stability:            %s ppm\n",
976                        ufptoa(ntohl(is->stability), 3));
977         (void) fprintf(fp, "broadcastdelay:       %s s\n",
978                        fptoa(NTOHS_FP(is->bdelay), 6));
979         NTOHL_FP(&is->authdelay, &tempts);
980         (void) fprintf(fp, "authdelay:            %s s\n", lfptoa(&tempts, 6));
981 }
982
983
984 /*
985  * sysstats - print system statistics
986  */
987 /*ARGSUSED*/
988 static void
989 sysstats(
990         struct parse *pcmd,
991         FILE *fp
992         )
993 {
994         struct info_sys_stats *ss;
995         int items;
996         int itemsize;
997         int res;
998
999 again:
1000         res = doquery(impl_ver, REQ_SYS_STATS, 0, 0, 0, (char *)NULL,
1001                       &items, &itemsize, (void *)&ss, 0, 
1002                       sizeof(struct info_sys_stats));
1003         
1004         if (res == INFO_ERR_IMPL && impl_ver == IMPL_XNTPD) {
1005                 impl_ver = IMPL_XNTPD_OLD;
1006                 goto again;
1007         }
1008
1009         if (res != 0 && items == 0)
1010             return;
1011
1012         if (!check1item(items, fp))
1013             return;
1014
1015         if (itemsize != sizeof(struct info_sys_stats) &&
1016             itemsize != sizeof(struct old_info_sys_stats)) {
1017                 /* issue warning according to new structure size */
1018                 checkitemsize(itemsize, sizeof(struct info_sys_stats));
1019                 return;
1020         }
1021         fprintf(fp, "time since restart:     %ld\n",
1022                (u_long)ntohl(ss->timeup));
1023         fprintf(fp, "time since reset:       %ld\n",
1024                 (u_long)ntohl(ss->timereset));
1025         fprintf(fp, "packets received:       %ld\n",
1026                 (u_long)ntohl(ss->received));
1027         fprintf(fp, "packets processed:      %ld\n",
1028                 (u_long)ntohl(ss->processed));
1029         fprintf(fp, "current version:        %ld\n",
1030                (u_long)ntohl(ss->newversionpkt));
1031         fprintf(fp, "previous version:       %ld\n",
1032                (u_long)ntohl(ss->oldversionpkt));
1033         fprintf(fp, "bad version:            %ld\n",
1034                (u_long)ntohl(ss->unknownversion));
1035         fprintf(fp, "access denied:          %ld\n",
1036                 (u_long)ntohl(ss->denied));
1037         fprintf(fp, "bad length or format:   %ld\n",
1038                (u_long)ntohl(ss->badlength));
1039         fprintf(fp, "bad authentication:     %ld\n",
1040                (u_long)ntohl(ss->badauth));
1041         if (itemsize != sizeof(struct info_sys_stats))
1042             return;
1043         
1044         fprintf(fp, "rate exceeded:          %ld\n",
1045                (u_long)ntohl(ss->limitrejected));
1046 }
1047
1048
1049
1050 /*
1051  * iostats - print I/O statistics
1052  */
1053 /*ARGSUSED*/
1054 static void
1055 iostats(
1056         struct parse *pcmd,
1057         FILE *fp
1058         )
1059 {
1060         struct info_io_stats *io;
1061         int items;
1062         int itemsize;
1063         int res;
1064
1065 again:
1066         res = doquery(impl_ver, REQ_IO_STATS, 0, 0, 0, (char *)NULL,
1067                       &items, &itemsize, (void *)&io, 0, 
1068                       sizeof(struct info_io_stats));
1069         
1070         if (res == INFO_ERR_IMPL && impl_ver == IMPL_XNTPD) {
1071                 impl_ver = IMPL_XNTPD_OLD;
1072                 goto again;
1073         }
1074
1075         if (res != 0 && items == 0)
1076             return;
1077
1078         if (!check1item(items, fp))
1079             return;
1080
1081         if (!checkitemsize(itemsize, sizeof(struct info_io_stats)))
1082             return;
1083
1084         (void) fprintf(fp, "time since reset:     %ld\n",
1085                        (u_long)ntohl(io->timereset));
1086         (void) fprintf(fp, "receive buffers:      %d\n",
1087                        ntohs(io->totalrecvbufs));
1088         (void) fprintf(fp, "free receive buffers: %d\n",
1089                        ntohs(io->freerecvbufs));
1090         (void) fprintf(fp, "used receive buffers: %d\n",
1091                        ntohs(io->fullrecvbufs));
1092         (void) fprintf(fp, "low water refills:    %d\n",
1093                        ntohs(io->lowwater));
1094         (void) fprintf(fp, "dropped packets:      %ld\n",
1095                        (u_long)ntohl(io->dropped));
1096         (void) fprintf(fp, "ignored packets:      %ld\n",
1097                        (u_long)ntohl(io->ignored));
1098         (void) fprintf(fp, "received packets:     %ld\n",
1099                        (u_long)ntohl(io->received));
1100         (void) fprintf(fp, "packets sent:         %ld\n",
1101                        (u_long)ntohl(io->sent));
1102         (void) fprintf(fp, "packets not sent:     %ld\n",
1103                        (u_long)ntohl(io->notsent));
1104         (void) fprintf(fp, "interrupts handled:   %ld\n",
1105                        (u_long)ntohl(io->interrupts));
1106         (void) fprintf(fp, "received by int:      %ld\n",
1107                        (u_long)ntohl(io->int_received));
1108 }
1109
1110
1111 /*
1112  * memstats - print peer memory statistics
1113  */
1114 /*ARGSUSED*/
1115 static void
1116 memstats(
1117         struct parse *pcmd,
1118         FILE *fp
1119         )
1120 {
1121         struct info_mem_stats *mem;
1122         int i;
1123         int items;
1124         int itemsize;
1125         int res;
1126
1127 again:
1128         res = doquery(impl_ver, REQ_MEM_STATS, 0, 0, 0, (char *)NULL,
1129                       &items, &itemsize, (void *)&mem, 0, 
1130                       sizeof(struct info_mem_stats));
1131         
1132         if (res == INFO_ERR_IMPL && impl_ver == IMPL_XNTPD) {
1133                 impl_ver = IMPL_XNTPD_OLD;
1134                 goto again;
1135         }
1136
1137         if (res != 0 && items == 0)
1138             return;
1139
1140         if (!check1item(items, fp))
1141             return;
1142
1143         if (!checkitemsize(itemsize, sizeof(struct info_mem_stats)))
1144             return;
1145
1146         (void) fprintf(fp, "time since reset:     %ld\n",
1147                        (u_long)ntohl(mem->timereset));
1148         (void) fprintf(fp, "total peer memory:    %d\n",
1149                        ntohs(mem->totalpeermem));
1150         (void) fprintf(fp, "free peer memory:     %d\n",
1151                        ntohs(mem->freepeermem));
1152         (void) fprintf(fp, "calls to findpeer:    %ld\n",
1153                        (u_long)ntohl(mem->findpeer_calls));
1154         (void) fprintf(fp, "new peer allocations: %ld\n",
1155                        (u_long)ntohl(mem->allocations));
1156         (void) fprintf(fp, "peer demobilizations: %ld\n",
1157                        (u_long)ntohl(mem->demobilizations));
1158
1159         (void) fprintf(fp, "hash table counts:   ");
1160         for (i = 0; i < HASH_SIZE; i++) {
1161                 (void) fprintf(fp, "%4d", (int)mem->hashcount[i]);
1162                 if ((i % 8) == 7 && i != (HASH_SIZE-1)) {
1163                         (void) fprintf(fp, "\n                     ");
1164                 }
1165         }
1166         (void) fprintf(fp, "\n");
1167 }
1168
1169
1170
1171 /*
1172  * timerstats - print timer statistics
1173  */
1174 /*ARGSUSED*/
1175 static void
1176 timerstats(
1177         struct parse *pcmd,
1178         FILE *fp
1179         )
1180 {
1181         struct info_timer_stats *tim;
1182         int items;
1183         int itemsize;
1184         int res;
1185
1186 again:
1187         res = doquery(impl_ver, REQ_TIMER_STATS, 0, 0, 0, (char *)NULL,
1188                       &items, &itemsize, (void *)&tim, 0, 
1189                       sizeof(struct info_timer_stats));
1190         
1191         if (res == INFO_ERR_IMPL && impl_ver == IMPL_XNTPD) {
1192                 impl_ver = IMPL_XNTPD_OLD;
1193                 goto again;
1194         }
1195
1196         if (res != 0 && items == 0)
1197             return;
1198
1199         if (!check1item(items, fp))
1200             return;
1201
1202         if (!checkitemsize(itemsize, sizeof(struct info_timer_stats)))
1203             return;
1204
1205         (void) fprintf(fp, "time since reset:  %ld\n",
1206                        (u_long)ntohl(tim->timereset));
1207         (void) fprintf(fp, "alarms handled:    %ld\n",
1208                        (u_long)ntohl(tim->alarms));
1209         (void) fprintf(fp, "alarm overruns:    %ld\n",
1210                        (u_long)ntohl(tim->overflows));
1211         (void) fprintf(fp, "calls to transmit: %ld\n",
1212                        (u_long)ntohl(tim->xmtcalls));
1213 }
1214
1215
1216 /*
1217  * addpeer - configure an active mode association
1218  */
1219 static void
1220 addpeer(
1221         struct parse *pcmd,
1222         FILE *fp
1223         )
1224 {
1225         doconfig(pcmd, fp, MODE_ACTIVE, 0);
1226 }
1227
1228
1229 /*
1230  * addserver - configure a client mode association
1231  */
1232 static void
1233 addserver(
1234         struct parse *pcmd,
1235         FILE *fp
1236         )
1237 {
1238         doconfig(pcmd, fp, MODE_CLIENT, 0);
1239 }
1240
1241 /*
1242  * addrefclock - configure a reference clock association
1243  */
1244 static void
1245 addrefclock(
1246         struct parse *pcmd,
1247         FILE *fp
1248         )
1249 {
1250         doconfig(pcmd, fp, MODE_CLIENT, 1);
1251 }
1252
1253 /*
1254  * broadcast - configure a broadcast mode association
1255  */
1256 static void
1257 broadcast(
1258         struct parse *pcmd,
1259         FILE *fp
1260         )
1261 {
1262         doconfig(pcmd, fp, MODE_BROADCAST, 0);
1263 }
1264
1265
1266 /*
1267  * config - configure a new peer association
1268  */
1269 static void
1270 doconfig(
1271         struct parse *pcmd,
1272         FILE *fp,
1273         int mode,
1274         int refc
1275         )
1276 {
1277         struct conf_peer cpeer;
1278         int items;
1279         int itemsize;
1280         char *dummy;
1281         u_long keyid;
1282         u_int version;
1283         u_char minpoll;
1284         u_int flags;
1285         u_char cmode;
1286         int res;
1287         int sendsize;
1288
1289 again:
1290         keyid = 0;
1291         version = NTP_OLDVERSION + 1;
1292         flags = 0;
1293         res = 0;
1294         cmode = 0;
1295         minpoll = NTP_MINDPOLL;
1296
1297         if (impl_ver == IMPL_XNTPD)
1298                 sendsize = sizeof(struct conf_peer);
1299         else
1300                 sendsize = v4sizeof(struct conf_peer);
1301
1302         items = pcmd->nargs;
1303
1304         if (refc) {
1305                 if (pcmd->nargs > 1) {
1306                         cmode = (u_char) pcmd->argval[1].uval;
1307                         items = 2;
1308                 }
1309         } else {
1310                 if (pcmd->nargs > 1) {
1311                         keyid = pcmd->argval[1].uval;
1312                         if (keyid > 0) {
1313                                 flags |= CONF_FLAG_AUTHENABLE;
1314                         }
1315                         if (pcmd->nargs > 2) {
1316                                 version = (u_int)pcmd->argval[2].uval;
1317                                 if (version > NTP_VERSION ||
1318                                     version < NTP_OLDVERSION) {
1319                                         (void)fprintf(fp,
1320                                         "invalid version number %u\n",
1321                                             version);
1322                                         res++;
1323                                 }
1324                                 items = 3;
1325                         }
1326                 }
1327         }
1328
1329         while (pcmd->nargs > items) {
1330                 if (STREQ(pcmd->argval[items].string, "prefer"))
1331                     flags |= CONF_FLAG_PREFER;
1332                 else if (STREQ(pcmd->argval[items].string, "burst"))
1333                     flags |= CONF_FLAG_BURST;
1334                 else {
1335                         long val;
1336                         if (!atoint(pcmd->argval[items].string, &val)) {
1337                                 (void) fprintf(fp,
1338                                     "%s not understood\n",
1339                                     pcmd->argval[items].string);
1340                                 res++;
1341                                 break;
1342                         } else {
1343                                 if (val >= NTP_MINPOLL && val <= NTP_MAXPOLL) {
1344                                         minpoll = (u_char)val;
1345                                 } else {
1346                                         (void) fprintf(fp,
1347                                                        "minpol must be within %d..%d\n",
1348                                                        NTP_MINPOLL, NTP_MAXPOLL);
1349                                         res++;
1350                                         break;
1351                                 }                                       
1352                         }
1353                 }
1354                 items++;
1355         }
1356
1357         if (res)
1358             return;
1359
1360         memset((void *)&cpeer, 0, sizeof(cpeer));
1361
1362         if (pcmd->argval[0].netnum.ss_family == AF_INET) {
1363                 cpeer.peeraddr = GET_INADDR(pcmd->argval[0].netnum);
1364                 if (impl_ver == IMPL_XNTPD)
1365                         cpeer.v6_flag = 0;
1366         } else {
1367                 if (impl_ver == IMPL_XNTPD_OLD) {
1368                         fprintf(stderr,
1369                             "***Server doesn't understand IPv6 addresses\n");
1370                         return;
1371                 }
1372                 cpeer.peeraddr6 = GET_INADDR6(pcmd->argval[0].netnum);
1373                 cpeer.v6_flag = 1;
1374         }
1375         cpeer.hmode = (u_char) mode;
1376         cpeer.keyid = keyid;
1377         cpeer.version = (u_char) version;
1378         cpeer.minpoll = minpoll;
1379         cpeer.maxpoll = NTP_MAXDPOLL;
1380         cpeer.flags = (u_char)flags;
1381         cpeer.ttl = cmode;
1382
1383         res = doquery(impl_ver, REQ_CONFIG, 1, 1,
1384                       sendsize, (char *)&cpeer, &items,
1385                       &itemsize, &dummy, 0, sizeof(struct conf_peer));
1386         
1387         if (res == INFO_ERR_IMPL && impl_ver == IMPL_XNTPD) {
1388                 impl_ver = IMPL_XNTPD_OLD;
1389                 goto again;
1390         }
1391
1392         if (res == INFO_ERR_FMT) {
1393                 (void) fprintf(fp,
1394                     "***Retrying command with old conf_peer size\n");
1395                 res = doquery(impl_ver, REQ_CONFIG, 1, 1,
1396                               sizeof(struct old_conf_peer), (char *)&cpeer,
1397                               &items, &itemsize, &dummy, 0,
1398                               sizeof(struct conf_peer));
1399         }
1400         if (res == 0)
1401             (void) fprintf(fp, "done!\n");
1402         return;
1403 }
1404
1405
1406 /*
1407  * unconfig - unconfigure some associations
1408  */
1409 static void
1410 unconfig(
1411         struct parse *pcmd,
1412         FILE *fp
1413         )
1414 {
1415         /* 8 is the maximum number of peers which will fit in a packet */
1416         struct conf_unpeer *pl, plist[min(MAXARGS, 8)];
1417         int qitems;
1418         int items;
1419         int itemsize;
1420         char *dummy;
1421         int res;
1422         int sendsize;
1423
1424 again:
1425         if (impl_ver == IMPL_XNTPD)
1426                 sendsize = sizeof(struct conf_unpeer);
1427         else
1428                 sendsize = v4sizeof(struct conf_unpeer);
1429
1430         for (qitems = 0, pl = plist; qitems < min(pcmd->nargs, 8); qitems++) {
1431                 if (pcmd->argval[0].netnum.ss_family == AF_INET) {
1432                         pl->peeraddr = GET_INADDR(pcmd->argval[qitems].netnum);
1433                         if (impl_ver == IMPL_XNTPD)
1434                                 pl->v6_flag = 0;
1435                 } else {
1436                         if (impl_ver == IMPL_XNTPD_OLD) {
1437                                 fprintf(stderr,
1438                                     "***Server doesn't understand IPv6 addresses\n");
1439                                 return;
1440                         }
1441                         pl->peeraddr6 =
1442                             GET_INADDR6(pcmd->argval[qitems].netnum);
1443                         pl->v6_flag = 1;
1444                 }
1445                 pl = (struct conf_unpeer *)((char *)pl + sendsize);
1446         }
1447
1448         res = doquery(impl_ver, REQ_UNCONFIG, 1, qitems,
1449                       sendsize, (char *)plist, &items,
1450                       &itemsize, &dummy, 0, sizeof(struct conf_unpeer));
1451         
1452         if (res == INFO_ERR_IMPL && impl_ver == IMPL_XNTPD) {
1453                 impl_ver = IMPL_XNTPD_OLD;
1454                 goto again;
1455         }
1456
1457         if (res == 0)
1458             (void) fprintf(fp, "done!\n");
1459 }
1460
1461
1462 /*
1463  * set - set some system flags
1464  */
1465 static void
1466 set(
1467         struct parse *pcmd,
1468         FILE *fp
1469         )
1470 {
1471         doset(pcmd, fp, REQ_SET_SYS_FLAG);
1472 }
1473
1474
1475 /*
1476  * clear - clear some system flags
1477  */
1478 static void
1479 sys_clear(
1480         struct parse *pcmd,
1481         FILE *fp
1482         )
1483 {
1484         doset(pcmd, fp, REQ_CLR_SYS_FLAG);
1485 }
1486
1487
1488 /*
1489  * doset - set/clear system flags
1490  */
1491 static void
1492 doset(
1493         struct parse *pcmd,
1494         FILE *fp,
1495         int req
1496         )
1497 {
1498         /* 8 is the maximum number of peers which will fit in a packet */
1499         struct conf_sys_flags sys;
1500         int items;
1501         int itemsize;
1502         char *dummy;
1503         int res;
1504
1505         sys.flags = 0;
1506         res = 0;
1507         for (items = 0; items < pcmd->nargs; items++) {
1508                 if (STREQ(pcmd->argval[items].string, "auth"))
1509                         sys.flags |= SYS_FLAG_AUTH;
1510                 else if (STREQ(pcmd->argval[items].string, "bclient"))
1511                         sys.flags |= SYS_FLAG_BCLIENT;
1512                 else if (STREQ(pcmd->argval[items].string, "calibrate"))
1513                         sys.flags |= SYS_FLAG_CAL;
1514                 else if (STREQ(pcmd->argval[items].string, "kernel"))
1515                         sys.flags |= SYS_FLAG_KERNEL;
1516                 else if (STREQ(pcmd->argval[items].string, "monitor"))
1517                         sys.flags |= SYS_FLAG_MONITOR;
1518                 else if (STREQ(pcmd->argval[items].string, "ntp"))
1519                         sys.flags |= SYS_FLAG_NTP;
1520                 else if (STREQ(pcmd->argval[items].string, "pps"))
1521                         sys.flags |= SYS_FLAG_PPS;
1522                 else if (STREQ(pcmd->argval[items].string, "stats"))
1523                         sys.flags |= SYS_FLAG_FILEGEN;
1524                 else {
1525                         (void) fprintf(fp, "Unknown flag %s\n",
1526                             pcmd->argval[items].string);
1527                         res = 1;
1528                 }
1529         }
1530
1531         if (res || sys.flags == 0)
1532             return;
1533
1534 again:
1535         res = doquery(impl_ver, req, 1, 1,
1536                       sizeof(struct conf_sys_flags), (char *)&sys, &items,
1537                       &itemsize, &dummy, 0, sizeof(struct conf_sys_flags));
1538         
1539         if (res == INFO_ERR_IMPL && impl_ver == IMPL_XNTPD) {
1540                 impl_ver = IMPL_XNTPD_OLD;
1541                 goto again;
1542         }
1543
1544         if (res == 0)
1545             (void) fprintf(fp, "done!\n");
1546 }
1547
1548
1549 /*
1550  * data for printing/interrpreting the restrict flags
1551  */
1552 struct resflags {
1553   const char *str;
1554         int bit;
1555 };
1556
1557 static struct resflags resflags[] = {
1558         { "ignore",     RES_IGNORE },
1559         { "noserve",    RES_DONTSERVE },
1560         { "notrust",    RES_DONTTRUST },
1561         { "noquery",    RES_NOQUERY },
1562         { "nomodify",   RES_NOMODIFY },
1563         { "nopeer",     RES_NOPEER },
1564         { "notrap",     RES_NOTRAP },
1565         { "lptrap",     RES_LPTRAP },
1566         { "limited",    RES_LIMITED },
1567         { "version",    RES_VERSION },
1568         { "kod",        RES_DEMOBILIZE },
1569         { "timeout",    RES_TIMEOUT },
1570
1571         { "",           0 }
1572 };
1573
1574 static struct resflags resmflags[] = {
1575         { "ntpport",    RESM_NTPONLY },
1576         { "interface",  RESM_INTERFACE },
1577         { "",           0 }
1578 };
1579
1580
1581 /*
1582  * reslist - obtain and print the server's restrict list
1583  */
1584 /*ARGSUSED*/
1585 static void
1586 reslist(
1587         struct parse *pcmd,
1588         FILE *fp
1589         )
1590 {
1591         struct info_restrict *rl;
1592         struct sockaddr_storage resaddr;
1593         struct sockaddr_storage maskaddr;
1594         int items;
1595         int itemsize;
1596         int res;
1597         int skip;
1598         char *addr;
1599         char *mask;
1600         struct resflags *rf;
1601         u_int32 count;
1602         u_short flags;
1603         u_short mflags;
1604         char flagstr[300];
1605         static const char *comma = ", ";
1606
1607 again:
1608         res = doquery(impl_ver, REQ_GET_RESTRICT, 0, 0, 0, (char *)NULL,
1609                       &items, &itemsize, (void *)&rl, 0, 
1610                       sizeof(struct info_restrict));
1611         
1612         if (res == INFO_ERR_IMPL && impl_ver == IMPL_XNTPD) {
1613                 impl_ver = IMPL_XNTPD_OLD;
1614                 goto again;
1615         }
1616
1617         if (res != 0 && items == 0)
1618             return;
1619
1620         if (!checkitems(items, fp))
1621             return;
1622
1623         if (!checkitemsize(itemsize, sizeof(struct info_restrict)) &&
1624             !checkitemsize(itemsize, v4sizeof(struct info_restrict)))
1625             return;
1626
1627         (void) fprintf(fp,
1628                "   address          mask            count        flags\n");
1629         (void) fprintf(fp,
1630                        "=====================================================================\n");
1631
1632         while (items > 0) {
1633                 memset((char *)&resaddr, 0, sizeof(resaddr));
1634                 memset((char *)&maskaddr, 0, sizeof(maskaddr));
1635                 if (rl->v6_flag != 0) {
1636                         GET_INADDR6(resaddr) = rl->addr6;
1637                         GET_INADDR6(maskaddr) = rl->mask6;
1638                         resaddr.ss_family = AF_INET6;
1639                         maskaddr.ss_family = AF_INET6;
1640 #ifdef HAVE_SA_LEN_IN_STRUCT_SOCKADDR
1641                         resaddr.ss_len = SOCKLEN(&resaddr);
1642 #endif
1643                         addr = nntohost(&resaddr);
1644                 } else {
1645                         GET_INADDR(resaddr) = rl->addr;
1646                         GET_INADDR(maskaddr) = rl->mask;
1647                         resaddr.ss_family = AF_INET;
1648                         maskaddr.ss_family = AF_INET;
1649 #ifdef HAVE_SA_LEN_IN_STRUCT_SOCKADDR
1650                         resaddr.ss_len = SOCKLEN(&resaddr);
1651 #endif
1652                         if ((rl->mask == (u_int32)0xffffffff))
1653                                 addr = nntohost(&resaddr);
1654                         else
1655                                 addr = stoa(&resaddr);
1656                 }
1657                 mask = stoa(&maskaddr);
1658                 skip = 1;
1659                 if ((pcmd->nargs == 0) ||
1660                     ((pcmd->argval->ival == 6) && (rl->v6_flag != 0)) ||
1661                     ((pcmd->argval->ival == 4) && (rl->v6_flag == 0)))
1662                         skip = 0;
1663                 count = ntohl(rl->count);
1664                 flags = ntohs(rl->flags);
1665                 mflags = ntohs(rl->mflags);
1666                 flagstr[0] = '\0';
1667
1668                 res = 1;
1669                 rf = &resmflags[0];
1670                 while (rf->bit != 0) {
1671                         if (mflags & rf->bit) {
1672                                 if (!res)
1673                                     (void) strcat(flagstr, comma);
1674                                 res = 0;
1675                                 (void) strcat(flagstr, rf->str);
1676                         }
1677                         rf++;
1678                 }
1679
1680                 rf = &resflags[0];
1681                 while (rf->bit != 0) {
1682                         if (flags & rf->bit) {
1683                                 if (!res)
1684                                     (void) strcat(flagstr, comma);
1685                                 res = 0;
1686                                 (void) strcat(flagstr, rf->str);
1687                         }
1688                         rf++;
1689                 }
1690
1691                 if (flagstr[0] == '\0')
1692                     (void) strcpy(flagstr, "none");
1693
1694                 if (!skip)
1695                         (void) fprintf(fp, "%-15.15s %-15.15s %9ld  %s\n",
1696                                         addr, mask, (u_long)count, flagstr);
1697                 rl++;
1698                 items--;
1699         }
1700 }
1701
1702
1703
1704 /*
1705  * new_restrict - create/add a set of restrictions
1706  */
1707 static void
1708 new_restrict(
1709         struct parse *pcmd,
1710         FILE *fp
1711         )
1712 {
1713         do_restrict(pcmd, fp, REQ_RESADDFLAGS);
1714 }
1715
1716
1717 /*
1718  * unrestrict - remove restriction flags from existing entry
1719  */
1720 static void
1721 unrestrict(
1722         struct parse *pcmd,
1723         FILE *fp
1724         )
1725 {
1726         do_restrict(pcmd, fp, REQ_RESSUBFLAGS);
1727 }
1728
1729
1730 /*
1731  * delrestrict - delete an existing restriction
1732  */
1733 static void
1734 delrestrict(
1735         struct parse *pcmd,
1736         FILE *fp
1737         )
1738 {
1739         do_restrict(pcmd, fp, REQ_UNRESTRICT);
1740 }
1741
1742
1743 /*
1744  * do_restrict - decode commandline restrictions and make the request
1745  */
1746 static void
1747 do_restrict(
1748         struct parse *pcmd,
1749         FILE *fp,
1750         int req_code
1751         )
1752 {
1753         struct conf_restrict cres;
1754         int items;
1755         int itemsize;
1756         char *dummy;
1757         u_int32 num;
1758         u_long bit;
1759         int i;
1760         int res;
1761         int err;
1762         int sendsize;
1763
1764         /* Initialize cres */
1765         cres.addr = 0;
1766         cres.mask = 0;
1767         cres.flags = 0;
1768         cres.mflags = 0;
1769         cres.v6_flag = 0;
1770
1771 again:
1772         if (impl_ver == IMPL_XNTPD)
1773                 sendsize = sizeof(struct conf_restrict);
1774         else
1775                 sendsize = v4sizeof(struct conf_restrict);
1776
1777         if (pcmd->argval[0].netnum.ss_family == AF_INET) {
1778                 cres.addr = GET_INADDR(pcmd->argval[0].netnum);
1779                 cres.mask = GET_INADDR(pcmd->argval[1].netnum);
1780                 if (impl_ver == IMPL_XNTPD)
1781                         cres.v6_flag = 0;
1782         } else {
1783                 if (impl_ver == IMPL_XNTPD_OLD) {
1784                         fprintf(stderr,
1785                             "***Server doesn't understand IPv6 addresses\n");
1786                         return;
1787                 }
1788                 cres.addr6 = GET_INADDR6(pcmd->argval[0].netnum);
1789                 cres.v6_flag = 1;
1790         }
1791         cres.flags = 0;
1792         cres.mflags = 0;
1793         err = 0;
1794         for (res = 2; res < pcmd->nargs; res++) {
1795                 if (STREQ(pcmd->argval[res].string, "ntpport")) {
1796                         cres.mflags |= RESM_NTPONLY;
1797                 } else {
1798                         for (i = 0; resflags[i].bit != 0; i++) {
1799                                 if (STREQ(pcmd->argval[res].string,
1800                                           resflags[i].str))
1801                                     break;
1802                         }
1803                         if (resflags[i].bit != 0) {
1804                                 cres.flags |= resflags[i].bit;
1805                                 if (req_code == REQ_UNRESTRICT) {
1806                                         (void) fprintf(fp,
1807                                                        "Flag %s inappropriate\n",
1808                                                        resflags[i].str);
1809                                         err++;
1810                                 }
1811                         } else {
1812                                 (void) fprintf(fp, "Unknown flag %s\n",
1813                                                pcmd->argval[res].string);
1814                                 err++;
1815                         }
1816                 }
1817         }
1818
1819         /*
1820          * Make sure mask for default address is zero.  Otherwise,
1821          * make sure mask bits are contiguous.
1822          */
1823         if (pcmd->argval[0].netnum.ss_family == AF_INET) {
1824                 if (cres.addr == 0) {
1825                         cres.mask = 0;
1826                 } else {
1827                         num = ntohl(cres.mask);
1828                         for (bit = 0x80000000; bit != 0; bit >>= 1)
1829                             if ((num & bit) == 0)
1830                                 break;
1831                         for ( ; bit != 0; bit >>= 1)
1832                             if ((num & bit) != 0)
1833                                 break;
1834                         if (bit != 0) {
1835                                 (void) fprintf(fp, "Invalid mask %s\n",
1836                                                numtoa(cres.mask));
1837                                 err++;
1838                         }
1839                 }
1840         } else {
1841                 /* XXX IPv6 sanity checking stuff */
1842         }
1843
1844         if (err)
1845             return;
1846
1847         res = doquery(impl_ver, req_code, 1, 1,
1848                       sendsize, (char *)&cres, &items,
1849                       &itemsize, &dummy, 0, sizeof(struct conf_restrict));
1850         
1851         if (res == INFO_ERR_IMPL && impl_ver == IMPL_XNTPD) {
1852                 impl_ver = IMPL_XNTPD_OLD;
1853                 goto again;
1854         }
1855
1856         if (res == 0)
1857             (void) fprintf(fp, "done!\n");
1858         return;
1859 }
1860
1861
1862 /*
1863  * monlist - obtain and print the server's monitor data
1864  */
1865 /*ARGSUSED*/
1866 static void
1867 monlist(
1868         struct parse *pcmd,
1869         FILE *fp
1870         )
1871 {
1872         char *struct_star;
1873         struct sockaddr_storage addr;
1874         struct sockaddr_storage dstadr;
1875         int items;
1876         int itemsize;
1877         int res;
1878         int version = -1;
1879
1880         if (pcmd->nargs > 0) {
1881                 version = pcmd->argval[0].ival;
1882         }
1883
1884 again:
1885         res = doquery(impl_ver,
1886                       (version == 1 || version == -1) ? REQ_MON_GETLIST_1 :
1887                       REQ_MON_GETLIST, 0, 0, 0, (char *)NULL,
1888                       &items, &itemsize, &struct_star,
1889                       (version < 0) ? (1 << INFO_ERR_REQ) : 0, 
1890                       sizeof(struct info_monitor_1));
1891
1892         if (res == INFO_ERR_IMPL && impl_ver == IMPL_XNTPD) {
1893                 impl_ver = IMPL_XNTPD_OLD;
1894                 goto again;
1895         }
1896
1897         if (res == INFO_ERR_REQ && version < 0) 
1898             res = doquery(impl_ver, REQ_MON_GETLIST, 0, 0, 0, (char *)NULL,
1899                           &items, &itemsize, &struct_star, 0, 
1900                           sizeof(struct info_monitor));
1901         
1902         if (res != 0 && items == 0)
1903             return;
1904
1905         if (!checkitems(items, fp))
1906             return;
1907
1908         if (itemsize == sizeof(struct info_monitor_1) ||
1909             itemsize == v4sizeof(struct info_monitor_1)) {
1910                 struct info_monitor_1 *ml = (struct info_monitor_1 *) struct_star;
1911
1912                 (void) fprintf(fp,
1913                                "remote address          port local address      count m ver code avgint  lstint\n");
1914                 (void) fprintf(fp,
1915                                "===============================================================================\n");
1916                 while (items > 0) {
1917                         memset((char *)&addr, 0, sizeof(addr));
1918                         memset((char *)&dstadr, 0, sizeof(dstadr));
1919                         if (ml->v6_flag != 0) {
1920                                 GET_INADDR6(addr) = ml->addr6;
1921                                 addr.ss_family = AF_INET6;
1922                                 GET_INADDR6(dstadr) = ml->daddr6;
1923                                 dstadr.ss_family = AF_INET6;
1924                         } else {
1925                                 GET_INADDR(addr) = ml->addr;
1926                                 addr.ss_family = AF_INET;
1927                                 GET_INADDR(dstadr) = ml->daddr;
1928                                 dstadr.ss_family = AF_INET;
1929                         }
1930 #ifdef HAVE_SA_LEN_IN_STRUCT_SOCKADDR
1931                         addr.ss_len = SOCKLEN(&addr);
1932                         dstadr.ss_len = SOCKLEN(&dstadr);
1933 #endif
1934                         if ((pcmd->nargs == 0) ||
1935                             ((pcmd->argval->ival == 6) && (ml->v6_flag != 0)) ||
1936                             ((pcmd->argval->ival == 4) && (ml->v6_flag == 0)))
1937                                 (void) fprintf(fp, 
1938                                     "%-22.22s %5d %-15s %8ld %1d %1d %6lx %6lu %7lu\n",
1939                                     nntohost(&addr), 
1940                                     ntohs(ml->port),
1941                                     stoa(&dstadr),
1942                                     (u_long)ntohl(ml->count),
1943                                     ml->mode,
1944                                     ml->version,
1945                                     (u_long)ntohl(ml->lastdrop),
1946                                     (u_long)ntohl(ml->lasttime),
1947                                     (u_long)ntohl(ml->firsttime));
1948                         ml++;
1949                         items--;
1950                 }
1951         } else if (itemsize == sizeof(struct info_monitor) ||
1952             itemsize == v4sizeof(struct info_monitor)) {
1953                 struct info_monitor *ml = (struct info_monitor *) struct_star;
1954
1955                 (void) fprintf(fp,
1956                                "     address               port     count mode ver code avgint  lstint\n");
1957                 (void) fprintf(fp,
1958                                "===============================================================================\n");
1959                 while (items > 0) {
1960                         memset((char *)&dstadr, 0, sizeof(dstadr));
1961                         if (ml->v6_flag != 0) {
1962                                 GET_INADDR6(dstadr) = ml->addr6;
1963                                 dstadr.ss_family = AF_INET6;
1964                         } else {
1965                                 GET_INADDR(dstadr) = ml->addr;
1966                                 dstadr.ss_family = AF_INET;
1967                         }
1968 #ifdef HAVE_SA_LEN_IN_STRUCT_SOCKADDR
1969                         dstadr.ss_len = SOCKLEN(&dstadr);
1970 #endif
1971                         if ((pcmd->nargs == 0) ||
1972                             ((pcmd->argval->ival == 6) && (ml->v6_flag != 0)) ||
1973                             ((pcmd->argval->ival == 4) && (ml->v6_flag == 0)))
1974                                 (void) fprintf(fp,
1975                                     "%-25.25s %5d %9ld %4d %2d %9lx %9lu %9lu\n",
1976                                     nntohost(&dstadr),
1977                                     ntohs(ml->port),
1978                                     (u_long)ntohl(ml->count),
1979                                     ml->mode,
1980                                     ml->version,
1981                                     (u_long)ntohl(ml->lastdrop),
1982                                     (u_long)ntohl(ml->lasttime),
1983                                     (u_long)ntohl(ml->firsttime));
1984                         ml++;
1985                         items--;
1986                 }
1987         } else if (itemsize == sizeof(struct old_info_monitor)) {
1988                 struct old_info_monitor *oml = (struct old_info_monitor *)struct_star;
1989                 (void) fprintf(fp,
1990                                "     address          port     count  mode version  lasttime firsttime\n");
1991                 (void) fprintf(fp,
1992                                "======================================================================\n");
1993                 while (items > 0) {
1994                         memset((char *)&dstadr, 0, sizeof(dstadr));
1995                         if (oml->v6_flag != 0) {
1996                                 GET_INADDR6(dstadr) = oml->addr6;
1997                                 dstadr.ss_family = AF_INET6;
1998                         } else {
1999                                 GET_INADDR(dstadr) = oml->addr;
2000                                 dstadr.ss_family = AF_INET;
2001                         }
2002 #ifdef HAVE_SA_LEN_IN_STRUCT_SOCKADDR
2003                         dstadr.ss_len = SOCKLEN(&dstadr);
2004 #endif
2005                         (void) fprintf(fp, "%-20.20s %5d %9ld %4d   %3d %9lu %9lu\n",
2006                                        nntohost(&dstadr),
2007                                        ntohs(oml->port),
2008                                        (u_long)ntohl(oml->count),
2009                                        oml->mode,
2010                                        oml->version,
2011                                        (u_long)ntohl(oml->lasttime),
2012                                        (u_long)ntohl(oml->firsttime));
2013                         oml++;
2014                         items--;
2015                 }
2016         } else {
2017                 /* issue warning according to new info_monitor size */
2018                 checkitemsize(itemsize, sizeof(struct info_monitor));
2019         }
2020 }
2021
2022
2023 /*
2024  * Mapping between command line strings and stat reset flags
2025  */
2026 struct statreset {
2027   const char *str;
2028         int flag;
2029 } sreset[] = {
2030         { "io",         RESET_FLAG_IO },
2031         { "sys",        RESET_FLAG_SYS },
2032         { "mem",        RESET_FLAG_MEM },
2033         { "timer",      RESET_FLAG_TIMER },
2034         { "auth",       RESET_FLAG_AUTH },
2035         { "allpeers",   RESET_FLAG_ALLPEERS },
2036         { "",           0 }
2037 };
2038
2039 /*
2040  * reset - reset statistic counters
2041  */
2042 static void
2043 reset(
2044         struct parse *pcmd,
2045         FILE *fp
2046         )
2047 {
2048         struct reset_flags rflags;
2049         int items;
2050         int itemsize;
2051         char *dummy;
2052         int i;
2053         int res;
2054         int err;
2055
2056         err = 0;
2057         rflags.flags = 0;
2058         for (res = 0; res < pcmd->nargs; res++) {
2059                 for (i = 0; sreset[i].flag != 0; i++) {
2060                         if (STREQ(pcmd->argval[res].string, sreset[i].str))
2061                             break;
2062                 }
2063                 if (sreset[i].flag == 0) {
2064                         (void) fprintf(fp, "Flag %s unknown\n",
2065                                        pcmd->argval[res].string);
2066                         err++;
2067                 } else {
2068                         rflags.flags |= sreset[i].flag;
2069                 }
2070         }
2071
2072         if (err) {
2073                 (void) fprintf(fp, "Not done due to errors\n");
2074                 return;
2075         }
2076
2077 again:
2078         res = doquery(impl_ver, REQ_RESET_STATS, 1, 1,
2079                       sizeof(struct reset_flags), (char *)&rflags, &items,
2080                       &itemsize, &dummy, 0, sizeof(struct reset_flags));
2081         
2082         if (res == INFO_ERR_IMPL && impl_ver == IMPL_XNTPD) {
2083                 impl_ver = IMPL_XNTPD_OLD;
2084                 goto again;
2085         }
2086
2087         if (res == 0)
2088             (void) fprintf(fp, "done!\n");
2089         return;
2090 }
2091
2092
2093
2094 /*
2095  * preset - reset stat counters for particular peers
2096  */
2097 static void
2098 preset(
2099         struct parse *pcmd,
2100         FILE *fp
2101         )
2102 {
2103         /* 8 is the maximum number of peers which will fit in a packet */
2104         struct conf_unpeer *pl, plist[min(MAXARGS, 8)];
2105         int qitems;
2106         int items;
2107         int itemsize;
2108         char *dummy;
2109         int res;
2110         int sendsize;
2111
2112 again:
2113         if (impl_ver == IMPL_XNTPD)
2114                 sendsize = sizeof(struct conf_unpeer);
2115         else
2116                 sendsize = v4sizeof(struct conf_unpeer);
2117
2118         for (qitems = 0, pl = plist; qitems < min(pcmd->nargs, 8); qitems++) {
2119                 if (pcmd->argval[qitems].netnum.ss_family == AF_INET) {
2120                         pl->peeraddr = GET_INADDR(pcmd->argval[qitems].netnum);
2121                         if (impl_ver == IMPL_XNTPD)
2122                                 pl->v6_flag = 0;
2123                 } else {
2124                         if (impl_ver == IMPL_XNTPD_OLD) {
2125                                 fprintf(stderr,
2126                                     "***Server doesn't understand IPv6 addresses\n");
2127                                 return;
2128                         }
2129                         pl->peeraddr6 =
2130                             GET_INADDR6(pcmd->argval[qitems].netnum);
2131                         pl->v6_flag = 1;
2132                 }
2133                 pl = (struct conf_unpeer *)((char *)pl + sendsize);
2134         }
2135
2136         res = doquery(impl_ver, REQ_RESET_PEER, 1, qitems,
2137                       sendsize, (char *)plist, &items,
2138                       &itemsize, &dummy, 0, sizeof(struct conf_unpeer));
2139         
2140         if (res == INFO_ERR_IMPL && impl_ver == IMPL_XNTPD) {
2141                 impl_ver = IMPL_XNTPD_OLD;
2142                 goto again;
2143         }
2144
2145         if (res == 0)
2146             (void) fprintf(fp, "done!\n");
2147 }
2148
2149
2150 /*
2151  * readkeys - request the server to reread the keys file
2152  */
2153 /*ARGSUSED*/
2154 static void
2155 readkeys(
2156         struct parse *pcmd,
2157         FILE *fp
2158         )
2159 {
2160         int items;
2161         int itemsize;
2162         char *dummy;
2163         int res;
2164
2165 again:
2166         res = doquery(impl_ver, REQ_REREAD_KEYS, 1, 0, 0, (char *)0,
2167                       &items, &itemsize, &dummy, 0, sizeof(dummy));
2168         
2169         if (res == INFO_ERR_IMPL && impl_ver == IMPL_XNTPD) {
2170                 impl_ver = IMPL_XNTPD_OLD;
2171                 goto again;
2172         }
2173
2174         if (res == 0)
2175             (void) fprintf(fp, "done!\n");
2176         return;
2177 }
2178
2179
2180 /*
2181  * trustkey - add some keys to the trusted key list
2182  */
2183 static void
2184 trustkey(
2185         struct parse *pcmd,
2186         FILE *fp
2187         )
2188 {
2189         do_trustkey(pcmd, fp, REQ_TRUSTKEY);
2190 }
2191
2192
2193 /*
2194  * untrustkey - remove some keys from the trusted key list
2195  */
2196 static void
2197 untrustkey(
2198         struct parse *pcmd,
2199         FILE *fp
2200         )
2201 {
2202         do_trustkey(pcmd, fp, REQ_UNTRUSTKEY);
2203 }
2204
2205
2206 /*
2207  * do_trustkey - do grunge work of adding/deleting keys
2208  */
2209 static void
2210 do_trustkey(
2211         struct parse *pcmd,
2212         FILE *fp,
2213         int req
2214         )
2215 {
2216         u_long keyids[MAXARGS];
2217         int i;
2218         int items;
2219         int itemsize;
2220         char *dummy;
2221         int ritems;
2222         int res;
2223
2224         ritems = 0;
2225         for (i = 0; i < pcmd->nargs; i++) {
2226                 keyids[ritems++] = pcmd->argval[i].uval;
2227         }
2228
2229 again:
2230         res = doquery(impl_ver, req, 1, ritems, sizeof(u_long),
2231                       (char *)keyids, &items, &itemsize, &dummy, 0, 
2232                       sizeof(dummy));
2233         
2234         if (res == INFO_ERR_IMPL && impl_ver == IMPL_XNTPD) {
2235                 impl_ver = IMPL_XNTPD_OLD;
2236                 goto again;
2237         }
2238
2239         if (res == 0)
2240             (void) fprintf(fp, "done!\n");
2241         return;
2242 }
2243
2244
2245
2246 /*
2247  * authinfo - obtain and print info about authentication
2248  */
2249 /*ARGSUSED*/
2250 static void
2251 authinfo(
2252         struct parse *pcmd,
2253         FILE *fp
2254         )
2255 {
2256         struct info_auth *ia;
2257         int items;
2258         int itemsize;
2259         int res;
2260
2261 again:
2262         res = doquery(impl_ver, REQ_AUTHINFO, 0, 0, 0, (char *)NULL,
2263                       &items, &itemsize, (void *)&ia, 0, 
2264                       sizeof(struct info_auth));
2265         
2266         if (res == INFO_ERR_IMPL && impl_ver == IMPL_XNTPD) {
2267                 impl_ver = IMPL_XNTPD_OLD;
2268                 goto again;
2269         }
2270
2271         if (res != 0 && items == 0)
2272             return;
2273
2274         if (!check1item(items, fp))
2275             return;
2276
2277         if (!checkitemsize(itemsize, sizeof(struct info_auth)))
2278             return;
2279
2280         (void) fprintf(fp, "time since reset:     %ld\n",
2281             (u_long)ntohl(ia->timereset));
2282         (void) fprintf(fp, "stored keys:          %ld\n",
2283             (u_long)ntohl(ia->numkeys));
2284         (void) fprintf(fp, "free keys:            %ld\n",
2285             (u_long)ntohl(ia->numfreekeys));
2286         (void) fprintf(fp, "key lookups:          %ld\n",
2287             (u_long)ntohl(ia->keylookups));
2288         (void) fprintf(fp, "keys not found:       %ld\n",
2289             (u_long)ntohl(ia->keynotfound));
2290         (void) fprintf(fp, "uncached keys:        %ld\n",
2291             (u_long)ntohl(ia->keyuncached));
2292         (void) fprintf(fp, "encryptions:          %ld\n",
2293             (u_long)ntohl(ia->encryptions));
2294         (void) fprintf(fp, "decryptions:          %ld\n",
2295             (u_long)ntohl(ia->decryptions));
2296         (void) fprintf(fp, "expired keys:         %ld\n",
2297             (u_long)ntohl(ia->expired));
2298 }
2299
2300
2301
2302 /*
2303  * traps - obtain and print a list of traps
2304  */
2305 /*ARGSUSED*/
2306 static void
2307 traps(
2308         struct parse *pcmd,
2309         FILE *fp
2310         )
2311 {
2312         int i;
2313         struct info_trap *it;
2314         struct sockaddr_storage trap_addr, local_addr;
2315         int items;
2316         int itemsize;
2317         int res;
2318
2319 again:
2320         res = doquery(impl_ver, REQ_TRAPS, 0, 0, 0, (char *)NULL,
2321                       &items, &itemsize, (void *)&it, 0, 
2322                       sizeof(struct info_trap));
2323         
2324         if (res == INFO_ERR_IMPL && impl_ver == IMPL_XNTPD) {
2325                 impl_ver = IMPL_XNTPD_OLD;
2326                 goto again;
2327         }
2328
2329         if (res != 0 && items == 0)
2330             return;
2331
2332         if (!checkitems(items, fp))
2333             return;
2334
2335         if (!checkitemsize(itemsize, sizeof(struct info_trap)) &&
2336             !checkitemsize(itemsize, v4sizeof(struct info_trap)))
2337             return;
2338
2339         for (i = 0; i < items; i++ ) {
2340                 if (i != 0)
2341                     (void) fprintf(fp, "\n");
2342                 memset((char *)&trap_addr, 0, sizeof(trap_addr));
2343                 memset((char *)&local_addr, 0, sizeof(local_addr));
2344                 if (it->v6_flag != 0) {
2345                         GET_INADDR6(trap_addr) = it->trap_address6;
2346                         GET_INADDR6(local_addr) = it->local_address6;
2347                         trap_addr.ss_family = AF_INET6;
2348                         local_addr.ss_family = AF_INET6;
2349                 } else {
2350                         GET_INADDR(trap_addr) = it->trap_address;
2351                         GET_INADDR(local_addr) = it->local_address;
2352                         trap_addr.ss_family = AF_INET;
2353                         local_addr.ss_family = AF_INET;
2354                 }
2355 #ifdef HAVE_SA_LEN_IN_STRUCT_SOCKADDR
2356                 trap_addr.ss_len = SOCKLEN(&trap_addr);
2357                 local_addr.ss_len = SOCKLEN(&local_addr);
2358 #endif
2359                 (void) fprintf(fp, "address %s, port %d\n",
2360                                 stoa(&trap_addr), 
2361                                 ntohs(it->trap_port));
2362                 (void) fprintf(fp, "interface: %s, ",
2363                                 (it->local_address == 0)
2364                                 ? "wildcard"
2365                                 : stoa(&local_addr));
2366                 if (ntohl(it->flags) & TRAP_CONFIGURED)
2367                     (void) fprintf(fp, "configured\n");
2368                 else if (ntohl(it->flags) & TRAP_NONPRIO)
2369                     (void) fprintf(fp, "low priority\n");
2370                 else
2371                     (void) fprintf(fp, "normal priority\n");
2372                 
2373                 (void) fprintf(fp, "set for %ld secs, last set %ld secs ago\n",
2374                                (long)ntohl(it->origtime),
2375                                (long)ntohl(it->settime));
2376                 (void) fprintf(fp, "sequence %d, number of resets %ld\n",
2377                                ntohs(it->sequence),
2378                                (long)ntohl(it->resets));
2379         }
2380 }
2381
2382
2383 /*
2384  * addtrap - configure a trap
2385  */
2386 static void
2387 addtrap(
2388         struct parse *pcmd,
2389         FILE *fp
2390         )
2391 {
2392         do_addclr_trap(pcmd, fp, REQ_ADD_TRAP);
2393 }
2394
2395
2396 /*
2397  * clrtrap - clear a trap from the server
2398  */
2399 static void
2400 clrtrap(
2401         struct parse *pcmd,
2402         FILE *fp
2403         )
2404 {
2405         do_addclr_trap(pcmd, fp, REQ_CLR_TRAP);
2406 }
2407
2408
2409 /*
2410  * do_addclr_trap - do grunge work of adding/deleting traps
2411  */
2412 static void
2413 do_addclr_trap(
2414         struct parse *pcmd,
2415         FILE *fp,
2416         int req
2417         )
2418 {
2419         struct conf_trap ctrap;
2420         int items;
2421         int itemsize;
2422         char *dummy;
2423         int res;
2424         int sendsize;
2425
2426 again:
2427         if (impl_ver == IMPL_XNTPD)
2428                 sendsize = sizeof(struct conf_trap);
2429         else
2430                 sendsize = v4sizeof(struct conf_trap);
2431
2432         if (pcmd->argval[0].netnum.ss_family == AF_INET) {
2433                 ctrap.trap_address = GET_INADDR(pcmd->argval[0].netnum);
2434                 if (impl_ver == IMPL_XNTPD)
2435                         ctrap.v6_flag = 0;
2436         } else {
2437                 if (impl_ver == IMPL_XNTPD_OLD) {
2438                         fprintf(stderr,
2439                             "***Server doesn't understand IPv6 addresses\n");
2440                         return;
2441                 }
2442                 ctrap.trap_address6 = GET_INADDR6(pcmd->argval[0].netnum);
2443                 ctrap.v6_flag = 1;
2444         }
2445         ctrap.local_address = 0;
2446         ctrap.trap_port = htons(TRAPPORT);
2447         ctrap.unused = 0;
2448
2449         if (pcmd->nargs > 1) {
2450                 ctrap.trap_port
2451                         = htons((u_short)(pcmd->argval[1].uval & 0xffff));
2452                 if (pcmd->nargs > 2) {
2453                         if (pcmd->argval[2].netnum.ss_family !=
2454                             pcmd->argval[0].netnum.ss_family) {
2455                                 fprintf(stderr,
2456                                     "***Cannot mix IPv4 and IPv6 addresses\n");
2457                                 return;
2458                         }
2459                         if (pcmd->argval[2].netnum.ss_family == AF_INET)
2460                                 ctrap.local_address = GET_INADDR(pcmd->argval[2].netnum);
2461                         else
2462                                 ctrap.local_address6 = GET_INADDR6(pcmd->argval[2].netnum);
2463                 }
2464         }
2465
2466         res = doquery(impl_ver, req, 1, 1, sendsize,
2467                       (char *)&ctrap, &items, &itemsize, &dummy, 0, 
2468                       sizeof(struct conf_trap));
2469         
2470         if (res == INFO_ERR_IMPL && impl_ver == IMPL_XNTPD) {
2471                 impl_ver = IMPL_XNTPD_OLD;
2472                 goto again;
2473         }
2474
2475         if (res == 0)
2476             (void) fprintf(fp, "done!\n");
2477         return;
2478 }
2479
2480
2481
2482 /*
2483  * requestkey - change the server's request key (a dangerous request)
2484  */
2485 static void
2486 requestkey(
2487         struct parse *pcmd,
2488         FILE *fp
2489         )
2490 {
2491         do_changekey(pcmd, fp, REQ_REQUEST_KEY);
2492 }
2493
2494
2495 /*
2496  * controlkey - change the server's control key
2497  */
2498 static void
2499 controlkey(
2500         struct parse *pcmd,
2501         FILE *fp
2502         )
2503 {
2504         do_changekey(pcmd, fp, REQ_CONTROL_KEY);
2505 }
2506
2507
2508
2509 /*
2510  * do_changekey - do grunge work of changing keys
2511  */
2512 static void
2513 do_changekey(
2514         struct parse *pcmd,
2515         FILE *fp,
2516         int req
2517         )
2518 {
2519         u_long key;
2520         int items;
2521         int itemsize;
2522         char *dummy;
2523         int res;
2524
2525
2526         key = htonl((u_int32)pcmd->argval[0].uval);
2527
2528 again:
2529         res = doquery(impl_ver, req, 1, 1, sizeof(u_int32),
2530                       (char *)&key, &items, &itemsize, &dummy, 0, 
2531                       sizeof(dummy));
2532         
2533         if (res == INFO_ERR_IMPL && impl_ver == IMPL_XNTPD) {
2534                 impl_ver = IMPL_XNTPD_OLD;
2535                 goto again;
2536         }
2537
2538         if (res == 0)
2539             (void) fprintf(fp, "done!\n");
2540         return;
2541 }
2542
2543
2544
2545 /*
2546  * ctlstats - obtain and print info about authentication
2547  */
2548 /*ARGSUSED*/
2549 static void
2550 ctlstats(
2551         struct parse *pcmd,
2552         FILE *fp
2553         )
2554 {
2555         struct info_control *ic;
2556         int items;
2557         int itemsize;
2558         int res;
2559
2560 again:
2561         res = doquery(impl_ver, REQ_GET_CTLSTATS, 0, 0, 0, (char *)NULL,
2562                       &items, &itemsize, (void *)&ic, 0, 
2563                       sizeof(struct info_control));
2564         
2565         if (res == INFO_ERR_IMPL && impl_ver == IMPL_XNTPD) {
2566                 impl_ver = IMPL_XNTPD_OLD;
2567                 goto again;
2568         }
2569
2570         if (res != 0 && items == 0)
2571             return;
2572
2573         if (!check1item(items, fp))
2574             return;
2575
2576         if (!checkitemsize(itemsize, sizeof(struct info_control)))
2577             return;
2578
2579         (void) fprintf(fp, "time since reset:       %ld\n",
2580                        (u_long)ntohl(ic->ctltimereset));
2581         (void) fprintf(fp, "requests received:      %ld\n",
2582                        (u_long)ntohl(ic->numctlreq));
2583         (void) fprintf(fp, "responses sent:         %ld\n",
2584                        (u_long)ntohl(ic->numctlresponses));
2585         (void) fprintf(fp, "fragments sent:         %ld\n",
2586                        (u_long)ntohl(ic->numctlfrags));
2587         (void) fprintf(fp, "async messages sent:    %ld\n",
2588                        (u_long)ntohl(ic->numasyncmsgs));
2589         (void) fprintf(fp, "error msgs sent:        %ld\n",
2590                        (u_long)ntohl(ic->numctlerrors));
2591         (void) fprintf(fp, "total bad pkts:         %ld\n",
2592                        (u_long)ntohl(ic->numctlbadpkts));
2593         (void) fprintf(fp, "packet too short:       %ld\n",
2594                        (u_long)ntohl(ic->numctltooshort));
2595         (void) fprintf(fp, "response on input:      %ld\n",
2596                        (u_long)ntohl(ic->numctlinputresp));
2597         (void) fprintf(fp, "fragment on input:      %ld\n",
2598                        (u_long)ntohl(ic->numctlinputfrag));
2599         (void) fprintf(fp, "error set on input:     %ld\n",
2600                        (u_long)ntohl(ic->numctlinputerr));
2601         (void) fprintf(fp, "bad offset on input:    %ld\n",
2602                        (u_long)ntohl(ic->numctlbadoffset));
2603         (void) fprintf(fp, "bad version packets:    %ld\n",
2604                        (u_long)ntohl(ic->numctlbadversion));
2605         (void) fprintf(fp, "data in pkt too short:  %ld\n",
2606                        (u_long)ntohl(ic->numctldatatooshort));
2607         (void) fprintf(fp, "unknown op codes:       %ld\n",
2608                        (u_long)ntohl(ic->numctlbadop));
2609 }
2610
2611
2612 /*
2613  * clockstat - get and print clock status information
2614  */
2615 static void
2616 clockstat(
2617         struct parse *pcmd,
2618         FILE *fp
2619         )
2620 {
2621         struct info_clock *cl;
2622         /* 8 is the maximum number of clocks which will fit in a packet */
2623         u_long clist[min(MAXARGS, 8)];
2624         int qitems;
2625         int items;
2626         int itemsize;
2627         int res;
2628         l_fp ts;
2629         struct clktype *clk;
2630         u_long ltemp;
2631
2632         for (qitems = 0; qitems < min(pcmd->nargs, 8); qitems++)
2633             clist[qitems] = GET_INADDR(pcmd->argval[qitems].netnum);
2634
2635 again:
2636         res = doquery(impl_ver, REQ_GET_CLOCKINFO, 0, qitems,
2637                       sizeof(u_int32), (char *)clist, &items,
2638                       &itemsize, (void *)&cl, 0, sizeof(struct info_clock));
2639         
2640         if (res == INFO_ERR_IMPL && impl_ver == IMPL_XNTPD) {
2641                 impl_ver = IMPL_XNTPD_OLD;
2642                 goto again;
2643         }
2644
2645         if (res != 0 && items == 0)
2646             return;
2647
2648         if (!checkitems(items, fp))
2649             return;
2650
2651         if (!checkitemsize(itemsize, sizeof(struct info_clock)))
2652             return;
2653
2654         while (items-- > 0) {
2655                 (void) fprintf(fp, "clock address:        %s\n",
2656                                numtoa(cl->clockadr));
2657                 for (clk = clktypes; clk->code >= 0; clk++)
2658                     if (clk->code == cl->type)
2659                         break;
2660                 if (clk->code >= 0)
2661                     (void) fprintf(fp, "clock type:           %s\n",
2662                                    clk->clocktype);
2663                 else
2664                     (void) fprintf(fp, "clock type:           unknown type (%d)\n",
2665                                    cl->type);
2666                 (void) fprintf(fp, "last event:           %d\n",
2667                                cl->lastevent);
2668                 (void) fprintf(fp, "current status:       %d\n",
2669                                cl->currentstatus);
2670                 (void) fprintf(fp, "number of polls:      %lu\n",
2671                                (u_long)ntohl(cl->polls));
2672                 (void) fprintf(fp, "no response to poll:  %lu\n",
2673                                (u_long)ntohl(cl->noresponse));
2674                 (void) fprintf(fp, "bad format responses: %lu\n",
2675                                (u_long)ntohl(cl->badformat));
2676                 (void) fprintf(fp, "bad data responses:   %lu\n",
2677                                (u_long)ntohl(cl->baddata));
2678                 (void) fprintf(fp, "running time:         %lu\n",
2679                                (u_long)ntohl(cl->timestarted));
2680                 NTOHL_FP(&cl->fudgetime1, &ts);
2681                 (void) fprintf(fp, "fudge time 1:         %s\n",
2682                                lfptoa(&ts, 6));
2683                 NTOHL_FP(&cl->fudgetime2, &ts);
2684                 (void) fprintf(fp, "fudge time 2:         %s\n",
2685                                lfptoa(&ts, 6));
2686                 (void) fprintf(fp, "stratum:              %ld\n",
2687                                (u_long)ntohl(cl->fudgeval1));
2688                 ltemp = ntohl(cl->fudgeval2);
2689                 (void) fprintf(fp, "reference ID:         %s\n",
2690                                (char *)&ltemp);
2691                 (void) fprintf(fp, "fudge flags:          0x%x\n",
2692                                cl->flags);
2693
2694                 if (items > 0)
2695                     (void) fprintf(fp, "\n");
2696                 cl++;
2697         }
2698 }
2699
2700
2701 /*
2702  * fudge - set clock fudge factors
2703  */
2704 static void
2705 fudge(
2706         struct parse *pcmd,
2707         FILE *fp
2708         )
2709 {
2710         struct conf_fudge fudgedata;
2711         int items;
2712         int itemsize;
2713         char *dummy;
2714         l_fp ts;
2715         int res;
2716         long val;
2717         u_long u_val;
2718         int err;
2719
2720
2721         err = 0;
2722         memset((char *)&fudgedata, 0, sizeof fudgedata);
2723         fudgedata.clockadr = GET_INADDR(pcmd->argval[0].netnum);
2724
2725         if (STREQ(pcmd->argval[1].string, "time1")) {
2726                 fudgedata.which = htonl(FUDGE_TIME1);
2727                 if (!atolfp(pcmd->argval[2].string, &ts))
2728                     err = 1;
2729                 else
2730                     NTOHL_FP(&ts, &fudgedata.fudgetime);
2731         } else if (STREQ(pcmd->argval[1].string, "time2")) {
2732                 fudgedata.which = htonl(FUDGE_TIME2);
2733                 if (!atolfp(pcmd->argval[2].string, &ts))
2734                     err = 1;
2735                 else
2736                     NTOHL_FP(&ts, &fudgedata.fudgetime);
2737         } else if (STREQ(pcmd->argval[1].string, "val1")) {
2738                 fudgedata.which = htonl(FUDGE_VAL1);
2739                 if (!atoint(pcmd->argval[2].string, &val))
2740                     err = 1;
2741                 else
2742                     fudgedata.fudgeval_flags = htonl(val);
2743         } else if (STREQ(pcmd->argval[1].string, "val2")) {
2744                 fudgedata.which = htonl(FUDGE_VAL2);
2745                 if (!atoint(pcmd->argval[2].string, &val))
2746                     err = 1;
2747                 else
2748                     fudgedata.fudgeval_flags = htonl((u_int32)val);
2749         } else if (STREQ(pcmd->argval[1].string, "flags")) {
2750                 fudgedata.which = htonl(FUDGE_FLAGS);
2751                 if (!hextoint(pcmd->argval[2].string, &u_val))
2752                     err = 1;
2753                 else
2754                     fudgedata.fudgeval_flags = htonl((u_int32)(u_val & 0xf));
2755         } else {
2756                 (void) fprintf(stderr, "What fudge is %s?\n",
2757                                pcmd->argval[1].string);
2758                 return;
2759         }
2760
2761         if (err) {
2762                 (void) fprintf(stderr, "Unknown fudge parameter %s\n",
2763                                pcmd->argval[2].string);
2764                 return;
2765         }
2766
2767 again:
2768         res = doquery(impl_ver, REQ_SET_CLKFUDGE, 1, 1,
2769                       sizeof(struct conf_fudge), (char *)&fudgedata, &items,
2770                       &itemsize, &dummy, 0, sizeof(dummy));
2771
2772         if (res == INFO_ERR_IMPL && impl_ver == IMPL_XNTPD) {
2773                 impl_ver = IMPL_XNTPD_OLD;
2774                 goto again;
2775         }
2776
2777         if (res == 0)
2778             (void) fprintf(fp, "done!\n");
2779         return;
2780 }
2781
2782 /*
2783  * clkbug - get and print clock debugging information
2784  */
2785 static void
2786 clkbug(
2787         struct parse *pcmd,
2788         FILE *fp
2789         )
2790 {
2791         register int i;
2792         register int n;
2793         register u_int32 s;
2794         struct info_clkbug *cl;
2795         /* 8 is the maximum number of clocks which will fit in a packet */
2796         u_long clist[min(MAXARGS, 8)];
2797         u_int32 ltemp;
2798         int qitems;
2799         int items;
2800         int itemsize;
2801         int res;
2802         int needsp;
2803         l_fp ts;
2804
2805         for (qitems = 0; qitems < min(pcmd->nargs, 8); qitems++)
2806             clist[qitems] = GET_INADDR(pcmd->argval[qitems].netnum);
2807
2808 again:
2809         res = doquery(impl_ver, REQ_GET_CLKBUGINFO, 0, qitems,
2810                       sizeof(u_int32), (char *)clist, &items,
2811                       &itemsize, (void *)&cl, 0, sizeof(struct info_clkbug));
2812         
2813         if (res == INFO_ERR_IMPL && impl_ver == IMPL_XNTPD) {
2814                 impl_ver = IMPL_XNTPD_OLD;
2815                 goto again;
2816         }
2817
2818         if (res != 0 && items == 0)
2819             return;
2820
2821         if (!checkitems(items, fp))
2822             return;
2823
2824         if (!checkitemsize(itemsize, sizeof(struct info_clkbug)))
2825             return;
2826
2827         while (items-- > 0) {
2828                 (void) fprintf(fp, "clock address:        %s\n",
2829                                numtoa(cl->clockadr));
2830                 n = (int)cl->nvalues;
2831                 (void) fprintf(fp, "values: %d", n);
2832                 s = ntohs(cl->svalues);
2833                 if (n > NUMCBUGVALUES)
2834                     n = NUMCBUGVALUES;
2835                 for (i = 0; i < n; i++) {
2836                         ltemp = ntohl(cl->values[i]);
2837                         ltemp &= 0xffffffff;    /* HMS: This does nothing now */
2838                         if ((i & 0x3) == 0)
2839                             (void) fprintf(fp, "\n");
2840                         if (s & (1 << i))
2841                             (void) fprintf(fp, "%12ld", (u_long)ltemp);
2842                         else
2843                             (void) fprintf(fp, "%12lu", (u_long)ltemp);
2844                 }
2845                 (void) fprintf(fp, "\n");
2846
2847                 n = (int)cl->ntimes;
2848                 (void) fprintf(fp, "times: %d", n);
2849                 s = ntohl(cl->stimes);
2850                 if (n > NUMCBUGTIMES)
2851                     n = NUMCBUGTIMES;
2852                 needsp = 0;
2853                 for (i = 0; i < n; i++) {
2854                         if ((i & 0x1) == 0) {
2855                             (void) fprintf(fp, "\n");
2856                         } else {
2857                                 for (;needsp > 0; needsp--)
2858                                     putc(' ', fp);
2859                         }
2860                         NTOHL_FP(&cl->times[i], &ts);
2861                         if (s & (1 << i)) {
2862                                 (void) fprintf(fp, "%17s",
2863                                                lfptoa(&ts, 6));
2864                                 needsp = 22;
2865                         } else {
2866                                 (void) fprintf(fp, "%37s",
2867                                                uglydate(&ts));
2868                                 needsp = 2;
2869                         }
2870                 }
2871                 (void) fprintf(fp, "\n");
2872                 if (items > 0) {
2873                         cl++;
2874                         (void) fprintf(fp, "\n");
2875                 }
2876         }
2877 }
2878
2879
2880 /*
2881  * kerninfo - display the kernel pll/pps variables
2882  */
2883 static void
2884 kerninfo(
2885         struct parse *pcmd,
2886         FILE *fp
2887         )
2888 {
2889         struct info_kernel *ik;
2890         int items;
2891         int itemsize;
2892         int res;
2893         unsigned status;
2894         double tscale = 1e-6;
2895
2896 again:
2897         res = doquery(impl_ver, REQ_GET_KERNEL, 0, 0, 0, (char *)NULL,
2898                       &items, &itemsize, (void *)&ik, 0, 
2899                       sizeof(struct info_kernel));
2900
2901         if (res == INFO_ERR_IMPL && impl_ver == IMPL_XNTPD) {
2902                 impl_ver = IMPL_XNTPD_OLD;
2903                 goto again;
2904         }
2905
2906         if (res != 0 && items == 0)
2907             return;
2908         if (!check1item(items, fp))
2909             return;
2910         if (!checkitemsize(itemsize, sizeof(struct info_kernel)))
2911             return;
2912
2913         status = ntohs(ik->status) & 0xffff;
2914         /*
2915          * pll variables. We know more than we should about the NANO bit.
2916          */
2917 #ifdef STA_NANO
2918         if (status & STA_NANO)
2919                 tscale = 1e-9;
2920 #endif
2921         (void)fprintf(fp, "pll offset:           %g s\n",
2922             (long)ntohl(ik->offset) * tscale);
2923         (void)fprintf(fp, "pll frequency:        %s ppm\n",
2924             fptoa((s_fp)ntohl(ik->freq), 3));
2925         (void)fprintf(fp, "maximum error:        %g s\n",
2926             (u_long)ntohl(ik->maxerror) * 1e-6);
2927         (void)fprintf(fp, "estimated error:      %g s\n",
2928             (u_long)ntohl(ik->esterror) * 1e-6);
2929         (void)fprintf(fp, "status:               %04x ", status);
2930 #ifdef STA_PLL
2931         if (status & STA_PLL) (void)fprintf(fp, " pll");
2932 #endif
2933 #ifdef STA_PPSFREQ
2934         if (status & STA_PPSFREQ) (void)fprintf(fp, " ppsfreq");
2935 #endif
2936 #ifdef STA_PPSTIME
2937         if (status & STA_PPSTIME) (void)fprintf(fp, " ppstime");
2938 #endif
2939 #ifdef STA_FLL
2940         if (status & STA_FLL) (void)fprintf(fp, " fll");
2941 #endif
2942 #ifdef STA_INS
2943         if (status & STA_INS) (void)fprintf(fp, " ins");
2944 #endif
2945 #ifdef STA_DEL
2946         if (status & STA_DEL) (void)fprintf(fp, " del");
2947 #endif
2948 #ifdef STA_UNSYNC
2949         if (status & STA_UNSYNC) (void)fprintf(fp, " unsync");
2950 #endif
2951 #ifdef STA_FREQHOLD
2952         if (status & STA_FREQHOLD) (void)fprintf(fp, " freqhold");
2953 #endif
2954 #ifdef STA_PPSSIGNAL
2955         if (status & STA_PPSSIGNAL) (void)fprintf(fp, " ppssignal");
2956 #endif
2957 #ifdef STA_PPSJITTER
2958         if (status & STA_PPSJITTER) (void)fprintf(fp, " ppsjitter");
2959 #endif
2960 #ifdef STA_PPSWANDER
2961         if (status & STA_PPSWANDER) (void)fprintf(fp, " ppswander");
2962 #endif
2963 #ifdef STA_PPSERROR
2964         if (status & STA_PPSERROR) (void)fprintf(fp, " ppserror");
2965 #endif
2966 #ifdef STA_CLOCKERR
2967         if (status & STA_CLOCKERR) (void)fprintf(fp, " clockerr");
2968 #endif
2969 #ifdef STA_NANO
2970         if (status & STA_NANO) (void)fprintf(fp, " nano");
2971 #endif
2972 #ifdef STA_MODE
2973         if (status & STA_MODE) (void)fprintf(fp, " mode=fll");
2974 #endif
2975 #ifdef STA_CLK
2976         if (status & STA_CLK) (void)fprintf(fp, " src=B");
2977 #endif
2978         (void)fprintf(fp, "\n");
2979         (void)fprintf(fp, "pll time constant:    %ld\n",
2980             (u_long)ntohl(ik->constant));
2981         (void)fprintf(fp, "precision:            %g s\n",
2982             (u_long)ntohl(ik->precision) * tscale);
2983         (void)fprintf(fp, "frequency tolerance:  %s ppm\n",
2984             fptoa((s_fp)ntohl(ik->tolerance), 0));
2985
2986         /*
2987          * For backwards compatibility (ugh), we find the pps variables
2988          * only if the shift member is nonzero.
2989          */
2990         if (!ik->shift)
2991             return;
2992
2993         /*
2994          * pps variables
2995          */
2996         (void)fprintf(fp, "pps frequency:        %s ppm\n",
2997             fptoa((s_fp)ntohl(ik->ppsfreq), 3));
2998         (void)fprintf(fp, "pps stability:        %s ppm\n",
2999             fptoa((s_fp)ntohl(ik->stabil), 3));
3000         (void)fprintf(fp, "pps jitter:           %g s\n",
3001             (u_long)ntohl(ik->jitter) * tscale);
3002         (void)fprintf(fp, "calibration interval: %d s\n",
3003                       1 << ntohs(ik->shift));
3004         (void)fprintf(fp, "calibration cycles:   %ld\n",
3005                       (u_long)ntohl(ik->calcnt));
3006         (void)fprintf(fp, "jitter exceeded:      %ld\n",
3007                       (u_long)ntohl(ik->jitcnt));
3008         (void)fprintf(fp, "stability exceeded:   %ld\n",
3009                       (u_long)ntohl(ik->stbcnt));
3010         (void)fprintf(fp, "calibration errors:   %ld\n",
3011                       (u_long)ntohl(ik->errcnt));
3012 }