1 /* $NetBSD: ntpq-subs.c,v 1.1.1.1 2009/12/13 16:56:29 kardel Exp $ */
4 * ntpq_ops.c - subroutines which are called to perform operations by ntpq
12 #include "ntp_stdlib.h"
14 #include "ntpq-opts.h"
16 extern const char * chosts
[];
17 extern char currenthost
[];
22 * Declarations for command handlers in here
24 static int checkassocid (u_int32
);
25 static struct varlist
*findlistvar (struct varlist
*, char *);
26 static void doaddvlist (struct varlist
*, char *);
27 static void dormvlist (struct varlist
*, char *);
28 static void doclearvlist (struct varlist
*);
29 static void makequerydata (struct varlist
*, int *, char *);
30 static int doquerylist (struct varlist
*, int, int, int,
31 u_short
*, int *, char **);
32 static void doprintvlist (struct varlist
*, FILE *);
33 static void addvars (struct parse
*, FILE *);
34 static void rmvars (struct parse
*, FILE *);
35 static void clearvars (struct parse
*, FILE *);
36 static void showvars (struct parse
*, FILE *);
37 static int dolist (struct varlist
*, int, int, int,
39 static void readlist (struct parse
*, FILE *);
40 static void writelist (struct parse
*, FILE *);
41 static void readvar (struct parse
*, FILE *);
42 static void writevar (struct parse
*, FILE *);
43 static void clocklist (struct parse
*, FILE *);
44 static void clockvar (struct parse
*, FILE *);
45 static int findassidrange (u_int32
, u_int32
, int *, int *);
46 static void mreadlist (struct parse
*, FILE *);
47 static void mreadvar (struct parse
*, FILE *);
48 static int dogetassoc (FILE *);
49 static void printassoc (int, FILE *);
50 static void associations (struct parse
*, FILE *);
51 static void lassociations (struct parse
*, FILE *);
52 static void passociations (struct parse
*, FILE *);
53 static void lpassociations (struct parse
*, FILE *);
56 static void radiostatus (struct parse
*, FILE *);
59 static void pstatus (struct parse
*, FILE *);
60 static long when (l_fp
*, l_fp
*, l_fp
*);
61 static char * prettyinterval (char *, long);
62 static int doprintpeers (struct varlist
*, int, int, int, char *, FILE *, int);
63 static int dogetpeers (struct varlist
*, int, FILE *, int);
64 static void dopeers (int, FILE *, int);
65 static void peers (struct parse
*, FILE *);
66 static void lpeers (struct parse
*, FILE *);
67 static void doopeers (int, FILE *, int);
68 static void opeers (struct parse
*, FILE *);
69 static void lopeers (struct parse
*, FILE *);
70 static void config (struct parse
*, FILE *);
71 static void saveconfig (struct parse
*, FILE *);
72 static void config_from_file(struct parse
*, FILE *);
76 * Commands we understand. Ntpdc imports this.
78 struct xcmd opcmds
[] = {
79 { "saveconfig", saveconfig
, { NTP_STR
, NO
, NO
, NO
},
80 { "filename", "", "", ""},
81 "save ntpd configuration to file, . for current config file"},
82 { "associations", associations
, { NO
, NO
, NO
, NO
},
84 "print list of association ID's and statuses for the server's peers" },
85 { "passociations", passociations
, { NO
, NO
, NO
, NO
},
87 "print list of associations returned by last associations command" },
88 { "lassociations", lassociations
, { NO
, NO
, NO
, NO
},
90 "print list of associations including all client information" },
91 { "lpassociations", lpassociations
, { NO
, NO
, NO
, NO
},
93 "print last obtained list of associations, including client information" },
94 { "addvars", addvars
, { NTP_STR
, NO
, NO
, NO
},
95 { "name[=value][,...]", "", "", "" },
96 "add variables to the variable list or change their values" },
97 { "rmvars", rmvars
, { NTP_STR
, NO
, NO
, NO
},
98 { "name[,...]", "", "", "" },
99 "remove variables from the variable list" },
100 { "clearvars", clearvars
, { NO
, NO
, NO
, NO
},
102 "remove all variables from the variable list" },
103 { "showvars", showvars
, { NO
, NO
, NO
, NO
},
105 "print variables on the variable list" },
106 { "readlist", readlist
, { OPT
|NTP_UINT
, NO
, NO
, NO
},
107 { "assocID", "", "", "" },
108 "read the system or peer variables included in the variable list" },
109 { "rl", readlist
, { OPT
|NTP_UINT
, NO
, NO
, NO
},
110 { "assocID", "", "", "" },
111 "read the system or peer variables included in the variable list" },
112 { "writelist", writelist
, { OPT
|NTP_UINT
, NO
, NO
, NO
},
113 { "assocID", "", "", "" },
114 "write the system or peer variables included in the variable list" },
115 { "readvar", readvar
, { OPT
|NTP_UINT
, OPT
|NTP_STR
, NO
, NO
},
116 { "assocID", "name=value[,...]", "", "" },
117 "read system or peer variables" },
118 { "rv", readvar
, { OPT
|NTP_UINT
, OPT
|NTP_STR
, NO
, NO
},
119 { "assocID", "name=value[,...]", "", "" },
120 "read system or peer variables" },
121 { "writevar", writevar
, { NTP_UINT
, NTP_STR
, NO
, NO
},
122 { "assocID", "name=value,[...]", "", "" },
123 "write system or peer variables" },
124 { "mreadlist", mreadlist
, { NTP_UINT
, NTP_UINT
, NO
, NO
},
125 { "assocID", "assocID", "", "" },
126 "read the peer variables in the variable list for multiple peers" },
127 { "mrl", mreadlist
, { NTP_UINT
, NTP_UINT
, NO
, NO
},
128 { "assocID", "assocID", "", "" },
129 "read the peer variables in the variable list for multiple peers" },
130 { "mreadvar", mreadvar
, { NTP_UINT
, NTP_UINT
, OPT
|NTP_STR
, NO
},
131 { "assocID", "assocID", "name=value[,...]", "" },
132 "read peer variables from multiple peers" },
133 { "mrv", mreadvar
, { NTP_UINT
, NTP_UINT
, OPT
|NTP_STR
, NO
},
134 { "assocID", "assocID", "name=value[,...]", "" },
135 "read peer variables from multiple peers" },
136 { "clocklist", clocklist
, { OPT
|NTP_UINT
, NO
, NO
, NO
},
137 { "assocID", "", "", "" },
138 "read the clock variables included in the variable list" },
139 { "cl", clocklist
, { OPT
|NTP_UINT
, NO
, NO
, NO
},
140 { "assocID", "", "", "" },
141 "read the clock variables included in the variable list" },
142 { "clockvar", clockvar
, { OPT
|NTP_UINT
, OPT
|NTP_STR
, NO
, NO
},
143 { "assocID", "name=value[,...]", "", "" },
144 "read clock variables" },
145 { "cv", clockvar
, { OPT
|NTP_UINT
, OPT
|NTP_STR
, NO
, NO
},
146 { "assocID", "name=value[,...]", "", "" },
147 "read clock variables" },
148 { "pstatus", pstatus
, { NTP_UINT
, NO
, NO
, NO
},
149 { "assocID", "", "", "" },
150 "print status information returned for a peer" },
151 { "peers", peers
, { OPT
|IP_VERSION
, NO
, NO
, NO
},
152 { "-4|-6", "", "", "" },
153 "obtain and print a list of the server's peers [IP version]" },
154 { "lpeers", lpeers
, { OPT
|IP_VERSION
, NO
, NO
, NO
},
155 { "-4|-6", "", "", "" },
156 "obtain and print a list of all peers and clients [IP version]" },
157 { "opeers", opeers
, { OPT
|IP_VERSION
, NO
, NO
, NO
},
158 { "-4|-6", "", "", "" },
159 "print peer list the old way, with dstadr shown rather than refid [IP version]" },
160 { "lopeers", lopeers
, { OPT
|IP_VERSION
, NO
, NO
, NO
},
161 { "-4|-6", "", "", "" },
162 "obtain and print a list of all peers and clients showing dstadr [IP version]" },
163 { ":config", config
, { NTP_STR
, NO
, NO
, NO
},
164 { "<configuration command line>", "", "", "" },
165 "send a remote configuration command to ntpd" },
166 { "config-from-file", config_from_file
, { NTP_STR
, NO
, NO
, NO
},
167 { "<configuration filename>", "", "", "" },
168 "configure ntpd using the configuration filename" },
169 { 0, 0, { NO
, NO
, NO
, NO
},
170 { "-4|-6", "", "", "" }, "" }
175 * Variable list data space
177 #define MAXLINE 512 /* maximum length of a line */
178 #define MAXLIST 64 /* maximum number of variables in list */
179 #define LENHOSTNAME 256 /* host name is 256 characters long */
181 * Old CTL_PST defines for version 2.
183 #define OLD_CTL_PST_CONFIG 0x80
184 #define OLD_CTL_PST_AUTHENABLE 0x40
185 #define OLD_CTL_PST_AUTHENTIC 0x20
186 #define OLD_CTL_PST_REACH 0x10
187 #define OLD_CTL_PST_SANE 0x08
188 #define OLD_CTL_PST_DISP 0x04
190 #define OLD_CTL_PST_SEL_REJECT 0
191 #define OLD_CTL_PST_SEL_SELCAND 1
192 #define OLD_CTL_PST_SEL_SYNCCAND 2
193 #define OLD_CTL_PST_SEL_SYSPEER 3
195 char flash2
[] = " .+* "; /* flash decode for version 2 */
196 char flash3
[] = " x.-+#*o"; /* flash decode for peer status version 3 */
201 } g_varlist
[MAXLIST
] = { { 0, 0 } };
204 * Imported from ntpq.c
206 extern int showhostnames
;
208 extern struct servent
*server_entry
;
209 extern struct association assoc_cache
[];
211 extern u_char pktversion
;
212 extern struct ctl_var peer_var
[];
215 * For quick string comparisons
217 #define STREQ(a, b) (*(a) == *(b) && strcmp((a), (b)) == 0)
221 * checkassocid - return the association ID, checking to see if it is valid
228 if (value
== 0 || value
>= 65536) {
229 (void) fprintf(stderr
, "***Invalid association ID specified\n");
237 * findlistvar - look for the named variable in a list and return if found
239 static struct varlist
*
241 struct varlist
*list
,
245 register struct varlist
*vl
;
247 for (vl
= list
; vl
< list
+ MAXLIST
&& vl
->name
!= 0; vl
++)
248 if (STREQ(name
, vl
->name
))
250 if (vl
< list
+ MAXLIST
)
252 return (struct varlist
*)0;
257 * doaddvlist - add variable(s) to the variable list
261 struct varlist
*vlist
,
265 register struct varlist
*vl
;
271 while (nextvar(&len
, &vars
, &name
, &value
)) {
272 vl
= findlistvar(vlist
, name
);
274 (void) fprintf(stderr
, "Variable list full\n");
279 vl
->name
= estrdup(name
);
280 } else if (vl
->value
!= 0) {
286 vl
->value
= estrdup(value
);
292 * dormvlist - remove variable(s) from the variable list
296 struct varlist
*vlist
,
300 register struct varlist
*vl
;
306 while (nextvar(&len
, &vars
, &name
, &value
)) {
307 vl
= findlistvar(vlist
, name
);
308 if (vl
== 0 || vl
->name
== 0) {
309 (void) fprintf(stderr
, "Variable `%s' not found\n",
312 free((void *)vl
->name
);
315 for ( ; (vl
+1) < (g_varlist
+ MAXLIST
)
316 && (vl
+1)->name
!= 0; vl
++) {
317 vl
->name
= (vl
+1)->name
;
318 vl
->value
= (vl
+1)->value
;
320 vl
->name
= vl
->value
= 0;
327 * doclearvlist - clear a variable list
331 struct varlist
*vlist
334 register struct varlist
*vl
;
336 for (vl
= vlist
; vl
< vlist
+ MAXLIST
&& vl
->name
!= 0; vl
++) {
337 free((void *)vl
->name
);
339 if (vl
->value
!= 0) {
348 * makequerydata - form a data buffer to be included with a query
352 struct varlist
*vlist
,
357 register struct varlist
*vl
;
358 register char *cp
, *cpend
;
359 register int namelen
, valuelen
;
360 register int totallen
;
363 cpend
= data
+ *datalen
;
365 for (vl
= vlist
; vl
< vlist
+ MAXLIST
&& vl
->name
!= 0; vl
++) {
366 namelen
= strlen(vl
->name
);
370 valuelen
= strlen(vl
->value
);
371 totallen
= namelen
+ valuelen
+ (valuelen
!= 0) + (cp
!= data
);
372 if (cp
+ totallen
> cpend
)
377 memmove(cp
, vl
->name
, (unsigned)namelen
);
381 memmove(cp
, vl
->value
, (unsigned)valuelen
);
385 *datalen
= cp
- data
;
390 * doquerylist - send a message including variables in a list
394 struct varlist
*vlist
,
403 char data
[CTL_MAX_DATA_LEN
];
406 datalen
= sizeof(data
);
407 makequerydata(vlist
, &datalen
, data
);
409 return doquery(op
, associd
, auth
, datalen
, data
, rstatus
,
415 * doprintvlist - print the variables on a list
419 struct varlist
*vlist
,
423 register struct varlist
*vl
;
425 if (vlist
->name
== 0) {
426 (void) fprintf(fp
, "No variables on list\n");
428 for (vl
= vlist
; vl
< vlist
+ MAXLIST
&& vl
->name
!= 0; vl
++) {
429 if (vl
->value
== 0) {
430 (void) fprintf(fp
, "%s\n", vl
->name
);
432 (void) fprintf(fp
, "%s=%s\n",
433 vl
->name
, vl
->value
);
440 * addvars - add variables to the variable list
449 doaddvlist(g_varlist
, pcmd
->argval
[0].string
);
454 * rmvars - remove variables from the variable list
463 dormvlist(g_varlist
, pcmd
->argval
[0].string
);
468 * clearvars - clear the variable list
477 doclearvlist(g_varlist
);
482 * showvars - show variables on the variable list
491 doprintvlist(g_varlist
, fp
);
496 * dolist - send a request with the given list of variables
500 struct varlist
*vlist
,
514 * if we're asking for specific variables don't include the
515 * status header line in the output.
520 quiet
= (vlist
->name
!= NULL
);
522 res
= doquerylist(vlist
, op
, associd
, 0, &rstatus
, &dsize
, &datap
);
528 (void) fprintf(fp
, "server=%s ", currenthost
);
531 (void) fprintf(fp
, "No system%s variables returned\n",
532 (type
== TYPE_CLOCK
) ? " clock" : "");
535 "No information returned for%s association %u\n",
536 (type
== TYPE_CLOCK
) ? " clock" : "", associd
);
541 fprintf(fp
,"associd=%d ",associd
);
542 printvars(dsize
, datap
, (int)rstatus
, type
, quiet
, fp
);
548 * readlist - send a read variables request with the variables on the list
558 if (pcmd
->nargs
== 0) {
561 /* HMS: I think we want the u_int32 target here, not the u_long */
562 if (pcmd
->argval
[0].uval
== 0)
564 else if ((associd
= checkassocid(pcmd
->argval
[0].uval
)) == 0)
568 (void) dolist(g_varlist
, associd
, CTL_OP_READVAR
,
569 (associd
== 0) ? TYPE_SYS
: TYPE_PEER
, fp
);
574 * writelist - send a write variables request with the variables on the list
588 if (pcmd
->nargs
== 0) {
591 /* HMS: Do we really want uval here? */
592 if (pcmd
->argval
[0].uval
== 0)
594 else if ((associd
= checkassocid(pcmd
->argval
[0].uval
)) == 0)
598 res
= doquerylist(g_varlist
, CTL_OP_WRITEVAR
, associd
, 1, &rstatus
,
605 (void) fprintf(fp
, "server=%s ", currenthost
);
607 (void) fprintf(fp
, "done! (no data returned)\n");
609 (void) fprintf(fp
,"associd=%d ",associd
);
610 printvars(dsize
, datap
, (int)rstatus
,
611 (associd
!= 0) ? TYPE_PEER
: TYPE_SYS
, 0, fp
);
618 * readvar - send a read variables request with the specified variables
627 struct varlist tmplist
[MAXLIST
];
630 if (pcmd
->nargs
== 0 || pcmd
->argval
[0].uval
== 0)
632 else if ((associd
= checkassocid(pcmd
->argval
[0].uval
)) == 0)
635 memset((char *)tmplist
, 0, sizeof(tmplist
));
636 if (pcmd
->nargs
>= 2)
637 doaddvlist(tmplist
, pcmd
->argval
[1].string
);
639 (void) dolist(tmplist
, associd
, CTL_OP_READVAR
,
640 (associd
== 0) ? TYPE_SYS
: TYPE_PEER
, fp
);
642 doclearvlist(tmplist
);
647 * writevar - send a write variables request with the specified variables
660 struct varlist tmplist
[MAXLIST
];
663 if (pcmd
->argval
[0].uval
== 0)
665 else if ((associd
= checkassocid(pcmd
->argval
[0].uval
)) == 0)
668 memset((char *)tmplist
, 0, sizeof(tmplist
));
669 doaddvlist(tmplist
, pcmd
->argval
[1].string
);
671 res
= doquerylist(tmplist
, CTL_OP_WRITEVAR
, associd
, 1, &rstatus
,
674 doclearvlist(tmplist
);
680 (void) fprintf(fp
, "server=%s ", currenthost
);
682 (void) fprintf(fp
, "done! (no data returned)\n");
684 (void) fprintf(fp
,"associd=%d ",associd
);
685 printvars(dsize
, datap
, (int)rstatus
,
696 * clocklist - send a clock variables request with the variables on the list
707 if (pcmd
->nargs
== 0) {
710 if (pcmd
->argval
[0].uval
== 0)
712 else if ((associd
= checkassocid(pcmd
->argval
[0].uval
)) == 0)
716 (void) dolist(g_varlist
, associd
, CTL_OP_READCLOCK
, TYPE_CLOCK
, fp
);
721 * clockvar - send a clock variables request with the specified variables
730 struct varlist tmplist
[MAXLIST
];
733 if (pcmd
->nargs
== 0 || pcmd
->argval
[0].uval
== 0)
735 else if ((associd
= checkassocid(pcmd
->argval
[0].uval
)) == 0)
738 memset((char *)tmplist
, 0, sizeof(tmplist
));
739 if (pcmd
->nargs
>= 2)
740 doaddvlist(tmplist
, pcmd
->argval
[1].string
);
742 (void) dolist(tmplist
, associd
, CTL_OP_READCLOCK
, TYPE_CLOCK
, fp
);
744 doclearvlist(tmplist
);
749 * findassidrange - verify a range of association ID's
762 if (assid1
== 0 || assid1
> 65535) {
763 (void) fprintf(stderr
,
764 "***Invalid association ID %lu specified\n", (u_long
)assid1
);
768 if (assid2
== 0 || assid2
> 65535) {
770 "***Invalid association ID %lu specified\n", (u_long
)assid2
);
775 for (i
= 0; i
< numassoc
; i
++) {
776 if (assoc_cache
[i
].assid
== assid1
) {
781 if (assoc_cache
[i
].assid
== assid2
) {
788 if (f
== -1 || t
== -1) {
789 (void) fprintf(stderr
,
790 "***Association ID %lu not found in list\n",
791 (f
== -1) ? (u_long
)assid1
: (u_long
)assid2
);
808 * mreadlist - send a read variables request for multiple associations
821 if (!findassidrange(pcmd
->argval
[0].uval
, pcmd
->argval
[1].uval
,
825 for (i
= from
; i
<= to
; i
++) {
827 (void) fprintf(fp
, "\n");
828 if (!dolist(g_varlist
, (int)assoc_cache
[i
].assid
,
829 CTL_OP_READVAR
, TYPE_PEER
, fp
))
837 * mreadvar - send a read variables request for multiple associations
848 struct varlist tmplist
[MAXLIST
];
851 if (!findassidrange(pcmd
->argval
[0].uval
, pcmd
->argval
[1].uval
,
855 memset((char *)tmplist
, 0, sizeof(tmplist
));
856 if (pcmd
->nargs
>= 3)
857 doaddvlist(tmplist
, pcmd
->argval
[2].string
);
859 for (i
= from
; i
<= to
; i
++) {
861 (void) fprintf(fp
, "\n");
862 if (!dolist(g_varlist
, (int)assoc_cache
[i
].assid
,
863 CTL_OP_READVAR
, TYPE_PEER
, fp
))
866 doclearvlist(tmplist
);
872 * dogetassoc - query the host for its list of associations
884 res
= doquery(CTL_OP_READSTAT
, 0, 0, 0, (char *)0, &rstatus
,
892 (void) fprintf(fp
, "server=%s ", currenthost
);
893 (void) fprintf(fp
, "No association ID's returned\n");
899 (void) fprintf(stderr
, "server=%s ", currenthost
);
900 (void) fprintf(stderr
,
901 "***Server returned %d octets, should be multiple of 4\n",
908 assoc_cache
[numassoc
].assid
= ntohs(*((u_short
*)datap
));
909 datap
+= sizeof(u_short
);
910 assoc_cache
[numassoc
].status
= ntohs(*((u_short
*)datap
));
911 datap
+= sizeof(u_short
);
912 if (++numassoc
>= MAXASSOC
)
914 dsize
-= sizeof(u_short
) + sizeof(u_short
);
922 * printassoc - print the current list of associations
938 const char *condition
= "";
939 const char *last_event
;
944 (void) fprintf(fp
, "No association ID's in list\n");
952 "\nind assid status conf reach auth condition last_event cnt\n");
954 "===========================================================\n");
955 for (i
= 0; i
< numassoc
; i
++) {
956 statval
= (u_char
) CTL_PEER_STATVAL(assoc_cache
[i
].status
);
957 if (!showall
&& !(statval
& (CTL_PST_CONFIG
|CTL_PST_REACH
)))
959 event
= CTL_PEER_EVENT(assoc_cache
[i
].status
);
960 event_count
= CTL_PEER_NEVNT(assoc_cache
[i
].status
);
961 if (statval
& CTL_PST_CONFIG
)
965 if (statval
& CTL_PST_BCAST
) {
967 if (statval
& CTL_PST_AUTHENABLE
)
972 if (statval
& CTL_PST_REACH
)
976 if (statval
& CTL_PST_AUTHENABLE
) {
977 if (statval
& CTL_PST_AUTHENTIC
)
985 if (pktversion
> NTP_OLDVERSION
) {
986 switch (statval
& 0x7) {
988 case CTL_PST_SEL_REJECT
:
989 condition
= "reject";
992 case CTL_PST_SEL_SANE
:
993 condition
= "falsetick";
996 case CTL_PST_SEL_CORRECT
:
997 condition
= "excess";
1000 case CTL_PST_SEL_SELCAND
:
1001 condition
= "outlyer";
1004 case CTL_PST_SEL_SYNCCAND
:
1005 condition
= "candidate";
1008 case CTL_PST_SEL_EXCESS
:
1009 condition
= "backup";
1012 case CTL_PST_SEL_SYSPEER
:
1013 condition
= "sys.peer";
1016 case CTL_PST_SEL_PPS
:
1017 condition
= "pps.peer";
1021 switch (statval
& 0x3) {
1023 case OLD_CTL_PST_SEL_REJECT
:
1024 if (!(statval
& OLD_CTL_PST_SANE
))
1025 condition
= "insane";
1026 else if (!(statval
& OLD_CTL_PST_DISP
))
1027 condition
= "hi_disp";
1032 case OLD_CTL_PST_SEL_SELCAND
:
1033 condition
= "sel_cand";
1036 case OLD_CTL_PST_SEL_SYNCCAND
:
1037 condition
= "sync_cand";
1040 case OLD_CTL_PST_SEL_SYSPEER
:
1041 condition
= "sys_peer";
1045 switch (PEER_EVENT
|event
) {
1048 last_event
= "mobilize";
1052 last_event
= "demobilize";
1056 last_event
= "reachable";
1060 last_event
= "unreachable";
1064 last_event
= "restart";
1068 last_event
= "no_reply";
1072 last_event
= "rate_exceeded";
1076 last_event
= "access_denied";
1080 last_event
= "leap_armed";
1084 last_event
= "sys_peer";
1088 last_event
= "clock_alarm";
1095 cnt
= uinttoa(event_count
);
1097 "%3d %5u %04x %3.3s %4s %4.4s %9.9s %11s %2s",
1098 i
+ 1, assoc_cache
[i
].assid
, assoc_cache
[i
].status
,
1099 conf
, reach
, auth
, condition
, last_event
, cnt
);
1100 bp
= &buf
[strlen(buf
)];
1101 while (bp
> buf
&& *(bp
-1) == ' ')
1103 (void) fprintf(fp
, "%s\n", buf
);
1109 * associations - get, record and print a list of associations
1124 * lassociations - get, record and print a long list of associations
1139 * passociations - print the association list
1153 * lpassociations - print the long association list
1167 * saveconfig - dump ntp server configuration to server file
1180 if (0 == pcmd
->nargs
)
1183 res
= doquery(CTL_OP_SAVECONFIG
, 0, 1,
1184 strlen(pcmd
->argval
[0].string
),
1185 pcmd
->argval
[0].string
, &rstatus
, &dsize
,
1192 fprintf(fp
, "(no response message, curiously)");
1194 datap
[dsize
] = '\0';
1195 fprintf(fp
, "%s", datap
);
1202 * radiostatus - print the radio status returned by the server
1216 res
= doquery(CTL_OP_READCLOCK
, 0, 0, 0, (char *)0, &rstatus
,
1223 (void) fprintf(fp
, "server=%s ", currenthost
);
1225 (void) fprintf(fp
, "No radio status string returned\n");
1229 asciize(dsize
, datap
, fp
);
1234 * pstatus - print peer status returned by the server
1249 if ((associd
= checkassocid(pcmd
->argval
[0].uval
)) == 0)
1252 res
= doquery(CTL_OP_READSTAT
, associd
, 0, 0, (char *)0, &rstatus
,
1259 (void) fprintf(fp
, "server=%s ", currenthost
);
1262 "No information returned for association %u\n",
1267 (void) fprintf(fp
,"associd=%d ",associd
);
1268 printvars(dsize
, datap
, (int)rstatus
, TYPE_PEER
, 0, fp
);
1273 * when - print how long its been since his last packet arrived
1286 else if (reftime
->l_ui
!= 0)
1291 return (ts
->l_ui
- lasttime
->l_ui
);
1296 * Pretty-print an interval into the given buffer, in a human-friendly format.
1311 (void) sprintf(buf
, "%ld", (long int)diff
);
1315 diff
= (diff
+ 29) / 60;
1317 (void) sprintf(buf
, "%ldm", (long int)diff
);
1321 diff
= (diff
+ 29) / 60;
1323 (void) sprintf(buf
, "%ldh", (long int)diff
);
1327 diff
= (diff
+ 11) / 24;
1328 (void) sprintf(buf
, "%ldd", (long int)diff
);
1342 dummy
= SRCADR(sock
);
1343 ch
= (char)(((dummy
&0xf0000000)==0xe0000000) ? 'm' :
1344 ((dummy
&0x000000ff)==0x000000ff) ? 'b' :
1345 ((dummy
&0xffffffff)==0x7f000001) ? 'l' :
1346 ((dummy
&0xffffffe0)==0x00000000) ? '-' :
1350 if (IN6_IS_ADDR_MULTICAST(PSOCK_ADDR6(sock
)))
1363 * A list of variables required by the peers command
1365 struct varlist opeervarlist
[] = {
1366 { "srcadr", 0 }, /* 0 */
1367 { "dstadr", 0 }, /* 1 */
1368 { "stratum", 0 }, /* 2 */
1369 { "hpoll", 0 }, /* 3 */
1370 { "ppoll", 0 }, /* 4 */
1371 { "reach", 0 }, /* 5 */
1372 { "delay", 0 }, /* 6 */
1373 { "offset", 0 }, /* 7 */
1374 { "jitter", 0 }, /* 8 */
1375 { "dispersion", 0 }, /* 9 */
1376 { "rec", 0 }, /* 10 */
1377 { "reftime", 0 }, /* 11 */
1378 { "srcport", 0 }, /* 12 */
1382 struct varlist peervarlist
[] = {
1383 { "srcadr", 0 }, /* 0 */
1384 { "refid", 0 }, /* 1 */
1385 { "stratum", 0 }, /* 2 */
1386 { "hpoll", 0 }, /* 3 */
1387 { "ppoll", 0 }, /* 4 */
1388 { "reach", 0 }, /* 5 */
1389 { "delay", 0 }, /* 6 */
1390 { "offset", 0 }, /* 7 */
1391 { "jitter", 0 }, /* 8 */
1392 { "dispersion", 0 }, /* 9 */
1393 { "rec", 0 }, /* 10 */
1394 { "reftime", 0 }, /* 11 */
1395 { "srcport", 0 }, /* 12 */
1399 #define HAVE_SRCADR 0
1400 #define HAVE_DSTADR 1
1401 #define HAVE_REFID 1
1402 #define HAVE_STRATUM 2
1403 #define HAVE_HPOLL 3
1404 #define HAVE_PPOLL 4
1405 #define HAVE_REACH 5
1406 #define HAVE_DELAY 6
1407 #define HAVE_OFFSET 7
1408 #define HAVE_JITTER 8
1409 #define HAVE_DISPERSION 9
1411 #define HAVE_REFTIME 11
1412 #define HAVE_SRCPORT 12
1416 * Decode an incoming data buffer and print a line in the peer list
1420 struct varlist
*pvl
,
1437 char *dstadr_refid
= "0.0.0.0";
1449 u_char havevar
[MAXHAVE
];
1452 char refid_string
[10];
1453 char whenbuf
[8], pollbuf
[8];
1454 char clock_name
[LENHOSTNAME
];
1456 memset((char *)havevar
, 0, sizeof(havevar
));
1462 /* Initialize by zeroing out estimate variables */
1463 memset((char *)&estoffset
, 0, sizeof(l_fp
));
1464 memset((char *)&estdelay
, 0, sizeof(l_fp
));
1465 memset((char *)&estjitter
, 0, sizeof(l_fp
));
1466 memset((char *)&estdisp
, 0, sizeof(l_fp
));
1468 while (nextvar(&datalen
, &data
, &name
, &value
)) {
1469 sockaddr_u dum_store
;
1471 i
= findvar(name
, peer_var
, 1);
1473 continue; /* don't know this one */
1476 if (decodenetnum(value
, &srcadr
)) {
1477 havevar
[HAVE_SRCADR
] = 1;
1481 if (decodenetnum(value
, &dum_store
)) {
1482 type
= decodeaddrtype(&dum_store
);
1483 if (pvl
== opeervarlist
) {
1484 havevar
[HAVE_DSTADR
] = 1;
1486 dstadr_refid
= stoa(&dstadr
);
1491 if (pvl
== peervarlist
) {
1492 havevar
[HAVE_REFID
] = 1;
1493 if (*value
== '\0') {
1494 dstadr_refid
= "0.0.0.0";
1495 } else if ((int)strlen(value
) <= 4) {
1496 refid_string
[0] = '.';
1497 (void) strcpy(&refid_string
[1], value
);
1498 i
= strlen(refid_string
);
1499 refid_string
[i
] = '.';
1500 refid_string
[i
+1] = '\0';
1501 dstadr_refid
= refid_string
;
1502 } else if (decodenetnum(value
, &dstadr
)) {
1503 if (SOCK_UNSPEC(&dstadr
))
1504 dstadr_refid
= "0.0.0.0";
1505 else if (ISREFCLOCKADR(&dstadr
))
1512 havevar
[HAVE_REFID
] = 0;
1517 if (decodeuint(value
, &stratum
))
1518 havevar
[HAVE_STRATUM
] = 1;
1521 if (decodeint(value
, &hpoll
)) {
1522 havevar
[HAVE_HPOLL
] = 1;
1524 hpoll
= NTP_MINPOLL
;
1528 if (decodeint(value
, &ppoll
)) {
1529 havevar
[HAVE_PPOLL
] = 1;
1531 ppoll
= NTP_MINPOLL
;
1535 if (decodeuint(value
, &reach
))
1536 havevar
[HAVE_REACH
] = 1;
1539 if (decodetime(value
, &estdelay
))
1540 havevar
[HAVE_DELAY
] = 1;
1543 if (decodetime(value
, &estoffset
))
1544 havevar
[HAVE_OFFSET
] = 1;
1547 if (pvl
== peervarlist
)
1548 if (decodetime(value
, &estjitter
))
1549 havevar
[HAVE_JITTER
] = 1;
1552 if (decodetime(value
, &estdisp
))
1553 havevar
[HAVE_DISPERSION
] = 1;
1556 if (decodets(value
, &rec
))
1557 havevar
[HAVE_REC
] = 1;
1560 if (decodeuint(value
, &srcport
))
1561 havevar
[HAVE_SRCPORT
] = 1;
1564 havevar
[HAVE_REFTIME
] = 1;
1565 if (!decodets(value
, &reftime
))
1574 * Check to see if the srcport is NTP's port. If not this probably
1575 * isn't a valid peer association.
1577 if (havevar
[HAVE_SRCPORT
] && srcport
!= NTP_PORT
)
1581 * Got everything, format the line
1583 poll_sec
= 1<<max(min3(ppoll
, hpoll
, NTP_MAXPOLL
), NTP_MINPOLL
);
1584 if (pktversion
> NTP_OLDVERSION
)
1585 c
= flash3
[CTL_PEER_STATVAL(rstatus
) & 0x7];
1587 c
= flash2
[CTL_PEER_STATVAL(rstatus
) & 0x3];
1589 (void) fprintf(fp
, "%-*s ", maxhostlen
, currenthost
);
1590 if (af
== 0 || AF(&srcadr
) == af
) {
1591 strcpy(clock_name
, nntohost(&srcadr
));
1594 "%c%-15.15s %-15.15s %2ld %c %4.4s %4.4s %3lo %7.7s %8.7s %7.7s\n",
1595 c
, clock_name
, dstadr_refid
, stratum
, type
,
1596 prettyinterval(whenbuf
, when(&ts
, &rec
, &reftime
)),
1597 prettyinterval(pollbuf
, (int)poll_sec
), reach
,
1598 lfptoms(&estdelay
, 3), lfptoms(&estoffset
, 3),
1599 havevar
[HAVE_JITTER
] ? lfptoms(&estjitter
, 3) :
1600 lfptoms(&estdisp
, 3));
1613 #undef HAVE_ESTDELAY
1614 #undef HAVE_ESTOFFSET
1625 * dogetpeers - given an association ID, read and print the spreadsheet
1630 struct varlist
*pvl
,
1642 res
= doquerylist(pvl
, CTL_OP_READVAR
, associd
, 0, &rstatus
,
1648 res
= doquery(CTL_OP_READVAR
, associd
, 0, 0, (char *)0, &rstatus
,
1657 (void) fprintf(stderr
, "server=%s ", currenthost
);
1658 (void) fprintf(stderr
,
1659 "***No information returned for association %d\n",
1664 return doprintpeers(pvl
, associd
, (int)rstatus
, dsize
, datap
, fp
, af
);
1669 * peers - print a peer spreadsheet
1679 char fullname
[LENHOSTNAME
];
1682 if (!dogetassoc(fp
))
1685 for (i
= 0; i
< numhosts
; ++i
) {
1686 if (getnetnum(chosts
[i
], &netnum
, fullname
, af
))
1687 if ((int)strlen(fullname
) > maxhostlen
)
1688 maxhostlen
= strlen(fullname
);
1691 (void) fprintf(fp
, "%-*.*s ", maxhostlen
, maxhostlen
, "server");
1693 " remote refid st t when poll reach delay offset jitter\n");
1695 for (i
= 0; i
<= maxhostlen
; ++i
)
1696 (void) fprintf(fp
, "=");
1698 "==============================================================================\n");
1700 for (i
= 0; i
< numassoc
; i
++) {
1702 !(CTL_PEER_STATVAL(assoc_cache
[i
].status
)
1703 & (CTL_PST_CONFIG
|CTL_PST_REACH
)))
1705 if (!dogetpeers(peervarlist
, (int)assoc_cache
[i
].assid
, fp
, af
)) {
1714 * peers - print a peer spreadsheet
1725 if (pcmd
->nargs
== 1) {
1726 if (pcmd
->argval
->ival
== 6)
1736 * lpeers - print a peer spreadsheet including all fuzzball peers
1747 if (pcmd
->nargs
== 1) {
1748 if (pcmd
->argval
->ival
== 6)
1758 * opeers - print a peer spreadsheet
1768 char fullname
[LENHOSTNAME
];
1771 if (!dogetassoc(fp
))
1774 for (i
= 0; i
< numhosts
; ++i
) {
1775 if (getnetnum(chosts
[i
], &netnum
, fullname
, af
))
1776 if ((int)strlen(fullname
) > maxhostlen
)
1777 maxhostlen
= strlen(fullname
);
1780 (void) fprintf(fp
, "%-*.*s ", maxhostlen
, maxhostlen
, "server");
1782 " remote local st t when poll reach delay offset disp\n");
1784 for (i
= 0; i
<= maxhostlen
; ++i
)
1785 (void) fprintf(fp
, "=");
1787 "==============================================================================\n");
1789 for (i
= 0; i
< numassoc
; i
++) {
1791 !(CTL_PEER_STATVAL(assoc_cache
[i
].status
)
1792 & (CTL_PST_CONFIG
|CTL_PST_REACH
)))
1794 if (!dogetpeers(opeervarlist
, (int)assoc_cache
[i
].assid
, fp
, af
)) {
1803 * opeers - print a peer spreadsheet the old way
1814 if (pcmd
->nargs
== 1) {
1815 if (pcmd
->argval
->ival
== 6)
1820 doopeers(0, fp
, af
);
1825 * lopeers - print a peer spreadsheet including all fuzzball peers
1836 if (pcmd
->nargs
== 1) {
1837 if (pcmd
->argval
->ival
== 6)
1842 doopeers(1, fp
, af
);
1847 * config - send a configuration command to a remote host
1863 cfgcmd
= pcmd
->argval
[0].string
;
1866 printf("In Config\n");
1867 printf("Keyword = %s\n", pcmd
->keyword
);
1868 printf("Command = %s\n", cfgcmd
);
1871 res
= doquery(CTL_OP_CONFIGURE
, 0, 1, strlen(cfgcmd
), cfgcmd
,
1872 &rstatus
, &rsize
, &rdata
);
1877 if (rsize
> 0 && '\n' == rdata
[rsize
- 1])
1879 rdata
[rsize
] = '\0';
1882 if (1 == sscanf(rdata
, "column %d syntax error", &col
)
1883 && col
>= 0 && (size_t)col
<= strlen(cfgcmd
) + 1) {
1885 printf("______"); /* "ntpq> " */
1886 printf("________"); /* ":config " */
1888 printf("%s\n", cfgcmd
);
1889 for (i
= 1; i
< col
; i
++)
1893 printf("%s\n", rdata
);
1898 * config_from_file - remotely configure an ntpd daemon using the
1899 * specified configuration file
1900 * SK: This function is a kludge at best and is full of bad design
1902 * 1. ntpq uses UDP, which means that there is no guarantee of in-order,
1903 * error-free delivery.
1904 * 2. The maximum length of a packet is constrained, and as a result, the
1905 * maximum length of a line in a configuration file is constrained.
1906 * Longer lines will lead to unpredictable results.
1907 * 3. Since this function is sending a line at a time, we can't update
1908 * the control key through the configuration file (YUCK!!)
1921 char config_cmd
[MAXLINE
];
1927 printf("In Config\n");
1928 printf("Keyword = %s\n", pcmd
->keyword
);
1929 printf("Filename = %s\n", pcmd
->argval
[0].string
);
1932 config_fd
= fopen(pcmd
->argval
[0].string
, "r");
1933 if (NULL
== config_fd
) {
1934 printf("ERROR!! Couldn't open file: %s\n",
1935 pcmd
->argval
[0].string
);
1939 printf("Sending configuration file, one line at a time.\n");
1941 while (fgets(config_cmd
, MAXLINE
, config_fd
) != NULL
) {
1942 config_len
= strlen(config_cmd
);
1943 /* ensure even the last line has newline, if possible */
1944 if (config_len
> 0 &&
1945 config_len
+ 2 < sizeof(config_cmd
) &&
1946 '\n' != config_cmd
[config_len
- 1])
1947 config_cmd
[config_len
++] = '\n';
1951 res
= doquery(CTL_OP_CONFIGURE
, 0, 1,
1952 strlen(config_cmd
), config_cmd
,
1953 &rstatus
, &rsize
, &rdata
);
1954 while (res
!= 0 && retry_limit
--);
1956 printf("Line No: %d query failed: %s", i
,
1958 printf("Subsequent lines not sent.\n");
1963 if (rsize
> 0 && '\n' == rdata
[rsize
- 1])
1965 if (rsize
> 0 && '\r' == rdata
[rsize
- 1])
1967 rdata
[rsize
] = '\0';
1968 printf("Line No: %d %s: %s", i
, rdata
, config_cmd
);
1970 printf("Done sending file\n");