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