1 /* $NetBSD: ntpq.c,v 1.12 2009/04/17 02:45:55 christos Exp $ */
4 * ntpq - query an NTP server using mode 6 commands
12 #include <sys/types.h>
16 #include "ntp_unixtime.h"
17 #include "ntp_calendar.h"
19 #include "ntp_select.h"
20 #include "ntp_stdlib.h"
21 /* Don't include ISC's version of IPv6 variables and structures */
24 #include "isc/result.h"
26 #include "ntpq-opts.h"
32 # define closesocket close
33 #endif /* SYS_WINNT */
35 #if defined(HAVE_LIBREADLINE) || defined(HAVE_LIBEDIT)
36 # include <readline/readline.h>
37 # include <readline/history.h>
38 #endif /* HAVE_LIBREADLINE || HAVE_LIBEDIT */
41 /* vxWorks needs mode flag -casey*/
42 # define open(name, flags) open(name, flags, 0777)
43 # define SERVER_PORT_NUM 123
46 /* we use COMMAND as an autogen keyword */
52 * Because we potentially understand a lot of commands we will run
53 * interactive if connected to a terminal.
55 int interactive
= 0; /* set to 1 when we should prompt */
56 const char *prompt
= "ntpq> "; /* prompt to ask him about */
62 s_char sys_precision
; /* local clock precision (log2 s) */
65 * Keyid used for authenticated requests. Obtained on the fly.
67 u_long info_auth_keyid
= 0;
72 #define KEY_TYPE_MD5 4
74 static int info_auth_keytype
= KEY_TYPE_MD5
; /* MD5 */
75 u_long current_time
; /* needed by authkeys; not used */
78 * Flag which indicates we should always send authenticated requests
83 * Flag which indicates raw mode output.
88 * Packet version number we use
90 u_char pktversion
= NTP_OLDVERSION
+ 1;
93 * Don't jump if no set jmp.
95 volatile int jump
= 0;
101 #define TS 1 /* time stamp */
102 #define FL 2 /* l_fp type value */
103 #define FU 3 /* u_fp type value */
104 #define FS 4 /* s_fp type value */
105 #define UI 5 /* unsigned integer value */
106 #define SI 6 /* signed integer value */
107 #define HA 7 /* host address */
108 #define NA 8 /* network address */
109 #define ST 9 /* string value */
110 #define RF 10 /* refid (sometimes string, sometimes not) */
111 #define LP 11 /* leap (print in binary) */
112 #define OC 12 /* integer, print in octal */
113 #define MD 13 /* mode */
114 #define AR 14 /* array of times */
115 #define FX 15 /* test flags */
116 #define EOV 255 /* end of table */
120 * System variable values. The array can be indexed by
121 * the variable index to find the textual name.
123 struct ctl_var sys_var
[] = {
124 { 0, PADDING
, "" }, /* 0 */
125 { CS_LEAP
, LP
, "leap" }, /* 1 */
126 { CS_STRATUM
, UI
, "stratum" }, /* 2 */
127 { CS_PRECISION
, SI
, "precision" }, /* 3 */
128 { CS_ROOTDELAY
, FS
, "rootdelay" }, /* 4 */
129 { CS_ROOTDISPERSION
, FU
, "rootdispersion" }, /* 5 */
130 { CS_REFID
, RF
, "refid" }, /* 6 */
131 { CS_REFTIME
, TS
, "reftime" }, /* 7 */
132 { CS_POLL
, UI
, "poll" }, /* 8 */
133 { CS_PEERID
, UI
, "peer" }, /* 9 */
134 { CS_STATE
, UI
, "state" }, /* 10 */
135 { CS_OFFSET
, FL
, "offset" }, /* 11 */
136 { CS_DRIFT
, FS
, "frequency" }, /* 12 */
137 { CS_JITTER
, FU
, "jitter" }, /* 13 */
138 { CS_CLOCK
, TS
, "clock" }, /* 14 */
139 { CS_PROCESSOR
, ST
, "processor" }, /* 15 */
140 { CS_SYSTEM
, ST
, "system" }, /* 16 */
141 { CS_VERSION
, ST
, "version" }, /* 17 */
142 { CS_STABIL
, FS
, "stability" }, /* 18 */
143 { CS_VARLIST
, ST
, "sys_var_list" }, /* 19 */
151 struct ctl_var peer_var
[] = {
152 { 0, PADDING
, "" }, /* 0 */
153 { CP_CONFIG
, UI
, "config" }, /* 1 */
154 { CP_AUTHENABLE
, UI
, "authenable" }, /* 2 */
155 { CP_AUTHENTIC
, UI
, "authentic" }, /* 3 */
156 { CP_SRCADR
, HA
, "srcadr" }, /* 4 */
157 { CP_SRCPORT
, UI
, "srcport" }, /* 5 */
158 { CP_DSTADR
, NA
, "dstadr" }, /* 6 */
159 { CP_DSTPORT
, UI
, "dstport" }, /* 7 */
160 { CP_LEAP
, LP
, "leap" }, /* 8 */
161 { CP_HMODE
, MD
, "hmode" }, /* 9 */
162 { CP_STRATUM
, UI
, "stratum" }, /* 10 */
163 { CP_PPOLL
, UI
, "ppoll" }, /* 11 */
164 { CP_HPOLL
, UI
, "hpoll" }, /* 12 */
165 { CP_PRECISION
, SI
, "precision" }, /* 13 */
166 { CP_ROOTDELAY
, FS
, "rootdelay" }, /* 14 */
167 { CP_ROOTDISPERSION
, FU
, "rootdispersion" }, /* 15 */
168 { CP_REFID
, RF
, "refid" }, /* 16 */
169 { CP_REFTIME
, TS
, "reftime" }, /* 17 */
170 { CP_ORG
, TS
, "org" }, /* 18 */
171 { CP_REC
, TS
, "rec" }, /* 19 */
172 { CP_XMT
, TS
, "xmt" }, /* 20 */
173 { CP_REACH
, OC
, "reach" }, /* 21 */
174 { CP_UNREACH
, UI
, "unreach" }, /* 22 */
175 { CP_TIMER
, UI
, "timer" }, /* 23 */
176 { CP_DELAY
, FS
, "delay" }, /* 24 */
177 { CP_OFFSET
, FL
, "offset" }, /* 25 */
178 { CP_JITTER
, FU
, "jitter" }, /* 26 */
179 { CP_DISPERSION
, FU
, "dispersion" }, /* 27 */
180 { CP_KEYID
, UI
, "keyid" }, /* 28 */
181 { CP_FILTDELAY
, AR
, "filtdelay" }, /* 29 */
182 { CP_FILTOFFSET
, AR
, "filtoffset" }, /* 30 */
183 { CP_PMODE
, ST
, "pmode" }, /* 31 */
184 { CP_RECEIVED
, UI
, "received" }, /* 32 */
185 { CP_SENT
, UI
, "sent" }, /* 33 */
186 { CP_FILTERROR
, AR
, "filtdisp" }, /* 34 */
187 { CP_FLASH
, FX
, "flash" }, /* 35 */
188 { CP_TTL
, UI
, "ttl" }, /* 36 */
190 * These are duplicate entries so that we can
191 * process deviant version of the ntp protocol.
193 { CP_SRCADR
, HA
, "peeraddr" }, /* 4 */
194 { CP_SRCPORT
, UI
, "peerport" }, /* 5 */
195 { CP_PPOLL
, UI
, "peerpoll" }, /* 11 */
196 { CP_HPOLL
, UI
, "hostpoll" }, /* 12 */
197 { CP_FILTERROR
, AR
, "filterror" }, /* 34 */
203 * Clock variable list
205 struct ctl_var clock_var
[] = {
206 { 0, PADDING
, "" }, /* 0 */
207 { CC_TYPE
, UI
, "type" }, /* 1 */
208 { CC_TIMECODE
, ST
, "timecode" }, /* 2 */
209 { CC_POLL
, UI
, "poll" }, /* 3 */
210 { CC_NOREPLY
, UI
, "noreply" }, /* 4 */
211 { CC_BADFORMAT
, UI
, "badformat" }, /* 5 */
212 { CC_BADDATA
, UI
, "baddata" }, /* 6 */
213 { CC_FUDGETIME1
, FL
, "fudgetime1" }, /* 7 */
214 { CC_FUDGETIME2
, FL
, "fudgetime2" }, /* 8 */
215 { CC_FUDGEVAL1
, UI
, "stratum" }, /* 9 */
216 { CC_FUDGEVAL2
, RF
, "refid" }, /* 10 */
217 { CC_FLAGS
, UI
, "flags" }, /* 11 */
218 { CC_DEVICE
, ST
, "device" }, /* 12 */
226 static const char *tstflagnames
[] = {
227 "pkt_dup", /* TEST1 */
228 "pkt_bogus", /* TEST2 */
229 "pkt_proto", /* TEST3 */
230 "pkt_denied", /* TEST4 */
231 "pkt_auth", /* TEST5 */
232 "pkt_synch", /* TEST6 */
233 "pkt_dist", /* TEST7 */
234 "pkt_autokey", /* TEST8 */
235 "pkt_crypto", /* TEST9 */
236 "peer_stratum", /* TEST10 */
237 "peer_dist", /* TEST11 */
238 "peer_loop", /* TEST12 */
239 "peer_unfit" /* TEST13 */
243 int ntpqmain
P((int, char **));
245 * Built in command handler declarations
247 static int openhost
P((const char *));
248 static int sendpkt
P((char *, int));
249 static int getresponse
P((int, int, u_short
*, int *, char **, int));
250 static int sendrequest
P((int, int, int, int, char *));
251 static char * tstflags
P((u_long
));
252 static void getcmds
P((void));
253 static RETSIGTYPE abortcmd
P((int));
254 static void docmd
P((const char *));
255 static void tokenize
P((const char *, char **, int *));
256 static int findcmd
P((char *, struct xcmd
*, struct xcmd
*, struct xcmd
**));
257 static int getarg
P((char *, int, arg_v
*));
258 static int rtdatetolfp
P((char *, l_fp
*));
259 static int decodearr
P((char *, int *, l_fp
*));
260 static void help
P((struct parse
*, FILE *));
261 #ifdef QSORT_USES_VOID_P
262 static int helpsort
P((const void *, const void *));
264 static int helpsort
P((char **, char **));
266 static void printusage
P((struct xcmd
*, FILE *));
267 static void timeout
P((struct parse
*, FILE *));
268 static void auth_delay
P((struct parse
*, FILE *));
269 static void host
P((struct parse
*, FILE *));
270 static void ntp_poll
P((struct parse
*, FILE *));
271 static void keyid
P((struct parse
*, FILE *));
272 static void keytype
P((struct parse
*, FILE *));
273 static void passwd
P((struct parse
*, FILE *));
274 static void hostnames
P((struct parse
*, FILE *));
275 static void setdebug
P((struct parse
*, FILE *));
276 static void quit
P((struct parse
*, FILE *));
277 static void version
P((struct parse
*, FILE *));
278 static void raw
P((struct parse
*, FILE *));
279 static void cooked
P((struct parse
*, FILE *));
280 static void authenticate
P((struct parse
*, FILE *));
281 static void ntpversion
P((struct parse
*, FILE *));
282 static void warning
P((const char *, const char *, const char *));
283 static void error
P((const char *, const char *, const char *));
284 static u_long getkeyid
P((const char *));
285 static void atoascii
P((int, char *, char *));
286 static void makeascii
P((int, char *, FILE *));
287 static void rawprint
P((int, int, char *, int, FILE *));
288 static void startoutput
P((void));
289 static void output
P((FILE *, char *, char *));
290 static void endoutput
P((FILE *));
291 static void outputarr
P((FILE *, char *, int, l_fp
*));
292 static void cookedprint
P((int, int, char *, int, FILE *));
293 #ifdef QSORT_USES_VOID_P
294 static int assoccmp
P((const void *, const void *));
296 static int assoccmp
P((struct association
*, struct association
*));
297 #endif /* sgi || bsdi */
301 * Built-in commands we understand
303 struct xcmd builtins
[] = {
304 { "?", help
, { OPT
|NTP_STR
, NO
, NO
, NO
},
305 { "command", "", "", "" },
306 "tell the use and syntax of commands" },
307 { "help", help
, { OPT
|NTP_STR
, NO
, NO
, NO
},
308 { "command", "", "", "" },
309 "tell the use and syntax of commands" },
310 { "timeout", timeout
, { OPT
|NTP_UINT
, NO
, NO
, NO
},
311 { "msec", "", "", "" },
312 "set the primary receive time out" },
313 { "delay", auth_delay
, { OPT
|NTP_INT
, NO
, NO
, NO
},
314 { "msec", "", "", "" },
315 "set the delay added to encryption time stamps" },
316 { "host", host
, { OPT
|NTP_STR
, OPT
|NTP_STR
, NO
, NO
},
317 { "-4|-6", "hostname", "", "" },
318 "specify the host whose NTP server we talk to" },
319 { "poll", ntp_poll
, { OPT
|NTP_UINT
, OPT
|NTP_STR
, NO
, NO
},
320 { "n", "verbose", "", "" },
321 "poll an NTP server in client mode `n' times" },
322 { "passwd", passwd
, { NO
, NO
, NO
, NO
},
324 "specify a password to use for authenticated requests"},
325 { "hostnames", hostnames
, { OPT
|NTP_STR
, NO
, NO
, NO
},
326 { "yes|no", "", "", "" },
327 "specify whether hostnames or net numbers are printed"},
328 { "debug", setdebug
, { OPT
|NTP_STR
, NO
, NO
, NO
},
329 { "no|more|less", "", "", "" },
330 "set/change debugging level" },
331 { "quit", quit
, { NO
, NO
, NO
, NO
},
334 { "exit", quit
, { NO
, NO
, NO
, NO
},
337 { "keyid", keyid
, { OPT
|NTP_UINT
, NO
, NO
, NO
},
338 { "key#", "", "", "" },
339 "set keyid to use for authenticated requests" },
340 { "version", version
, { NO
, NO
, NO
, NO
},
342 "print version number" },
343 { "raw", raw
, { NO
, NO
, NO
, NO
},
345 "do raw mode variable output" },
346 { "cooked", cooked
, { NO
, NO
, NO
, NO
},
348 "do cooked mode variable output" },
349 { "authenticate", authenticate
, { OPT
|NTP_STR
, NO
, NO
, NO
},
350 { "yes|no", "", "", "" },
351 "always authenticate requests to this server" },
352 { "ntpversion", ntpversion
, { OPT
|NTP_UINT
, NO
, NO
, NO
},
353 { "version number", "", "", "" },
354 "set the NTP version number to use for requests" },
355 { "keytype", keytype
, { OPT
|NTP_STR
, NO
, NO
, NO
},
356 { "key type (md5|des)", "", "", "" },
357 "set key type to use for authenticated requests (des|md5)" },
358 { 0, 0, { NO
, NO
, NO
, NO
},
359 { "", "", "", "" }, "" }
364 * Default values we use.
366 #define DEFTIMEOUT (5) /* 5 second time out */
367 #define DEFSTIMEOUT (2) /* 2 second time out after first */
368 #define DEFDELAY 0x51EB852 /* 20 milliseconds, l_fp fraction */
369 #define DEFHOST "localhost" /* default host name */
370 #define LENHOSTNAME 256 /* host name is 256 characters long */
371 #define MAXCMDS 100 /* maximum commands on cmd line */
372 #define MAXHOSTS 200 /* maximum hosts on cmd line */
373 #define MAXLINE 512 /* maximum line length */
374 #define MAXTOKENS (1+MAXARGS+2) /* maximum number of usable tokens */
375 #define MAXVARLEN 256 /* maximum length of a variable name */
376 #define MAXVALLEN 400 /* maximum length of a variable value */
377 #define MAXOUTLINE 72 /* maximum length of an output line */
378 #define SCREENWIDTH 76 /* nominal screen width in columns */
381 * Some variables used and manipulated locally
383 struct timeval tvout
= { DEFTIMEOUT
, 0 }; /* time out for reads */
384 struct timeval tvsout
= { DEFSTIMEOUT
, 0 }; /* secondary time out */
385 l_fp delay_time
; /* delay time */
386 char currenthost
[LENHOSTNAME
]; /* current host name */
387 struct sockaddr_in hostaddr
= { 0 }; /* host address */
388 int showhostnames
= 1; /* show host names by default */
390 int ai_fam_templ
; /* address family */
391 int ai_fam_default
; /* default address family */
392 SOCKET sockfd
; /* fd socket is opened on */
393 int havehost
= 0; /* set to 1 when host open */
395 struct servent
*server_entry
= NULL
; /* server entry for ntp */
398 DWORD NumberOfBytesWritten
;
400 HANDLE TimerThreadHandle
= NULL
; /* 1998/06/03 - Used in ntplib/machines.c */
401 void timer(void) { ; }; /* 1998/06/03 - Used in ntplib/machines.c */
403 #endif /* SYS_WINNT */
406 * Sequence number used for requests. It is incremented before
412 * Holds data returned from queries. Declare buffer long to be sure of
415 #define MAXFRAGS 24 /* maximum number of fragments */
416 #define DATASIZE (MAXFRAGS*480) /* maximum amount of data */
417 long pktdata
[DATASIZE
/sizeof(long)];
420 * Holds association data for use with the &n operator.
422 struct association assoc_cache
[MAXASSOC
];
423 int numassoc
= 0; /* number of cached associations */
426 * For commands typed on the command line (with the -c option)
429 const char *ccmds
[MAXCMDS
];
430 #define ADDCMD(cp) if (numcmds < MAXCMDS) ccmds[numcmds++] = (cp)
433 * When multiple hosts are specified.
436 const char *chosts
[MAXHOSTS
];
437 #define ADDHOST(cp) if (numhosts < MAXHOSTS) chosts[numhosts++] = (cp)
440 * Error codes for internal use
442 #define ERR_UNSPEC 256
443 #define ERR_INCOMPLETE 257
444 #define ERR_TIMEOUT 258
445 #define ERR_TOOMUCH 259
448 * Macro definitions we use
450 #define ISSPACE(c) ((c) == ' ' || (c) == '\t')
451 #define ISEOL(c) ((c) == '\n' || (c) == '\r' || (c) == '\0')
452 #define STREQ(a, b) (*(a) == *(b) && strcmp((a), (b)) == 0)
455 * Jump buffer for longjumping back to the command level
457 jmp_buf interrupt_buf
;
460 * Points at file being currently printed into
462 FILE *current_output
;
465 * Command table imported from ntpdc_ops.c
467 extern struct xcmd opcmds
[];
472 #ifdef NO_MAIN_ALLOWED
473 CALL(ntpq
,"ntpq",ntpqmain
);
475 void clear_globals(void)
477 extern int ntp_optind
;
478 showhostnames
= 0; /* don'tshow host names by default */
480 server_entry
= NULL
; /* server entry for ntp */
481 havehost
= 0; /* set to 1 when host open */
482 numassoc
= 0; /* number of cached associations */
489 * main - parse arguments and handle options
491 #ifndef NO_MAIN_ALLOWED
498 return ntpqmain(argc
, argv
);
508 extern int ntp_optind
;
512 taskPrioritySet(taskIdSelf(), 100 );
516 delay_time
.l_uf
= DEFDELAY
;
519 if (!Win32InitSockets())
521 fprintf(stderr
, "No useable winsock.dll:");
524 #endif /* SYS_WINNT */
526 /* Check to see if we have IPv6. Otherwise force the -4 flag */
527 if (isc_net_probeipv6() != ISC_R_SUCCESS
) {
528 ai_fam_default
= AF_INET
;
534 int optct
= optionProcess(&ntpqOptions
, argc
, argv
);
539 switch (WHICH_IDX_IPV4
) {
541 ai_fam_templ
= AF_INET
;
544 ai_fam_templ
= AF_INET6
;
547 ai_fam_templ
= ai_fam_default
;
551 if (HAVE_OPT(COMMAND
)) {
552 int cmdct
= STACKCT_OPT( COMMAND
);
553 const char** cmds
= STACKLST_OPT( COMMAND
);
555 while (cmdct
-- > 0) {
560 debug
= DESC(DEBUG_LEVEL
).optOccCt
;
562 if (HAVE_OPT(INTERACTIVE
)) {
566 if (HAVE_OPT(NUMERIC
)) {
570 if (HAVE_OPT(PEERS
)) {
575 while ((c
= ntp_getopt(argc
, argv
, "46c:dinp")) != EOF
)
578 ai_fam_templ
= AF_INET
;
581 ai_fam_templ
= AF_INET6
;
603 (void) fprintf(stderr
,
604 "usage: %s [-46dinp] [-c cmd] host ...\n",
609 if (ntp_optind
== argc
) {
612 for (; ntp_optind
< argc
; ntp_optind
++)
613 ADDHOST(argv
[ntp_optind
]);
616 if (numcmds
== 0 && interactive
== 0
617 && isatty(fileno(stdin
)) && isatty(fileno(stderr
))) {
621 #ifndef SYS_WINNT /* Under NT cannot handle SIGINT, WIN32 spawns a handler */
623 (void) signal_no_reset(SIGINT
, abortcmd
);
624 #endif /* SYS_WINNT */
627 (void) openhost(chosts
[0]);
633 for (ihost
= 0; ihost
< numhosts
; ihost
++) {
634 if (openhost(chosts
[ihost
]))
635 for (icmd
= 0; icmd
< numcmds
; icmd
++)
641 #endif /* SYS_WINNT */
647 * openhost - open a socket to a host
654 char temphost
[LENHOSTNAME
];
656 struct addrinfo hints
, *ai
= NULL
;
657 register const char *cp
;
658 char name
[LENHOSTNAME
];
662 * We need to get by the [] if they were entered
669 for(i
= 0; *cp
!= ']'; cp
++, i
++)
676 * First try to resolve it as an ip address and if that fails,
677 * do a fullblown (dns) lookup. That way we only use the dns
678 * when it is needed and work around some implementations that
679 * will return an "IPv4-mapped IPv6 address" address if you
680 * give it an IPv4 address to lookup.
682 strcpy(service
, "ntp");
683 memset((char *)&hints
, 0, sizeof(struct addrinfo
));
684 hints
.ai_family
= ai_fam_templ
;
685 hints
.ai_protocol
= IPPROTO_UDP
;
686 hints
.ai_socktype
= SOCK_DGRAM
;
687 hints
.ai_flags
= AI_NUMERICHOST
;
689 a_info
= getaddrinfo(hname
, service
, &hints
, &ai
);
690 if (a_info
== EAI_NONAME
692 || a_info
== EAI_NODATA
695 hints
.ai_flags
= AI_CANONNAME
;
697 hints
.ai_flags
|= AI_ADDRCONFIG
;
699 a_info
= getaddrinfo(hname
, service
, &hints
, &ai
);
701 /* Some older implementations don't like AI_ADDRCONFIG. */
702 if (a_info
== EAI_BADFLAGS
) {
703 hints
.ai_flags
= AI_CANONNAME
;
704 a_info
= getaddrinfo(hname
, service
, &hints
, &ai
);
707 (void) fprintf(stderr
, "%s\n", gai_strerror(a_info
));
711 if (ai
->ai_canonname
== NULL
) {
712 strncpy(temphost
, stoa((struct sockaddr_storage
*)ai
->ai_addr
),
714 temphost
[LENHOSTNAME
-1] = '\0';
717 strncpy(temphost
, ai
->ai_canonname
, LENHOSTNAME
);
718 temphost
[LENHOSTNAME
-1] = '\0';
722 printf("Opening host %s\n", temphost
);
726 printf("Closing old host %s\n", currenthost
);
727 (void) closesocket(sockfd
);
730 (void) strcpy(currenthost
, temphost
);
732 /* port maps to the same location in both families */
733 s_port
= ((struct sockaddr_in6
*)ai
->ai_addr
)->sin6_port
;
735 ((struct sockaddr_in6
*)&hostaddr
)->sin6_port
= htons(SERVER_PORT_NUM
);
736 if (ai
->ai_family
== AF_INET
)
737 *(struct sockaddr_in
*)&hostaddr
=
738 *((struct sockaddr_in
*)ai
->ai_addr
);
740 *(struct sockaddr_in6
*)&hostaddr
=
741 *((struct sockaddr_in6
*)ai
->ai_addr
);
742 #endif /* SYS_VXWORKS */
746 int optionValue
= SO_SYNCHRONOUS_NONALERT
;
749 err
= setsockopt(INVALID_SOCKET
, SOL_SOCKET
, SO_OPENTYPE
, (char *)&optionValue
, sizeof(optionValue
));
750 if (err
!= NO_ERROR
) {
751 (void) fprintf(stderr
, "cannot open nonoverlapped sockets\n");
755 #endif /* SYS_WINNT */
757 sockfd
= socket(ai
->ai_family
, SOCK_DGRAM
, 0);
758 if (sockfd
== INVALID_SOCKET
) {
759 error("socket", "", "");
763 #ifdef NEED_RCVBUF_SLOP
765 { int rbufsize
= DATASIZE
+ 2048; /* 2K for slop */
766 if (setsockopt(sockfd
, SOL_SOCKET
, SO_RCVBUF
,
767 &rbufsize
, sizeof(int)) == -1)
768 error("setsockopt", "", "");
774 if (connect(sockfd
, (struct sockaddr
*)&hostaddr
,
775 sizeof(hostaddr
)) == -1)
777 if (connect(sockfd
, (struct sockaddr
*)ai
->ai_addr
,
778 ai
->ai_addrlen
) == -1)
779 #endif /* SYS_VXWORKS */
780 error("connect", "", "");
788 /* XXX ELIMINATE sendpkt similar in ntpq.c, ntpdc.c, ntp_io.c, ntptrace.c */
790 * sendpkt - send a packet to the remote host
799 printf("Sending %d octets\n", xdatalen
);
802 if (send(sockfd
, xdata
, (size_t)xdatalen
, 0) == -1) {
803 warning("write to %s failed", currenthost
, "");
809 printf("Packet data:\n");
810 while (xdatalen
-- > 0) {
815 printf(" %02x", *xdata
++ & 0xff);
825 * getresponse - get a (series of) response packet(s) and return the data
837 struct ntp_control rpkt
;
839 u_short offsets
[MAXFRAGS
+1];
840 u_short counts
[MAXFRAGS
+1];
849 * This is pretty tricky. We may get between 1 and MAXFRAG packets
850 * back in response to the request. We peel the data out of
851 * each packet and collect it in one long block. When the last
852 * packet in the sequence is received we'll know how much data we
853 * should have had. Note we use one long time out, should reconsider.
858 *rdata
= (char *)pktdata
;
871 FD_SET(sockfd
, &fds
);
872 n
= select(sockfd
+1, &fds
, (fd_set
*)0, (fd_set
*)0, &tvo
);
876 printf("select() returns %d\n", n
);
880 warning("select fails", "", "");
885 * Timed out. Return what we have
889 (void) fprintf(stderr
,
890 "%s: timed out, nothing received\n",
895 (void) fprintf(stderr
,
896 "%s: timed out with incomplete data\n",
899 printf("Received fragments:\n");
900 for (n
= 0; n
< numfrags
; n
++)
901 printf("%4d %d\n", offsets
[n
],
904 printf("last fragment received\n");
906 printf("last fragment not received\n");
908 return ERR_INCOMPLETE
;
912 n
= recv(sockfd
, (char *)&rpkt
, sizeof(rpkt
), 0);
914 warning("read", "", "");
919 int len
= n
, first
= 8;
920 char *data
= (char *)&rpkt
;
922 printf("Packet data:\n");
928 printf(" %02x", *data
++ & 0xff);
934 * Check for format errors. Bug proofing.
936 if (n
< CTL_HEADER_LEN
) {
938 printf("Short (%d byte) packet received\n", n
);
941 if (PKT_VERSION(rpkt
.li_vn_mode
) > NTP_VERSION
942 || PKT_VERSION(rpkt
.li_vn_mode
) < NTP_OLDVERSION
) {
944 printf("Packet received with version %d\n",
945 PKT_VERSION(rpkt
.li_vn_mode
));
948 if (PKT_MODE(rpkt
.li_vn_mode
) != MODE_CONTROL
) {
950 printf("Packet received with mode %d\n",
951 PKT_MODE(rpkt
.li_vn_mode
));
954 if (!CTL_ISRESPONSE(rpkt
.r_m_e_op
)) {
956 printf("Received request packet, wanted response\n");
961 * Check opcode and sequence number for a match.
962 * Could be old data getting to us.
964 if (ntohs(rpkt
.sequence
) != sequence
) {
967 "Received sequnce number %d, wanted %d\n",
968 ntohs(rpkt
.sequence
), sequence
);
971 if (CTL_OP(rpkt
.r_m_e_op
) != opcode
) {
974 "Received opcode %d, wanted %d (sequence number okay)\n",
975 CTL_OP(rpkt
.r_m_e_op
), opcode
);
980 * Check the error code. If non-zero, return it.
982 if (CTL_ISERROR(rpkt
.r_m_e_op
)) {
985 errcode
= (ntohs(rpkt
.status
) >> 8) & 0xff;
986 if (debug
&& CTL_ISMORE(rpkt
.r_m_e_op
)) {
987 printf("Error code %d received on not-final packet\n",
990 if (errcode
== CERR_UNSPEC
)
996 * Check the association ID to make sure it matches what
999 if (ntohs(rpkt
.associd
) != associd
) {
1001 printf("Association ID %d doesn't match expected %d\n",
1002 ntohs(rpkt
.associd
), associd
);
1004 * Hack for silly fuzzballs which, at the time of writing,
1005 * return an assID of sys.peer when queried for system variables.
1013 * Collect offset and count. Make sure they make sense.
1015 offset
= ntohs(rpkt
.offset
);
1016 count
= ntohs(rpkt
.count
);
1025 * Usually we ignore authentication, but for debugging purposes
1028 shouldbesize
= CTL_HEADER_LEN
+ count
;
1030 /* round to 8 octet boundary */
1031 shouldbesize
= (shouldbesize
+ 7) & ~7;
1034 printf("Packet not padded, size = %d\n", n
);
1035 } if ((maclen
= n
- shouldbesize
) >= MIN_MAC_LEN
) {
1037 "Packet shows signs of authentication (total %d, data %d, mac %d)\n",
1038 n
, shouldbesize
, maclen
);
1039 lpkt
= (u_long
*)&rpkt
;
1040 printf("%08lx %08lx %08lx %08lx %08lx %08lx\n",
1041 (u_long
)ntohl(lpkt
[(n
- maclen
)/sizeof(u_long
) - 3]),
1042 (u_long
)ntohl(lpkt
[(n
- maclen
)/sizeof(u_long
) - 2]),
1043 (u_long
)ntohl(lpkt
[(n
- maclen
)/sizeof(u_long
) - 1]),
1044 (u_long
)ntohl(lpkt
[(n
- maclen
)/sizeof(u_long
)]),
1045 (u_long
)ntohl(lpkt
[(n
- maclen
)/sizeof(u_long
) + 1]),
1046 (u_long
)ntohl(lpkt
[(n
- maclen
)/sizeof(u_long
) + 2]));
1047 key
= ntohl(lpkt
[(n
- maclen
) / sizeof(u_long
)]);
1048 printf("Authenticated with keyid %lu\n", (u_long
)key
);
1049 if (key
!= 0 && key
!= info_auth_keyid
) {
1050 printf("We don't know that key\n");
1052 if (authdecrypt(key
, (u_int32
*)&rpkt
,
1053 n
- maclen
, maclen
)) {
1054 printf("Auth okay!\n");
1056 printf("Auth failed!\n");
1063 printf("Got packet, size = %d\n", n
);
1064 if (count
> (u_short
)(n
-CTL_HEADER_LEN
)) {
1067 "Received count of %d octets, data in packet is %d\n",
1068 count
, n
-CTL_HEADER_LEN
);
1071 if (count
== 0 && CTL_ISMORE(rpkt
.r_m_e_op
)) {
1073 printf("Received count of 0 in non-final fragment\n");
1076 if (offset
+ count
> sizeof(pktdata
)) {
1078 printf("Offset %d, count %d, too big for buffer\n",
1082 if (seenlastfrag
&& !CTL_ISMORE(rpkt
.r_m_e_op
)) {
1084 printf("Received second last fragment packet\n");
1089 * So far, so good. Record this fragment, making sure it doesn't
1093 printf("Packet okay\n");;
1095 if (numfrags
== MAXFRAGS
) {
1097 printf("Number of fragments exceeds maximum\n");
1101 for (n
= 0; n
< numfrags
; n
++) {
1102 if (offset
== offsets
[n
])
1103 goto again
; /* duplicate */
1104 if (offset
< offsets
[n
])
1108 if ((u_short
)(n
> 0 && offsets
[n
-1] + counts
[n
-1]) > offset
)
1110 if (n
< numfrags
&& (u_short
)(offset
+ count
) > offsets
[n
])
1116 for (i
= numfrags
; i
> n
; i
--) {
1117 offsets
[i
] = offsets
[i
-1];
1118 counts
[i
] = counts
[i
-1];
1121 offsets
[n
] = offset
;
1126 * Got that stuffed in right. Figure out if this was the last.
1127 * Record status info out of the last packet.
1129 if (!CTL_ISMORE(rpkt
.r_m_e_op
)) {
1132 *rstatus
= ntohs(rpkt
.status
);
1136 * Copy the data into the data buffer.
1138 memmove((char *)pktdata
+ offset
, (char *)rpkt
.data
, count
);
1141 * If we've seen the last fragment, look for holes in the sequence.
1142 * If there aren't any, we're done.
1144 if (seenlastfrag
&& offsets
[0] == 0) {
1145 for (n
= 1; n
< numfrags
; n
++) {
1146 if (offsets
[n
-1] + counts
[n
-1] != offsets
[n
])
1149 if (n
== numfrags
) {
1150 *rsize
= offsets
[numfrags
-1] + counts
[numfrags
-1];
1158 * Print debugging message about overlapping fragments
1161 printf("Overlapping fragments returned in response\n");
1167 * sendrequest - format and send a request packet
1178 struct ntp_control qpkt
;
1182 * Check to make sure the data will fit in one packet
1184 if (qsize
> CTL_MAX_DATA_LEN
) {
1185 (void) fprintf(stderr
,
1186 "***Internal error! qsize (%d) too large\n",
1192 * Fill in the packet
1194 qpkt
.li_vn_mode
= PKT_LI_VN_MODE(0, pktversion
, MODE_CONTROL
);
1195 qpkt
.r_m_e_op
= (u_char
)(opcode
& CTL_OP_MASK
);
1196 qpkt
.sequence
= htons(sequence
);
1198 qpkt
.associd
= htons((u_short
)associd
);
1200 qpkt
.count
= htons((u_short
)qsize
);
1203 * If we have data, copy it in and pad it out to a 64
1207 memmove((char *)qpkt
.data
, qdata
, (unsigned)qsize
);
1208 pktsize
= qsize
+ CTL_HEADER_LEN
;
1209 while (pktsize
& (sizeof(u_long
) - 1)) {
1210 qpkt
.data
[qsize
++] = 0;
1214 pktsize
= CTL_HEADER_LEN
;
1218 * If it isn't authenticated we can just send it. Otherwise
1219 * we're going to have to think about it a little.
1221 if (!auth
&& !always_auth
) {
1222 return sendpkt((char *)&qpkt
, pktsize
);
1224 const char *pass
= "\0";
1229 * Pad out packet to a multiple of 8 octets to be sure
1230 * receiver can handle it.
1232 while (pktsize
& 7) {
1233 qpkt
.data
[qsize
++] = 0;
1238 * Get the keyid and the password if we don't have one.
1240 if (info_auth_keyid
== 0) {
1241 int u_keyid
= getkeyid("Keyid: ");
1242 if (u_keyid
== 0 || u_keyid
> NTP_MAXKEY
) {
1243 (void) fprintf(stderr
,
1244 "Invalid key identifier\n");
1247 info_auth_keyid
= u_keyid
;
1249 if (!authistrusted(info_auth_keyid
)) {
1250 pass
= getpass("MD5 Password: ");
1251 if (*pass
== '\0') {
1252 (void) fprintf(stderr
,
1253 "Invalid password\n");
1257 authusekey(info_auth_keyid
, info_auth_keytype
, (const u_char
*)pass
);
1258 authtrust(info_auth_keyid
, 1);
1261 * Stick the keyid in the packet where
1262 * cp currently points. Cp should be aligned
1263 * properly. Then do the encryptions.
1265 my_keyid
= htonl(info_auth_keyid
);
1266 memcpy(&qpkt
.data
[qsize
], &my_keyid
, sizeof my_keyid
);
1267 maclen
= authencrypt(info_auth_keyid
, (u_int32
*)&qpkt
,
1270 (void) fprintf(stderr
, "Key not found\n");
1273 return sendpkt((char *)&qpkt
, pktsize
+ maclen
);
1280 * doquery - send a request and process the response
1298 * Check to make sure host is open
1301 (void) fprintf(stderr
, "***No host open, use `host' command\n");
1312 res
= sendrequest(opcode
, associd
, auth
, qsize
, qdata
);
1317 * Get the response. If we got a standard error, print a message
1319 res
= getresponse(opcode
, associd
, rstatus
, rsize
, rdata
, done
);
1322 if (!done
&& (res
== ERR_TIMEOUT
|| res
== ERR_INCOMPLETE
)) {
1323 if (res
== ERR_INCOMPLETE
) {
1325 * better bump the sequence so we don't
1326 * get confused about differing fragments.
1334 (void) fprintf(stderr
, "server=%s ", currenthost
);
1337 (void) fprintf(stderr
,
1338 "***Server reports a bad format request packet\n");
1340 case CERR_PERMISSION
:
1341 (void) fprintf(stderr
,
1342 "***Server disallowed request (authentication?)\n");
1345 (void) fprintf(stderr
,
1346 "***Server reports a bad opcode in request\n");
1349 (void) fprintf(stderr
,
1350 "***Association ID %d unknown to server\n",associd
);
1352 case CERR_UNKNOWNVAR
:
1353 (void) fprintf(stderr
,
1354 "***A request variable unknown to the server\n");
1357 (void) fprintf(stderr
,
1358 "***Server indicates a request variable was bad\n");
1361 (void) fprintf(stderr
,
1362 "***Server returned an unspecified error\n");
1365 (void) fprintf(stderr
, "***Request timed out\n");
1367 case ERR_INCOMPLETE
:
1368 (void) fprintf(stderr
,
1369 "***Response from server was incomplete\n");
1372 (void) fprintf(stderr
,
1373 "***Buffer size exceeded for returned data\n");
1376 (void) fprintf(stderr
,
1377 "***Server returns unknown error code %d\n", res
);
1386 * getcmds - read commands from the standard input and execute them
1391 #if defined(HAVE_LIBREADLINE) || defined(HAVE_LIBEDIT)
1395 if ((line
= readline(interactive
?prompt
:"")) == NULL
) return;
1396 if (*line
) add_history(line
);
1400 #else /* not (HAVE_LIBREADLINE || HAVE_LIBEDIT) */
1405 #ifdef VMS /* work around a problem with mixing stdout & stderr */
1408 (void) fputs(prompt
, stderr
);
1409 (void) fflush(stderr
);
1412 if (fgets(line
, sizeof line
, stdin
) == NULL
)
1417 #endif /* not (HAVE_LIBREADLINE || HAVE_LIBEDIT) */
1420 #ifndef SYS_WINNT /* Under NT cannot handle SIGINT, WIN32 spawns a handler */
1422 * abortcmd - catch interrupts and abort the current command
1429 if (current_output
== stdout
)
1430 (void) fflush(stdout
);
1432 (void) fflush(stderr
);
1433 if (jump
) longjmp(interrupt_buf
, 1);
1435 #endif /* SYS_WINNT */
1438 * docmd - decode the command line and execute a command
1445 char *tokens
[1+MAXARGS
+2];
1449 struct xcmd
*xcmd
= NULL
;
1452 * Tokenize the command line. If nothing on it, return.
1454 tokenize(cmdline
, tokens
, &ntok
);
1459 * Find the appropriate command description.
1461 i
= findcmd(tokens
[0], builtins
, opcmds
, &xcmd
);
1463 (void) fprintf(stderr
, "***Command `%s' unknown\n",
1466 } else if (i
>= 2) {
1467 (void) fprintf(stderr
, "***Command `%s' ambiguous\n",
1473 * Save the keyword, then walk through the arguments, interpreting
1476 pcmd
.keyword
= tokens
[0];
1478 for (i
= 0; i
< MAXARGS
&& xcmd
->arg
[i
] != NO
; i
++) {
1479 if ((i
+1) >= ntok
) {
1480 if (!(xcmd
->arg
[i
] & OPT
)) {
1481 printusage(xcmd
, stderr
);
1486 if ((xcmd
->arg
[i
] & OPT
) && (*tokens
[i
+1] == '>'))
1488 if (!getarg(tokens
[i
+1], (int)xcmd
->arg
[i
], &pcmd
.argval
[i
]))
1494 if (i
< ntok
&& *tokens
[i
] == '>') {
1497 if (*(tokens
[i
]+1) != '\0')
1498 fname
= tokens
[i
]+1;
1499 else if ((i
+1) < ntok
)
1500 fname
= tokens
[i
+1];
1502 (void) fprintf(stderr
, "***No file for redirect\n");
1506 current_output
= fopen(fname
, "w");
1507 if (current_output
== NULL
) {
1508 (void) fprintf(stderr
, "***Error opening %s: ", fname
);
1512 i
= 1; /* flag we need a close */
1514 current_output
= stdout
;
1515 i
= 0; /* flag no close */
1518 if (interactive
&& setjmp(interrupt_buf
)) {
1523 (xcmd
->handler
)(&pcmd
, current_output
);
1524 jump
= 0; /* HMS: 961106: was after fclose() */
1525 if (i
) (void) fclose(current_output
);
1531 * tokenize - turn a command line into tokens
1540 register const char *cp
;
1542 static char tspace
[MAXLINE
];
1546 for (*ntok
= 0; *ntok
< MAXTOKENS
; (*ntok
)++) {
1548 while (ISSPACE(*cp
))
1554 } while (!ISSPACE(*cp
) && !ISEOL(*cp
));
1563 * findcmd - find a command in a command description table
1568 struct xcmd
*clist1
,
1569 struct xcmd
*clist2
,
1573 register struct xcmd
*cl
;
1576 struct xcmd
*nearmatch
= NULL
;
1583 else if (clist2
!= 0)
1589 for (cl
= clist
; cl
->keyword
!= 0; cl
++) {
1590 /* do a first character check, for efficiency */
1591 if (*str
!= *(cl
->keyword
))
1593 if (strncmp(str
, cl
->keyword
, (unsigned)clen
) == 0) {
1595 * Could be extact match, could be approximate.
1596 * Is exact if the length of the keyword is the
1599 if (*((cl
->keyword
) + clen
) == '\0') {
1609 * See if there is more to do. If so, go again. Sorry about the
1610 * goto, too much looking at BSD sources...
1612 if (clist
== clist1
&& clist2
!= 0) {
1618 * If we got extactly 1 near match, use it, else return number
1630 * getarg - interpret an argument token
1641 static const char *digits
= "0123456789";
1643 switch (code
& ~OPT
) {
1648 if (!getnetnum(str
, &(argp
->netnum
), (char *)0, 0)) {
1660 (void) fprintf(stderr
,
1661 "***Association value `%s' invalid/undecodable\n", str
);
1664 if (isneg
> numassoc
) {
1665 if (numassoc
== 0) {
1666 (void) fprintf(stderr
,
1667 "***Association for `%s' unknown (max &%d)\n",
1674 argp
->uval
= assoc_cache
[isneg
-1].assid
;
1685 cp
= strchr(digits
, *np
);
1687 (void) fprintf(stderr
,
1688 "***Illegal integer value %s\n", str
);
1692 argp
->uval
+= (cp
- digits
);
1693 } while (*(++np
) != '\0');
1696 if ((code
& ~OPT
) == NTP_UINT
) {
1697 (void) fprintf(stderr
,
1698 "***Value %s should be unsigned\n", str
);
1701 argp
->ival
= -argp
->ival
;
1705 if (!strcmp("-6", str
))
1707 else if (!strcmp("-4", str
))
1710 (void) fprintf(stderr
,
1711 "***Version must be either 4 or 6\n");
1722 * getnetnum - given a host name, return its net number
1723 * and (optional) full name
1728 struct sockaddr_storage
*num
,
1734 struct addrinfo hints
, *ai
= NULL
;
1736 sockaddr_len
= (af
== AF_INET
)
1737 ? sizeof(struct sockaddr_in
)
1738 : sizeof(struct sockaddr_in6
);
1739 memset((char *)&hints
, 0, sizeof(struct addrinfo
));
1740 hints
.ai_flags
= AI_CANONNAME
;
1741 #ifdef AI_ADDRCONFIG
1742 hints
.ai_flags
|= AI_ADDRCONFIG
;
1745 /* decodenetnum works with addresses only */
1746 if (decodenetnum(hname
, num
)) {
1747 if (fullhost
!= 0) {
1748 getnameinfo((struct sockaddr
*)num
, sockaddr_len
,
1749 fullhost
, sizeof(fullhost
), NULL
, 0,
1753 } else if (getaddrinfo(hname
, "ntp", &hints
, &ai
) == 0) {
1754 memmove((char *)num
, ai
->ai_addr
, ai
->ai_addrlen
);
1755 if (ai
->ai_canonname
!= 0)
1756 (void) strcpy(fullhost
, ai
->ai_canonname
);
1759 (void) fprintf(stderr
, "***Can't find host %s\n", hname
);
1766 * nntohost - convert network number to host name. This routine enforces
1767 * the showhostnames setting.
1771 struct sockaddr_storage
*netnum
1775 return stoa(netnum
);
1776 if ((netnum
->ss_family
== AF_INET
) && ISREFCLOCKADR(netnum
))
1777 return refnumtoa(netnum
);
1778 return socktohost(netnum
);
1783 * rtdatetolfp - decode an RT-11 date into an l_fp
1793 struct calendar cal
;
1795 static const char *months
[12] = {
1796 "Jan", "Feb", "Mar", "Apr", "May", "Jun",
1797 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
1803 * An RT-11 date looks like:
1805 * d[d]-Mth-y[y] hh:mm:ss
1807 * (No docs, but assume 4-digit years are also legal...)
1809 * d[d]-Mth-y[y[y[y]]] hh:mm:ss
1812 if (!isdigit((int)*cp
)) {
1815 * Catch special case
1823 cal
.monthday
= (u_char
) (*cp
++ - '0'); /* ascii dependent */
1824 if (isdigit((int)*cp
)) {
1825 cal
.monthday
= (u_char
)((cal
.monthday
<< 3) + (cal
.monthday
<< 1));
1826 cal
.monthday
= (u_char
)(cal
.monthday
+ *cp
++ - '0');
1832 for (i
= 0; i
< 3; i
++)
1836 for (i
= 0; i
< 12; i
++)
1837 if (STREQ(buf
, months
[i
]))
1841 cal
.month
= (u_char
)(i
+ 1);
1846 if (!isdigit((int)*cp
))
1848 cal
.year
= (u_short
)(*cp
++ - '0');
1849 if (isdigit((int)*cp
)) {
1850 cal
.year
= (u_short
)((cal
.year
<< 3) + (cal
.year
<< 1));
1851 cal
.year
= (u_short
)(*cp
++ - '0');
1853 if (isdigit((int)*cp
)) {
1854 cal
.year
= (u_short
)((cal
.year
<< 3) + (cal
.year
<< 1));
1855 cal
.year
= (u_short
)(cal
.year
+ *cp
++ - '0');
1857 if (isdigit((int)*cp
)) {
1858 cal
.year
= (u_short
)((cal
.year
<< 3) + (cal
.year
<< 1));
1859 cal
.year
= (u_short
)(cal
.year
+ *cp
++ - '0');
1863 * Catch special case. If cal.year == 0 this is a zero timestamp.
1865 if (cal
.year
== 0) {
1870 if (*cp
++ != ' ' || !isdigit((int)*cp
))
1872 cal
.hour
= (u_char
)(*cp
++ - '0');
1873 if (isdigit((int)*cp
)) {
1874 cal
.hour
= (u_char
)((cal
.hour
<< 3) + (cal
.hour
<< 1));
1875 cal
.hour
= (u_char
)(cal
.hour
+ *cp
++ - '0');
1878 if (*cp
++ != ':' || !isdigit((int)*cp
))
1880 cal
.minute
= (u_char
)(*cp
++ - '0');
1881 if (isdigit((int)*cp
)) {
1882 cal
.minute
= (u_char
)((cal
.minute
<< 3) + (cal
.minute
<< 1));
1883 cal
.minute
= (u_char
)(cal
.minute
+ *cp
++ - '0');
1886 if (*cp
++ != ':' || !isdigit((int)*cp
))
1888 cal
.second
= (u_char
)(*cp
++ - '0');
1889 if (isdigit((int)*cp
)) {
1890 cal
.second
= (u_char
)((cal
.second
<< 3) + (cal
.second
<< 1));
1891 cal
.second
= (u_char
)(cal
.second
+ *cp
++ - '0');
1895 * For RT-11, 1972 seems to be the pivot year
1902 lfp
->l_ui
= caltontp(&cal
);
1909 * decodets - decode a timestamp into an l_fp format number, with
1910 * consideration of fuzzball formats.
1919 * If it starts with a 0x, decode as hex.
1921 if (*str
== '0' && (*(str
+1) == 'x' || *(str
+1) == 'X'))
1922 return hextolfp(str
+2, lfp
);
1925 * If it starts with a '"', try it as an RT-11 date.
1928 register char *cp
= str
+1;
1933 while (*cp
!= '"' && *cp
!= '\0' && bp
< &buf
[29])
1936 return rtdatetolfp(buf
, lfp
);
1940 * Might still be hex. Check out the first character. Talk
1943 if ((*str
>= 'A' && *str
<= 'F') || (*str
>= 'a' && *str
<= 'f'))
1944 return hextolfp(str
, lfp
);
1947 * Try it as a decimal. If this fails, try as an unquoted
1948 * RT-11 date. This code should go away eventually.
1950 if (atolfp(str
, lfp
))
1952 return rtdatetolfp(str
, lfp
);
1957 * decodetime - decode a time value. It should be in milliseconds
1965 return mstolfp(str
, lfp
);
1970 * decodeint - decode an integer
1979 if (*(str
+1) == 'x' || *(str
+1) == 'X')
1980 return hextoint(str
+2, (u_long
*)val
);
1981 return octtoint(str
, (u_long
*)val
);
1983 return atoint(str
, val
);
1988 * decodeuint - decode an unsigned integer
1997 if (*(str
+ 1) == 'x' || *(str
+ 1) == 'X')
1998 return (hextoint(str
+ 2, val
));
1999 return (octtoint(str
, val
));
2001 return (atouint(str
, val
));
2006 * decodearr - decode an array of time values
2015 register char *cp
, *bp
;
2024 while (isspace((int)*cp
))
2030 while (!isspace((int)*cp
) && *cp
!= '\0')
2034 if (!decodetime(buf
, lfp
))
2044 * Finally, the built in command handlers
2048 * help - tell about commands, or details of a particular command
2058 const char *list
[100];
2063 if (pcmd
->nargs
== 0) {
2065 for (xcp
= builtins
; xcp
->keyword
!= 0; xcp
++) {
2066 if (*(xcp
->keyword
) != '?')
2067 list
[words
++] = xcp
->keyword
;
2069 for (xcp
= opcmds
; xcp
->keyword
!= 0; xcp
++)
2070 list
[words
++] = xcp
->keyword
;
2073 #ifdef QSORT_USES_VOID_P
2078 (list
), (size_t)(words
), sizeof(char *), helpsort
);
2080 for (word
= 0; word
< words
; word
++) {
2081 int length
= strlen(list
[word
]);
2087 cols
= SCREENWIDTH
/ ++col
;
2088 rows
= (words
+ cols
- 1) / cols
;
2090 (void) fprintf(fp
, "ntpq commands:\n");
2092 for (row
= 0; row
< rows
; row
++) {
2093 for (word
= row
; word
< words
; word
+= rows
) {
2094 (void) fprintf(fp
, "%-*.*s", col
, col
-1, list
[word
]);
2096 (void) fprintf(fp
, "\n");
2099 cmd
= pcmd
->argval
[0].string
;
2100 words
= findcmd(cmd
, builtins
, opcmds
, &xcp
);
2102 (void) fprintf(stderr
,
2103 "Command `%s' is unknown\n", cmd
);
2105 } else if (words
>= 2) {
2106 (void) fprintf(stderr
,
2107 "Command `%s' is ambiguous\n", cmd
);
2110 (void) fprintf(fp
, "function: %s\n", xcp
->comment
);
2111 printusage(xcp
, fp
);
2117 * helpsort - do hostname qsort comparisons
2119 #ifdef QSORT_USES_VOID_P
2126 char const * const * name1
= (char const * const *)t1
;
2127 char const * const * name2
= (char const * const *)t2
;
2129 return strcmp(*name1
, *name2
);
2139 return strcmp(*name1
, *name2
);
2144 * printusage - print usage information for a command
2154 (void) fprintf(fp
, "usage: %s", xcp
->keyword
);
2155 for (i
= 0; i
< MAXARGS
&& xcp
->arg
[i
] != NO
; i
++) {
2156 if (xcp
->arg
[i
] & OPT
)
2157 (void) fprintf(fp
, " [ %s ]", xcp
->desc
[i
]);
2159 (void) fprintf(fp
, " %s", xcp
->desc
[i
]);
2161 (void) fprintf(fp
, "\n");
2166 * timeout - set time out time
2176 if (pcmd
->nargs
== 0) {
2177 val
= tvout
.tv_sec
* 1000 + tvout
.tv_usec
/ 1000;
2178 (void) fprintf(fp
, "primary timeout %d ms\n", val
);
2180 tvout
.tv_sec
= pcmd
->argval
[0].uval
/ 1000;
2181 tvout
.tv_usec
= (pcmd
->argval
[0].uval
- (tvout
.tv_sec
* 1000))
2188 * auth_delay - set delay for auth requests
2199 if (pcmd
->nargs
== 0) {
2200 val
= delay_time
.l_ui
* 1000 + delay_time
.l_uf
/ 4294967;
2201 (void) fprintf(fp
, "delay %lu ms\n", val
);
2203 if (pcmd
->argval
[0].ival
< 0) {
2205 val
= (u_long
)(-pcmd
->argval
[0].ival
);
2208 val
= (u_long
)pcmd
->argval
[0].ival
;
2211 delay_time
.l_ui
= val
/ 1000;
2213 delay_time
.l_uf
= val
* 4294967; /* 2**32/1000 */
2222 * host - set the host we are dealing with.
2232 if (pcmd
->nargs
== 0) {
2234 (void) fprintf(fp
, "current host is %s\n", currenthost
);
2236 (void) fprintf(fp
, "no current host\n");
2241 ai_fam_templ
= ai_fam_default
;
2242 if (pcmd
->nargs
== 2) {
2243 if (!strcmp("-4", pcmd
->argval
[i
].string
))
2244 ai_fam_templ
= AF_INET
;
2245 else if (!strcmp("-6", pcmd
->argval
[i
].string
))
2246 ai_fam_templ
= AF_INET6
;
2250 "current host remains %s\n", currenthost
);
2252 (void) fprintf(fp
, "still no current host\n");
2257 if (openhost(pcmd
->argval
[i
].string
)) {
2258 (void) fprintf(fp
, "current host set to %s\n", currenthost
);
2263 "current host remains %s\n", currenthost
);
2265 (void) fprintf(fp
, "still no current host\n");
2271 * poll - do one (or more) polls of the host via NTP
2280 (void) fprintf(fp
, "poll not implemented yet\n");
2285 * keyid - get a keyid to use for authenticating requests
2293 if (pcmd
->nargs
== 0) {
2294 if (info_auth_keyid
== 0)
2295 (void) fprintf(fp
, "no keyid defined\n");
2297 (void) fprintf(fp
, "keyid is %lu\n", (u_long
)info_auth_keyid
);
2299 /* allow zero so that keyid can be cleared. */
2300 if(pcmd
->argval
[0].uval
> NTP_MAXKEY
)
2301 (void) fprintf(fp
, "Invalid key identifier\n");
2302 info_auth_keyid
= pcmd
->argval
[0].uval
;
2307 * keytype - get type of key to use for authenticating requests
2315 if (pcmd
->nargs
== 0)
2316 fprintf(fp
, "keytype is %s\n",
2317 (info_auth_keytype
== KEY_TYPE_MD5
) ? "MD5" : "???");
2319 switch (*(pcmd
->argval
[0].string
)) {
2322 info_auth_keytype
= KEY_TYPE_MD5
;
2326 fprintf(fp
, "keytype must be 'md5'\n");
2333 * passwd - get an authentication key
2344 if (info_auth_keyid
== 0) {
2345 int u_keyid
= getkeyid("Keyid: ");
2346 if (u_keyid
== 0 || u_keyid
> NTP_MAXKEY
) {
2347 (void)fprintf(fp
, "Invalid key identifier\n");
2350 info_auth_keyid
= u_keyid
;
2352 pass
= getpass("MD5 Password: ");
2354 (void) fprintf(fp
, "Password unchanged\n");
2356 authusekey(info_auth_keyid
, info_auth_keytype
, (u_char
*)pass
);
2357 authtrust(info_auth_keyid
, 1);
2363 * hostnames - set the showhostnames flag
2371 if (pcmd
->nargs
== 0) {
2373 (void) fprintf(fp
, "hostnames being shown\n");
2375 (void) fprintf(fp
, "hostnames not being shown\n");
2377 if (STREQ(pcmd
->argval
[0].string
, "yes"))
2379 else if (STREQ(pcmd
->argval
[0].string
, "no"))
2382 (void)fprintf(stderr
, "What?\n");
2389 * setdebug - set/change debugging level
2397 if (pcmd
->nargs
== 0) {
2398 (void) fprintf(fp
, "debug level is %d\n", debug
);
2400 } else if (STREQ(pcmd
->argval
[0].string
, "no")) {
2402 } else if (STREQ(pcmd
->argval
[0].string
, "more")) {
2404 } else if (STREQ(pcmd
->argval
[0].string
, "less")) {
2407 (void) fprintf(fp
, "What?\n");
2410 (void) fprintf(fp
, "debug level set to %d\n", debug
);
2415 * quit - stop this nonsense
2425 closesocket(sockfd
); /* cleanliness next to godliness */
2431 * version - print the current version number
2441 (void) fprintf(fp
, "%s\n", Version
);
2447 * raw - set raw mode output
2457 (void) fprintf(fp
, "Output set to raw\n");
2462 * cooked - set cooked mode output
2472 (void) fprintf(fp
, "Output set to cooked\n");
2478 * authenticate - always authenticate requests to this host
2486 if (pcmd
->nargs
== 0) {
2489 "authenticated requests being sent\n");
2492 "unauthenticated requests being sent\n");
2494 if (STREQ(pcmd
->argval
[0].string
, "yes")) {
2496 } else if (STREQ(pcmd
->argval
[0].string
, "no")) {
2499 (void)fprintf(stderr
, "What?\n");
2505 * ntpversion - choose the NTP version to use
2513 if (pcmd
->nargs
== 0) {
2515 "NTP version being claimed is %d\n", pktversion
);
2517 if (pcmd
->argval
[0].uval
< NTP_OLDVERSION
2518 || pcmd
->argval
[0].uval
> NTP_VERSION
) {
2519 (void) fprintf(stderr
, "versions %d to %d, please\n",
2520 NTP_OLDVERSION
, NTP_VERSION
);
2522 pktversion
= (u_char
) pcmd
->argval
[0].uval
;
2529 * warning - print a warning message
2538 (void) fprintf(stderr
, "%s: ", progname
);
2539 (void) fprintf(stderr
, fmt
, st1
, st2
);
2540 (void) fprintf(stderr
, ": ");
2546 * error - print a message and exit
2555 warning(fmt
, st1
, st2
);
2560 * getkeyid - prompt the user for a keyid to use
2564 const char *keyprompt
2573 if ((fi
= fdopen(open("/dev/tty", 2), "r")) == NULL
)
2575 if ((fi
= _fdopen((int)GetStdHandle(STD_INPUT_HANDLE
), "r")) == NULL
)
2576 #endif /* SYS_WINNT */
2579 setbuf(fi
, (char *)NULL
);
2580 fprintf(stderr
, "%s", keyprompt
); fflush(stderr
);
2581 for (p
=pbuf
; (c
= getc(fi
))!='\n' && c
!=EOF
;) {
2588 if (strcmp(pbuf
, "0") == 0)
2591 return (u_long
) atoi(pbuf
);
2596 * atoascii - printable-ize possibly ascii data using the character
2597 * transformations cat -v uses.
2606 register u_char
*cp
;
2607 register u_char
*ocp
;
2616 ocp
= (u_char
*)outdata
;
2617 for (cp
= (u_char
*)data
; cp
< (u_char
*)data
+ length
; cp
++) {
2631 *ocp
++ = (u_char
)(c
+ '@');
2632 } else if (c
== 0177) {
2638 if (ocp
>= ((u_char
*)outdata
+ length
- 4))
2647 * makeascii - print possibly ascii data using the character
2648 * transformations that cat -v uses.
2657 register u_char
*cp
;
2660 for (cp
= (u_char
*)data
; cp
< (u_char
*)data
+ length
; cp
++) {
2671 } else if (c
== 0177) {
2682 * asciize - same thing as makeascii except add a newline
2691 makeascii(length
, data
, fp
);
2697 * Some circular buffer space
2702 char circ_buf
[NUMCB
][CBLEN
];
2706 * nextvar - find the next variable in the buffer
2718 register char *cpend
;
2719 register char *npend
; /* character after last */
2721 static char name
[MAXVARLEN
];
2722 static char value
[MAXVALLEN
];
2725 cpend
= cp
+ *datalen
;
2728 * Space past commas and white space
2730 while (cp
< cpend
&& (*cp
== ',' || isspace((int)*cp
)))
2736 * Copy name until we hit a ',', an '=', a '\r' or a '\n'. Backspace
2737 * over any white space and terminate it.
2740 npend
= &name
[MAXVARLEN
];
2741 while (cp
< cpend
&& np
< npend
&& *cp
!= ',' && *cp
!= '='
2742 && *cp
!= '\r' && *cp
!= '\n')
2745 * Check if we ran out of name space, without reaching the end or a
2746 * terminating character
2748 if (np
== npend
&& !(cp
== cpend
|| *cp
== ',' || *cp
== '=' ||
2749 *cp
== '\r' || *cp
== '\n'))
2751 while (isspace((int)(*(np
-1))))
2757 * Check if we hit the end of the buffer or a ','. If so we are done.
2759 if (cp
== cpend
|| *cp
== ',' || *cp
== '\r' || *cp
== '\n') {
2763 *datalen
= cpend
- cp
;
2764 *vvalue
= (char *)0;
2769 * So far, so good. Copy out the value
2771 cp
++; /* past '=' */
2772 while (cp
< cpend
&& (isspace((int)*cp
) && *cp
!= '\r' && *cp
!= '\n'))
2775 npend
= &value
[MAXVALLEN
];
2776 while (cp
< cpend
&& np
< npend
&& ((*cp
!= ',') || quoted
))
2778 quoted
^= ((*np
++ = *cp
++) == '"');
2782 * Check if we overran the value buffer while still in a quoted string
2783 * or without finding a comma
2785 if (np
== npend
&& (quoted
|| *cp
!= ','))
2788 * Trim off any trailing whitespace
2790 while (np
> value
&& isspace((int)(*(np
-1))))
2795 * Return this. All done.
2800 *datalen
= cpend
- cp
;
2807 * findvar - see if this variable is known to us.
2808 * If "code" is 1, return ctl_var->code.
2809 * Otherwise return the ordinal position of the found variable.
2814 struct ctl_var
*varlist
,
2819 register struct ctl_var
*vl
;
2823 while (vl
->fmt
!= EOV
) {
2824 if (vl
->fmt
!= PADDING
&& STREQ(np
, vl
->text
))
2837 * printvars - print variables returned in response packet
2849 rawprint(sttype
, length
, data
, status
, fp
);
2851 cookedprint(sttype
, length
, data
, status
, fp
);
2856 * rawprint - do a printout of the data in raw mode
2868 register char *cpend
;
2871 * Essentially print the data as is. We reformat unprintables, though.
2874 cpend
= data
+ length
;
2876 (void) fprintf(fp
, "status=0x%04x,\n", status
);
2878 while (cp
< cpend
) {
2881 * If this is a \r and the next character is a
2882 * \n, supress this, else pretty print it. Otherwise
2883 * just output the character.
2885 if (cp
== (cpend
-1) || *(cp
+1) != '\n')
2886 makeascii(1, cp
, fp
);
2887 } else if (isspace((int)*cp
) || isprint((int)*cp
)) {
2890 makeascii(1, cp
, fp
);
2898 * Global data used by the cooked output routines
2900 int out_chars
; /* number of characters output */
2901 int out_linecount
; /* number of characters output on this line */
2905 * startoutput - get ready to do cooked output
2916 * output - output a variable=value combination
2928 lenname
= strlen(name
);
2929 lenvalue
= strlen(value
);
2931 if (out_chars
!= 0) {
2935 if ((out_linecount
+ lenname
+ lenvalue
+ 3) > MAXOUTLINE
) {
2949 out_chars
+= lenname
+ 1 + lenvalue
;
2950 out_linecount
+= lenname
+ 1 + lenvalue
;
2955 * endoutput - terminate a block of cooked output
2968 * outputarr - output an array of values
2986 * Hack to align delay and offset values
2988 for (i
= (int)strlen(name
); i
< 11; i
++)
2991 for (i
= narr
; i
> 0; i
--) {
2994 cp
= lfptoms(lfp
, 2);
3009 output(fp
, name
, buf
);
3017 register char *cb
, *s
;
3019 register const char *sep
;
3023 s
= cb
= &circ_buf
[nextcb
][0];
3024 if (++nextcb
>= NUMCB
)
3027 sprintf(cb
, "%02lx", val
);
3034 for (i
= 0; i
< 13; i
++) {
3036 sprintf(cb
, "%s%s", sep
, tstflagnames
[i
]);
3048 * cookedprint - output variables in cooked mode
3064 struct ctl_var
*varlist
;
3067 struct sockaddr_storage hval
;
3080 varlist
= clock_var
;
3083 (void) fprintf(stderr
, "Unknown datatype(0x%x) in cookedprint\n", datatype
);
3087 (void) fprintf(fp
, "status=%04x %s,\n", status
,
3088 statustoa(datatype
, status
));
3091 while (nextvar(&length
, &data
, &name
, &value
)) {
3092 varid
= findvar(name
, varlist
, 0);
3097 fmt
= varlist
[varid
].fmt
;
3100 if (!decodets(value
, &lfp
))
3103 output(fp
, name
, prettydate(&lfp
));
3108 if (!decodetime(value
, &lfp
))
3129 if (!decodeuint(value
, &uval
))
3132 output(fp
, name
, uinttoa(uval
));
3136 if (!decodeint(value
, &ival
))
3139 output(fp
, name
, inttoa(ival
));
3144 if (!decodenetnum(value
, &hval
))
3146 else if (fmt
== HA
){
3147 output(fp
, name
, nntohost(&hval
));
3149 output(fp
, name
, stoa(&hval
));
3158 if (decodenetnum(value
, &hval
)) {
3159 if ((hval
.ss_family
== AF_INET
) &&
3160 ISREFCLOCKADR(&hval
))
3164 output(fp
, name
, stoa(&hval
));
3165 } else if ((int)strlen(value
) <= 4)
3166 output(fp
, name
, value
);
3172 if (!decodeuint(value
, &uval
) || uval
> 3)
3182 output(fp
, name
, b
);
3187 if (!decodeuint(value
, &uval
))
3192 (void) snprintf(b
, sizeof(b
), "%03lo",
3194 output(fp
, name
, b
);
3199 if (!decodeuint(value
, &uval
))
3202 output(fp
, name
, uinttoa(uval
));
3206 if (!decodearr(value
, &narr
, lfparr
))
3209 outputarr(fp
, name
, narr
, lfparr
);
3213 if (!decodeuint(value
, &uval
))
3216 output(fp
, name
, tstflags(uval
));
3220 (void) fprintf(stderr
,
3221 "Internal error in cookedprint, %s=%s, fmt %d\n",
3227 if (output_raw
!= 0) {
3232 atoascii(400, name
, bn
);
3233 atoascii(400, value
, bv
);
3234 if (output_raw
!= '*') {
3236 bv
[len
] = output_raw
;
3247 * sortassoc - sort associations in the cache into ascending order
3254 #ifdef QSORT_USES_VOID_P
3259 assoc_cache
, (size_t)numassoc
,
3260 sizeof(struct association
), assoccmp
);
3265 * assoccmp - compare two associations
3267 #ifdef QSORT_USES_VOID_P
3274 const struct association
*ass1
= (const struct association
*)t1
;
3275 const struct association
*ass2
= (const struct association
*)t2
;
3277 if (ass1
->assid
< ass2
->assid
)
3279 if (ass1
->assid
> ass2
->assid
)
3286 struct association
*ass1
,
3287 struct association
*ass2
3290 if (ass1
->assid
< ass2
->assid
)
3292 if (ass1
->assid
> ass2
->assid
)
3296 #endif /* not QSORT_USES_VOID_P */