ntpq.c revision 1.5 1 1.5 kardel /* $NetBSD: ntpq.c,v 1.5 2012/02/01 20:48:01 kardel Exp $ */
2 1.1 kardel
3 1.1 kardel /*
4 1.1 kardel * ntpq - query an NTP server using mode 6 commands
5 1.1 kardel */
6 1.1 kardel
7 1.1 kardel #include <stdio.h>
8 1.1 kardel
9 1.1 kardel #include <ctype.h>
10 1.1 kardel #include <signal.h>
11 1.1 kardel #include <setjmp.h>
12 1.1 kardel #include <sys/types.h>
13 1.1 kardel #include <sys/time.h>
14 1.1 kardel
15 1.1 kardel #include "ntpq.h"
16 1.1 kardel #include "ntp_unixtime.h"
17 1.1 kardel #include "ntp_calendar.h"
18 1.1 kardel #include "ntp_io.h"
19 1.1 kardel #include "ntp_select.h"
20 1.1 kardel #include "ntp_stdlib.h"
21 1.1 kardel #include "ntp_assert.h"
22 1.1 kardel #include "ntp_lineedit.h"
23 1.1 kardel #include "ntp_debug.h"
24 1.1 kardel #include "isc/net.h"
25 1.1 kardel #include "isc/result.h"
26 1.1 kardel #include <ssl_applink.c>
27 1.1 kardel
28 1.4 kardel #include "ntp_libopts.h"
29 1.1 kardel #include "ntpq-opts.h"
30 1.1 kardel
31 1.1 kardel #ifdef SYS_WINNT
32 1.1 kardel # include <Mswsock.h>
33 1.1 kardel # include <io.h>
34 1.1 kardel #endif /* SYS_WINNT */
35 1.1 kardel
36 1.1 kardel #ifdef SYS_VXWORKS
37 1.1 kardel /* vxWorks needs mode flag -casey*/
38 1.1 kardel # define open(name, flags) open(name, flags, 0777)
39 1.1 kardel # define SERVER_PORT_NUM 123
40 1.1 kardel #endif
41 1.1 kardel
42 1.1 kardel /* we use COMMAND as an autogen keyword */
43 1.1 kardel #ifdef COMMAND
44 1.1 kardel # undef COMMAND
45 1.1 kardel #endif
46 1.1 kardel
47 1.1 kardel /*
48 1.1 kardel * Because we potentially understand a lot of commands we will run
49 1.1 kardel * interactive if connected to a terminal.
50 1.1 kardel */
51 1.1 kardel int interactive = 0; /* set to 1 when we should prompt */
52 1.1 kardel const char *prompt = "ntpq> "; /* prompt to ask him about */
53 1.1 kardel
54 1.1 kardel /*
55 1.1 kardel * use old readvars behavior? --old-rv processing in ntpq resets
56 1.1 kardel * this value based on the presence or absence of --old-rv. It is
57 1.1 kardel * initialized to 1 here to maintain backward compatibility with
58 1.1 kardel * libntpq clients such as ntpsnmpd, which are free to reset it as
59 1.1 kardel * desired.
60 1.1 kardel */
61 1.1 kardel int old_rv = 1;
62 1.1 kardel
63 1.1 kardel
64 1.1 kardel /*
65 1.1 kardel * for get_systime()
66 1.1 kardel */
67 1.1 kardel s_char sys_precision; /* local clock precision (log2 s) */
68 1.1 kardel
69 1.1 kardel /*
70 1.1 kardel * Keyid used for authenticated requests. Obtained on the fly.
71 1.1 kardel */
72 1.1 kardel u_long info_auth_keyid = 0;
73 1.1 kardel
74 1.1 kardel static int info_auth_keytype = NID_md5; /* MD5 */
75 1.1 kardel static size_t info_auth_hashlen = 16; /* MD5 */
76 1.1 kardel u_long current_time; /* needed by authkeys; not used */
77 1.1 kardel
78 1.1 kardel /*
79 1.1 kardel * Flag which indicates we should always send authenticated requests
80 1.1 kardel */
81 1.1 kardel int always_auth = 0;
82 1.1 kardel
83 1.1 kardel /*
84 1.1 kardel * Flag which indicates raw mode output.
85 1.1 kardel */
86 1.1 kardel int rawmode = 0;
87 1.1 kardel
88 1.1 kardel /*
89 1.1 kardel * Packet version number we use
90 1.1 kardel */
91 1.1 kardel u_char pktversion = NTP_OLDVERSION + 1;
92 1.1 kardel
93 1.1 kardel /*
94 1.1 kardel * Don't jump if no set jmp.
95 1.1 kardel */
96 1.1 kardel volatile int jump = 0;
97 1.1 kardel
98 1.1 kardel /*
99 1.1 kardel * Format values
100 1.1 kardel */
101 1.1 kardel #define PADDING 0
102 1.1 kardel #define TS 1 /* time stamp */
103 1.1 kardel #define FL 2 /* l_fp type value */
104 1.1 kardel #define FU 3 /* u_fp type value */
105 1.1 kardel #define FS 4 /* s_fp type value */
106 1.1 kardel #define UI 5 /* unsigned integer value */
107 1.1 kardel #define SI 6 /* signed integer value */
108 1.1 kardel #define HA 7 /* host address */
109 1.1 kardel #define NA 8 /* network address */
110 1.1 kardel #define ST 9 /* string value */
111 1.1 kardel #define RF 10 /* refid (sometimes string, sometimes not) */
112 1.1 kardel #define LP 11 /* leap (print in binary) */
113 1.1 kardel #define OC 12 /* integer, print in octal */
114 1.1 kardel #define MD 13 /* mode */
115 1.1 kardel #define AR 14 /* array of times */
116 1.1 kardel #define FX 15 /* test flags */
117 1.1 kardel #define EOV 255 /* end of table */
118 1.1 kardel
119 1.1 kardel
120 1.1 kardel /*
121 1.1 kardel * System variable values. The array can be indexed by
122 1.1 kardel * the variable index to find the textual name.
123 1.1 kardel */
124 1.1 kardel struct ctl_var sys_var[] = {
125 1.1 kardel { 0, PADDING, "" }, /* 0 */
126 1.1 kardel { CS_LEAP, LP, "leap" }, /* 1 */
127 1.1 kardel { CS_STRATUM, UI, "stratum" }, /* 2 */
128 1.1 kardel { CS_PRECISION, SI, "precision" }, /* 3 */
129 1.1 kardel { CS_ROOTDELAY, FS, "rootdelay" }, /* 4 */
130 1.1 kardel { CS_ROOTDISPERSION, FU, "rootdispersion" }, /* 5 */
131 1.1 kardel { CS_REFID, RF, "refid" }, /* 6 */
132 1.1 kardel { CS_REFTIME, TS, "reftime" }, /* 7 */
133 1.1 kardel { CS_POLL, UI, "poll" }, /* 8 */
134 1.1 kardel { CS_PEERID, UI, "peer" }, /* 9 */
135 1.1 kardel { CS_OFFSET, FL, "offset" }, /* 10 */
136 1.1 kardel { CS_DRIFT, FS, "frequency" }, /* 11 */
137 1.1 kardel { CS_JITTER, FU, "jitter" }, /* 12 */
138 1.1 kardel { CS_CLOCK, TS, "clock" }, /* 13 */
139 1.1 kardel { CS_PROCESSOR, ST, "processor" }, /* 14 */
140 1.1 kardel { CS_SYSTEM, ST, "system" }, /* 15 */
141 1.1 kardel { CS_VERSION, ST, "version" }, /* 16 */
142 1.1 kardel { CS_STABIL, FS, "stability" }, /* 17 */
143 1.1 kardel { CS_VARLIST, ST, "sys_var_list" }, /* 18 */
144 1.1 kardel { 0, EOV, "" }
145 1.1 kardel };
146 1.1 kardel
147 1.1 kardel
148 1.1 kardel /*
149 1.1 kardel * Peer variable list
150 1.1 kardel */
151 1.1 kardel struct ctl_var peer_var[] = {
152 1.1 kardel { 0, PADDING, "" }, /* 0 */
153 1.1 kardel { CP_CONFIG, UI, "config" }, /* 1 */
154 1.1 kardel { CP_AUTHENABLE, UI, "authenable" }, /* 2 */
155 1.1 kardel { CP_AUTHENTIC, UI, "authentic" }, /* 3 */
156 1.1 kardel { CP_SRCADR, HA, "srcadr" }, /* 4 */
157 1.1 kardel { CP_SRCPORT, UI, "srcport" }, /* 5 */
158 1.1 kardel { CP_DSTADR, NA, "dstadr" }, /* 6 */
159 1.1 kardel { CP_DSTPORT, UI, "dstport" }, /* 7 */
160 1.1 kardel { CP_LEAP, LP, "leap" }, /* 8 */
161 1.1 kardel { CP_HMODE, MD, "hmode" }, /* 9 */
162 1.1 kardel { CP_STRATUM, UI, "stratum" }, /* 10 */
163 1.1 kardel { CP_PPOLL, UI, "ppoll" }, /* 11 */
164 1.1 kardel { CP_HPOLL, UI, "hpoll" }, /* 12 */
165 1.1 kardel { CP_PRECISION, SI, "precision" }, /* 13 */
166 1.1 kardel { CP_ROOTDELAY, FS, "rootdelay" }, /* 14 */
167 1.1 kardel { CP_ROOTDISPERSION, FU, "rootdisp" }, /* 15 */
168 1.1 kardel { CP_REFID, RF, "refid" }, /* 16 */
169 1.1 kardel { CP_REFTIME, TS, "reftime" }, /* 17 */
170 1.1 kardel { CP_ORG, TS, "org" }, /* 18 */
171 1.1 kardel { CP_REC, TS, "rec" }, /* 19 */
172 1.1 kardel { CP_XMT, TS, "xmt" }, /* 20 */
173 1.1 kardel { CP_REACH, OC, "reach" }, /* 21 */
174 1.1 kardel { CP_UNREACH, UI, "unreach" }, /* 22 */
175 1.1 kardel { CP_TIMER, UI, "timer" }, /* 23 */
176 1.1 kardel { CP_DELAY, FS, "delay" }, /* 24 */
177 1.1 kardel { CP_OFFSET, FL, "offset" }, /* 25 */
178 1.1 kardel { CP_JITTER, FU, "jitter" }, /* 26 */
179 1.1 kardel { CP_DISPERSION, FU, "dispersion" }, /* 27 */
180 1.1 kardel { CP_KEYID, UI, "keyid" }, /* 28 */
181 1.1 kardel { CP_FILTDELAY, AR, "filtdelay" }, /* 29 */
182 1.1 kardel { CP_FILTOFFSET, AR, "filtoffset" }, /* 30 */
183 1.1 kardel { CP_PMODE, ST, "pmode" }, /* 31 */
184 1.1 kardel { CP_RECEIVED, UI, "received" }, /* 32 */
185 1.1 kardel { CP_SENT, UI, "sent" }, /* 33 */
186 1.1 kardel { CP_FILTERROR, AR, "filtdisp" }, /* 34 */
187 1.1 kardel { CP_FLASH, FX, "flash" }, /* 35 */
188 1.1 kardel { CP_TTL, UI, "ttl" }, /* 36 */
189 1.1 kardel /*
190 1.1 kardel * These are duplicate entries so that we can
191 1.1 kardel * process deviant version of the ntp protocol.
192 1.1 kardel */
193 1.1 kardel { CP_SRCADR, HA, "peeraddr" }, /* 4 */
194 1.1 kardel { CP_SRCPORT, UI, "peerport" }, /* 5 */
195 1.1 kardel { CP_PPOLL, UI, "peerpoll" }, /* 11 */
196 1.1 kardel { CP_HPOLL, UI, "hostpoll" }, /* 12 */
197 1.1 kardel { CP_FILTERROR, AR, "filterror" }, /* 34 */
198 1.1 kardel { 0, EOV, "" }
199 1.1 kardel };
200 1.1 kardel
201 1.1 kardel
202 1.1 kardel /*
203 1.1 kardel * Clock variable list
204 1.1 kardel */
205 1.1 kardel struct ctl_var clock_var[] = {
206 1.1 kardel { 0, PADDING, "" }, /* 0 */
207 1.1 kardel { CC_TYPE, UI, "type" }, /* 1 */
208 1.1 kardel { CC_TIMECODE, ST, "timecode" }, /* 2 */
209 1.1 kardel { CC_POLL, UI, "poll" }, /* 3 */
210 1.1 kardel { CC_NOREPLY, UI, "noreply" }, /* 4 */
211 1.1 kardel { CC_BADFORMAT, UI, "badformat" }, /* 5 */
212 1.1 kardel { CC_BADDATA, UI, "baddata" }, /* 6 */
213 1.1 kardel { CC_FUDGETIME1, FL, "fudgetime1" }, /* 7 */
214 1.1 kardel { CC_FUDGETIME2, FL, "fudgetime2" }, /* 8 */
215 1.1 kardel { CC_FUDGEVAL1, UI, "stratum" }, /* 9 */
216 1.1 kardel { CC_FUDGEVAL2, RF, "refid" }, /* 10 */
217 1.1 kardel { CC_FLAGS, UI, "flags" }, /* 11 */
218 1.1 kardel { CC_DEVICE, ST, "device" }, /* 12 */
219 1.1 kardel { 0, EOV, "" }
220 1.1 kardel };
221 1.1 kardel
222 1.1 kardel
223 1.1 kardel /*
224 1.1 kardel * flasher bits
225 1.1 kardel */
226 1.1 kardel static const char *tstflagnames[] = {
227 1.1 kardel "pkt_dup", /* TEST1 */
228 1.1 kardel "pkt_bogus", /* TEST2 */
229 1.1 kardel "pkt_unsync", /* TEST3 */
230 1.1 kardel "pkt_denied", /* TEST4 */
231 1.1 kardel "pkt_auth", /* TEST5 */
232 1.1 kardel "pkt_stratum", /* TEST6 */
233 1.1 kardel "pkt_header", /* TEST7 */
234 1.1 kardel "pkt_autokey", /* TEST8 */
235 1.1 kardel "pkt_crypto", /* TEST9 */
236 1.1 kardel "peer_stratum", /* TEST10 */
237 1.1 kardel "peer_dist", /* TEST11 */
238 1.1 kardel "peer_loop", /* TEST12 */
239 1.1 kardel "peer_unreach" /* TEST13 */
240 1.1 kardel };
241 1.1 kardel
242 1.1 kardel
243 1.1 kardel int ntpqmain (int, char **);
244 1.1 kardel /*
245 1.1 kardel * Built in command handler declarations
246 1.1 kardel */
247 1.1 kardel static int openhost (const char *);
248 1.1 kardel
249 1.1 kardel static int sendpkt (void *, size_t);
250 1.4 kardel static int getresponse (int, int, u_short *, int *, const char **, int);
251 1.1 kardel static int sendrequest (int, int, int, int, char *);
252 1.1 kardel static char * tstflags (u_long);
253 1.1 kardel #ifndef BUILD_AS_LIB
254 1.1 kardel static void getcmds (void);
255 1.1 kardel #ifndef SYS_WINNT
256 1.1 kardel static RETSIGTYPE abortcmd (int);
257 1.1 kardel #endif /* SYS_WINNT */
258 1.1 kardel static void docmd (const char *);
259 1.1 kardel static void tokenize (const char *, char **, int *);
260 1.1 kardel static int getarg (char *, int, arg_v *);
261 1.1 kardel #endif /* BUILD_AS_LIB */
262 1.1 kardel static int findcmd (char *, struct xcmd *, struct xcmd *, struct xcmd **);
263 1.1 kardel static int rtdatetolfp (char *, l_fp *);
264 1.1 kardel static int decodearr (char *, int *, l_fp *);
265 1.1 kardel static void help (struct parse *, FILE *);
266 1.1 kardel static int helpsort (const void *, const void *);
267 1.1 kardel static void printusage (struct xcmd *, FILE *);
268 1.1 kardel static void timeout (struct parse *, FILE *);
269 1.1 kardel static void auth_delay (struct parse *, FILE *);
270 1.1 kardel static void host (struct parse *, FILE *);
271 1.1 kardel static void ntp_poll (struct parse *, FILE *);
272 1.1 kardel static void keyid (struct parse *, FILE *);
273 1.1 kardel static void keytype (struct parse *, FILE *);
274 1.1 kardel static void passwd (struct parse *, FILE *);
275 1.1 kardel static void hostnames (struct parse *, FILE *);
276 1.1 kardel static void setdebug (struct parse *, FILE *);
277 1.1 kardel static void quit (struct parse *, FILE *);
278 1.1 kardel static void version (struct parse *, FILE *);
279 1.1 kardel static void raw (struct parse *, FILE *);
280 1.1 kardel static void cooked (struct parse *, FILE *);
281 1.1 kardel static void authenticate (struct parse *, FILE *);
282 1.1 kardel static void ntpversion (struct parse *, FILE *);
283 1.3 christos static void warning (const char *, ...)
284 1.3 christos __attribute__((__format__(__printf__, 1, 2)));
285 1.3 christos static void error (const char *, ...)
286 1.3 christos __attribute__((__format__(__printf__, 1, 2)));
287 1.1 kardel static u_long getkeyid (const char *);
288 1.1 kardel static void atoascii (const char *, size_t, char *, size_t);
289 1.4 kardel static void cookedprint (int, int, const char *, int, int, FILE *);
290 1.4 kardel static void rawprint (int, int, const char *, int, int, FILE *);
291 1.1 kardel static void startoutput (void);
292 1.4 kardel static void output (FILE *, char *, const char *);
293 1.1 kardel static void endoutput (FILE *);
294 1.1 kardel static void outputarr (FILE *, char *, int, l_fp *);
295 1.1 kardel static int assoccmp (const void *, const void *);
296 1.1 kardel void ntpq_custom_opt_handler (tOptions *, tOptDesc *);
297 1.1 kardel
298 1.1 kardel
299 1.1 kardel /*
300 1.1 kardel * Built-in commands we understand
301 1.1 kardel */
302 1.1 kardel struct xcmd builtins[] = {
303 1.1 kardel { "?", help, { OPT|NTP_STR, NO, NO, NO },
304 1.1 kardel { "command", "", "", "" },
305 1.1 kardel "tell the use and syntax of commands" },
306 1.1 kardel { "help", help, { OPT|NTP_STR, NO, NO, NO },
307 1.1 kardel { "command", "", "", "" },
308 1.1 kardel "tell the use and syntax of commands" },
309 1.1 kardel { "timeout", timeout, { OPT|NTP_UINT, NO, NO, NO },
310 1.1 kardel { "msec", "", "", "" },
311 1.1 kardel "set the primary receive time out" },
312 1.1 kardel { "delay", auth_delay, { OPT|NTP_INT, NO, NO, NO },
313 1.1 kardel { "msec", "", "", "" },
314 1.1 kardel "set the delay added to encryption time stamps" },
315 1.1 kardel { "host", host, { OPT|NTP_STR, OPT|NTP_STR, NO, NO },
316 1.1 kardel { "-4|-6", "hostname", "", "" },
317 1.1 kardel "specify the host whose NTP server we talk to" },
318 1.1 kardel { "poll", ntp_poll, { OPT|NTP_UINT, OPT|NTP_STR, NO, NO },
319 1.1 kardel { "n", "verbose", "", "" },
320 1.1 kardel "poll an NTP server in client mode `n' times" },
321 1.1 kardel { "passwd", passwd, { NO, NO, NO, NO },
322 1.1 kardel { "", "", "", "" },
323 1.1 kardel "specify a password to use for authenticated requests"},
324 1.1 kardel { "hostnames", hostnames, { OPT|NTP_STR, NO, NO, NO },
325 1.1 kardel { "yes|no", "", "", "" },
326 1.1 kardel "specify whether hostnames or net numbers are printed"},
327 1.1 kardel { "debug", setdebug, { OPT|NTP_STR, NO, NO, NO },
328 1.1 kardel { "no|more|less", "", "", "" },
329 1.1 kardel "set/change debugging level" },
330 1.1 kardel { "quit", quit, { NO, NO, NO, NO },
331 1.1 kardel { "", "", "", "" },
332 1.1 kardel "exit ntpq" },
333 1.1 kardel { "exit", quit, { NO, NO, NO, NO },
334 1.1 kardel { "", "", "", "" },
335 1.1 kardel "exit ntpq" },
336 1.1 kardel { "keyid", keyid, { OPT|NTP_UINT, NO, NO, NO },
337 1.1 kardel { "key#", "", "", "" },
338 1.1 kardel "set keyid to use for authenticated requests" },
339 1.1 kardel { "version", version, { NO, NO, NO, NO },
340 1.1 kardel { "", "", "", "" },
341 1.1 kardel "print version number" },
342 1.1 kardel { "raw", raw, { NO, NO, NO, NO },
343 1.1 kardel { "", "", "", "" },
344 1.1 kardel "do raw mode variable output" },
345 1.1 kardel { "cooked", cooked, { NO, NO, NO, NO },
346 1.1 kardel { "", "", "", "" },
347 1.1 kardel "do cooked mode variable output" },
348 1.1 kardel { "authenticate", authenticate, { OPT|NTP_STR, NO, NO, NO },
349 1.1 kardel { "yes|no", "", "", "" },
350 1.1 kardel "always authenticate requests to this server" },
351 1.1 kardel { "ntpversion", ntpversion, { OPT|NTP_UINT, NO, NO, NO },
352 1.1 kardel { "version number", "", "", "" },
353 1.1 kardel "set the NTP version number to use for requests" },
354 1.1 kardel { "keytype", keytype, { OPT|NTP_STR, NO, NO, NO },
355 1.1 kardel { "key type (md5|des)", "", "", "" },
356 1.1 kardel "set key type to use for authenticated requests (des|md5)" },
357 1.1 kardel { 0, 0, { NO, NO, NO, NO },
358 1.1 kardel { "", "", "", "" }, "" }
359 1.1 kardel };
360 1.1 kardel
361 1.1 kardel
362 1.1 kardel /*
363 1.1 kardel * Default values we use.
364 1.1 kardel */
365 1.1 kardel #define DEFHOST "localhost" /* default host name */
366 1.1 kardel #define DEFTIMEOUT (5) /* 5 second time out */
367 1.1 kardel #define DEFSTIMEOUT (2) /* 2 second time out after first */
368 1.1 kardel #define DEFDELAY 0x51EB852 /* 20 milliseconds, l_fp fraction */
369 1.1 kardel #define LENHOSTNAME 256 /* host name is 256 characters long */
370 1.1 kardel #define MAXCMDS 100 /* maximum commands on cmd line */
371 1.1 kardel #define MAXHOSTS 200 /* maximum hosts on cmd line */
372 1.1 kardel #define MAXLINE 512 /* maximum line length */
373 1.1 kardel #define MAXTOKENS (1+MAXARGS+2) /* maximum number of usable tokens */
374 1.1 kardel #define MAXVARLEN 256 /* maximum length of a variable name */
375 1.1 kardel #define MAXVALLEN 400 /* maximum length of a variable value */
376 1.1 kardel #define MAXOUTLINE 72 /* maximum length of an output line */
377 1.1 kardel #define SCREENWIDTH 76 /* nominal screen width in columns */
378 1.1 kardel
379 1.1 kardel /*
380 1.1 kardel * Some variables used and manipulated locally
381 1.1 kardel */
382 1.1 kardel struct sock_timeval tvout = { DEFTIMEOUT, 0 }; /* time out for reads */
383 1.1 kardel struct sock_timeval tvsout = { DEFSTIMEOUT, 0 };/* secondary time out */
384 1.1 kardel l_fp delay_time; /* delay time */
385 1.1 kardel char currenthost[LENHOSTNAME]; /* current host name */
386 1.4 kardel int currenthostisnum; /* is prior text from IP? */
387 1.5 kardel struct sockaddr_in hostaddr; /* host address */
388 1.1 kardel int showhostnames = 1; /* show host names by default */
389 1.1 kardel
390 1.1 kardel int ai_fam_templ; /* address family */
391 1.1 kardel int ai_fam_default; /* default address family */
392 1.1 kardel SOCKET sockfd; /* fd socket is opened on */
393 1.1 kardel int havehost = 0; /* set to 1 when host open */
394 1.1 kardel int s_port = 0;
395 1.1 kardel struct servent *server_entry = NULL; /* server entry for ntp */
396 1.1 kardel
397 1.1 kardel
398 1.1 kardel /*
399 1.1 kardel * Sequence number used for requests. It is incremented before
400 1.1 kardel * it is used.
401 1.1 kardel */
402 1.1 kardel u_short sequence;
403 1.1 kardel
404 1.1 kardel /*
405 1.1 kardel * Holds data returned from queries. Declare buffer long to be sure of
406 1.1 kardel * alignment.
407 1.1 kardel */
408 1.1 kardel #define MAXFRAGS 24 /* maximum number of fragments */
409 1.1 kardel #define DATASIZE (MAXFRAGS*480) /* maximum amount of data */
410 1.1 kardel long pktdata[DATASIZE/sizeof(long)];
411 1.1 kardel
412 1.1 kardel /*
413 1.1 kardel * Holds association data for use with the &n operator.
414 1.1 kardel */
415 1.1 kardel struct association assoc_cache[MAXASSOC];
416 1.1 kardel int numassoc = 0; /* number of cached associations */
417 1.1 kardel
418 1.1 kardel /*
419 1.1 kardel * For commands typed on the command line (with the -c option)
420 1.1 kardel */
421 1.1 kardel int numcmds = 0;
422 1.1 kardel const char *ccmds[MAXCMDS];
423 1.1 kardel #define ADDCMD(cp) if (numcmds < MAXCMDS) ccmds[numcmds++] = (cp)
424 1.1 kardel
425 1.1 kardel /*
426 1.1 kardel * When multiple hosts are specified.
427 1.1 kardel */
428 1.1 kardel int numhosts = 0;
429 1.1 kardel const char *chosts[MAXHOSTS];
430 1.1 kardel #define ADDHOST(cp) if (numhosts < MAXHOSTS) chosts[numhosts++] = (cp)
431 1.1 kardel
432 1.1 kardel /*
433 1.1 kardel * Error codes for internal use
434 1.1 kardel */
435 1.1 kardel #define ERR_UNSPEC 256
436 1.1 kardel #define ERR_INCOMPLETE 257
437 1.1 kardel #define ERR_TIMEOUT 258
438 1.1 kardel #define ERR_TOOMUCH 259
439 1.1 kardel
440 1.1 kardel /*
441 1.1 kardel * Macro definitions we use
442 1.1 kardel */
443 1.1 kardel #define ISSPACE(c) ((c) == ' ' || (c) == '\t')
444 1.1 kardel #define ISEOL(c) ((c) == '\n' || (c) == '\r' || (c) == '\0')
445 1.1 kardel #define STREQ(a, b) (*(a) == *(b) && strcmp((a), (b)) == 0)
446 1.1 kardel
447 1.1 kardel /*
448 1.1 kardel * Jump buffer for longjumping back to the command level
449 1.1 kardel */
450 1.1 kardel jmp_buf interrupt_buf;
451 1.1 kardel
452 1.1 kardel /*
453 1.1 kardel * Points at file being currently printed into
454 1.1 kardel */
455 1.1 kardel FILE *current_output;
456 1.1 kardel
457 1.1 kardel /*
458 1.1 kardel * Command table imported from ntpdc_ops.c
459 1.1 kardel */
460 1.1 kardel extern struct xcmd opcmds[];
461 1.1 kardel
462 1.1 kardel char *progname;
463 1.1 kardel volatile int debug;
464 1.1 kardel
465 1.1 kardel #ifdef NO_MAIN_ALLOWED
466 1.1 kardel #ifndef BUILD_AS_LIB
467 1.1 kardel CALL(ntpq,"ntpq",ntpqmain);
468 1.1 kardel
469 1.1 kardel void clear_globals(void)
470 1.1 kardel {
471 1.1 kardel extern int ntp_optind;
472 1.1 kardel showhostnames = 0; /* don'tshow host names by default */
473 1.1 kardel ntp_optind = 0;
474 1.1 kardel server_entry = NULL; /* server entry for ntp */
475 1.1 kardel havehost = 0; /* set to 1 when host open */
476 1.1 kardel numassoc = 0; /* number of cached associations */
477 1.1 kardel numcmds = 0;
478 1.1 kardel numhosts = 0;
479 1.1 kardel }
480 1.1 kardel #endif /* !BUILD_AS_LIB */
481 1.1 kardel #endif /* NO_MAIN_ALLOWED */
482 1.1 kardel
483 1.1 kardel /*
484 1.1 kardel * main - parse arguments and handle options
485 1.1 kardel */
486 1.1 kardel #ifndef NO_MAIN_ALLOWED
487 1.1 kardel int
488 1.1 kardel main(
489 1.1 kardel int argc,
490 1.1 kardel char *argv[]
491 1.1 kardel )
492 1.1 kardel {
493 1.1 kardel return ntpqmain(argc, argv);
494 1.1 kardel }
495 1.1 kardel #endif
496 1.1 kardel
497 1.1 kardel #ifndef BUILD_AS_LIB
498 1.1 kardel int
499 1.1 kardel ntpqmain(
500 1.1 kardel int argc,
501 1.1 kardel char *argv[]
502 1.1 kardel )
503 1.1 kardel {
504 1.1 kardel extern int ntp_optind;
505 1.1 kardel
506 1.1 kardel #ifdef SYS_VXWORKS
507 1.1 kardel clear_globals();
508 1.1 kardel taskPrioritySet(taskIdSelf(), 100 );
509 1.1 kardel #endif
510 1.1 kardel
511 1.1 kardel delay_time.l_ui = 0;
512 1.1 kardel delay_time.l_uf = DEFDELAY;
513 1.1 kardel
514 1.1 kardel init_lib(); /* sets up ipv4_works, ipv6_works */
515 1.1 kardel ssl_applink();
516 1.1 kardel
517 1.1 kardel /* Check to see if we have IPv6. Otherwise default to IPv4 */
518 1.1 kardel if (!ipv6_works)
519 1.1 kardel ai_fam_default = AF_INET;
520 1.1 kardel
521 1.1 kardel progname = argv[0];
522 1.1 kardel
523 1.1 kardel {
524 1.4 kardel int optct = ntpOptionProcess(&ntpqOptions, argc, argv);
525 1.1 kardel argc -= optct;
526 1.1 kardel argv += optct;
527 1.1 kardel }
528 1.1 kardel
529 1.1 kardel /*
530 1.1 kardel * Process options other than -c and -p, which are specially
531 1.1 kardel * handled by ntpq_custom_opt_handler().
532 1.1 kardel */
533 1.1 kardel
534 1.1 kardel debug = DESC(DEBUG_LEVEL).optOccCt;
535 1.1 kardel
536 1.1 kardel if (HAVE_OPT(IPV4))
537 1.1 kardel ai_fam_templ = AF_INET;
538 1.1 kardel else if (HAVE_OPT(IPV6))
539 1.1 kardel ai_fam_templ = AF_INET6;
540 1.1 kardel else
541 1.1 kardel ai_fam_templ = ai_fam_default;
542 1.1 kardel
543 1.1 kardel if (HAVE_OPT(INTERACTIVE))
544 1.1 kardel interactive = 1;
545 1.1 kardel
546 1.1 kardel if (HAVE_OPT(NUMERIC))
547 1.1 kardel showhostnames = 0;
548 1.1 kardel
549 1.1 kardel old_rv = HAVE_OPT(OLD_RV);
550 1.1 kardel
551 1.1 kardel #if 0
552 1.1 kardel while ((c = ntp_getopt(argc, argv, "46c:dinp")) != EOF)
553 1.1 kardel switch (c) {
554 1.1 kardel case '4':
555 1.1 kardel ai_fam_templ = AF_INET;
556 1.1 kardel break;
557 1.1 kardel case '6':
558 1.1 kardel ai_fam_templ = AF_INET6;
559 1.1 kardel break;
560 1.1 kardel case 'c':
561 1.1 kardel ADDCMD(ntp_optarg);
562 1.1 kardel break;
563 1.1 kardel case 'd':
564 1.1 kardel ++debug;
565 1.1 kardel break;
566 1.1 kardel case 'i':
567 1.1 kardel interactive = 1;
568 1.1 kardel break;
569 1.1 kardel case 'n':
570 1.1 kardel showhostnames = 0;
571 1.1 kardel break;
572 1.1 kardel case 'p':
573 1.1 kardel ADDCMD("peers");
574 1.1 kardel break;
575 1.1 kardel default:
576 1.1 kardel errflg++;
577 1.1 kardel break;
578 1.1 kardel }
579 1.1 kardel if (errflg) {
580 1.1 kardel (void) fprintf(stderr,
581 1.1 kardel "usage: %s [-46dinp] [-c cmd] host ...\n",
582 1.1 kardel progname);
583 1.1 kardel exit(2);
584 1.1 kardel }
585 1.1 kardel #endif
586 1.1 kardel NTP_INSIST(ntp_optind <= argc);
587 1.1 kardel if (ntp_optind == argc) {
588 1.1 kardel ADDHOST(DEFHOST);
589 1.1 kardel } else {
590 1.1 kardel for (; ntp_optind < argc; ntp_optind++)
591 1.1 kardel ADDHOST(argv[ntp_optind]);
592 1.1 kardel }
593 1.1 kardel
594 1.1 kardel if (numcmds == 0 && interactive == 0
595 1.1 kardel && isatty(fileno(stdin)) && isatty(fileno(stderr))) {
596 1.1 kardel interactive = 1;
597 1.1 kardel }
598 1.1 kardel
599 1.1 kardel #ifndef SYS_WINNT /* Under NT cannot handle SIGINT, WIN32 spawns a handler */
600 1.1 kardel if (interactive)
601 1.1 kardel (void) signal_no_reset(SIGINT, abortcmd);
602 1.1 kardel #endif /* SYS_WINNT */
603 1.1 kardel
604 1.1 kardel if (numcmds == 0) {
605 1.1 kardel (void) openhost(chosts[0]);
606 1.1 kardel getcmds();
607 1.1 kardel } else {
608 1.1 kardel int ihost;
609 1.1 kardel int icmd;
610 1.1 kardel
611 1.1 kardel for (ihost = 0; ihost < numhosts; ihost++) {
612 1.1 kardel if (openhost(chosts[ihost]))
613 1.1 kardel for (icmd = 0; icmd < numcmds; icmd++)
614 1.1 kardel docmd(ccmds[icmd]);
615 1.1 kardel }
616 1.1 kardel }
617 1.1 kardel #ifdef SYS_WINNT
618 1.1 kardel WSACleanup();
619 1.1 kardel #endif /* SYS_WINNT */
620 1.1 kardel return 0;
621 1.1 kardel }
622 1.1 kardel #endif /* !BUILD_AS_LIB */
623 1.1 kardel
624 1.1 kardel /*
625 1.1 kardel * openhost - open a socket to a host
626 1.1 kardel */
627 1.1 kardel static int
628 1.1 kardel openhost(
629 1.1 kardel const char *hname
630 1.1 kardel )
631 1.1 kardel {
632 1.1 kardel char temphost[LENHOSTNAME];
633 1.1 kardel int a_info, i;
634 1.1 kardel struct addrinfo hints, *ai = NULL;
635 1.1 kardel register const char *cp;
636 1.1 kardel char name[LENHOSTNAME];
637 1.1 kardel char service[5];
638 1.1 kardel
639 1.1 kardel /*
640 1.1 kardel * We need to get by the [] if they were entered
641 1.1 kardel */
642 1.1 kardel
643 1.1 kardel cp = hname;
644 1.1 kardel
645 1.1 kardel if (*cp == '[') {
646 1.1 kardel cp++;
647 1.1 kardel for (i = 0; *cp && *cp != ']'; cp++, i++)
648 1.1 kardel name[i] = *cp;
649 1.1 kardel if (*cp == ']') {
650 1.1 kardel name[i] = '\0';
651 1.1 kardel hname = name;
652 1.1 kardel } else {
653 1.1 kardel return 0;
654 1.1 kardel }
655 1.1 kardel }
656 1.1 kardel
657 1.1 kardel /*
658 1.1 kardel * First try to resolve it as an ip address and if that fails,
659 1.1 kardel * do a fullblown (dns) lookup. That way we only use the dns
660 1.1 kardel * when it is needed and work around some implementations that
661 1.1 kardel * will return an "IPv4-mapped IPv6 address" address if you
662 1.1 kardel * give it an IPv4 address to lookup.
663 1.1 kardel */
664 1.1 kardel strcpy(service, "ntp");
665 1.4 kardel ZERO(hints);
666 1.1 kardel hints.ai_family = ai_fam_templ;
667 1.1 kardel hints.ai_protocol = IPPROTO_UDP;
668 1.1 kardel hints.ai_socktype = SOCK_DGRAM;
669 1.4 kardel hints.ai_flags = Z_AI_NUMERICHOST;
670 1.1 kardel
671 1.1 kardel a_info = getaddrinfo(hname, service, &hints, &ai);
672 1.1 kardel if (a_info == EAI_NONAME
673 1.1 kardel #ifdef EAI_NODATA
674 1.1 kardel || a_info == EAI_NODATA
675 1.1 kardel #endif
676 1.1 kardel ) {
677 1.1 kardel hints.ai_flags = AI_CANONNAME;
678 1.1 kardel #ifdef AI_ADDRCONFIG
679 1.1 kardel hints.ai_flags |= AI_ADDRCONFIG;
680 1.1 kardel #endif
681 1.1 kardel a_info = getaddrinfo(hname, service, &hints, &ai);
682 1.1 kardel }
683 1.1 kardel #ifdef AI_ADDRCONFIG
684 1.1 kardel /* Some older implementations don't like AI_ADDRCONFIG. */
685 1.1 kardel if (a_info == EAI_BADFLAGS) {
686 1.1 kardel hints.ai_flags = AI_CANONNAME;
687 1.1 kardel a_info = getaddrinfo(hname, service, &hints, &ai);
688 1.1 kardel }
689 1.1 kardel #endif
690 1.1 kardel if (a_info != 0) {
691 1.1 kardel (void) fprintf(stderr, "%s\n", gai_strerror(a_info));
692 1.1 kardel return 0;
693 1.1 kardel }
694 1.1 kardel
695 1.4 kardel if (!showhostnames || ai->ai_canonname == NULL) {
696 1.1 kardel strncpy(temphost,
697 1.1 kardel stoa((sockaddr_u *)ai->ai_addr),
698 1.1 kardel LENHOSTNAME);
699 1.4 kardel currenthostisnum = TRUE;
700 1.1 kardel } else {
701 1.1 kardel strncpy(temphost, ai->ai_canonname, LENHOSTNAME);
702 1.4 kardel currenthostisnum = FALSE;
703 1.1 kardel }
704 1.1 kardel temphost[LENHOSTNAME-1] = '\0';
705 1.1 kardel
706 1.1 kardel if (debug > 2)
707 1.1 kardel printf("Opening host %s\n", temphost);
708 1.1 kardel
709 1.1 kardel if (havehost == 1) {
710 1.1 kardel if (debug > 2)
711 1.1 kardel printf("Closing old host %s\n", currenthost);
712 1.1 kardel (void) closesocket(sockfd);
713 1.1 kardel havehost = 0;
714 1.1 kardel }
715 1.1 kardel (void) strcpy(currenthost, temphost);
716 1.1 kardel
717 1.1 kardel /* port maps to the same location in both families */
718 1.1 kardel s_port = ((struct sockaddr_in6 *)ai->ai_addr)->sin6_port;
719 1.1 kardel #ifdef SYS_VXWORKS
720 1.1 kardel ((struct sockaddr_in6 *)&hostaddr)->sin6_port = htons(SERVER_PORT_NUM);
721 1.1 kardel if (ai->ai_family == AF_INET)
722 1.1 kardel *(struct sockaddr_in *)&hostaddr=
723 1.1 kardel *((struct sockaddr_in *)ai->ai_addr);
724 1.1 kardel else
725 1.1 kardel *(struct sockaddr_in6 *)&hostaddr=
726 1.1 kardel *((struct sockaddr_in6 *)ai->ai_addr);
727 1.1 kardel #endif /* SYS_VXWORKS */
728 1.1 kardel
729 1.1 kardel #ifdef SYS_WINNT
730 1.1 kardel {
731 1.1 kardel int optionValue = SO_SYNCHRONOUS_NONALERT;
732 1.1 kardel int err;
733 1.1 kardel
734 1.1 kardel err = setsockopt(INVALID_SOCKET, SOL_SOCKET, SO_OPENTYPE,
735 1.1 kardel (char *)&optionValue, sizeof(optionValue));
736 1.1 kardel if (err) {
737 1.1 kardel err = WSAGetLastError();
738 1.1 kardel fprintf(stderr,
739 1.1 kardel "setsockopt(SO_SYNCHRONOUS_NONALERT) "
740 1.1 kardel "error: %s\n", strerror(err));
741 1.1 kardel exit(1);
742 1.1 kardel }
743 1.1 kardel }
744 1.1 kardel #endif /* SYS_WINNT */
745 1.1 kardel
746 1.1 kardel sockfd = socket(ai->ai_family, SOCK_DGRAM, 0);
747 1.1 kardel if (sockfd == INVALID_SOCKET) {
748 1.3 christos error("socket");
749 1.1 kardel }
750 1.1 kardel
751 1.1 kardel
752 1.1 kardel #ifdef NEED_RCVBUF_SLOP
753 1.1 kardel # ifdef SO_RCVBUF
754 1.1 kardel { int rbufsize = DATASIZE + 2048; /* 2K for slop */
755 1.1 kardel if (setsockopt(sockfd, SOL_SOCKET, SO_RCVBUF,
756 1.1 kardel &rbufsize, sizeof(int)) == -1)
757 1.3 christos error("setsockopt");
758 1.1 kardel }
759 1.1 kardel # endif
760 1.1 kardel #endif
761 1.1 kardel
762 1.1 kardel #ifdef SYS_VXWORKS
763 1.1 kardel if (connect(sockfd, (struct sockaddr *)&hostaddr,
764 1.1 kardel sizeof(hostaddr)) == -1)
765 1.1 kardel #else
766 1.1 kardel if (connect(sockfd, (struct sockaddr *)ai->ai_addr,
767 1.1 kardel ai->ai_addrlen) == -1)
768 1.1 kardel #endif /* SYS_VXWORKS */
769 1.3 christos error("connect");
770 1.1 kardel if (a_info == 0)
771 1.1 kardel freeaddrinfo(ai);
772 1.1 kardel havehost = 1;
773 1.1 kardel return 1;
774 1.1 kardel }
775 1.1 kardel
776 1.1 kardel
777 1.1 kardel /* XXX ELIMINATE sendpkt similar in ntpq.c, ntpdc.c, ntp_io.c, ntptrace.c */
778 1.1 kardel /*
779 1.1 kardel * sendpkt - send a packet to the remote host
780 1.1 kardel */
781 1.1 kardel static int
782 1.1 kardel sendpkt(
783 1.1 kardel void * xdata,
784 1.1 kardel size_t xdatalen
785 1.1 kardel )
786 1.1 kardel {
787 1.1 kardel if (debug >= 3)
788 1.2 christos printf("Sending %zu octets\n", xdatalen);
789 1.1 kardel
790 1.1 kardel if (send(sockfd, xdata, (size_t)xdatalen, 0) == -1) {
791 1.3 christos warning("write to %s failed", currenthost);
792 1.1 kardel return -1;
793 1.1 kardel }
794 1.1 kardel
795 1.1 kardel if (debug >= 4) {
796 1.1 kardel int first = 8;
797 1.1 kardel char *cdata = xdata;
798 1.1 kardel
799 1.1 kardel printf("Packet data:\n");
800 1.1 kardel while (xdatalen-- > 0) {
801 1.1 kardel if (first-- == 0) {
802 1.1 kardel printf("\n");
803 1.1 kardel first = 7;
804 1.1 kardel }
805 1.1 kardel printf(" %02x", *cdata++ & 0xff);
806 1.1 kardel }
807 1.1 kardel printf("\n");
808 1.1 kardel }
809 1.1 kardel return 0;
810 1.1 kardel }
811 1.1 kardel
812 1.1 kardel
813 1.1 kardel
814 1.1 kardel /*
815 1.1 kardel * getresponse - get a (series of) response packet(s) and return the data
816 1.1 kardel */
817 1.1 kardel static int
818 1.1 kardel getresponse(
819 1.1 kardel int opcode,
820 1.1 kardel int associd,
821 1.1 kardel u_short *rstatus,
822 1.1 kardel int *rsize,
823 1.4 kardel const char **rdata,
824 1.1 kardel int timeo
825 1.1 kardel )
826 1.1 kardel {
827 1.1 kardel struct ntp_control rpkt;
828 1.1 kardel struct sock_timeval tvo;
829 1.1 kardel u_short offsets[MAXFRAGS+1];
830 1.1 kardel u_short counts[MAXFRAGS+1];
831 1.1 kardel u_short offset;
832 1.1 kardel u_short count;
833 1.4 kardel size_t numfrags;
834 1.4 kardel size_t f;
835 1.4 kardel size_t ff;
836 1.1 kardel int seenlastfrag;
837 1.1 kardel int shouldbesize;
838 1.1 kardel fd_set fds;
839 1.1 kardel int n;
840 1.4 kardel int len;
841 1.4 kardel int first;
842 1.4 kardel char *data;
843 1.1 kardel
844 1.1 kardel /*
845 1.1 kardel * This is pretty tricky. We may get between 1 and MAXFRAG packets
846 1.1 kardel * back in response to the request. We peel the data out of
847 1.1 kardel * each packet and collect it in one long block. When the last
848 1.1 kardel * packet in the sequence is received we'll know how much data we
849 1.1 kardel * should have had. Note we use one long time out, should reconsider.
850 1.1 kardel */
851 1.1 kardel *rsize = 0;
852 1.1 kardel if (rstatus)
853 1.4 kardel *rstatus = 0;
854 1.1 kardel *rdata = (char *)pktdata;
855 1.1 kardel
856 1.1 kardel numfrags = 0;
857 1.1 kardel seenlastfrag = 0;
858 1.1 kardel
859 1.1 kardel FD_ZERO(&fds);
860 1.1 kardel
861 1.1 kardel /*
862 1.1 kardel * Loop until we have an error or a complete response. Nearly all
863 1.4 kardel * code paths to loop again use continue.
864 1.1 kardel */
865 1.1 kardel for (;;) {
866 1.1 kardel
867 1.1 kardel if (numfrags == 0)
868 1.4 kardel tvo = tvout;
869 1.1 kardel else
870 1.4 kardel tvo = tvsout;
871 1.1 kardel
872 1.1 kardel FD_SET(sockfd, &fds);
873 1.4 kardel n = select(sockfd + 1, &fds, NULL, NULL, &tvo);
874 1.1 kardel
875 1.1 kardel if (n == -1) {
876 1.3 christos warning("select fails");
877 1.1 kardel return -1;
878 1.1 kardel }
879 1.1 kardel if (n == 0) {
880 1.1 kardel /*
881 1.1 kardel * Timed out. Return what we have
882 1.1 kardel */
883 1.1 kardel if (numfrags == 0) {
884 1.1 kardel if (timeo)
885 1.4 kardel fprintf(stderr,
886 1.4 kardel "%s: timed out, nothing received\n",
887 1.4 kardel currenthost);
888 1.1 kardel return ERR_TIMEOUT;
889 1.1 kardel }
890 1.4 kardel if (timeo)
891 1.4 kardel fprintf(stderr,
892 1.4 kardel "%s: timed out with incomplete data\n",
893 1.4 kardel currenthost);
894 1.4 kardel if (debug) {
895 1.4 kardel fprintf(stderr,
896 1.4 kardel "ERR_INCOMPLETE: Received fragments:\n");
897 1.4 kardel for (f = 0; f < numfrags; f++)
898 1.4 kardel fprintf(stderr,
899 1.5 kardel "%2zu: %5d %5d\t%3d octets\n",
900 1.4 kardel f, offsets[f],
901 1.4 kardel offsets[f] +
902 1.4 kardel counts[f],
903 1.4 kardel counts[f]);
904 1.4 kardel fprintf(stderr,
905 1.4 kardel "last fragment %sreceived\n",
906 1.4 kardel (seenlastfrag)
907 1.4 kardel ? ""
908 1.4 kardel : "not ");
909 1.4 kardel }
910 1.4 kardel return ERR_INCOMPLETE;
911 1.1 kardel }
912 1.1 kardel
913 1.1 kardel n = recv(sockfd, (char *)&rpkt, sizeof(rpkt), 0);
914 1.1 kardel if (n == -1) {
915 1.3 christos warning("read");
916 1.1 kardel return -1;
917 1.1 kardel }
918 1.1 kardel
919 1.1 kardel if (debug >= 4) {
920 1.4 kardel len = n;
921 1.4 kardel first = 8;
922 1.4 kardel data = (char *)&rpkt;
923 1.1 kardel
924 1.1 kardel printf("Packet data:\n");
925 1.1 kardel while (len-- > 0) {
926 1.1 kardel if (first-- == 0) {
927 1.1 kardel printf("\n");
928 1.1 kardel first = 7;
929 1.1 kardel }
930 1.1 kardel printf(" %02x", *data++ & 0xff);
931 1.1 kardel }
932 1.1 kardel printf("\n");
933 1.1 kardel }
934 1.1 kardel
935 1.1 kardel /*
936 1.1 kardel * Check for format errors. Bug proofing.
937 1.1 kardel */
938 1.5 kardel if (n < (int)CTL_HEADER_LEN) {
939 1.1 kardel if (debug)
940 1.4 kardel printf("Short (%d byte) packet received\n", n);
941 1.1 kardel continue;
942 1.1 kardel }
943 1.1 kardel if (PKT_VERSION(rpkt.li_vn_mode) > NTP_VERSION
944 1.1 kardel || PKT_VERSION(rpkt.li_vn_mode) < NTP_OLDVERSION) {
945 1.1 kardel if (debug)
946 1.4 kardel printf("Packet received with version %d\n",
947 1.4 kardel PKT_VERSION(rpkt.li_vn_mode));
948 1.1 kardel continue;
949 1.1 kardel }
950 1.1 kardel if (PKT_MODE(rpkt.li_vn_mode) != MODE_CONTROL) {
951 1.1 kardel if (debug)
952 1.4 kardel printf("Packet received with mode %d\n",
953 1.4 kardel PKT_MODE(rpkt.li_vn_mode));
954 1.1 kardel continue;
955 1.1 kardel }
956 1.1 kardel if (!CTL_ISRESPONSE(rpkt.r_m_e_op)) {
957 1.1 kardel if (debug)
958 1.4 kardel printf("Received request packet, wanted response\n");
959 1.1 kardel continue;
960 1.1 kardel }
961 1.1 kardel
962 1.1 kardel /*
963 1.1 kardel * Check opcode and sequence number for a match.
964 1.1 kardel * Could be old data getting to us.
965 1.1 kardel */
966 1.1 kardel if (ntohs(rpkt.sequence) != sequence) {
967 1.1 kardel if (debug)
968 1.4 kardel printf("Received sequnce number %d, wanted %d\n",
969 1.4 kardel ntohs(rpkt.sequence), sequence);
970 1.1 kardel continue;
971 1.1 kardel }
972 1.1 kardel if (CTL_OP(rpkt.r_m_e_op) != opcode) {
973 1.1 kardel if (debug)
974 1.1 kardel printf(
975 1.1 kardel "Received opcode %d, wanted %d (sequence number okay)\n",
976 1.1 kardel CTL_OP(rpkt.r_m_e_op), opcode);
977 1.1 kardel continue;
978 1.1 kardel }
979 1.1 kardel
980 1.1 kardel /*
981 1.1 kardel * Check the error code. If non-zero, return it.
982 1.1 kardel */
983 1.1 kardel if (CTL_ISERROR(rpkt.r_m_e_op)) {
984 1.1 kardel int errcode;
985 1.1 kardel
986 1.1 kardel errcode = (ntohs(rpkt.status) >> 8) & 0xff;
987 1.1 kardel if (debug && CTL_ISMORE(rpkt.r_m_e_op)) {
988 1.1 kardel printf("Error code %d received on not-final packet\n",
989 1.1 kardel errcode);
990 1.1 kardel }
991 1.1 kardel if (errcode == CERR_UNSPEC)
992 1.1 kardel return ERR_UNSPEC;
993 1.1 kardel return errcode;
994 1.1 kardel }
995 1.1 kardel
996 1.1 kardel /*
997 1.1 kardel * Check the association ID to make sure it matches what
998 1.1 kardel * we sent.
999 1.1 kardel */
1000 1.1 kardel if (ntohs(rpkt.associd) != associd) {
1001 1.1 kardel if (debug)
1002 1.1 kardel printf("Association ID %d doesn't match expected %d\n",
1003 1.1 kardel ntohs(rpkt.associd), associd);
1004 1.1 kardel /*
1005 1.1 kardel * Hack for silly fuzzballs which, at the time of writing,
1006 1.1 kardel * return an assID of sys.peer when queried for system variables.
1007 1.1 kardel */
1008 1.1 kardel #ifdef notdef
1009 1.1 kardel continue;
1010 1.1 kardel #endif
1011 1.1 kardel }
1012 1.1 kardel
1013 1.1 kardel /*
1014 1.1 kardel * Collect offset and count. Make sure they make sense.
1015 1.1 kardel */
1016 1.1 kardel offset = ntohs(rpkt.offset);
1017 1.1 kardel count = ntohs(rpkt.count);
1018 1.1 kardel
1019 1.1 kardel /*
1020 1.1 kardel * validate received payload size is padded to next 32-bit
1021 1.1 kardel * boundary and no smaller than claimed by rpkt.count
1022 1.1 kardel */
1023 1.1 kardel if (n & 0x3) {
1024 1.1 kardel if (debug)
1025 1.1 kardel printf("Response packet not padded, "
1026 1.1 kardel "size = %d\n", n);
1027 1.1 kardel continue;
1028 1.1 kardel }
1029 1.1 kardel
1030 1.1 kardel shouldbesize = (CTL_HEADER_LEN + count + 3) & ~3;
1031 1.1 kardel
1032 1.1 kardel if (n < shouldbesize) {
1033 1.1 kardel printf("Response packet claims %u octets "
1034 1.5 kardel "payload, above %ld received\n",
1035 1.1 kardel count,
1036 1.1 kardel n - CTL_HEADER_LEN
1037 1.1 kardel );
1038 1.1 kardel return ERR_INCOMPLETE;
1039 1.1 kardel }
1040 1.1 kardel
1041 1.1 kardel if (debug >= 3 && shouldbesize > n) {
1042 1.1 kardel u_int32 key;
1043 1.1 kardel u_int32 *lpkt;
1044 1.1 kardel int maclen;
1045 1.1 kardel
1046 1.1 kardel /*
1047 1.1 kardel * Usually we ignore authentication, but for debugging purposes
1048 1.1 kardel * we watch it here.
1049 1.1 kardel */
1050 1.1 kardel /* round to 8 octet boundary */
1051 1.1 kardel shouldbesize = (shouldbesize + 7) & ~7;
1052 1.1 kardel
1053 1.1 kardel maclen = n - shouldbesize;
1054 1.2 christos if (maclen >= (int)MIN_MAC_LEN) {
1055 1.1 kardel printf(
1056 1.1 kardel "Packet shows signs of authentication (total %d, data %d, mac %d)\n",
1057 1.1 kardel n, shouldbesize, maclen);
1058 1.1 kardel lpkt = (u_int32 *)&rpkt;
1059 1.1 kardel printf("%08lx %08lx %08lx %08lx %08lx %08lx\n",
1060 1.1 kardel (u_long)ntohl(lpkt[(n - maclen)/sizeof(u_int32) - 3]),
1061 1.1 kardel (u_long)ntohl(lpkt[(n - maclen)/sizeof(u_int32) - 2]),
1062 1.1 kardel (u_long)ntohl(lpkt[(n - maclen)/sizeof(u_int32) - 1]),
1063 1.1 kardel (u_long)ntohl(lpkt[(n - maclen)/sizeof(u_int32)]),
1064 1.1 kardel (u_long)ntohl(lpkt[(n - maclen)/sizeof(u_int32) + 1]),
1065 1.1 kardel (u_long)ntohl(lpkt[(n - maclen)/sizeof(u_int32) + 2]));
1066 1.1 kardel key = ntohl(lpkt[(n - maclen) / sizeof(u_int32)]);
1067 1.1 kardel printf("Authenticated with keyid %lu\n", (u_long)key);
1068 1.1 kardel if (key != 0 && key != info_auth_keyid) {
1069 1.1 kardel printf("We don't know that key\n");
1070 1.1 kardel } else {
1071 1.1 kardel if (authdecrypt(key, (u_int32 *)&rpkt,
1072 1.1 kardel n - maclen, maclen)) {
1073 1.1 kardel printf("Auth okay!\n");
1074 1.1 kardel } else {
1075 1.1 kardel printf("Auth failed!\n");
1076 1.1 kardel }
1077 1.1 kardel }
1078 1.1 kardel }
1079 1.1 kardel }
1080 1.1 kardel
1081 1.1 kardel if (debug >= 2)
1082 1.4 kardel printf("Got packet, size = %d\n", n);
1083 1.1 kardel if ((int)count > (n - CTL_HEADER_LEN)) {
1084 1.1 kardel if (debug)
1085 1.1 kardel printf("Received count of %d octets, "
1086 1.5 kardel "data in packet is %lu\n",
1087 1.1 kardel count, n-CTL_HEADER_LEN);
1088 1.1 kardel continue;
1089 1.1 kardel }
1090 1.1 kardel if (count == 0 && CTL_ISMORE(rpkt.r_m_e_op)) {
1091 1.1 kardel if (debug)
1092 1.4 kardel printf("Received count of 0 in non-final fragment\n");
1093 1.1 kardel continue;
1094 1.1 kardel }
1095 1.1 kardel if (offset + count > sizeof(pktdata)) {
1096 1.1 kardel if (debug)
1097 1.4 kardel printf("Offset %d, count %d, too big for buffer\n",
1098 1.4 kardel offset, count);
1099 1.1 kardel return ERR_TOOMUCH;
1100 1.1 kardel }
1101 1.1 kardel if (seenlastfrag && !CTL_ISMORE(rpkt.r_m_e_op)) {
1102 1.1 kardel if (debug)
1103 1.4 kardel printf("Received second last fragment packet\n");
1104 1.1 kardel continue;
1105 1.1 kardel }
1106 1.1 kardel
1107 1.1 kardel /*
1108 1.1 kardel * So far, so good. Record this fragment, making sure it doesn't
1109 1.1 kardel * overlap anything.
1110 1.1 kardel */
1111 1.1 kardel if (debug >= 2)
1112 1.4 kardel printf("Packet okay\n");;
1113 1.1 kardel
1114 1.1 kardel if (numfrags > (MAXFRAGS - 1)) {
1115 1.1 kardel if (debug)
1116 1.4 kardel printf("Number of fragments exceeds maximum %d\n",
1117 1.4 kardel MAXFRAGS - 1);
1118 1.1 kardel return ERR_TOOMUCH;
1119 1.1 kardel }
1120 1.1 kardel
1121 1.1 kardel /*
1122 1.1 kardel * Find the position for the fragment relative to any
1123 1.1 kardel * previously received.
1124 1.1 kardel */
1125 1.4 kardel for (f = 0;
1126 1.4 kardel f < numfrags && offsets[f] < offset;
1127 1.4 kardel f++) {
1128 1.1 kardel /* empty body */ ;
1129 1.1 kardel }
1130 1.1 kardel
1131 1.4 kardel if (f < numfrags && offset == offsets[f]) {
1132 1.1 kardel if (debug)
1133 1.4 kardel printf("duplicate %u octets at %u ignored, prior %u at %u\n",
1134 1.4 kardel count, offset, counts[f],
1135 1.4 kardel offsets[f]);
1136 1.1 kardel continue;
1137 1.1 kardel }
1138 1.1 kardel
1139 1.4 kardel if (f > 0 && (offsets[f-1] + counts[f-1]) > offset) {
1140 1.1 kardel if (debug)
1141 1.4 kardel printf("received frag at %u overlaps with %u octet frag at %u\n",
1142 1.4 kardel offset, counts[f-1],
1143 1.4 kardel offsets[f-1]);
1144 1.1 kardel continue;
1145 1.1 kardel }
1146 1.1 kardel
1147 1.4 kardel if (f < numfrags && (offset + count) > offsets[f]) {
1148 1.1 kardel if (debug)
1149 1.4 kardel printf("received %u octet frag at %u overlaps with frag at %u\n",
1150 1.4 kardel count, offset, offsets[f]);
1151 1.1 kardel continue;
1152 1.1 kardel }
1153 1.1 kardel
1154 1.4 kardel for (ff = numfrags; ff > f; ff--) {
1155 1.4 kardel offsets[ff] = offsets[ff-1];
1156 1.4 kardel counts[ff] = counts[ff-1];
1157 1.1 kardel }
1158 1.4 kardel offsets[f] = offset;
1159 1.4 kardel counts[f] = count;
1160 1.1 kardel numfrags++;
1161 1.1 kardel
1162 1.1 kardel /*
1163 1.1 kardel * Got that stuffed in right. Figure out if this was the last.
1164 1.1 kardel * Record status info out of the last packet.
1165 1.1 kardel */
1166 1.1 kardel if (!CTL_ISMORE(rpkt.r_m_e_op)) {
1167 1.1 kardel seenlastfrag = 1;
1168 1.1 kardel if (rstatus != 0)
1169 1.4 kardel *rstatus = ntohs(rpkt.status);
1170 1.1 kardel }
1171 1.1 kardel
1172 1.1 kardel /*
1173 1.1 kardel * Copy the data into the data buffer.
1174 1.1 kardel */
1175 1.4 kardel memcpy((char *)pktdata + offset, rpkt.data, count);
1176 1.1 kardel
1177 1.1 kardel /*
1178 1.1 kardel * If we've seen the last fragment, look for holes in the sequence.
1179 1.1 kardel * If there aren't any, we're done.
1180 1.1 kardel */
1181 1.1 kardel if (seenlastfrag && offsets[0] == 0) {
1182 1.4 kardel for (f = 1; f < numfrags; f++)
1183 1.4 kardel if (offsets[f-1] + counts[f-1] !=
1184 1.4 kardel offsets[f])
1185 1.1 kardel break;
1186 1.4 kardel if (f == numfrags) {
1187 1.4 kardel *rsize = offsets[f-1] + counts[f-1];
1188 1.4 kardel if (debug)
1189 1.4 kardel fprintf(stderr,
1190 1.5 kardel "%zu packets reassembled into response\n",
1191 1.4 kardel numfrags);
1192 1.1 kardel return 0;
1193 1.1 kardel }
1194 1.1 kardel }
1195 1.1 kardel } /* giant for (;;) collecting response packets */
1196 1.1 kardel } /* getresponse() */
1197 1.1 kardel
1198 1.1 kardel
1199 1.1 kardel /*
1200 1.1 kardel * sendrequest - format and send a request packet
1201 1.1 kardel */
1202 1.1 kardel static int
1203 1.1 kardel sendrequest(
1204 1.1 kardel int opcode,
1205 1.1 kardel int associd,
1206 1.1 kardel int auth,
1207 1.1 kardel int qsize,
1208 1.1 kardel char *qdata
1209 1.1 kardel )
1210 1.1 kardel {
1211 1.1 kardel struct ntp_control qpkt;
1212 1.1 kardel int pktsize;
1213 1.1 kardel u_long key_id;
1214 1.1 kardel char * pass;
1215 1.1 kardel int maclen;
1216 1.1 kardel
1217 1.1 kardel /*
1218 1.1 kardel * Check to make sure the data will fit in one packet
1219 1.1 kardel */
1220 1.1 kardel if (qsize > CTL_MAX_DATA_LEN) {
1221 1.1 kardel fprintf(stderr,
1222 1.1 kardel "***Internal error! qsize (%d) too large\n",
1223 1.1 kardel qsize);
1224 1.1 kardel return 1;
1225 1.1 kardel }
1226 1.1 kardel
1227 1.1 kardel /*
1228 1.1 kardel * Fill in the packet
1229 1.1 kardel */
1230 1.1 kardel qpkt.li_vn_mode = PKT_LI_VN_MODE(0, pktversion, MODE_CONTROL);
1231 1.1 kardel qpkt.r_m_e_op = (u_char)(opcode & CTL_OP_MASK);
1232 1.1 kardel qpkt.sequence = htons(sequence);
1233 1.1 kardel qpkt.status = 0;
1234 1.1 kardel qpkt.associd = htons((u_short)associd);
1235 1.1 kardel qpkt.offset = 0;
1236 1.1 kardel qpkt.count = htons((u_short)qsize);
1237 1.1 kardel
1238 1.1 kardel pktsize = CTL_HEADER_LEN;
1239 1.1 kardel
1240 1.1 kardel /*
1241 1.1 kardel * If we have data, copy and pad it out to a 32-bit boundary.
1242 1.1 kardel */
1243 1.1 kardel if (qsize > 0) {
1244 1.1 kardel memcpy(qpkt.data, qdata, (size_t)qsize);
1245 1.1 kardel pktsize += qsize;
1246 1.1 kardel while (pktsize & (sizeof(u_int32) - 1)) {
1247 1.1 kardel qpkt.data[qsize++] = 0;
1248 1.1 kardel pktsize++;
1249 1.1 kardel }
1250 1.1 kardel }
1251 1.1 kardel
1252 1.1 kardel /*
1253 1.1 kardel * If it isn't authenticated we can just send it. Otherwise
1254 1.1 kardel * we're going to have to think about it a little.
1255 1.1 kardel */
1256 1.1 kardel if (!auth && !always_auth) {
1257 1.1 kardel return sendpkt(&qpkt, pktsize);
1258 1.1 kardel }
1259 1.1 kardel
1260 1.1 kardel /*
1261 1.1 kardel * Pad out packet to a multiple of 8 octets to be sure
1262 1.1 kardel * receiver can handle it.
1263 1.1 kardel */
1264 1.1 kardel while (pktsize & 7) {
1265 1.1 kardel qpkt.data[qsize++] = 0;
1266 1.1 kardel pktsize++;
1267 1.1 kardel }
1268 1.1 kardel
1269 1.1 kardel /*
1270 1.1 kardel * Get the keyid and the password if we don't have one.
1271 1.1 kardel */
1272 1.1 kardel if (info_auth_keyid == 0) {
1273 1.1 kardel key_id = getkeyid("Keyid: ");
1274 1.1 kardel if (key_id == 0 || key_id > NTP_MAXKEY) {
1275 1.1 kardel fprintf(stderr,
1276 1.1 kardel "Invalid key identifier\n");
1277 1.1 kardel return 1;
1278 1.1 kardel }
1279 1.1 kardel info_auth_keyid = key_id;
1280 1.1 kardel }
1281 1.1 kardel if (!authistrusted(info_auth_keyid)) {
1282 1.4 kardel pass = getpass_keytype(info_auth_keytype);
1283 1.1 kardel if ('\0' == pass[0]) {
1284 1.1 kardel fprintf(stderr, "Invalid password\n");
1285 1.1 kardel return 1;
1286 1.1 kardel }
1287 1.1 kardel authusekey(info_auth_keyid, info_auth_keytype,
1288 1.1 kardel (u_char *)pass);
1289 1.1 kardel authtrust(info_auth_keyid, 1);
1290 1.1 kardel }
1291 1.1 kardel
1292 1.1 kardel /*
1293 1.1 kardel * Do the encryption.
1294 1.1 kardel */
1295 1.1 kardel maclen = authencrypt(info_auth_keyid, (void *)&qpkt, pktsize);
1296 1.1 kardel if (!maclen) {
1297 1.1 kardel fprintf(stderr, "Key not found\n");
1298 1.1 kardel return 1;
1299 1.1 kardel } else if ((size_t)maclen != (info_auth_hashlen + sizeof(keyid_t))) {
1300 1.1 kardel fprintf(stderr,
1301 1.2 christos "%d octet MAC, %zu expected with %zu octet digest\n",
1302 1.1 kardel maclen, (info_auth_hashlen + sizeof(keyid_t)),
1303 1.1 kardel info_auth_hashlen);
1304 1.1 kardel return 1;
1305 1.1 kardel }
1306 1.1 kardel
1307 1.1 kardel return sendpkt((char *)&qpkt, pktsize + maclen);
1308 1.1 kardel }
1309 1.1 kardel
1310 1.1 kardel
1311 1.1 kardel /*
1312 1.4 kardel * show_error_msg - display the error text for a mode 6 error response.
1313 1.4 kardel */
1314 1.4 kardel void
1315 1.4 kardel show_error_msg(
1316 1.4 kardel int m6resp,
1317 1.4 kardel associd_t associd
1318 1.4 kardel )
1319 1.4 kardel {
1320 1.4 kardel if (numhosts > 1)
1321 1.4 kardel fprintf(stderr, "server=%s ", currenthost);
1322 1.4 kardel
1323 1.4 kardel switch(m6resp) {
1324 1.4 kardel
1325 1.4 kardel case CERR_BADFMT:
1326 1.4 kardel fprintf(stderr,
1327 1.4 kardel "***Server reports a bad format request packet\n");
1328 1.4 kardel break;
1329 1.4 kardel
1330 1.4 kardel case CERR_PERMISSION:
1331 1.4 kardel fprintf(stderr,
1332 1.4 kardel "***Server disallowed request (authentication?)\n");
1333 1.4 kardel break;
1334 1.4 kardel
1335 1.4 kardel case CERR_BADOP:
1336 1.4 kardel fprintf(stderr,
1337 1.4 kardel "***Server reports a bad opcode in request\n");
1338 1.4 kardel break;
1339 1.4 kardel
1340 1.4 kardel case CERR_BADASSOC:
1341 1.4 kardel fprintf(stderr,
1342 1.4 kardel "***Association ID %d unknown to server\n",
1343 1.4 kardel associd);
1344 1.4 kardel break;
1345 1.4 kardel
1346 1.4 kardel case CERR_UNKNOWNVAR:
1347 1.4 kardel fprintf(stderr,
1348 1.4 kardel "***A request variable unknown to the server\n");
1349 1.4 kardel break;
1350 1.4 kardel
1351 1.4 kardel case CERR_BADVALUE:
1352 1.4 kardel fprintf(stderr,
1353 1.4 kardel "***Server indicates a request variable was bad\n");
1354 1.4 kardel break;
1355 1.4 kardel
1356 1.4 kardel case ERR_UNSPEC:
1357 1.4 kardel fprintf(stderr,
1358 1.4 kardel "***Server returned an unspecified error\n");
1359 1.4 kardel break;
1360 1.4 kardel
1361 1.4 kardel case ERR_TIMEOUT:
1362 1.4 kardel fprintf(stderr, "***Request timed out\n");
1363 1.4 kardel break;
1364 1.4 kardel
1365 1.4 kardel case ERR_INCOMPLETE:
1366 1.4 kardel fprintf(stderr,
1367 1.4 kardel "***Response from server was incomplete\n");
1368 1.4 kardel break;
1369 1.4 kardel
1370 1.4 kardel case ERR_TOOMUCH:
1371 1.4 kardel fprintf(stderr,
1372 1.4 kardel "***Buffer size exceeded for returned data\n");
1373 1.4 kardel break;
1374 1.4 kardel
1375 1.4 kardel default:
1376 1.4 kardel fprintf(stderr,
1377 1.4 kardel "***Server returns unknown error code %d\n",
1378 1.4 kardel m6resp);
1379 1.4 kardel }
1380 1.4 kardel }
1381 1.4 kardel
1382 1.4 kardel /*
1383 1.4 kardel * doquery - send a request and process the response, displaying
1384 1.4 kardel * error messages for any error responses.
1385 1.1 kardel */
1386 1.1 kardel int
1387 1.1 kardel doquery(
1388 1.1 kardel int opcode,
1389 1.4 kardel associd_t associd,
1390 1.4 kardel int auth,
1391 1.4 kardel int qsize,
1392 1.4 kardel char *qdata,
1393 1.4 kardel u_short *rstatus,
1394 1.4 kardel int *rsize,
1395 1.4 kardel const char **rdata
1396 1.4 kardel )
1397 1.4 kardel {
1398 1.4 kardel return doqueryex(opcode, associd, auth, qsize, qdata, rstatus,
1399 1.4 kardel rsize, rdata, FALSE);
1400 1.4 kardel }
1401 1.4 kardel
1402 1.4 kardel
1403 1.4 kardel /*
1404 1.4 kardel * doqueryex - send a request and process the response, optionally
1405 1.4 kardel * displaying error messages for any error responses.
1406 1.4 kardel */
1407 1.4 kardel int
1408 1.4 kardel doqueryex(
1409 1.4 kardel int opcode,
1410 1.4 kardel associd_t associd,
1411 1.1 kardel int auth,
1412 1.1 kardel int qsize,
1413 1.1 kardel char *qdata,
1414 1.1 kardel u_short *rstatus,
1415 1.1 kardel int *rsize,
1416 1.4 kardel const char **rdata,
1417 1.4 kardel int quiet
1418 1.1 kardel )
1419 1.1 kardel {
1420 1.1 kardel int res;
1421 1.1 kardel int done;
1422 1.1 kardel
1423 1.1 kardel /*
1424 1.1 kardel * Check to make sure host is open
1425 1.1 kardel */
1426 1.1 kardel if (!havehost) {
1427 1.4 kardel fprintf(stderr, "***No host open, use `host' command\n");
1428 1.1 kardel return -1;
1429 1.1 kardel }
1430 1.1 kardel
1431 1.1 kardel done = 0;
1432 1.1 kardel sequence++;
1433 1.1 kardel
1434 1.1 kardel again:
1435 1.1 kardel /*
1436 1.1 kardel * send a request
1437 1.1 kardel */
1438 1.1 kardel res = sendrequest(opcode, associd, auth, qsize, qdata);
1439 1.1 kardel if (res != 0)
1440 1.4 kardel return res;
1441 1.1 kardel
1442 1.1 kardel /*
1443 1.1 kardel * Get the response. If we got a standard error, print a message
1444 1.1 kardel */
1445 1.1 kardel res = getresponse(opcode, associd, rstatus, rsize, rdata, done);
1446 1.1 kardel
1447 1.1 kardel if (res > 0) {
1448 1.1 kardel if (!done && (res == ERR_TIMEOUT || res == ERR_INCOMPLETE)) {
1449 1.1 kardel if (res == ERR_INCOMPLETE) {
1450 1.1 kardel /*
1451 1.1 kardel * better bump the sequence so we don't
1452 1.1 kardel * get confused about differing fragments.
1453 1.1 kardel */
1454 1.1 kardel sequence++;
1455 1.1 kardel }
1456 1.1 kardel done = 1;
1457 1.1 kardel goto again;
1458 1.1 kardel }
1459 1.4 kardel if (!quiet)
1460 1.4 kardel show_error_msg(res, associd);
1461 1.4 kardel
1462 1.1 kardel }
1463 1.1 kardel return res;
1464 1.1 kardel }
1465 1.1 kardel
1466 1.1 kardel
1467 1.1 kardel #ifndef BUILD_AS_LIB
1468 1.1 kardel /*
1469 1.1 kardel * getcmds - read commands from the standard input and execute them
1470 1.1 kardel */
1471 1.1 kardel static void
1472 1.1 kardel getcmds(void)
1473 1.1 kardel {
1474 1.1 kardel char * line;
1475 1.1 kardel int count;
1476 1.1 kardel
1477 1.1 kardel ntp_readline_init(interactive ? prompt : NULL);
1478 1.1 kardel
1479 1.1 kardel for (;;) {
1480 1.1 kardel line = ntp_readline(&count);
1481 1.1 kardel if (NULL == line)
1482 1.1 kardel break;
1483 1.1 kardel docmd(line);
1484 1.1 kardel free(line);
1485 1.1 kardel }
1486 1.1 kardel
1487 1.1 kardel ntp_readline_uninit();
1488 1.1 kardel }
1489 1.1 kardel #endif /* !BUILD_AS_LIB */
1490 1.1 kardel
1491 1.1 kardel
1492 1.1 kardel #if !defined(SYS_WINNT) && !defined(BUILD_AS_LIB)
1493 1.1 kardel /*
1494 1.1 kardel * abortcmd - catch interrupts and abort the current command
1495 1.1 kardel */
1496 1.1 kardel static RETSIGTYPE
1497 1.1 kardel abortcmd(
1498 1.1 kardel int sig
1499 1.1 kardel )
1500 1.1 kardel {
1501 1.1 kardel if (current_output == stdout)
1502 1.1 kardel (void) fflush(stdout);
1503 1.1 kardel putc('\n', stderr);
1504 1.1 kardel (void) fflush(stderr);
1505 1.1 kardel if (jump) longjmp(interrupt_buf, 1);
1506 1.1 kardel }
1507 1.1 kardel #endif /* !SYS_WINNT && !BUILD_AS_LIB */
1508 1.1 kardel
1509 1.1 kardel
1510 1.1 kardel #ifndef BUILD_AS_LIB
1511 1.1 kardel /*
1512 1.1 kardel * docmd - decode the command line and execute a command
1513 1.1 kardel */
1514 1.1 kardel static void
1515 1.1 kardel docmd(
1516 1.1 kardel const char *cmdline
1517 1.1 kardel )
1518 1.1 kardel {
1519 1.1 kardel char *tokens[1+MAXARGS+2];
1520 1.1 kardel struct parse pcmd;
1521 1.1 kardel int ntok;
1522 1.1 kardel static int i;
1523 1.1 kardel struct xcmd *xcmd;
1524 1.1 kardel
1525 1.1 kardel /*
1526 1.1 kardel * Tokenize the command line. If nothing on it, return.
1527 1.1 kardel */
1528 1.1 kardel tokenize(cmdline, tokens, &ntok);
1529 1.1 kardel if (ntok == 0)
1530 1.1 kardel return;
1531 1.1 kardel
1532 1.1 kardel /*
1533 1.1 kardel * Find the appropriate command description.
1534 1.1 kardel */
1535 1.1 kardel i = findcmd(tokens[0], builtins, opcmds, &xcmd);
1536 1.1 kardel if (i == 0) {
1537 1.1 kardel (void) fprintf(stderr, "***Command `%s' unknown\n",
1538 1.1 kardel tokens[0]);
1539 1.1 kardel return;
1540 1.1 kardel } else if (i >= 2) {
1541 1.1 kardel (void) fprintf(stderr, "***Command `%s' ambiguous\n",
1542 1.1 kardel tokens[0]);
1543 1.1 kardel return;
1544 1.1 kardel }
1545 1.1 kardel
1546 1.1 kardel /*
1547 1.1 kardel * Save the keyword, then walk through the arguments, interpreting
1548 1.1 kardel * as we go.
1549 1.1 kardel */
1550 1.1 kardel pcmd.keyword = tokens[0];
1551 1.1 kardel pcmd.nargs = 0;
1552 1.1 kardel for (i = 0; i < MAXARGS && xcmd->arg[i] != NO; i++) {
1553 1.1 kardel if ((i+1) >= ntok) {
1554 1.1 kardel if (!(xcmd->arg[i] & OPT)) {
1555 1.1 kardel printusage(xcmd, stderr);
1556 1.1 kardel return;
1557 1.1 kardel }
1558 1.1 kardel break;
1559 1.1 kardel }
1560 1.1 kardel if ((xcmd->arg[i] & OPT) && (*tokens[i+1] == '>'))
1561 1.1 kardel break;
1562 1.1 kardel if (!getarg(tokens[i+1], (int)xcmd->arg[i], &pcmd.argval[i]))
1563 1.1 kardel return;
1564 1.1 kardel pcmd.nargs++;
1565 1.1 kardel }
1566 1.1 kardel
1567 1.1 kardel i++;
1568 1.1 kardel if (i < ntok && *tokens[i] == '>') {
1569 1.1 kardel char *fname;
1570 1.1 kardel
1571 1.1 kardel if (*(tokens[i]+1) != '\0')
1572 1.1 kardel fname = tokens[i]+1;
1573 1.1 kardel else if ((i+1) < ntok)
1574 1.1 kardel fname = tokens[i+1];
1575 1.1 kardel else {
1576 1.1 kardel (void) fprintf(stderr, "***No file for redirect\n");
1577 1.1 kardel return;
1578 1.1 kardel }
1579 1.1 kardel
1580 1.1 kardel current_output = fopen(fname, "w");
1581 1.1 kardel if (current_output == NULL) {
1582 1.1 kardel (void) fprintf(stderr, "***Error opening %s: ", fname);
1583 1.1 kardel perror("");
1584 1.1 kardel return;
1585 1.1 kardel }
1586 1.1 kardel i = 1; /* flag we need a close */
1587 1.1 kardel } else {
1588 1.1 kardel current_output = stdout;
1589 1.1 kardel i = 0; /* flag no close */
1590 1.1 kardel }
1591 1.1 kardel
1592 1.1 kardel if (interactive && setjmp(interrupt_buf)) {
1593 1.1 kardel jump = 0;
1594 1.1 kardel return;
1595 1.1 kardel } else {
1596 1.1 kardel jump++;
1597 1.1 kardel (xcmd->handler)(&pcmd, current_output);
1598 1.1 kardel jump = 0; /* HMS: 961106: was after fclose() */
1599 1.1 kardel if (i) (void) fclose(current_output);
1600 1.1 kardel }
1601 1.1 kardel }
1602 1.1 kardel
1603 1.1 kardel
1604 1.1 kardel /*
1605 1.1 kardel * tokenize - turn a command line into tokens
1606 1.1 kardel *
1607 1.1 kardel * SK: Modified to allow a quoted string
1608 1.1 kardel *
1609 1.1 kardel * HMS: If the first character of the first token is a ':' then (after
1610 1.1 kardel * eating inter-token whitespace) the 2nd token is the rest of the line.
1611 1.1 kardel */
1612 1.1 kardel
1613 1.1 kardel static void
1614 1.1 kardel tokenize(
1615 1.1 kardel const char *line,
1616 1.1 kardel char **tokens,
1617 1.1 kardel int *ntok
1618 1.1 kardel )
1619 1.1 kardel {
1620 1.1 kardel register const char *cp;
1621 1.1 kardel register char *sp;
1622 1.1 kardel static char tspace[MAXLINE];
1623 1.1 kardel
1624 1.1 kardel sp = tspace;
1625 1.1 kardel cp = line;
1626 1.1 kardel for (*ntok = 0; *ntok < MAXTOKENS; (*ntok)++) {
1627 1.1 kardel tokens[*ntok] = sp;
1628 1.1 kardel
1629 1.1 kardel /* Skip inter-token whitespace */
1630 1.1 kardel while (ISSPACE(*cp))
1631 1.1 kardel cp++;
1632 1.1 kardel
1633 1.1 kardel /* If we're at EOL we're done */
1634 1.1 kardel if (ISEOL(*cp))
1635 1.1 kardel break;
1636 1.1 kardel
1637 1.1 kardel /* If this is the 2nd token and the first token begins
1638 1.1 kardel * with a ':', then just grab to EOL.
1639 1.1 kardel */
1640 1.1 kardel
1641 1.1 kardel if (*ntok == 1 && tokens[0][0] == ':') {
1642 1.1 kardel do {
1643 1.1 kardel *sp++ = *cp++;
1644 1.1 kardel } while (!ISEOL(*cp));
1645 1.1 kardel }
1646 1.1 kardel
1647 1.1 kardel /* Check if this token begins with a double quote.
1648 1.1 kardel * If yes, continue reading till the next double quote
1649 1.1 kardel */
1650 1.1 kardel else if (*cp == '\"') {
1651 1.1 kardel ++cp;
1652 1.1 kardel do {
1653 1.1 kardel *sp++ = *cp++;
1654 1.1 kardel } while ((*cp != '\"') && !ISEOL(*cp));
1655 1.1 kardel /* HMS: a missing closing " should be an error */
1656 1.1 kardel }
1657 1.1 kardel else {
1658 1.1 kardel do {
1659 1.1 kardel *sp++ = *cp++;
1660 1.1 kardel } while ((*cp != '\"') && !ISSPACE(*cp) && !ISEOL(*cp));
1661 1.1 kardel /* HMS: Why check for a " in the previous line? */
1662 1.1 kardel }
1663 1.1 kardel
1664 1.1 kardel *sp++ = '\0';
1665 1.1 kardel }
1666 1.1 kardel }
1667 1.1 kardel
1668 1.1 kardel
1669 1.1 kardel /*
1670 1.1 kardel * getarg - interpret an argument token
1671 1.1 kardel */
1672 1.1 kardel static int
1673 1.1 kardel getarg(
1674 1.1 kardel char *str,
1675 1.1 kardel int code,
1676 1.1 kardel arg_v *argp
1677 1.1 kardel )
1678 1.1 kardel {
1679 1.1 kardel int isneg;
1680 1.1 kardel char *cp, *np;
1681 1.1 kardel static const char *digits = "0123456789";
1682 1.1 kardel
1683 1.1 kardel switch (code & ~OPT) {
1684 1.1 kardel case NTP_STR:
1685 1.1 kardel argp->string = str;
1686 1.1 kardel break;
1687 1.1 kardel case NTP_ADD:
1688 1.1 kardel if (!getnetnum(str, &(argp->netnum), (char *)0, 0)) {
1689 1.1 kardel return 0;
1690 1.1 kardel }
1691 1.1 kardel break;
1692 1.1 kardel case NTP_INT:
1693 1.1 kardel case NTP_UINT:
1694 1.1 kardel isneg = 0;
1695 1.1 kardel np = str;
1696 1.1 kardel if (*np == '&') {
1697 1.1 kardel np++;
1698 1.1 kardel isneg = atoi(np);
1699 1.1 kardel if (isneg <= 0) {
1700 1.1 kardel (void) fprintf(stderr,
1701 1.1 kardel "***Association value `%s' invalid/undecodable\n", str);
1702 1.1 kardel return 0;
1703 1.1 kardel }
1704 1.1 kardel if (isneg > numassoc) {
1705 1.1 kardel if (numassoc == 0) {
1706 1.1 kardel (void) fprintf(stderr,
1707 1.1 kardel "***Association for `%s' unknown (max &%d)\n",
1708 1.1 kardel str, numassoc);
1709 1.1 kardel return 0;
1710 1.1 kardel } else {
1711 1.1 kardel isneg = numassoc;
1712 1.1 kardel }
1713 1.1 kardel }
1714 1.1 kardel argp->uval = assoc_cache[isneg-1].assid;
1715 1.1 kardel break;
1716 1.1 kardel }
1717 1.1 kardel
1718 1.1 kardel if (*np == '-') {
1719 1.1 kardel np++;
1720 1.1 kardel isneg = 1;
1721 1.1 kardel }
1722 1.1 kardel
1723 1.1 kardel argp->uval = 0;
1724 1.1 kardel do {
1725 1.1 kardel cp = strchr(digits, *np);
1726 1.1 kardel if (cp == NULL) {
1727 1.1 kardel (void) fprintf(stderr,
1728 1.1 kardel "***Illegal integer value %s\n", str);
1729 1.1 kardel return 0;
1730 1.1 kardel }
1731 1.1 kardel argp->uval *= 10;
1732 1.1 kardel argp->uval += (cp - digits);
1733 1.1 kardel } while (*(++np) != '\0');
1734 1.1 kardel
1735 1.1 kardel if (isneg) {
1736 1.1 kardel if ((code & ~OPT) == NTP_UINT) {
1737 1.1 kardel (void) fprintf(stderr,
1738 1.1 kardel "***Value %s should be unsigned\n", str);
1739 1.1 kardel return 0;
1740 1.1 kardel }
1741 1.1 kardel argp->ival = -argp->ival;
1742 1.1 kardel }
1743 1.1 kardel break;
1744 1.1 kardel case IP_VERSION:
1745 1.1 kardel if (!strcmp("-6", str))
1746 1.1 kardel argp->ival = 6 ;
1747 1.1 kardel else if (!strcmp("-4", str))
1748 1.1 kardel argp->ival = 4 ;
1749 1.1 kardel else {
1750 1.1 kardel (void) fprintf(stderr,
1751 1.1 kardel "***Version must be either 4 or 6\n");
1752 1.1 kardel return 0;
1753 1.1 kardel }
1754 1.1 kardel break;
1755 1.1 kardel }
1756 1.1 kardel
1757 1.1 kardel return 1;
1758 1.1 kardel }
1759 1.1 kardel #endif /* !BUILD_AS_LIB */
1760 1.1 kardel
1761 1.1 kardel
1762 1.1 kardel /*
1763 1.1 kardel * findcmd - find a command in a command description table
1764 1.1 kardel */
1765 1.1 kardel static int
1766 1.1 kardel findcmd(
1767 1.1 kardel register char *str,
1768 1.1 kardel struct xcmd *clist1,
1769 1.1 kardel struct xcmd *clist2,
1770 1.1 kardel struct xcmd **cmd
1771 1.1 kardel )
1772 1.1 kardel {
1773 1.1 kardel register struct xcmd *cl;
1774 1.1 kardel register int clen;
1775 1.1 kardel int nmatch;
1776 1.1 kardel struct xcmd *nearmatch = NULL;
1777 1.1 kardel struct xcmd *clist;
1778 1.1 kardel
1779 1.1 kardel clen = strlen(str);
1780 1.1 kardel nmatch = 0;
1781 1.1 kardel if (clist1 != 0)
1782 1.1 kardel clist = clist1;
1783 1.1 kardel else if (clist2 != 0)
1784 1.1 kardel clist = clist2;
1785 1.1 kardel else
1786 1.1 kardel return 0;
1787 1.1 kardel
1788 1.1 kardel again:
1789 1.1 kardel for (cl = clist; cl->keyword != 0; cl++) {
1790 1.1 kardel /* do a first character check, for efficiency */
1791 1.1 kardel if (*str != *(cl->keyword))
1792 1.1 kardel continue;
1793 1.1 kardel if (strncmp(str, cl->keyword, (unsigned)clen) == 0) {
1794 1.1 kardel /*
1795 1.1 kardel * Could be extact match, could be approximate.
1796 1.1 kardel * Is exact if the length of the keyword is the
1797 1.1 kardel * same as the str.
1798 1.1 kardel */
1799 1.1 kardel if (*((cl->keyword) + clen) == '\0') {
1800 1.1 kardel *cmd = cl;
1801 1.1 kardel return 1;
1802 1.1 kardel }
1803 1.1 kardel nmatch++;
1804 1.1 kardel nearmatch = cl;
1805 1.1 kardel }
1806 1.1 kardel }
1807 1.1 kardel
1808 1.1 kardel /*
1809 1.1 kardel * See if there is more to do. If so, go again. Sorry about the
1810 1.1 kardel * goto, too much looking at BSD sources...
1811 1.1 kardel */
1812 1.1 kardel if (clist == clist1 && clist2 != 0) {
1813 1.1 kardel clist = clist2;
1814 1.1 kardel goto again;
1815 1.1 kardel }
1816 1.1 kardel
1817 1.1 kardel /*
1818 1.1 kardel * If we got extactly 1 near match, use it, else return number
1819 1.1 kardel * of matches.
1820 1.1 kardel */
1821 1.1 kardel if (nmatch == 1) {
1822 1.1 kardel *cmd = nearmatch;
1823 1.1 kardel return 1;
1824 1.1 kardel }
1825 1.1 kardel return nmatch;
1826 1.1 kardel }
1827 1.1 kardel
1828 1.1 kardel
1829 1.1 kardel /*
1830 1.1 kardel * getnetnum - given a host name, return its net number
1831 1.1 kardel * and (optional) full name
1832 1.1 kardel */
1833 1.1 kardel int
1834 1.1 kardel getnetnum(
1835 1.1 kardel const char *hname,
1836 1.1 kardel sockaddr_u *num,
1837 1.1 kardel char *fullhost,
1838 1.1 kardel int af
1839 1.1 kardel )
1840 1.1 kardel {
1841 1.1 kardel struct addrinfo hints, *ai = NULL;
1842 1.1 kardel
1843 1.4 kardel ZERO(hints);
1844 1.1 kardel hints.ai_flags = AI_CANONNAME;
1845 1.1 kardel #ifdef AI_ADDRCONFIG
1846 1.1 kardel hints.ai_flags |= AI_ADDRCONFIG;
1847 1.1 kardel #endif
1848 1.1 kardel
1849 1.4 kardel /*
1850 1.4 kardel * decodenetnum only works with addresses, but handles syntax
1851 1.4 kardel * that getaddrinfo doesn't: [2001::1]:1234
1852 1.4 kardel */
1853 1.1 kardel if (decodenetnum(hname, num)) {
1854 1.4 kardel if (fullhost != NULL)
1855 1.4 kardel getnameinfo(&num->sa, SOCKLEN(num), fullhost,
1856 1.4 kardel LENHOSTNAME, NULL, 0, 0);
1857 1.1 kardel return 1;
1858 1.1 kardel } else if (getaddrinfo(hname, "ntp", &hints, &ai) == 0) {
1859 1.4 kardel NTP_INSIST(sizeof(*num) >= ai->ai_addrlen);
1860 1.4 kardel memcpy(num, ai->ai_addr, ai->ai_addrlen);
1861 1.4 kardel if (fullhost != NULL) {
1862 1.4 kardel if (ai->ai_canonname != NULL) {
1863 1.4 kardel strncpy(fullhost, ai->ai_canonname,
1864 1.4 kardel LENHOSTNAME);
1865 1.4 kardel fullhost[LENHOSTNAME - 1] = '\0';
1866 1.4 kardel } else {
1867 1.4 kardel getnameinfo(&num->sa, SOCKLEN(num),
1868 1.4 kardel fullhost, LENHOSTNAME, NULL,
1869 1.4 kardel 0, 0);
1870 1.4 kardel }
1871 1.4 kardel }
1872 1.1 kardel return 1;
1873 1.1 kardel }
1874 1.4 kardel fprintf(stderr, "***Can't find host %s\n", hname);
1875 1.4 kardel
1876 1.4 kardel return 0;
1877 1.1 kardel }
1878 1.1 kardel
1879 1.1 kardel /*
1880 1.1 kardel * nntohost - convert network number to host name. This routine enforces
1881 1.1 kardel * the showhostnames setting.
1882 1.1 kardel */
1883 1.4 kardel const char *
1884 1.1 kardel nntohost(
1885 1.1 kardel sockaddr_u *netnum
1886 1.1 kardel )
1887 1.1 kardel {
1888 1.4 kardel return nntohost_col(netnum, LIB_BUFLENGTH - 1, FALSE);
1889 1.4 kardel }
1890 1.4 kardel
1891 1.4 kardel
1892 1.4 kardel /*
1893 1.4 kardel * nntohost_col - convert network number to host name in fixed width.
1894 1.4 kardel * This routine enforces the showhostnames setting.
1895 1.4 kardel * When displaying hostnames longer than the width,
1896 1.4 kardel * the first part of the hostname is displayed. When
1897 1.4 kardel * displaying numeric addresses longer than the width,
1898 1.4 kardel * Such as IPv6 addresses, the caller decides whether
1899 1.4 kardel * the first or last of the numeric address is used.
1900 1.4 kardel */
1901 1.4 kardel const char *
1902 1.4 kardel nntohost_col(
1903 1.4 kardel sockaddr_u * addr,
1904 1.4 kardel size_t width,
1905 1.4 kardel int preserve_lowaddrbits
1906 1.4 kardel )
1907 1.4 kardel {
1908 1.4 kardel const char * out;
1909 1.4 kardel
1910 1.4 kardel if (!showhostnames) {
1911 1.4 kardel if (preserve_lowaddrbits)
1912 1.4 kardel out = trunc_left(stoa(addr), width);
1913 1.4 kardel else
1914 1.4 kardel out = trunc_right(stoa(addr), width);
1915 1.4 kardel } else if (ISREFCLOCKADR(addr)) {
1916 1.4 kardel out = refnumtoa(addr);
1917 1.4 kardel } else {
1918 1.4 kardel out = trunc_right(socktohost(addr), width);
1919 1.4 kardel }
1920 1.4 kardel return out;
1921 1.1 kardel }
1922 1.1 kardel
1923 1.1 kardel
1924 1.1 kardel /*
1925 1.1 kardel * rtdatetolfp - decode an RT-11 date into an l_fp
1926 1.1 kardel */
1927 1.1 kardel static int
1928 1.1 kardel rtdatetolfp(
1929 1.1 kardel char *str,
1930 1.1 kardel l_fp *lfp
1931 1.1 kardel )
1932 1.1 kardel {
1933 1.1 kardel register char *cp;
1934 1.1 kardel register int i;
1935 1.1 kardel struct calendar cal;
1936 1.1 kardel char buf[4];
1937 1.1 kardel static const char *months[12] = {
1938 1.1 kardel "Jan", "Feb", "Mar", "Apr", "May", "Jun",
1939 1.1 kardel "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
1940 1.1 kardel };
1941 1.1 kardel
1942 1.1 kardel cal.yearday = 0;
1943 1.1 kardel
1944 1.1 kardel /*
1945 1.1 kardel * An RT-11 date looks like:
1946 1.1 kardel *
1947 1.1 kardel * d[d]-Mth-y[y] hh:mm:ss
1948 1.1 kardel *
1949 1.1 kardel * (No docs, but assume 4-digit years are also legal...)
1950 1.1 kardel *
1951 1.1 kardel * d[d]-Mth-y[y[y[y]]] hh:mm:ss
1952 1.1 kardel */
1953 1.1 kardel cp = str;
1954 1.1 kardel if (!isdigit((int)*cp)) {
1955 1.1 kardel if (*cp == '-') {
1956 1.1 kardel /*
1957 1.1 kardel * Catch special case
1958 1.1 kardel */
1959 1.1 kardel L_CLR(lfp);
1960 1.1 kardel return 1;
1961 1.1 kardel }
1962 1.1 kardel return 0;
1963 1.1 kardel }
1964 1.1 kardel
1965 1.1 kardel cal.monthday = (u_char) (*cp++ - '0'); /* ascii dependent */
1966 1.1 kardel if (isdigit((int)*cp)) {
1967 1.1 kardel cal.monthday = (u_char)((cal.monthday << 3) + (cal.monthday << 1));
1968 1.1 kardel cal.monthday = (u_char)(cal.monthday + *cp++ - '0');
1969 1.1 kardel }
1970 1.1 kardel
1971 1.1 kardel if (*cp++ != '-')
1972 1.1 kardel return 0;
1973 1.1 kardel
1974 1.1 kardel for (i = 0; i < 3; i++)
1975 1.1 kardel buf[i] = *cp++;
1976 1.1 kardel buf[3] = '\0';
1977 1.1 kardel
1978 1.1 kardel for (i = 0; i < 12; i++)
1979 1.1 kardel if (STREQ(buf, months[i]))
1980 1.1 kardel break;
1981 1.1 kardel if (i == 12)
1982 1.1 kardel return 0;
1983 1.1 kardel cal.month = (u_char)(i + 1);
1984 1.1 kardel
1985 1.1 kardel if (*cp++ != '-')
1986 1.1 kardel return 0;
1987 1.1 kardel
1988 1.1 kardel if (!isdigit((int)*cp))
1989 1.1 kardel return 0;
1990 1.1 kardel cal.year = (u_short)(*cp++ - '0');
1991 1.1 kardel if (isdigit((int)*cp)) {
1992 1.1 kardel cal.year = (u_short)((cal.year << 3) + (cal.year << 1));
1993 1.1 kardel cal.year = (u_short)(*cp++ - '0');
1994 1.1 kardel }
1995 1.1 kardel if (isdigit((int)*cp)) {
1996 1.1 kardel cal.year = (u_short)((cal.year << 3) + (cal.year << 1));
1997 1.1 kardel cal.year = (u_short)(cal.year + *cp++ - '0');
1998 1.1 kardel }
1999 1.1 kardel if (isdigit((int)*cp)) {
2000 1.1 kardel cal.year = (u_short)((cal.year << 3) + (cal.year << 1));
2001 1.1 kardel cal.year = (u_short)(cal.year + *cp++ - '0');
2002 1.1 kardel }
2003 1.1 kardel
2004 1.1 kardel /*
2005 1.1 kardel * Catch special case. If cal.year == 0 this is a zero timestamp.
2006 1.1 kardel */
2007 1.1 kardel if (cal.year == 0) {
2008 1.1 kardel L_CLR(lfp);
2009 1.1 kardel return 1;
2010 1.1 kardel }
2011 1.1 kardel
2012 1.1 kardel if (*cp++ != ' ' || !isdigit((int)*cp))
2013 1.1 kardel return 0;
2014 1.1 kardel cal.hour = (u_char)(*cp++ - '0');
2015 1.1 kardel if (isdigit((int)*cp)) {
2016 1.1 kardel cal.hour = (u_char)((cal.hour << 3) + (cal.hour << 1));
2017 1.1 kardel cal.hour = (u_char)(cal.hour + *cp++ - '0');
2018 1.1 kardel }
2019 1.1 kardel
2020 1.1 kardel if (*cp++ != ':' || !isdigit((int)*cp))
2021 1.1 kardel return 0;
2022 1.1 kardel cal.minute = (u_char)(*cp++ - '0');
2023 1.1 kardel if (isdigit((int)*cp)) {
2024 1.1 kardel cal.minute = (u_char)((cal.minute << 3) + (cal.minute << 1));
2025 1.1 kardel cal.minute = (u_char)(cal.minute + *cp++ - '0');
2026 1.1 kardel }
2027 1.1 kardel
2028 1.1 kardel if (*cp++ != ':' || !isdigit((int)*cp))
2029 1.1 kardel return 0;
2030 1.1 kardel cal.second = (u_char)(*cp++ - '0');
2031 1.1 kardel if (isdigit((int)*cp)) {
2032 1.1 kardel cal.second = (u_char)((cal.second << 3) + (cal.second << 1));
2033 1.1 kardel cal.second = (u_char)(cal.second + *cp++ - '0');
2034 1.1 kardel }
2035 1.1 kardel
2036 1.1 kardel /*
2037 1.1 kardel * For RT-11, 1972 seems to be the pivot year
2038 1.1 kardel */
2039 1.1 kardel if (cal.year < 72)
2040 1.1 kardel cal.year += 2000;
2041 1.1 kardel if (cal.year < 100)
2042 1.1 kardel cal.year += 1900;
2043 1.1 kardel
2044 1.1 kardel lfp->l_ui = caltontp(&cal);
2045 1.1 kardel lfp->l_uf = 0;
2046 1.1 kardel return 1;
2047 1.1 kardel }
2048 1.1 kardel
2049 1.1 kardel
2050 1.1 kardel /*
2051 1.1 kardel * decodets - decode a timestamp into an l_fp format number, with
2052 1.1 kardel * consideration of fuzzball formats.
2053 1.1 kardel */
2054 1.1 kardel int
2055 1.1 kardel decodets(
2056 1.1 kardel char *str,
2057 1.1 kardel l_fp *lfp
2058 1.1 kardel )
2059 1.1 kardel {
2060 1.4 kardel char *cp;
2061 1.4 kardel char buf[30];
2062 1.4 kardel size_t b;
2063 1.4 kardel
2064 1.1 kardel /*
2065 1.1 kardel * If it starts with a 0x, decode as hex.
2066 1.1 kardel */
2067 1.1 kardel if (*str == '0' && (*(str+1) == 'x' || *(str+1) == 'X'))
2068 1.1 kardel return hextolfp(str+2, lfp);
2069 1.1 kardel
2070 1.1 kardel /*
2071 1.1 kardel * If it starts with a '"', try it as an RT-11 date.
2072 1.1 kardel */
2073 1.1 kardel if (*str == '"') {
2074 1.4 kardel cp = str + 1;
2075 1.4 kardel b = 0;
2076 1.4 kardel while ('"' != *cp && '\0' != *cp &&
2077 1.4 kardel b < COUNTOF(buf) - 1)
2078 1.4 kardel buf[b++] = *cp++;
2079 1.4 kardel buf[b] = '\0';
2080 1.1 kardel return rtdatetolfp(buf, lfp);
2081 1.1 kardel }
2082 1.1 kardel
2083 1.1 kardel /*
2084 1.1 kardel * Might still be hex. Check out the first character. Talk
2085 1.1 kardel * about heuristics!
2086 1.1 kardel */
2087 1.1 kardel if ((*str >= 'A' && *str <= 'F') || (*str >= 'a' && *str <= 'f'))
2088 1.1 kardel return hextolfp(str, lfp);
2089 1.1 kardel
2090 1.1 kardel /*
2091 1.1 kardel * Try it as a decimal. If this fails, try as an unquoted
2092 1.1 kardel * RT-11 date. This code should go away eventually.
2093 1.1 kardel */
2094 1.1 kardel if (atolfp(str, lfp))
2095 1.1 kardel return 1;
2096 1.1 kardel
2097 1.1 kardel return rtdatetolfp(str, lfp);
2098 1.1 kardel }
2099 1.1 kardel
2100 1.1 kardel
2101 1.1 kardel /*
2102 1.1 kardel * decodetime - decode a time value. It should be in milliseconds
2103 1.1 kardel */
2104 1.1 kardel int
2105 1.1 kardel decodetime(
2106 1.1 kardel char *str,
2107 1.1 kardel l_fp *lfp
2108 1.1 kardel )
2109 1.1 kardel {
2110 1.1 kardel return mstolfp(str, lfp);
2111 1.1 kardel }
2112 1.1 kardel
2113 1.1 kardel
2114 1.1 kardel /*
2115 1.1 kardel * decodeint - decode an integer
2116 1.1 kardel */
2117 1.1 kardel int
2118 1.1 kardel decodeint(
2119 1.1 kardel char *str,
2120 1.1 kardel long *val
2121 1.1 kardel )
2122 1.1 kardel {
2123 1.1 kardel if (*str == '0') {
2124 1.1 kardel if (*(str+1) == 'x' || *(str+1) == 'X')
2125 1.1 kardel return hextoint(str+2, (u_long *)val);
2126 1.1 kardel return octtoint(str, (u_long *)val);
2127 1.1 kardel }
2128 1.1 kardel return atoint(str, val);
2129 1.1 kardel }
2130 1.1 kardel
2131 1.1 kardel
2132 1.1 kardel /*
2133 1.1 kardel * decodeuint - decode an unsigned integer
2134 1.1 kardel */
2135 1.1 kardel int
2136 1.1 kardel decodeuint(
2137 1.1 kardel char *str,
2138 1.1 kardel u_long *val
2139 1.1 kardel )
2140 1.1 kardel {
2141 1.1 kardel if (*str == '0') {
2142 1.1 kardel if (*(str + 1) == 'x' || *(str + 1) == 'X')
2143 1.1 kardel return (hextoint(str + 2, val));
2144 1.1 kardel return (octtoint(str, val));
2145 1.1 kardel }
2146 1.1 kardel return (atouint(str, val));
2147 1.1 kardel }
2148 1.1 kardel
2149 1.1 kardel
2150 1.1 kardel /*
2151 1.1 kardel * decodearr - decode an array of time values
2152 1.1 kardel */
2153 1.1 kardel static int
2154 1.1 kardel decodearr(
2155 1.1 kardel char *str,
2156 1.1 kardel int *narr,
2157 1.1 kardel l_fp *lfparr
2158 1.1 kardel )
2159 1.1 kardel {
2160 1.1 kardel register char *cp, *bp;
2161 1.1 kardel register l_fp *lfp;
2162 1.1 kardel char buf[60];
2163 1.1 kardel
2164 1.1 kardel lfp = lfparr;
2165 1.1 kardel cp = str;
2166 1.1 kardel *narr = 0;
2167 1.1 kardel
2168 1.1 kardel while (*narr < 8) {
2169 1.1 kardel while (isspace((int)*cp))
2170 1.1 kardel cp++;
2171 1.1 kardel if (*cp == '\0')
2172 1.1 kardel break;
2173 1.1 kardel
2174 1.1 kardel bp = buf;
2175 1.1 kardel while (!isspace((int)*cp) && *cp != '\0')
2176 1.1 kardel *bp++ = *cp++;
2177 1.1 kardel *bp++ = '\0';
2178 1.1 kardel
2179 1.1 kardel if (!decodetime(buf, lfp))
2180 1.1 kardel return 0;
2181 1.1 kardel (*narr)++;
2182 1.1 kardel lfp++;
2183 1.1 kardel }
2184 1.1 kardel return 1;
2185 1.1 kardel }
2186 1.1 kardel
2187 1.1 kardel
2188 1.1 kardel /*
2189 1.1 kardel * Finally, the built in command handlers
2190 1.1 kardel */
2191 1.1 kardel
2192 1.1 kardel /*
2193 1.1 kardel * help - tell about commands, or details of a particular command
2194 1.1 kardel */
2195 1.1 kardel static void
2196 1.1 kardel help(
2197 1.1 kardel struct parse *pcmd,
2198 1.1 kardel FILE *fp
2199 1.1 kardel )
2200 1.1 kardel {
2201 1.1 kardel struct xcmd *xcp = NULL; /* quiet warning */
2202 1.1 kardel char *cmd;
2203 1.1 kardel const char *list[100];
2204 1.4 kardel size_t word, words;
2205 1.4 kardel size_t row, rows;
2206 1.4 kardel size_t col, cols;
2207 1.4 kardel size_t length;
2208 1.1 kardel
2209 1.1 kardel if (pcmd->nargs == 0) {
2210 1.1 kardel words = 0;
2211 1.4 kardel for (xcp = builtins; xcp->keyword != NULL; xcp++) {
2212 1.1 kardel if (*(xcp->keyword) != '?')
2213 1.1 kardel list[words++] = xcp->keyword;
2214 1.1 kardel }
2215 1.4 kardel for (xcp = opcmds; xcp->keyword != NULL; xcp++)
2216 1.1 kardel list[words++] = xcp->keyword;
2217 1.1 kardel
2218 1.4 kardel qsort((void *)list, (size_t)words, sizeof(list[0]),
2219 1.4 kardel helpsort);
2220 1.1 kardel col = 0;
2221 1.1 kardel for (word = 0; word < words; word++) {
2222 1.4 kardel length = strlen(list[word]);
2223 1.4 kardel col = max(col, length);
2224 1.1 kardel }
2225 1.1 kardel
2226 1.1 kardel cols = SCREENWIDTH / ++col;
2227 1.1 kardel rows = (words + cols - 1) / cols;
2228 1.1 kardel
2229 1.4 kardel fprintf(fp, "ntpq commands:\n");
2230 1.1 kardel
2231 1.1 kardel for (row = 0; row < rows; row++) {
2232 1.4 kardel for (word = row; word < words; word += rows)
2233 1.5 kardel fprintf(fp, "%-*.*s", (int)col, (int)col-1,
2234 1.4 kardel list[word]);
2235 1.4 kardel fprintf(fp, "\n");
2236 1.1 kardel }
2237 1.1 kardel } else {
2238 1.1 kardel cmd = pcmd->argval[0].string;
2239 1.1 kardel words = findcmd(cmd, builtins, opcmds, &xcp);
2240 1.1 kardel if (words == 0) {
2241 1.4 kardel fprintf(stderr,
2242 1.4 kardel "Command `%s' is unknown\n", cmd);
2243 1.1 kardel return;
2244 1.1 kardel } else if (words >= 2) {
2245 1.4 kardel fprintf(stderr,
2246 1.4 kardel "Command `%s' is ambiguous\n", cmd);
2247 1.1 kardel return;
2248 1.1 kardel }
2249 1.4 kardel fprintf(fp, "function: %s\n", xcp->comment);
2250 1.1 kardel printusage(xcp, fp);
2251 1.1 kardel }
2252 1.1 kardel }
2253 1.1 kardel
2254 1.1 kardel
2255 1.1 kardel /*
2256 1.1 kardel * helpsort - do hostname qsort comparisons
2257 1.1 kardel */
2258 1.1 kardel static int
2259 1.1 kardel helpsort(
2260 1.1 kardel const void *t1,
2261 1.1 kardel const void *t2
2262 1.1 kardel )
2263 1.1 kardel {
2264 1.4 kardel const char * const * name1 = t1;
2265 1.4 kardel const char * const * name2 = t2;
2266 1.1 kardel
2267 1.1 kardel return strcmp(*name1, *name2);
2268 1.1 kardel }
2269 1.1 kardel
2270 1.1 kardel
2271 1.1 kardel /*
2272 1.1 kardel * printusage - print usage information for a command
2273 1.1 kardel */
2274 1.1 kardel static void
2275 1.1 kardel printusage(
2276 1.1 kardel struct xcmd *xcp,
2277 1.1 kardel FILE *fp
2278 1.1 kardel )
2279 1.1 kardel {
2280 1.1 kardel register int i;
2281 1.1 kardel
2282 1.1 kardel (void) fprintf(fp, "usage: %s", xcp->keyword);
2283 1.1 kardel for (i = 0; i < MAXARGS && xcp->arg[i] != NO; i++) {
2284 1.1 kardel if (xcp->arg[i] & OPT)
2285 1.1 kardel (void) fprintf(fp, " [ %s ]", xcp->desc[i]);
2286 1.1 kardel else
2287 1.1 kardel (void) fprintf(fp, " %s", xcp->desc[i]);
2288 1.1 kardel }
2289 1.1 kardel (void) fprintf(fp, "\n");
2290 1.1 kardel }
2291 1.1 kardel
2292 1.1 kardel
2293 1.1 kardel /*
2294 1.1 kardel * timeout - set time out time
2295 1.1 kardel */
2296 1.1 kardel static void
2297 1.1 kardel timeout(
2298 1.1 kardel struct parse *pcmd,
2299 1.1 kardel FILE *fp
2300 1.1 kardel )
2301 1.1 kardel {
2302 1.1 kardel int val;
2303 1.1 kardel
2304 1.1 kardel if (pcmd->nargs == 0) {
2305 1.1 kardel val = (int)tvout.tv_sec * 1000 + tvout.tv_usec / 1000;
2306 1.1 kardel (void) fprintf(fp, "primary timeout %d ms\n", val);
2307 1.1 kardel } else {
2308 1.1 kardel tvout.tv_sec = pcmd->argval[0].uval / 1000;
2309 1.1 kardel tvout.tv_usec = (pcmd->argval[0].uval - ((long)tvout.tv_sec * 1000))
2310 1.1 kardel * 1000;
2311 1.1 kardel }
2312 1.1 kardel }
2313 1.1 kardel
2314 1.1 kardel
2315 1.1 kardel /*
2316 1.1 kardel * auth_delay - set delay for auth requests
2317 1.1 kardel */
2318 1.1 kardel static void
2319 1.1 kardel auth_delay(
2320 1.1 kardel struct parse *pcmd,
2321 1.1 kardel FILE *fp
2322 1.1 kardel )
2323 1.1 kardel {
2324 1.1 kardel int isneg;
2325 1.1 kardel u_long val;
2326 1.1 kardel
2327 1.1 kardel if (pcmd->nargs == 0) {
2328 1.1 kardel val = delay_time.l_ui * 1000 + delay_time.l_uf / 4294967;
2329 1.1 kardel (void) fprintf(fp, "delay %lu ms\n", val);
2330 1.1 kardel } else {
2331 1.1 kardel if (pcmd->argval[0].ival < 0) {
2332 1.1 kardel isneg = 1;
2333 1.1 kardel val = (u_long)(-pcmd->argval[0].ival);
2334 1.1 kardel } else {
2335 1.1 kardel isneg = 0;
2336 1.1 kardel val = (u_long)pcmd->argval[0].ival;
2337 1.1 kardel }
2338 1.1 kardel
2339 1.1 kardel delay_time.l_ui = val / 1000;
2340 1.1 kardel val %= 1000;
2341 1.1 kardel delay_time.l_uf = val * 4294967; /* 2**32/1000 */
2342 1.1 kardel
2343 1.1 kardel if (isneg)
2344 1.1 kardel L_NEG(&delay_time);
2345 1.1 kardel }
2346 1.1 kardel }
2347 1.1 kardel
2348 1.1 kardel
2349 1.1 kardel /*
2350 1.1 kardel * host - set the host we are dealing with.
2351 1.1 kardel */
2352 1.1 kardel static void
2353 1.1 kardel host(
2354 1.1 kardel struct parse *pcmd,
2355 1.1 kardel FILE *fp
2356 1.1 kardel )
2357 1.1 kardel {
2358 1.1 kardel int i;
2359 1.1 kardel
2360 1.1 kardel if (pcmd->nargs == 0) {
2361 1.1 kardel if (havehost)
2362 1.1 kardel (void) fprintf(fp, "current host is %s\n",
2363 1.1 kardel currenthost);
2364 1.1 kardel else
2365 1.1 kardel (void) fprintf(fp, "no current host\n");
2366 1.1 kardel return;
2367 1.1 kardel }
2368 1.1 kardel
2369 1.1 kardel i = 0;
2370 1.1 kardel ai_fam_templ = ai_fam_default;
2371 1.1 kardel if (pcmd->nargs == 2) {
2372 1.1 kardel if (!strcmp("-4", pcmd->argval[i].string))
2373 1.1 kardel ai_fam_templ = AF_INET;
2374 1.1 kardel else if (!strcmp("-6", pcmd->argval[i].string))
2375 1.1 kardel ai_fam_templ = AF_INET6;
2376 1.1 kardel else {
2377 1.1 kardel if (havehost)
2378 1.1 kardel (void) fprintf(fp,
2379 1.1 kardel "current host remains %s\n",
2380 1.1 kardel currenthost);
2381 1.1 kardel else
2382 1.1 kardel (void) fprintf(fp, "still no current host\n");
2383 1.1 kardel return;
2384 1.1 kardel }
2385 1.1 kardel i = 1;
2386 1.1 kardel }
2387 1.1 kardel if (openhost(pcmd->argval[i].string)) {
2388 1.1 kardel (void) fprintf(fp, "current host set to %s\n", currenthost);
2389 1.1 kardel numassoc = 0;
2390 1.1 kardel } else {
2391 1.1 kardel if (havehost)
2392 1.1 kardel (void) fprintf(fp,
2393 1.1 kardel "current host remains %s\n",
2394 1.1 kardel currenthost);
2395 1.1 kardel else
2396 1.1 kardel (void) fprintf(fp, "still no current host\n");
2397 1.1 kardel }
2398 1.1 kardel }
2399 1.1 kardel
2400 1.1 kardel
2401 1.1 kardel /*
2402 1.1 kardel * poll - do one (or more) polls of the host via NTP
2403 1.1 kardel */
2404 1.1 kardel /*ARGSUSED*/
2405 1.1 kardel static void
2406 1.1 kardel ntp_poll(
2407 1.1 kardel struct parse *pcmd,
2408 1.1 kardel FILE *fp
2409 1.1 kardel )
2410 1.1 kardel {
2411 1.1 kardel (void) fprintf(fp, "poll not implemented yet\n");
2412 1.1 kardel }
2413 1.1 kardel
2414 1.1 kardel
2415 1.1 kardel /*
2416 1.1 kardel * keyid - get a keyid to use for authenticating requests
2417 1.1 kardel */
2418 1.1 kardel static void
2419 1.1 kardel keyid(
2420 1.1 kardel struct parse *pcmd,
2421 1.1 kardel FILE *fp
2422 1.1 kardel )
2423 1.1 kardel {
2424 1.1 kardel if (pcmd->nargs == 0) {
2425 1.1 kardel if (info_auth_keyid == 0)
2426 1.1 kardel (void) fprintf(fp, "no keyid defined\n");
2427 1.1 kardel else
2428 1.1 kardel (void) fprintf(fp, "keyid is %lu\n", (u_long)info_auth_keyid);
2429 1.1 kardel } else {
2430 1.1 kardel /* allow zero so that keyid can be cleared. */
2431 1.1 kardel if(pcmd->argval[0].uval > NTP_MAXKEY)
2432 1.1 kardel (void) fprintf(fp, "Invalid key identifier\n");
2433 1.1 kardel info_auth_keyid = pcmd->argval[0].uval;
2434 1.1 kardel }
2435 1.1 kardel }
2436 1.1 kardel
2437 1.1 kardel /*
2438 1.1 kardel * keytype - get type of key to use for authenticating requests
2439 1.1 kardel */
2440 1.1 kardel static void
2441 1.1 kardel keytype(
2442 1.1 kardel struct parse *pcmd,
2443 1.1 kardel FILE *fp
2444 1.1 kardel )
2445 1.1 kardel {
2446 1.1 kardel const char * digest_name;
2447 1.1 kardel size_t digest_len;
2448 1.1 kardel int key_type;
2449 1.1 kardel
2450 1.1 kardel if (!pcmd->nargs) {
2451 1.2 christos fprintf(fp, "keytype is %s with %zu octet digests\n",
2452 1.1 kardel keytype_name(info_auth_keytype),
2453 1.4 kardel (u_long)info_auth_hashlen);
2454 1.1 kardel return;
2455 1.1 kardel }
2456 1.1 kardel
2457 1.1 kardel digest_name = pcmd->argval[0].string;
2458 1.1 kardel digest_len = 0;
2459 1.1 kardel key_type = keytype_from_text(digest_name, &digest_len);
2460 1.1 kardel
2461 1.1 kardel if (!key_type) {
2462 1.1 kardel fprintf(fp, "keytype must be 'md5'%s\n",
2463 1.1 kardel #ifdef OPENSSL
2464 1.1 kardel " or a digest type provided by OpenSSL");
2465 1.1 kardel #else
2466 1.1 kardel "");
2467 1.1 kardel #endif
2468 1.1 kardel return;
2469 1.1 kardel }
2470 1.1 kardel
2471 1.1 kardel info_auth_keytype = key_type;
2472 1.1 kardel info_auth_hashlen = digest_len;
2473 1.1 kardel }
2474 1.1 kardel
2475 1.1 kardel
2476 1.1 kardel /*
2477 1.1 kardel * passwd - get an authentication key
2478 1.1 kardel */
2479 1.1 kardel /*ARGSUSED*/
2480 1.1 kardel static void
2481 1.1 kardel passwd(
2482 1.1 kardel struct parse *pcmd,
2483 1.1 kardel FILE *fp
2484 1.1 kardel )
2485 1.1 kardel {
2486 1.1 kardel char *pass;
2487 1.1 kardel
2488 1.1 kardel if (info_auth_keyid == 0) {
2489 1.1 kardel int u_keyid = getkeyid("Keyid: ");
2490 1.1 kardel if (u_keyid == 0 || u_keyid > NTP_MAXKEY) {
2491 1.1 kardel (void)fprintf(fp, "Invalid key identifier\n");
2492 1.1 kardel return;
2493 1.1 kardel }
2494 1.1 kardel info_auth_keyid = u_keyid;
2495 1.1 kardel }
2496 1.4 kardel if (pcmd->nargs >= 1)
2497 1.4 kardel pass = pcmd->argval[0].string;
2498 1.1 kardel else {
2499 1.4 kardel pass = getpass_keytype(info_auth_keytype);
2500 1.4 kardel if ('\0' == pass[0]) {
2501 1.4 kardel fprintf(fp, "Password unchanged\n");
2502 1.4 kardel return;
2503 1.4 kardel }
2504 1.1 kardel }
2505 1.4 kardel authusekey(info_auth_keyid, info_auth_keytype, (u_char *)pass);
2506 1.4 kardel authtrust(info_auth_keyid, 1);
2507 1.1 kardel }
2508 1.1 kardel
2509 1.1 kardel
2510 1.1 kardel /*
2511 1.1 kardel * hostnames - set the showhostnames flag
2512 1.1 kardel */
2513 1.1 kardel static void
2514 1.1 kardel hostnames(
2515 1.1 kardel struct parse *pcmd,
2516 1.1 kardel FILE *fp
2517 1.1 kardel )
2518 1.1 kardel {
2519 1.1 kardel if (pcmd->nargs == 0) {
2520 1.1 kardel if (showhostnames)
2521 1.1 kardel (void) fprintf(fp, "hostnames being shown\n");
2522 1.1 kardel else
2523 1.1 kardel (void) fprintf(fp, "hostnames not being shown\n");
2524 1.1 kardel } else {
2525 1.1 kardel if (STREQ(pcmd->argval[0].string, "yes"))
2526 1.1 kardel showhostnames = 1;
2527 1.1 kardel else if (STREQ(pcmd->argval[0].string, "no"))
2528 1.1 kardel showhostnames = 0;
2529 1.1 kardel else
2530 1.1 kardel (void)fprintf(stderr, "What?\n");
2531 1.1 kardel }
2532 1.1 kardel }
2533 1.1 kardel
2534 1.1 kardel
2535 1.1 kardel
2536 1.1 kardel /*
2537 1.1 kardel * setdebug - set/change debugging level
2538 1.1 kardel */
2539 1.1 kardel static void
2540 1.1 kardel setdebug(
2541 1.1 kardel struct parse *pcmd,
2542 1.1 kardel FILE *fp
2543 1.1 kardel )
2544 1.1 kardel {
2545 1.1 kardel if (pcmd->nargs == 0) {
2546 1.1 kardel (void) fprintf(fp, "debug level is %d\n", debug);
2547 1.1 kardel return;
2548 1.1 kardel } else if (STREQ(pcmd->argval[0].string, "no")) {
2549 1.1 kardel debug = 0;
2550 1.1 kardel } else if (STREQ(pcmd->argval[0].string, "more")) {
2551 1.1 kardel debug++;
2552 1.1 kardel } else if (STREQ(pcmd->argval[0].string, "less")) {
2553 1.1 kardel debug--;
2554 1.1 kardel } else {
2555 1.1 kardel (void) fprintf(fp, "What?\n");
2556 1.1 kardel return;
2557 1.1 kardel }
2558 1.1 kardel (void) fprintf(fp, "debug level set to %d\n", debug);
2559 1.1 kardel }
2560 1.1 kardel
2561 1.1 kardel
2562 1.1 kardel /*
2563 1.1 kardel * quit - stop this nonsense
2564 1.1 kardel */
2565 1.1 kardel /*ARGSUSED*/
2566 1.1 kardel static void
2567 1.1 kardel quit(
2568 1.1 kardel struct parse *pcmd,
2569 1.1 kardel FILE *fp
2570 1.1 kardel )
2571 1.1 kardel {
2572 1.1 kardel if (havehost)
2573 1.1 kardel closesocket(sockfd); /* cleanliness next to godliness */
2574 1.1 kardel exit(0);
2575 1.1 kardel }
2576 1.1 kardel
2577 1.1 kardel
2578 1.1 kardel /*
2579 1.1 kardel * version - print the current version number
2580 1.1 kardel */
2581 1.1 kardel /*ARGSUSED*/
2582 1.1 kardel static void
2583 1.1 kardel version(
2584 1.1 kardel struct parse *pcmd,
2585 1.1 kardel FILE *fp
2586 1.1 kardel )
2587 1.1 kardel {
2588 1.1 kardel
2589 1.1 kardel (void) fprintf(fp, "%s\n", Version);
2590 1.1 kardel return;
2591 1.1 kardel }
2592 1.1 kardel
2593 1.1 kardel
2594 1.1 kardel /*
2595 1.1 kardel * raw - set raw mode output
2596 1.1 kardel */
2597 1.1 kardel /*ARGSUSED*/
2598 1.1 kardel static void
2599 1.1 kardel raw(
2600 1.1 kardel struct parse *pcmd,
2601 1.1 kardel FILE *fp
2602 1.1 kardel )
2603 1.1 kardel {
2604 1.1 kardel rawmode = 1;
2605 1.1 kardel (void) fprintf(fp, "Output set to raw\n");
2606 1.1 kardel }
2607 1.1 kardel
2608 1.1 kardel
2609 1.1 kardel /*
2610 1.1 kardel * cooked - set cooked mode output
2611 1.1 kardel */
2612 1.1 kardel /*ARGSUSED*/
2613 1.1 kardel static void
2614 1.1 kardel cooked(
2615 1.1 kardel struct parse *pcmd,
2616 1.1 kardel FILE *fp
2617 1.1 kardel )
2618 1.1 kardel {
2619 1.1 kardel rawmode = 0;
2620 1.1 kardel (void) fprintf(fp, "Output set to cooked\n");
2621 1.1 kardel return;
2622 1.1 kardel }
2623 1.1 kardel
2624 1.1 kardel
2625 1.1 kardel /*
2626 1.1 kardel * authenticate - always authenticate requests to this host
2627 1.1 kardel */
2628 1.1 kardel static void
2629 1.1 kardel authenticate(
2630 1.1 kardel struct parse *pcmd,
2631 1.1 kardel FILE *fp
2632 1.1 kardel )
2633 1.1 kardel {
2634 1.1 kardel if (pcmd->nargs == 0) {
2635 1.1 kardel if (always_auth) {
2636 1.1 kardel (void) fprintf(fp,
2637 1.1 kardel "authenticated requests being sent\n");
2638 1.1 kardel } else
2639 1.1 kardel (void) fprintf(fp,
2640 1.1 kardel "unauthenticated requests being sent\n");
2641 1.1 kardel } else {
2642 1.1 kardel if (STREQ(pcmd->argval[0].string, "yes")) {
2643 1.1 kardel always_auth = 1;
2644 1.1 kardel } else if (STREQ(pcmd->argval[0].string, "no")) {
2645 1.1 kardel always_auth = 0;
2646 1.1 kardel } else
2647 1.1 kardel (void)fprintf(stderr, "What?\n");
2648 1.1 kardel }
2649 1.1 kardel }
2650 1.1 kardel
2651 1.1 kardel
2652 1.1 kardel /*
2653 1.1 kardel * ntpversion - choose the NTP version to use
2654 1.1 kardel */
2655 1.1 kardel static void
2656 1.1 kardel ntpversion(
2657 1.1 kardel struct parse *pcmd,
2658 1.1 kardel FILE *fp
2659 1.1 kardel )
2660 1.1 kardel {
2661 1.1 kardel if (pcmd->nargs == 0) {
2662 1.1 kardel (void) fprintf(fp,
2663 1.1 kardel "NTP version being claimed is %d\n", pktversion);
2664 1.1 kardel } else {
2665 1.1 kardel if (pcmd->argval[0].uval < NTP_OLDVERSION
2666 1.1 kardel || pcmd->argval[0].uval > NTP_VERSION) {
2667 1.1 kardel (void) fprintf(stderr, "versions %d to %d, please\n",
2668 1.1 kardel NTP_OLDVERSION, NTP_VERSION);
2669 1.1 kardel } else {
2670 1.1 kardel pktversion = (u_char) pcmd->argval[0].uval;
2671 1.1 kardel }
2672 1.1 kardel }
2673 1.1 kardel }
2674 1.1 kardel
2675 1.1 kardel
2676 1.3 christos static void __attribute__((__format__(__printf__, 1, 0)))
2677 1.3 christos vwarning(const char *fmt, va_list ap)
2678 1.3 christos {
2679 1.3 christos int serrno = errno;
2680 1.3 christos (void) fprintf(stderr, "%s: ", progname);
2681 1.3 christos vfprintf(stderr, fmt, ap);
2682 1.3 christos (void) fprintf(stderr, ": %s", strerror(serrno));
2683 1.3 christos }
2684 1.3 christos
2685 1.1 kardel /*
2686 1.1 kardel * warning - print a warning message
2687 1.1 kardel */
2688 1.3 christos static void __attribute__((__format__(__printf__, 1, 2)))
2689 1.1 kardel warning(
2690 1.1 kardel const char *fmt,
2691 1.3 christos ...
2692 1.1 kardel )
2693 1.1 kardel {
2694 1.3 christos va_list ap;
2695 1.3 christos va_start(ap, fmt);
2696 1.3 christos vwarning(fmt, ap);
2697 1.3 christos va_end(ap);
2698 1.1 kardel }
2699 1.1 kardel
2700 1.1 kardel
2701 1.1 kardel /*
2702 1.1 kardel * error - print a message and exit
2703 1.1 kardel */
2704 1.3 christos static void __attribute__((__format__(__printf__, 1, 2)))
2705 1.1 kardel error(
2706 1.1 kardel const char *fmt,
2707 1.3 christos ...
2708 1.1 kardel )
2709 1.1 kardel {
2710 1.3 christos va_list ap;
2711 1.3 christos va_start(ap, fmt);
2712 1.3 christos vwarning(fmt, ap);
2713 1.3 christos va_end(ap);
2714 1.1 kardel exit(1);
2715 1.1 kardel }
2716 1.1 kardel /*
2717 1.1 kardel * getkeyid - prompt the user for a keyid to use
2718 1.1 kardel */
2719 1.1 kardel static u_long
2720 1.1 kardel getkeyid(
2721 1.1 kardel const char *keyprompt
2722 1.1 kardel )
2723 1.1 kardel {
2724 1.4 kardel int c;
2725 1.1 kardel FILE *fi;
2726 1.1 kardel char pbuf[20];
2727 1.4 kardel size_t i;
2728 1.4 kardel size_t ilim;
2729 1.1 kardel
2730 1.1 kardel #ifndef SYS_WINNT
2731 1.1 kardel if ((fi = fdopen(open("/dev/tty", 2), "r")) == NULL)
2732 1.1 kardel #else
2733 1.1 kardel if ((fi = _fdopen(open("CONIN$", _O_TEXT), "r")) == NULL)
2734 1.1 kardel #endif /* SYS_WINNT */
2735 1.1 kardel fi = stdin;
2736 1.4 kardel else
2737 1.1 kardel setbuf(fi, (char *)NULL);
2738 1.1 kardel fprintf(stderr, "%s", keyprompt); fflush(stderr);
2739 1.4 kardel for (i = 0, ilim = COUNTOF(pbuf) - 1;
2740 1.4 kardel i < ilim && (c = getc(fi)) != '\n' && c != EOF;
2741 1.4 kardel )
2742 1.4 kardel pbuf[i++] = (char)c;
2743 1.4 kardel pbuf[i] = '\0';
2744 1.1 kardel if (fi != stdin)
2745 1.4 kardel fclose(fi);
2746 1.1 kardel
2747 1.1 kardel return (u_long) atoi(pbuf);
2748 1.1 kardel }
2749 1.1 kardel
2750 1.1 kardel
2751 1.1 kardel /*
2752 1.1 kardel * atoascii - printable-ize possibly ascii data using the character
2753 1.1 kardel * transformations cat -v uses.
2754 1.1 kardel */
2755 1.1 kardel static void
2756 1.1 kardel atoascii(
2757 1.1 kardel const char *in,
2758 1.1 kardel size_t in_octets,
2759 1.1 kardel char *out,
2760 1.1 kardel size_t out_octets
2761 1.1 kardel )
2762 1.1 kardel {
2763 1.1 kardel register const u_char * pchIn;
2764 1.1 kardel const u_char * pchInLimit;
2765 1.1 kardel register u_char * pchOut;
2766 1.1 kardel register u_char c;
2767 1.1 kardel
2768 1.1 kardel pchIn = (const u_char *)in;
2769 1.1 kardel pchInLimit = pchIn + in_octets;
2770 1.1 kardel pchOut = (u_char *)out;
2771 1.1 kardel
2772 1.1 kardel if (NULL == pchIn) {
2773 1.1 kardel if (0 < out_octets)
2774 1.1 kardel *pchOut = '\0';
2775 1.1 kardel return;
2776 1.1 kardel }
2777 1.1 kardel
2778 1.1 kardel #define ONEOUT(c) \
2779 1.1 kardel do { \
2780 1.1 kardel if (0 == --out_octets) { \
2781 1.1 kardel *pchOut = '\0'; \
2782 1.1 kardel return; \
2783 1.1 kardel } \
2784 1.1 kardel *pchOut++ = (c); \
2785 1.1 kardel } while (0)
2786 1.1 kardel
2787 1.1 kardel for ( ; pchIn < pchInLimit; pchIn++) {
2788 1.1 kardel c = *pchIn;
2789 1.1 kardel if ('\0' == c)
2790 1.1 kardel break;
2791 1.1 kardel if (c & 0x80) {
2792 1.1 kardel ONEOUT('M');
2793 1.1 kardel ONEOUT('-');
2794 1.1 kardel c &= 0x7f;
2795 1.1 kardel }
2796 1.1 kardel if (c < ' ') {
2797 1.1 kardel ONEOUT('^');
2798 1.1 kardel ONEOUT((u_char)(c + '@'));
2799 1.1 kardel } else if (0x7f == c) {
2800 1.1 kardel ONEOUT('^');
2801 1.1 kardel ONEOUT('?');
2802 1.1 kardel } else
2803 1.1 kardel ONEOUT(c);
2804 1.1 kardel }
2805 1.1 kardel ONEOUT('\0');
2806 1.1 kardel
2807 1.1 kardel #undef ONEOUT
2808 1.1 kardel }
2809 1.1 kardel
2810 1.1 kardel
2811 1.1 kardel /*
2812 1.1 kardel * makeascii - print possibly ascii data using the character
2813 1.1 kardel * transformations that cat -v uses.
2814 1.1 kardel */
2815 1.4 kardel void
2816 1.1 kardel makeascii(
2817 1.1 kardel int length,
2818 1.4 kardel const char *data,
2819 1.1 kardel FILE *fp
2820 1.1 kardel )
2821 1.1 kardel {
2822 1.4 kardel const u_char *data_u_char;
2823 1.4 kardel const u_char *cp;
2824 1.4 kardel int c;
2825 1.4 kardel
2826 1.4 kardel data_u_char = (const u_char *)data;
2827 1.1 kardel
2828 1.4 kardel for (cp = data_u_char; cp < data_u_char + length; cp++) {
2829 1.1 kardel c = (int)*cp;
2830 1.1 kardel if (c & 0x80) {
2831 1.1 kardel putc('M', fp);
2832 1.1 kardel putc('-', fp);
2833 1.1 kardel c &= 0x7f;
2834 1.1 kardel }
2835 1.1 kardel
2836 1.1 kardel if (c < ' ') {
2837 1.1 kardel putc('^', fp);
2838 1.1 kardel putc(c + '@', fp);
2839 1.1 kardel } else if (0x7f == c) {
2840 1.1 kardel putc('^', fp);
2841 1.1 kardel putc('?', fp);
2842 1.1 kardel } else
2843 1.1 kardel putc(c, fp);
2844 1.1 kardel }
2845 1.1 kardel }
2846 1.1 kardel
2847 1.1 kardel
2848 1.1 kardel /*
2849 1.1 kardel * asciize - same thing as makeascii except add a newline
2850 1.1 kardel */
2851 1.1 kardel void
2852 1.1 kardel asciize(
2853 1.1 kardel int length,
2854 1.1 kardel char *data,
2855 1.1 kardel FILE *fp
2856 1.1 kardel )
2857 1.1 kardel {
2858 1.1 kardel makeascii(length, data, fp);
2859 1.1 kardel putc('\n', fp);
2860 1.1 kardel }
2861 1.1 kardel
2862 1.1 kardel
2863 1.1 kardel /*
2864 1.4 kardel * truncate string to fit clipping excess at end.
2865 1.4 kardel * "too long" -> "too l"
2866 1.4 kardel * Used for hostnames.
2867 1.4 kardel */
2868 1.4 kardel const char *
2869 1.4 kardel trunc_right(
2870 1.4 kardel const char * src,
2871 1.4 kardel size_t width
2872 1.4 kardel )
2873 1.4 kardel {
2874 1.4 kardel size_t sl;
2875 1.4 kardel char * out;
2876 1.4 kardel
2877 1.4 kardel
2878 1.4 kardel sl = strlen(src);
2879 1.4 kardel if (sl > width && LIB_BUFLENGTH - 1 > width && width > 0) {
2880 1.4 kardel LIB_GETBUF(out);
2881 1.4 kardel memcpy(out, src, width);
2882 1.4 kardel out[width] = '\0';
2883 1.4 kardel
2884 1.4 kardel return out;
2885 1.4 kardel }
2886 1.4 kardel
2887 1.4 kardel return src;
2888 1.4 kardel }
2889 1.4 kardel
2890 1.4 kardel
2891 1.4 kardel /*
2892 1.4 kardel * truncate string to fit by preserving right side and using '_' to hint
2893 1.4 kardel * "too long" -> "_long"
2894 1.4 kardel * Used for local IPv6 addresses, where low bits differentiate.
2895 1.4 kardel */
2896 1.4 kardel const char *
2897 1.4 kardel trunc_left(
2898 1.4 kardel const char * src,
2899 1.4 kardel size_t width
2900 1.4 kardel )
2901 1.4 kardel {
2902 1.4 kardel size_t sl;
2903 1.4 kardel char * out;
2904 1.4 kardel
2905 1.4 kardel
2906 1.4 kardel sl = strlen(src);
2907 1.4 kardel if (sl > width && LIB_BUFLENGTH - 1 > width && width > 1) {
2908 1.4 kardel LIB_GETBUF(out);
2909 1.4 kardel out[0] = '_';
2910 1.4 kardel memcpy(&out[1], &src[sl + 1 - width], width);
2911 1.4 kardel
2912 1.4 kardel return out;
2913 1.4 kardel }
2914 1.4 kardel
2915 1.4 kardel return src;
2916 1.4 kardel }
2917 1.4 kardel
2918 1.4 kardel
2919 1.4 kardel /*
2920 1.1 kardel * Some circular buffer space
2921 1.1 kardel */
2922 1.1 kardel #define CBLEN 80
2923 1.1 kardel #define NUMCB 6
2924 1.1 kardel
2925 1.1 kardel char circ_buf[NUMCB][CBLEN];
2926 1.1 kardel int nextcb = 0;
2927 1.1 kardel
2928 1.1 kardel /*
2929 1.1 kardel * nextvar - find the next variable in the buffer
2930 1.1 kardel */
2931 1.1 kardel int
2932 1.1 kardel nextvar(
2933 1.1 kardel int *datalen,
2934 1.4 kardel const char **datap,
2935 1.1 kardel char **vname,
2936 1.1 kardel char **vvalue
2937 1.1 kardel )
2938 1.1 kardel {
2939 1.4 kardel const char *cp;
2940 1.4 kardel char *np;
2941 1.4 kardel const char *cpend;
2942 1.4 kardel char *npend; /* character after last */
2943 1.1 kardel int quoted = 0;
2944 1.1 kardel static char name[MAXVARLEN];
2945 1.1 kardel static char value[MAXVALLEN];
2946 1.1 kardel
2947 1.1 kardel cp = *datap;
2948 1.1 kardel cpend = cp + *datalen;
2949 1.1 kardel
2950 1.1 kardel /*
2951 1.1 kardel * Space past commas and white space
2952 1.1 kardel */
2953 1.1 kardel while (cp < cpend && (*cp == ',' || isspace((int)*cp)))
2954 1.4 kardel cp++;
2955 1.1 kardel if (cp == cpend)
2956 1.4 kardel return 0;
2957 1.1 kardel
2958 1.1 kardel /*
2959 1.1 kardel * Copy name until we hit a ',', an '=', a '\r' or a '\n'. Backspace
2960 1.1 kardel * over any white space and terminate it.
2961 1.1 kardel */
2962 1.1 kardel np = name;
2963 1.1 kardel npend = &name[MAXVARLEN];
2964 1.1 kardel while (cp < cpend && np < npend && *cp != ',' && *cp != '='
2965 1.1 kardel && *cp != '\r' && *cp != '\n')
2966 1.1 kardel *np++ = *cp++;
2967 1.1 kardel /*
2968 1.1 kardel * Check if we ran out of name space, without reaching the end or a
2969 1.1 kardel * terminating character
2970 1.1 kardel */
2971 1.1 kardel if (np == npend && !(cp == cpend || *cp == ',' || *cp == '=' ||
2972 1.1 kardel *cp == '\r' || *cp == '\n'))
2973 1.1 kardel return 0;
2974 1.1 kardel while (isspace((int)(*(np-1))))
2975 1.1 kardel np--;
2976 1.1 kardel *np = '\0';
2977 1.1 kardel *vname = name;
2978 1.1 kardel
2979 1.1 kardel /*
2980 1.1 kardel * Check if we hit the end of the buffer or a ','. If so we are done.
2981 1.1 kardel */
2982 1.1 kardel if (cp == cpend || *cp == ',' || *cp == '\r' || *cp == '\n') {
2983 1.1 kardel if (cp != cpend)
2984 1.1 kardel cp++;
2985 1.1 kardel *datap = cp;
2986 1.1 kardel *datalen = cpend - cp;
2987 1.1 kardel *vvalue = (char *)0;
2988 1.1 kardel return 1;
2989 1.1 kardel }
2990 1.1 kardel
2991 1.1 kardel /*
2992 1.1 kardel * So far, so good. Copy out the value
2993 1.1 kardel */
2994 1.1 kardel cp++; /* past '=' */
2995 1.1 kardel while (cp < cpend && (isspace((int)*cp) && *cp != '\r' && *cp != '\n'))
2996 1.1 kardel cp++;
2997 1.1 kardel np = value;
2998 1.1 kardel npend = &value[MAXVALLEN];
2999 1.1 kardel while (cp < cpend && np < npend && ((*cp != ',') || quoted))
3000 1.1 kardel {
3001 1.1 kardel quoted ^= ((*np++ = *cp++) == '"');
3002 1.1 kardel }
3003 1.1 kardel
3004 1.1 kardel /*
3005 1.1 kardel * Check if we overran the value buffer while still in a quoted string
3006 1.1 kardel * or without finding a comma
3007 1.1 kardel */
3008 1.1 kardel if (np == npend && (quoted || *cp != ','))
3009 1.1 kardel return 0;
3010 1.1 kardel /*
3011 1.1 kardel * Trim off any trailing whitespace
3012 1.1 kardel */
3013 1.1 kardel while (np > value && isspace((int)(*(np-1))))
3014 1.1 kardel np--;
3015 1.1 kardel *np = '\0';
3016 1.1 kardel
3017 1.1 kardel /*
3018 1.1 kardel * Return this. All done.
3019 1.1 kardel */
3020 1.1 kardel if (cp != cpend)
3021 1.1 kardel cp++;
3022 1.1 kardel *datap = cp;
3023 1.1 kardel *datalen = cpend - cp;
3024 1.1 kardel *vvalue = value;
3025 1.1 kardel return 1;
3026 1.1 kardel }
3027 1.1 kardel
3028 1.1 kardel
3029 1.1 kardel /*
3030 1.1 kardel * findvar - see if this variable is known to us.
3031 1.1 kardel * If "code" is 1, return ctl_var->code.
3032 1.1 kardel * Otherwise return the ordinal position of the found variable.
3033 1.1 kardel */
3034 1.1 kardel int
3035 1.1 kardel findvar(
3036 1.1 kardel char *varname,
3037 1.1 kardel struct ctl_var *varlist,
3038 1.1 kardel int code
3039 1.1 kardel )
3040 1.1 kardel {
3041 1.1 kardel register char *np;
3042 1.1 kardel register struct ctl_var *vl;
3043 1.1 kardel
3044 1.1 kardel vl = varlist;
3045 1.1 kardel np = varname;
3046 1.1 kardel while (vl->fmt != EOV) {
3047 1.1 kardel if (vl->fmt != PADDING && STREQ(np, vl->text))
3048 1.1 kardel return (code)
3049 1.1 kardel ? vl->code
3050 1.1 kardel : (vl - varlist)
3051 1.1 kardel ;
3052 1.1 kardel vl++;
3053 1.1 kardel }
3054 1.1 kardel return 0;
3055 1.1 kardel }
3056 1.1 kardel
3057 1.1 kardel
3058 1.1 kardel
3059 1.1 kardel /*
3060 1.1 kardel * printvars - print variables returned in response packet
3061 1.1 kardel */
3062 1.1 kardel void
3063 1.1 kardel printvars(
3064 1.1 kardel int length,
3065 1.4 kardel const char *data,
3066 1.1 kardel int status,
3067 1.1 kardel int sttype,
3068 1.1 kardel int quiet,
3069 1.1 kardel FILE *fp
3070 1.1 kardel )
3071 1.1 kardel {
3072 1.1 kardel if (rawmode)
3073 1.1 kardel rawprint(sttype, length, data, status, quiet, fp);
3074 1.1 kardel else
3075 1.1 kardel cookedprint(sttype, length, data, status, quiet, fp);
3076 1.1 kardel }
3077 1.1 kardel
3078 1.1 kardel
3079 1.1 kardel /*
3080 1.1 kardel * rawprint - do a printout of the data in raw mode
3081 1.1 kardel */
3082 1.1 kardel static void
3083 1.1 kardel rawprint(
3084 1.1 kardel int datatype,
3085 1.1 kardel int length,
3086 1.4 kardel const char *data,
3087 1.1 kardel int status,
3088 1.1 kardel int quiet,
3089 1.1 kardel FILE *fp
3090 1.1 kardel )
3091 1.1 kardel {
3092 1.4 kardel const char *cp;
3093 1.4 kardel const char *cpend;
3094 1.1 kardel
3095 1.1 kardel /*
3096 1.1 kardel * Essentially print the data as is. We reformat unprintables, though.
3097 1.1 kardel */
3098 1.1 kardel cp = data;
3099 1.1 kardel cpend = data + length;
3100 1.1 kardel
3101 1.1 kardel if (!quiet)
3102 1.1 kardel (void) fprintf(fp, "status=0x%04x,\n", status);
3103 1.1 kardel
3104 1.1 kardel while (cp < cpend) {
3105 1.1 kardel if (*cp == '\r') {
3106 1.1 kardel /*
3107 1.1 kardel * If this is a \r and the next character is a
3108 1.1 kardel * \n, supress this, else pretty print it. Otherwise
3109 1.1 kardel * just output the character.
3110 1.1 kardel */
3111 1.1 kardel if (cp == (cpend - 1) || *(cp + 1) != '\n')
3112 1.1 kardel makeascii(1, cp, fp);
3113 1.2 christos } else if (isspace((unsigned char)*cp) || isprint((unsigned char)*cp))
3114 1.1 kardel putc(*cp, fp);
3115 1.1 kardel else
3116 1.1 kardel makeascii(1, cp, fp);
3117 1.1 kardel cp++;
3118 1.1 kardel }
3119 1.1 kardel }
3120 1.1 kardel
3121 1.1 kardel
3122 1.1 kardel /*
3123 1.1 kardel * Global data used by the cooked output routines
3124 1.1 kardel */
3125 1.1 kardel int out_chars; /* number of characters output */
3126 1.1 kardel int out_linecount; /* number of characters output on this line */
3127 1.1 kardel
3128 1.1 kardel
3129 1.1 kardel /*
3130 1.1 kardel * startoutput - get ready to do cooked output
3131 1.1 kardel */
3132 1.1 kardel static void
3133 1.1 kardel startoutput(void)
3134 1.1 kardel {
3135 1.1 kardel out_chars = 0;
3136 1.1 kardel out_linecount = 0;
3137 1.1 kardel }
3138 1.1 kardel
3139 1.1 kardel
3140 1.1 kardel /*
3141 1.1 kardel * output - output a variable=value combination
3142 1.1 kardel */
3143 1.1 kardel static void
3144 1.1 kardel output(
3145 1.1 kardel FILE *fp,
3146 1.1 kardel char *name,
3147 1.4 kardel const char *value
3148 1.1 kardel )
3149 1.1 kardel {
3150 1.1 kardel size_t len;
3151 1.1 kardel
3152 1.1 kardel /* strlen of "name=value" */
3153 1.1 kardel len = strlen(name) + 1 + strlen(value);
3154 1.1 kardel
3155 1.1 kardel if (out_chars != 0) {
3156 1.1 kardel out_chars += 2;
3157 1.1 kardel if ((out_linecount + len + 2) > MAXOUTLINE) {
3158 1.1 kardel fputs(",\n", fp);
3159 1.1 kardel out_linecount = 0;
3160 1.1 kardel } else {
3161 1.1 kardel fputs(", ", fp);
3162 1.1 kardel out_linecount += 2;
3163 1.1 kardel }
3164 1.1 kardel }
3165 1.1 kardel
3166 1.1 kardel fputs(name, fp);
3167 1.1 kardel putc('=', fp);
3168 1.1 kardel fputs(value, fp);
3169 1.1 kardel out_chars += len;
3170 1.1 kardel out_linecount += len;
3171 1.1 kardel }
3172 1.1 kardel
3173 1.1 kardel
3174 1.1 kardel /*
3175 1.1 kardel * endoutput - terminate a block of cooked output
3176 1.1 kardel */
3177 1.1 kardel static void
3178 1.1 kardel endoutput(
3179 1.1 kardel FILE *fp
3180 1.1 kardel )
3181 1.1 kardel {
3182 1.1 kardel if (out_chars != 0)
3183 1.1 kardel putc('\n', fp);
3184 1.1 kardel }
3185 1.1 kardel
3186 1.1 kardel
3187 1.1 kardel /*
3188 1.1 kardel * outputarr - output an array of values
3189 1.1 kardel */
3190 1.1 kardel static void
3191 1.1 kardel outputarr(
3192 1.1 kardel FILE *fp,
3193 1.1 kardel char *name,
3194 1.1 kardel int narr,
3195 1.1 kardel l_fp *lfp
3196 1.1 kardel )
3197 1.1 kardel {
3198 1.1 kardel register char *bp;
3199 1.1 kardel register char *cp;
3200 1.1 kardel register int i;
3201 1.1 kardel register int len;
3202 1.1 kardel char buf[256];
3203 1.1 kardel
3204 1.1 kardel bp = buf;
3205 1.1 kardel /*
3206 1.1 kardel * Hack to align delay and offset values
3207 1.1 kardel */
3208 1.1 kardel for (i = (int)strlen(name); i < 11; i++)
3209 1.1 kardel *bp++ = ' ';
3210 1.1 kardel
3211 1.1 kardel for (i = narr; i > 0; i--) {
3212 1.1 kardel if (i != narr)
3213 1.1 kardel *bp++ = ' ';
3214 1.1 kardel cp = lfptoms(lfp, 2);
3215 1.1 kardel len = strlen(cp);
3216 1.1 kardel if (len > 7) {
3217 1.1 kardel cp[7] = '\0';
3218 1.1 kardel len = 7;
3219 1.1 kardel }
3220 1.1 kardel while (len < 7) {
3221 1.1 kardel *bp++ = ' ';
3222 1.1 kardel len++;
3223 1.1 kardel }
3224 1.1 kardel while (*cp != '\0')
3225 1.1 kardel *bp++ = *cp++;
3226 1.1 kardel lfp++;
3227 1.1 kardel }
3228 1.1 kardel *bp = '\0';
3229 1.1 kardel output(fp, name, buf);
3230 1.1 kardel }
3231 1.1 kardel
3232 1.1 kardel static char *
3233 1.1 kardel tstflags(
3234 1.1 kardel u_long val
3235 1.1 kardel )
3236 1.1 kardel {
3237 1.4 kardel register char *cp, *s;
3238 1.4 kardel size_t cb;
3239 1.1 kardel register int i;
3240 1.1 kardel register const char *sep;
3241 1.1 kardel
3242 1.1 kardel sep = "";
3243 1.1 kardel i = 0;
3244 1.4 kardel s = cp = circ_buf[nextcb];
3245 1.1 kardel if (++nextcb >= NUMCB)
3246 1.4 kardel nextcb = 0;
3247 1.4 kardel cb = sizeof(circ_buf[0]);
3248 1.1 kardel
3249 1.4 kardel snprintf(cp, cb, "%02lx", val);
3250 1.4 kardel cp += strlen(cp);
3251 1.4 kardel cb -= strlen(cp);
3252 1.1 kardel if (!val) {
3253 1.4 kardel strncat(cp, " ok", cb);
3254 1.4 kardel cp += strlen(cp);
3255 1.4 kardel cb -= strlen(cp);
3256 1.1 kardel } else {
3257 1.4 kardel if (cb) {
3258 1.4 kardel *cp++ = ' ';
3259 1.4 kardel cb--;
3260 1.4 kardel }
3261 1.5 kardel for (i = 0; i < (int)COUNTOF(tstflagnames); i++) {
3262 1.1 kardel if (val & 0x1) {
3263 1.4 kardel snprintf(cp, cb, "%s%s", sep,
3264 1.4 kardel tstflagnames[i]);
3265 1.1 kardel sep = ", ";
3266 1.4 kardel cp += strlen(cp);
3267 1.4 kardel cb -= strlen(cp);
3268 1.1 kardel }
3269 1.1 kardel val >>= 1;
3270 1.1 kardel }
3271 1.1 kardel }
3272 1.4 kardel if (cb)
3273 1.4 kardel *cp = '\0';
3274 1.4 kardel
3275 1.1 kardel return s;
3276 1.1 kardel }
3277 1.1 kardel
3278 1.1 kardel /*
3279 1.1 kardel * cookedprint - output variables in cooked mode
3280 1.1 kardel */
3281 1.1 kardel static void
3282 1.1 kardel cookedprint(
3283 1.1 kardel int datatype,
3284 1.1 kardel int length,
3285 1.4 kardel const char *data,
3286 1.1 kardel int status,
3287 1.1 kardel int quiet,
3288 1.1 kardel FILE *fp
3289 1.1 kardel )
3290 1.1 kardel {
3291 1.1 kardel register int varid;
3292 1.1 kardel char *name;
3293 1.1 kardel char *value;
3294 1.1 kardel char output_raw;
3295 1.1 kardel int fmt;
3296 1.1 kardel struct ctl_var *varlist;
3297 1.1 kardel l_fp lfp;
3298 1.1 kardel long ival;
3299 1.1 kardel sockaddr_u hval;
3300 1.1 kardel u_long uval;
3301 1.1 kardel l_fp lfparr[8];
3302 1.1 kardel int narr;
3303 1.1 kardel
3304 1.1 kardel switch (datatype) {
3305 1.1 kardel case TYPE_PEER:
3306 1.1 kardel varlist = peer_var;
3307 1.1 kardel break;
3308 1.1 kardel case TYPE_SYS:
3309 1.1 kardel varlist = sys_var;
3310 1.1 kardel break;
3311 1.1 kardel case TYPE_CLOCK:
3312 1.1 kardel varlist = clock_var;
3313 1.1 kardel break;
3314 1.1 kardel default:
3315 1.1 kardel fprintf(stderr, "Unknown datatype(0x%x) in cookedprint\n",
3316 1.1 kardel datatype);
3317 1.1 kardel return;
3318 1.1 kardel }
3319 1.1 kardel
3320 1.1 kardel if (!quiet)
3321 1.1 kardel fprintf(fp, "status=%04x %s,\n", status,
3322 1.1 kardel statustoa(datatype, status));
3323 1.1 kardel
3324 1.1 kardel startoutput();
3325 1.1 kardel while (nextvar(&length, &data, &name, &value)) {
3326 1.1 kardel varid = findvar(name, varlist, 0);
3327 1.1 kardel if (varid == 0) {
3328 1.1 kardel output_raw = '*';
3329 1.1 kardel } else {
3330 1.1 kardel output_raw = 0;
3331 1.1 kardel fmt = varlist[varid].fmt;
3332 1.1 kardel switch(fmt) {
3333 1.1 kardel case TS:
3334 1.1 kardel if (!decodets(value, &lfp))
3335 1.1 kardel output_raw = '?';
3336 1.1 kardel else
3337 1.1 kardel output(fp, name, prettydate(&lfp));
3338 1.1 kardel break;
3339 1.1 kardel case FL:
3340 1.1 kardel case FU:
3341 1.1 kardel case FS:
3342 1.1 kardel if (!decodetime(value, &lfp))
3343 1.1 kardel output_raw = '?';
3344 1.1 kardel else {
3345 1.1 kardel switch (fmt) {
3346 1.1 kardel case FL:
3347 1.1 kardel output(fp, name,
3348 1.1 kardel lfptoms(&lfp, 3));
3349 1.1 kardel break;
3350 1.1 kardel case FU:
3351 1.1 kardel output(fp, name,
3352 1.1 kardel ulfptoms(&lfp, 3));
3353 1.1 kardel break;
3354 1.1 kardel case FS:
3355 1.1 kardel output(fp, name,
3356 1.1 kardel lfptoms(&lfp, 3));
3357 1.1 kardel break;
3358 1.1 kardel }
3359 1.1 kardel }
3360 1.1 kardel break;
3361 1.1 kardel
3362 1.1 kardel case UI:
3363 1.1 kardel if (!decodeuint(value, &uval))
3364 1.1 kardel output_raw = '?';
3365 1.1 kardel else
3366 1.1 kardel output(fp, name, uinttoa(uval));
3367 1.1 kardel break;
3368 1.1 kardel
3369 1.1 kardel case SI:
3370 1.1 kardel if (!decodeint(value, &ival))
3371 1.1 kardel output_raw = '?';
3372 1.1 kardel else
3373 1.1 kardel output(fp, name, inttoa(ival));
3374 1.1 kardel break;
3375 1.1 kardel
3376 1.1 kardel case HA:
3377 1.1 kardel case NA:
3378 1.1 kardel if (!decodenetnum(value, &hval))
3379 1.1 kardel output_raw = '?';
3380 1.1 kardel else if (fmt == HA){
3381 1.1 kardel output(fp, name, nntohost(&hval));
3382 1.1 kardel } else {
3383 1.1 kardel output(fp, name, stoa(&hval));
3384 1.1 kardel }
3385 1.1 kardel break;
3386 1.1 kardel
3387 1.1 kardel case ST:
3388 1.1 kardel output_raw = '*';
3389 1.1 kardel break;
3390 1.1 kardel
3391 1.1 kardel case RF:
3392 1.1 kardel if (decodenetnum(value, &hval)) {
3393 1.1 kardel if (ISREFCLOCKADR(&hval))
3394 1.1 kardel output(fp, name,
3395 1.1 kardel refnumtoa(&hval));
3396 1.1 kardel else
3397 1.1 kardel output(fp, name, stoa(&hval));
3398 1.1 kardel } else if ((int)strlen(value) <= 4)
3399 1.1 kardel output(fp, name, value);
3400 1.1 kardel else
3401 1.1 kardel output_raw = '?';
3402 1.1 kardel break;
3403 1.1 kardel
3404 1.1 kardel case LP:
3405 1.1 kardel if (!decodeuint(value, &uval) || uval > 3)
3406 1.1 kardel output_raw = '?';
3407 1.1 kardel else {
3408 1.1 kardel char b[3];
3409 1.1 kardel b[0] = b[1] = '0';
3410 1.1 kardel if (uval & 0x2)
3411 1.1 kardel b[0] = '1';
3412 1.1 kardel if (uval & 0x1)
3413 1.1 kardel b[1] = '1';
3414 1.1 kardel b[2] = '\0';
3415 1.1 kardel output(fp, name, b);
3416 1.1 kardel }
3417 1.1 kardel break;
3418 1.1 kardel
3419 1.1 kardel case OC:
3420 1.1 kardel if (!decodeuint(value, &uval))
3421 1.1 kardel output_raw = '?';
3422 1.1 kardel else {
3423 1.1 kardel char b[12];
3424 1.1 kardel
3425 1.1 kardel (void) snprintf(b, sizeof b, "%03lo", uval);
3426 1.1 kardel output(fp, name, b);
3427 1.1 kardel }
3428 1.1 kardel break;
3429 1.1 kardel
3430 1.1 kardel case MD:
3431 1.1 kardel if (!decodeuint(value, &uval))
3432 1.1 kardel output_raw = '?';
3433 1.1 kardel else
3434 1.1 kardel output(fp, name, uinttoa(uval));
3435 1.1 kardel break;
3436 1.1 kardel
3437 1.1 kardel case AR:
3438 1.1 kardel if (!decodearr(value, &narr, lfparr))
3439 1.1 kardel output_raw = '?';
3440 1.1 kardel else
3441 1.1 kardel outputarr(fp, name, narr, lfparr);
3442 1.1 kardel break;
3443 1.1 kardel
3444 1.1 kardel case FX:
3445 1.1 kardel if (!decodeuint(value, &uval))
3446 1.1 kardel output_raw = '?';
3447 1.1 kardel else
3448 1.1 kardel output(fp, name, tstflags(uval));
3449 1.1 kardel break;
3450 1.1 kardel
3451 1.1 kardel default:
3452 1.1 kardel (void) fprintf(stderr,
3453 1.1 kardel "Internal error in cookedprint, %s=%s, fmt %d\n",
3454 1.1 kardel name, value, fmt);
3455 1.1 kardel break;
3456 1.1 kardel }
3457 1.1 kardel
3458 1.1 kardel }
3459 1.1 kardel if (output_raw != 0) {
3460 1.1 kardel char bn[401];
3461 1.1 kardel char bv[401];
3462 1.1 kardel int len;
3463 1.1 kardel
3464 1.1 kardel atoascii(name, MAXVARLEN, bn, sizeof(bn));
3465 1.1 kardel atoascii(value, MAXVARLEN, bv, sizeof(bv));
3466 1.1 kardel if (output_raw != '*') {
3467 1.1 kardel len = strlen(bv);
3468 1.1 kardel bv[len] = output_raw;
3469 1.1 kardel bv[len+1] = '\0';
3470 1.1 kardel }
3471 1.1 kardel output(fp, bn, bv);
3472 1.1 kardel }
3473 1.1 kardel }
3474 1.1 kardel endoutput(fp);
3475 1.1 kardel }
3476 1.1 kardel
3477 1.1 kardel
3478 1.1 kardel /*
3479 1.1 kardel * sortassoc - sort associations in the cache into ascending order
3480 1.1 kardel */
3481 1.1 kardel void
3482 1.1 kardel sortassoc(void)
3483 1.1 kardel {
3484 1.1 kardel if (numassoc > 1)
3485 1.4 kardel qsort((void *)assoc_cache, (size_t)numassoc,
3486 1.4 kardel sizeof(assoc_cache[0]), assoccmp);
3487 1.1 kardel }
3488 1.1 kardel
3489 1.1 kardel
3490 1.1 kardel /*
3491 1.1 kardel * assoccmp - compare two associations
3492 1.1 kardel */
3493 1.1 kardel static int
3494 1.1 kardel assoccmp(
3495 1.1 kardel const void *t1,
3496 1.1 kardel const void *t2
3497 1.1 kardel )
3498 1.1 kardel {
3499 1.4 kardel const struct association *ass1 = t1;
3500 1.4 kardel const struct association *ass2 = t2;
3501 1.1 kardel
3502 1.1 kardel if (ass1->assid < ass2->assid)
3503 1.1 kardel return -1;
3504 1.1 kardel if (ass1->assid > ass2->assid)
3505 1.1 kardel return 1;
3506 1.1 kardel return 0;
3507 1.1 kardel }
3508 1.4 kardel
3509 1.1 kardel
3510 1.1 kardel /*
3511 1.1 kardel * ntpq_custom_opt_handler - autoopts handler for -c and -p
3512 1.1 kardel *
3513 1.1 kardel * By default, autoopts loses the relative order of -c and -p options
3514 1.1 kardel * on the command line. This routine replaces the default handler for
3515 1.1 kardel * those routines and builds a list of commands to execute preserving
3516 1.1 kardel * the order.
3517 1.1 kardel */
3518 1.1 kardel void
3519 1.1 kardel ntpq_custom_opt_handler(
3520 1.1 kardel tOptions *pOptions,
3521 1.1 kardel tOptDesc *pOptDesc
3522 1.1 kardel )
3523 1.1 kardel {
3524 1.1 kardel switch (pOptDesc->optValue) {
3525 1.1 kardel
3526 1.1 kardel default:
3527 1.1 kardel fprintf(stderr,
3528 1.1 kardel "ntpq_custom_opt_handler unexpected option '%c' (%d)\n",
3529 1.1 kardel pOptDesc->optValue, pOptDesc->optValue);
3530 1.1 kardel exit(-1);
3531 1.1 kardel
3532 1.1 kardel case 'c':
3533 1.1 kardel ADDCMD(pOptDesc->pzLastArg);
3534 1.1 kardel break;
3535 1.1 kardel
3536 1.1 kardel case 'p':
3537 1.1 kardel ADDCMD("peers");
3538 1.1 kardel break;
3539 1.1 kardel }
3540 1.1 kardel }
3541