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