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