diff options
Diffstat (limited to 'ntpq/ntpq.c')
-rw-r--r-- | ntpq/ntpq.c | 2002 |
1 files changed, 1118 insertions, 884 deletions
diff --git a/ntpq/ntpq.c b/ntpq/ntpq.c index 2e51b35..bc1acc6 100644 --- a/ntpq/ntpq.c +++ b/ntpq/ntpq.c @@ -16,25 +16,21 @@ #include "ntp_io.h" #include "ntp_select.h" #include "ntp_stdlib.h" -/* Don't include ISC's version of IPv6 variables and structures */ -#define ISC_IPV6_H 1 +#include "ntp_assert.h" +#include "ntp_lineedit.h" +#include "ntp_debug.h" #include "isc/net.h" #include "isc/result.h" +#include <ssl_applink.c> +#include "ntp_libopts.h" #include "ntpq-opts.h" #ifdef SYS_WINNT # include <Mswsock.h> # include <io.h> -#else -# define closesocket close #endif /* SYS_WINNT */ -#if defined(HAVE_LIBREADLINE) || defined(HAVE_LIBEDIT) -# include <readline/readline.h> -# include <readline/history.h> -#endif /* HAVE_LIBREADLINE || HAVE_LIBEDIT */ - #ifdef SYS_VXWORKS /* vxWorks needs mode flag -casey*/ # define open(name, flags) open(name, flags, 0777) @@ -53,6 +49,15 @@ int interactive = 0; /* set to 1 when we should prompt */ const char *prompt = "ntpq> "; /* prompt to ask him about */ +/* + * use old readvars behavior? --old-rv processing in ntpq resets + * this value based on the presence or absence of --old-rv. It is + * initialized to 1 here to maintain backward compatibility with + * libntpq clients such as ntpsnmpd, which are free to reset it as + * desired. + */ +int old_rv = 1; + /* * for get_systime() @@ -64,12 +69,8 @@ s_char sys_precision; /* local clock precision (log2 s) */ */ u_long info_auth_keyid = 0; -/* - * Type of key md5 - */ -#define KEY_TYPE_MD5 4 - -static int info_auth_keytype = KEY_TYPE_MD5; /* MD5 */ +static int info_auth_keytype = NID_md5; /* MD5 */ +static size_t info_auth_hashlen = 16; /* MD5 */ u_long current_time; /* needed by authkeys; not used */ /* @@ -129,16 +130,15 @@ struct ctl_var sys_var[] = { { CS_REFTIME, TS, "reftime" }, /* 7 */ { CS_POLL, UI, "poll" }, /* 8 */ { CS_PEERID, UI, "peer" }, /* 9 */ - { CS_STATE, UI, "state" }, /* 10 */ - { CS_OFFSET, FL, "offset" }, /* 11 */ - { CS_DRIFT, FS, "frequency" }, /* 12 */ - { CS_JITTER, FU, "jitter" }, /* 13 */ - { CS_CLOCK, TS, "clock" }, /* 14 */ - { CS_PROCESSOR, ST, "processor" }, /* 15 */ - { CS_SYSTEM, ST, "system" }, /* 16 */ - { CS_VERSION, ST, "version" }, /* 17 */ - { CS_STABIL, FS, "stability" }, /* 18 */ - { CS_VARLIST, ST, "sys_var_list" }, /* 19 */ + { CS_OFFSET, FL, "offset" }, /* 10 */ + { CS_DRIFT, FS, "frequency" }, /* 11 */ + { CS_JITTER, FU, "jitter" }, /* 12 */ + { CS_CLOCK, TS, "clock" }, /* 13 */ + { CS_PROCESSOR, ST, "processor" }, /* 14 */ + { CS_SYSTEM, ST, "system" }, /* 15 */ + { CS_VERSION, ST, "version" }, /* 16 */ + { CS_STABIL, FS, "stability" }, /* 17 */ + { CS_VARLIST, ST, "sys_var_list" }, /* 18 */ { 0, EOV, "" } }; @@ -162,7 +162,7 @@ struct ctl_var peer_var[] = { { CP_HPOLL, UI, "hpoll" }, /* 12 */ { CP_PRECISION, SI, "precision" }, /* 13 */ { CP_ROOTDELAY, FS, "rootdelay" }, /* 14 */ - { CP_ROOTDISPERSION, FU, "rootdispersion" }, /* 15 */ + { CP_ROOTDISPERSION, FU, "rootdisp" }, /* 15 */ { CP_REFID, RF, "refid" }, /* 16 */ { CP_REFTIME, TS, "reftime" }, /* 17 */ { CP_ORG, TS, "org" }, /* 18 */ @@ -224,75 +224,72 @@ struct ctl_var clock_var[] = { static const char *tstflagnames[] = { "pkt_dup", /* TEST1 */ "pkt_bogus", /* TEST2 */ - "pkt_proto", /* TEST3 */ + "pkt_unsync", /* TEST3 */ "pkt_denied", /* TEST4 */ "pkt_auth", /* TEST5 */ - "pkt_synch", /* TEST6 */ - "pkt_dist", /* TEST7 */ + "pkt_stratum", /* TEST6 */ + "pkt_header", /* TEST7 */ "pkt_autokey", /* TEST8 */ "pkt_crypto", /* TEST9 */ "peer_stratum", /* TEST10 */ "peer_dist", /* TEST11 */ "peer_loop", /* TEST12 */ - "peer_unfit" /* TEST13 */ + "peer_unreach" /* TEST13 */ }; -int ntpqmain P((int, char **)); +int ntpqmain (int, char **); /* * Built in command handler declarations */ -static int openhost P((const char *)); -static int sendpkt P((char *, int)); -static int getresponse P((int, int, u_short *, int *, char **, int)); -static int sendrequest P((int, int, int, int, char *)); -static char * tstflags P((u_long)); -static void getcmds P((void)); -static RETSIGTYPE abortcmd P((int)); -static void docmd P((const char *)); -static void tokenize P((const char *, char **, int *)); -static int findcmd P((char *, struct xcmd *, struct xcmd *, struct xcmd **)); -static int getarg P((char *, int, arg_v *)); -static int rtdatetolfp P((char *, l_fp *)); -static int decodearr P((char *, int *, l_fp *)); -static void help P((struct parse *, FILE *)); -#ifdef QSORT_USES_VOID_P -static int helpsort P((const void *, const void *)); -#else -static int helpsort P((char **, char **)); -#endif -static void printusage P((struct xcmd *, FILE *)); -static void timeout P((struct parse *, FILE *)); -static void auth_delay P((struct parse *, FILE *)); -static void host P((struct parse *, FILE *)); -static void ntp_poll P((struct parse *, FILE *)); -static void keyid P((struct parse *, FILE *)); -static void keytype P((struct parse *, FILE *)); -static void passwd P((struct parse *, FILE *)); -static void hostnames P((struct parse *, FILE *)); -static void setdebug P((struct parse *, FILE *)); -static void quit P((struct parse *, FILE *)); -static void version P((struct parse *, FILE *)); -static void raw P((struct parse *, FILE *)); -static void cooked P((struct parse *, FILE *)); -static void authenticate P((struct parse *, FILE *)); -static void ntpversion P((struct parse *, FILE *)); -static void warning P((const char *, const char *, const char *)); -static void error P((const char *, const char *, const char *)); -static u_long getkeyid P((const char *)); -static void atoascii P((int, char *, char *)); -static void makeascii P((int, char *, FILE *)); -static void rawprint P((int, int, char *, int, FILE *)); -static void startoutput P((void)); -static void output P((FILE *, char *, char *)); -static void endoutput P((FILE *)); -static void outputarr P((FILE *, char *, int, l_fp *)); -static void cookedprint P((int, int, char *, int, FILE *)); -#ifdef QSORT_USES_VOID_P -static int assoccmp P((const void *, const void *)); -#else -static int assoccmp P((struct association *, struct association *)); -#endif /* sgi || bsdi */ +static int openhost (const char *); + +static int sendpkt (void *, size_t); +static int getresponse (int, int, u_short *, int *, const char **, int); +static int sendrequest (int, int, int, int, char *); +static char * tstflags (u_long); +#ifndef BUILD_AS_LIB +static void getcmds (void); +#ifndef SYS_WINNT +static RETSIGTYPE abortcmd (int); +#endif /* SYS_WINNT */ +static void docmd (const char *); +static void tokenize (const char *, char **, int *); +static int getarg (char *, int, arg_v *); +#endif /* BUILD_AS_LIB */ +static int findcmd (char *, struct xcmd *, struct xcmd *, struct xcmd **); +static int rtdatetolfp (char *, l_fp *); +static int decodearr (char *, int *, l_fp *); +static void help (struct parse *, FILE *); +static int helpsort (const void *, const void *); +static void printusage (struct xcmd *, FILE *); +static void timeout (struct parse *, FILE *); +static void auth_delay (struct parse *, FILE *); +static void host (struct parse *, FILE *); +static void ntp_poll (struct parse *, FILE *); +static void keyid (struct parse *, FILE *); +static void keytype (struct parse *, FILE *); +static void passwd (struct parse *, FILE *); +static void hostnames (struct parse *, FILE *); +static void setdebug (struct parse *, FILE *); +static void quit (struct parse *, FILE *); +static void version (struct parse *, FILE *); +static void raw (struct parse *, FILE *); +static void cooked (struct parse *, FILE *); +static void authenticate (struct parse *, FILE *); +static void ntpversion (struct parse *, FILE *); +static void warning (const char *, const char *, const char *); +static void error (const char *, const char *, const char *); +static u_long getkeyid (const char *); +static void atoascii (const char *, size_t, char *, size_t); +static void cookedprint (int, int, const char *, int, int, FILE *); +static void rawprint (int, int, const char *, int, int, FILE *); +static void startoutput (void); +static void output (FILE *, char *, char *); +static void endoutput (FILE *); +static void outputarr (FILE *, char *, int, l_fp *); +static int assoccmp (const void *, const void *); +void ntpq_custom_opt_handler (tOptions *, tOptDesc *); /* @@ -361,10 +358,10 @@ struct xcmd builtins[] = { /* * Default values we use. */ +#define DEFHOST "localhost" /* default host name */ #define DEFTIMEOUT (5) /* 5 second time out */ #define DEFSTIMEOUT (2) /* 2 second time out after first */ #define DEFDELAY 0x51EB852 /* 20 milliseconds, l_fp fraction */ -#define DEFHOST "localhost" /* default host name */ #define LENHOSTNAME 256 /* host name is 256 characters long */ #define MAXCMDS 100 /* maximum commands on cmd line */ #define MAXHOSTS 200 /* maximum hosts on cmd line */ @@ -373,15 +370,16 @@ struct xcmd builtins[] = { #define MAXVARLEN 256 /* maximum length of a variable name */ #define MAXVALLEN 400 /* maximum length of a variable value */ #define MAXOUTLINE 72 /* maximum length of an output line */ -#define SCREENWIDTH 76 /* nominal screen width in columns */ +#define SCREENWIDTH 76 /* nominal screen width in columns */ /* * Some variables used and manipulated locally */ -struct timeval tvout = { DEFTIMEOUT, 0 }; /* time out for reads */ -struct timeval tvsout = { DEFSTIMEOUT, 0 }; /* secondary time out */ +struct sock_timeval tvout = { DEFTIMEOUT, 0 }; /* time out for reads */ +struct sock_timeval tvsout = { DEFSTIMEOUT, 0 };/* secondary time out */ l_fp delay_time; /* delay time */ char currenthost[LENHOSTNAME]; /* current host name */ +int currenthostisnum; /* is prior text from IP? */ struct sockaddr_in hostaddr = { 0 }; /* host address */ int showhostnames = 1; /* show host names by default */ @@ -392,13 +390,6 @@ int havehost = 0; /* set to 1 when host open */ int s_port = 0; struct servent *server_entry = NULL; /* server entry for ntp */ -#ifdef SYS_WINNT -DWORD NumberOfBytesWritten; - -HANDLE TimerThreadHandle = NULL; /* 1998/06/03 - Used in ntplib/machines.c */ -void timer(void) { ; }; /* 1998/06/03 - Used in ntplib/machines.c */ - -#endif /* SYS_WINNT */ /* * Sequence number used for requests. It is incremented before @@ -468,20 +459,22 @@ char *progname; volatile int debug; #ifdef NO_MAIN_ALLOWED +#ifndef BUILD_AS_LIB CALL(ntpq,"ntpq",ntpqmain); void clear_globals(void) { - extern int ntp_optind; - showhostnames = 0; /* don'tshow host names by default */ - ntp_optind = 0; - server_entry = NULL; /* server entry for ntp */ - havehost = 0; /* set to 1 when host open */ - numassoc = 0; /* number of cached associations */ - numcmds = 0; - numhosts = 0; + extern int ntp_optind; + showhostnames = 0; /* don'tshow host names by default */ + ntp_optind = 0; + server_entry = NULL; /* server entry for ntp */ + havehost = 0; /* set to 1 when host open */ + numassoc = 0; /* number of cached associations */ + numcmds = 0; + numhosts = 0; } -#endif +#endif /* !BUILD_AS_LIB */ +#endif /* NO_MAIN_ALLOWED */ /* * main - parse arguments and handle options @@ -497,6 +490,7 @@ main( } #endif +#ifndef BUILD_AS_LIB int ntpqmain( int argc, @@ -513,61 +507,42 @@ ntpqmain( delay_time.l_ui = 0; delay_time.l_uf = DEFDELAY; -#ifdef SYS_WINNT - if (!Win32InitSockets()) - { - fprintf(stderr, "No useable winsock.dll:"); - exit(1); - } -#endif /* SYS_WINNT */ + init_lib(); /* sets up ipv4_works, ipv6_works */ + ssl_applink(); - /* Check to see if we have IPv6. Otherwise force the -4 flag */ - if (isc_net_probeipv6() != ISC_R_SUCCESS) { + /* Check to see if we have IPv6. Otherwise default to IPv4 */ + if (!ipv6_works) ai_fam_default = AF_INET; - } progname = argv[0]; { - int optct = optionProcess(&ntpqOptions, argc, argv); + int optct = ntpOptionProcess(&ntpqOptions, argc, argv); argc -= optct; argv += optct; } - switch (WHICH_IDX_IPV4) { - case INDEX_OPT_IPV4: + /* + * Process options other than -c and -p, which are specially + * handled by ntpq_custom_opt_handler(). + */ + + debug = DESC(DEBUG_LEVEL).optOccCt; + + if (HAVE_OPT(IPV4)) ai_fam_templ = AF_INET; - break; - case INDEX_OPT_IPV6: + else if (HAVE_OPT(IPV6)) ai_fam_templ = AF_INET6; - break; - default: + else ai_fam_templ = ai_fam_default; - break; - } - - if (HAVE_OPT(COMMAND)) { - int cmdct = STACKCT_OPT( COMMAND ); - const char** cmds = STACKLST_OPT( COMMAND ); - while (cmdct-- > 0) { - ADDCMD(*cmds++); - } - } - - debug = DESC(DEBUG_LEVEL).optOccCt; - - if (HAVE_OPT(INTERACTIVE)) { + if (HAVE_OPT(INTERACTIVE)) interactive = 1; - } - if (HAVE_OPT(NUMERIC)) { + if (HAVE_OPT(NUMERIC)) showhostnames = 0; - } - if (HAVE_OPT(PEERS)) { - ADDCMD("peers"); - } + old_rv = HAVE_OPT(OLD_RV); #if 0 while ((c = ntp_getopt(argc, argv, "46c:dinp")) != EOF) @@ -604,11 +579,12 @@ ntpqmain( exit(2); } #endif + NTP_INSIST(ntp_optind <= argc); if (ntp_optind == argc) { ADDHOST(DEFHOST); } else { for (; ntp_optind < argc; ntp_optind++) - ADDHOST(argv[ntp_optind]); + ADDHOST(argv[ntp_optind]); } if (numcmds == 0 && interactive == 0 @@ -630,8 +606,8 @@ ntpqmain( for (ihost = 0; ihost < numhosts; ihost++) { if (openhost(chosts[ihost])) - for (icmd = 0; icmd < numcmds; icmd++) - docmd(ccmds[icmd]); + for (icmd = 0; icmd < numcmds; icmd++) + docmd(ccmds[icmd]); } } #ifdef SYS_WINNT @@ -639,12 +615,12 @@ ntpqmain( #endif /* SYS_WINNT */ return 0; } - +#endif /* !BUILD_AS_LIB */ /* * openhost - open a socket to a host */ -static int +static int openhost( const char *hname ) @@ -662,12 +638,16 @@ openhost( cp = hname; - if(*cp == '[') { + if (*cp == '[') { cp++; - for(i = 0; *cp != ']'; cp++, i++) + for (i = 0; *cp && *cp != ']'; cp++, i++) name[i] = *cp; - name[i] = '\0'; - hname = name; + if (*cp == ']') { + name[i] = '\0'; + hname = name; + } else { + return 0; + } } /* @@ -678,11 +658,11 @@ openhost( * give it an IPv4 address to lookup. */ strcpy(service, "ntp"); - memset((char *)&hints, 0, sizeof(struct addrinfo)); + ZERO(hints); hints.ai_family = ai_fam_templ; hints.ai_protocol = IPPROTO_UDP; hints.ai_socktype = SOCK_DGRAM; - hints.ai_flags = AI_NUMERICHOST; + hints.ai_flags = Z_AI_NUMERICHOST; a_info = getaddrinfo(hname, service, &hints, &ai); if (a_info == EAI_NONAME @@ -696,32 +676,35 @@ openhost( #endif a_info = getaddrinfo(hname, service, &hints, &ai); } +#ifdef AI_ADDRCONFIG /* Some older implementations don't like AI_ADDRCONFIG. */ if (a_info == EAI_BADFLAGS) { hints.ai_flags = AI_CANONNAME; a_info = getaddrinfo(hname, service, &hints, &ai); } +#endif if (a_info != 0) { (void) fprintf(stderr, "%s\n", gai_strerror(a_info)); return 0; } - if (ai->ai_canonname == NULL) { - strncpy(temphost, stoa((struct sockaddr_storage *)ai->ai_addr), - LENHOSTNAME); - temphost[LENHOSTNAME-1] = '\0'; - + if (!showhostnames || ai->ai_canonname == NULL) { + strncpy(temphost, + stoa((sockaddr_u *)ai->ai_addr), + LENHOSTNAME); + currenthostisnum = TRUE; } else { strncpy(temphost, ai->ai_canonname, LENHOSTNAME); - temphost[LENHOSTNAME-1] = '\0'; + currenthostisnum = FALSE; } + temphost[LENHOSTNAME-1] = '\0'; if (debug > 2) - printf("Opening host %s\n", temphost); + printf("Opening host %s\n", temphost); if (havehost == 1) { if (debug > 2) - printf("Closing old host %s\n", currenthost); + printf("Closing old host %s\n", currenthost); (void) closesocket(sockfd); havehost = 0; } @@ -744,9 +727,13 @@ openhost( int optionValue = SO_SYNCHRONOUS_NONALERT; int err; - err = setsockopt(INVALID_SOCKET, SOL_SOCKET, SO_OPENTYPE, (char *)&optionValue, sizeof(optionValue)); - if (err != NO_ERROR) { - (void) fprintf(stderr, "cannot open nonoverlapped sockets\n"); + err = setsockopt(INVALID_SOCKET, SOL_SOCKET, SO_OPENTYPE, + (char *)&optionValue, sizeof(optionValue)); + if (err) { + err = WSAGetLastError(); + fprintf(stderr, + "setsockopt(SO_SYNCHRONOUS_NONALERT) " + "error: %s\n", strerror(err)); exit(1); } } @@ -789,13 +776,12 @@ openhost( */ static int sendpkt( - char *xdata, - int xdatalen + void * xdata, + size_t xdatalen ) { if (debug >= 3) - printf("Sending %d octets\n", xdatalen); - + printf("Sending %lu octets\n", (u_long)xdatalen); if (send(sockfd, xdata, (size_t)xdatalen, 0) == -1) { warning("write to %s failed", currenthost, ""); @@ -804,13 +790,15 @@ sendpkt( if (debug >= 4) { int first = 8; + char *cdata = xdata; + printf("Packet data:\n"); while (xdatalen-- > 0) { if (first-- == 0) { printf("\n"); first = 7; } - printf(" %02x", *xdata++ & 0xff); + printf(" %02x", *cdata++ & 0xff); } printf("\n"); } @@ -828,20 +816,26 @@ getresponse( int associd, u_short *rstatus, int *rsize, - char **rdata, + const char **rdata, int timeo ) { struct ntp_control rpkt; - struct timeval tvo; + struct sock_timeval tvo; u_short offsets[MAXFRAGS+1]; u_short counts[MAXFRAGS+1]; u_short offset; u_short count; - int numfrags; + size_t numfrags; + size_t f; + size_t ff; int seenlastfrag; + int shouldbesize; fd_set fds; int n; + int len; + int first; + char *data; /* * This is pretty tricky. We may get between 1 and MAXFRAG packets @@ -852,7 +846,7 @@ getresponse( */ *rsize = 0; if (rstatus) - *rstatus = 0; + *rstatus = 0; *rdata = (char *)pktdata; numfrags = 0; @@ -860,305 +854,342 @@ getresponse( FD_ZERO(&fds); - again: - if (numfrags == 0) - tvo = tvout; - else - tvo = tvsout; - - FD_SET(sockfd, &fds); - n = select(sockfd+1, &fds, (fd_set *)0, (fd_set *)0, &tvo); + /* + * Loop until we have an error or a complete response. Nearly all + * code paths to loop again use continue. + */ + for (;;) { -#if 0 - if (debug >= 1) - printf("select() returns %d\n", n); -#endif + if (numfrags == 0) + tvo = tvout; + else + tvo = tvsout; + + FD_SET(sockfd, &fds); + n = select(sockfd + 1, &fds, NULL, NULL, &tvo); - if (n == -1) { - warning("select fails", "", ""); - return -1; - } - if (n == 0) { - /* - * Timed out. Return what we have - */ - if (numfrags == 0) { - if (timeo) - (void) fprintf(stderr, - "%s: timed out, nothing received\n", - currenthost); - return ERR_TIMEOUT; - } else { + if (n == -1) { + warning("select fails", "", ""); + return -1; + } + if (n == 0) { + /* + * Timed out. Return what we have + */ + if (numfrags == 0) { + if (timeo) + fprintf(stderr, + "%s: timed out, nothing received\n", + currenthost); + return ERR_TIMEOUT; + } if (timeo) - (void) fprintf(stderr, - "%s: timed out with incomplete data\n", - currenthost); + fprintf(stderr, + "%s: timed out with incomplete data\n", + currenthost); if (debug) { - printf("Received fragments:\n"); - for (n = 0; n < numfrags; n++) - printf("%4d %d\n", offsets[n], - counts[n]); - if (seenlastfrag) - printf("last fragment received\n"); - else - printf("last fragment not received\n"); + fprintf(stderr, + "ERR_INCOMPLETE: Received fragments:\n"); + for (f = 0; f < numfrags; f++) + fprintf(stderr, + "%2u: %5d %5d\t%3d octets\n", + f, offsets[f], + offsets[f] + + counts[f], + counts[f]); + fprintf(stderr, + "last fragment %sreceived\n", + (seenlastfrag) + ? "" + : "not "); } return ERR_INCOMPLETE; } - } - n = recv(sockfd, (char *)&rpkt, sizeof(rpkt), 0); - if (n == -1) { - warning("read", "", ""); - return -1; - } + n = recv(sockfd, (char *)&rpkt, sizeof(rpkt), 0); + if (n == -1) { + warning("read", "", ""); + return -1; + } - if (debug >= 4) { - int len = n, first = 8; - char *data = (char *)&rpkt; + if (debug >= 4) { + len = n; + first = 8; + data = (char *)&rpkt; - printf("Packet data:\n"); - while (len-- > 0) { - if (first-- == 0) { - printf("\n"); - first = 7; + printf("Packet data:\n"); + while (len-- > 0) { + if (first-- == 0) { + printf("\n"); + first = 7; + } + printf(" %02x", *data++ & 0xff); } - printf(" %02x", *data++ & 0xff); + printf("\n"); } - printf("\n"); - } - /* - * Check for format errors. Bug proofing. - */ - if (n < CTL_HEADER_LEN) { - if (debug) - printf("Short (%d byte) packet received\n", n); - goto again; - } - if (PKT_VERSION(rpkt.li_vn_mode) > NTP_VERSION - || PKT_VERSION(rpkt.li_vn_mode) < NTP_OLDVERSION) { - if (debug) - printf("Packet received with version %d\n", - PKT_VERSION(rpkt.li_vn_mode)); - goto again; - } - if (PKT_MODE(rpkt.li_vn_mode) != MODE_CONTROL) { - if (debug) - printf("Packet received with mode %d\n", - PKT_MODE(rpkt.li_vn_mode)); - goto again; - } - if (!CTL_ISRESPONSE(rpkt.r_m_e_op)) { - if (debug) - printf("Received request packet, wanted response\n"); - goto again; - } + /* + * Check for format errors. Bug proofing. + */ + if (n < CTL_HEADER_LEN) { + if (debug) + printf("Short (%d byte) packet received\n", n); + continue; + } + if (PKT_VERSION(rpkt.li_vn_mode) > NTP_VERSION + || PKT_VERSION(rpkt.li_vn_mode) < NTP_OLDVERSION) { + if (debug) + printf("Packet received with version %d\n", + PKT_VERSION(rpkt.li_vn_mode)); + continue; + } + if (PKT_MODE(rpkt.li_vn_mode) != MODE_CONTROL) { + if (debug) + printf("Packet received with mode %d\n", + PKT_MODE(rpkt.li_vn_mode)); + continue; + } + if (!CTL_ISRESPONSE(rpkt.r_m_e_op)) { + if (debug) + printf("Received request packet, wanted response\n"); + continue; + } - /* - * Check opcode and sequence number for a match. - * Could be old data getting to us. - */ - if (ntohs(rpkt.sequence) != sequence) { - if (debug) - printf( - "Received sequnce number %d, wanted %d\n", - ntohs(rpkt.sequence), sequence); - goto again; - } - if (CTL_OP(rpkt.r_m_e_op) != opcode) { - if (debug) - printf( - "Received opcode %d, wanted %d (sequence number okay)\n", - CTL_OP(rpkt.r_m_e_op), opcode); - goto again; - } + /* + * Check opcode and sequence number for a match. + * Could be old data getting to us. + */ + if (ntohs(rpkt.sequence) != sequence) { + if (debug) + printf("Received sequnce number %d, wanted %d\n", + ntohs(rpkt.sequence), sequence); + continue; + } + if (CTL_OP(rpkt.r_m_e_op) != opcode) { + if (debug) + printf( + "Received opcode %d, wanted %d (sequence number okay)\n", + CTL_OP(rpkt.r_m_e_op), opcode); + continue; + } - /* - * Check the error code. If non-zero, return it. - */ - if (CTL_ISERROR(rpkt.r_m_e_op)) { - int errcode; + /* + * Check the error code. If non-zero, return it. + */ + if (CTL_ISERROR(rpkt.r_m_e_op)) { + int errcode; - errcode = (ntohs(rpkt.status) >> 8) & 0xff; - if (debug && CTL_ISMORE(rpkt.r_m_e_op)) { - printf("Error code %d received on not-final packet\n", - errcode); + errcode = (ntohs(rpkt.status) >> 8) & 0xff; + if (debug && CTL_ISMORE(rpkt.r_m_e_op)) { + printf("Error code %d received on not-final packet\n", + errcode); + } + if (errcode == CERR_UNSPEC) + return ERR_UNSPEC; + return errcode; } - if (errcode == CERR_UNSPEC) - return ERR_UNSPEC; - return errcode; - } - /* - * Check the association ID to make sure it matches what - * we sent. - */ - if (ntohs(rpkt.associd) != associd) { - if (debug) - printf("Association ID %d doesn't match expected %d\n", - ntohs(rpkt.associd), associd); /* - * Hack for silly fuzzballs which, at the time of writing, - * return an assID of sys.peer when queried for system variables. + * Check the association ID to make sure it matches what + * we sent. */ + if (ntohs(rpkt.associd) != associd) { + if (debug) + printf("Association ID %d doesn't match expected %d\n", + ntohs(rpkt.associd), associd); + /* + * Hack for silly fuzzballs which, at the time of writing, + * return an assID of sys.peer when queried for system variables. + */ #ifdef notdef - goto again; + continue; #endif - } - - /* - * Collect offset and count. Make sure they make sense. - */ - offset = ntohs(rpkt.offset); - count = ntohs(rpkt.count); + } - if (debug >= 3) { - int shouldbesize; - u_long key; - u_long *lpkt; - int maclen; + /* + * Collect offset and count. Make sure they make sense. + */ + offset = ntohs(rpkt.offset); + count = ntohs(rpkt.count); /* - * Usually we ignore authentication, but for debugging purposes - * we watch it here. + * validate received payload size is padded to next 32-bit + * boundary and no smaller than claimed by rpkt.count */ - shouldbesize = CTL_HEADER_LEN + count; + if (n & 0x3) { + if (debug) + printf("Response packet not padded, " + "size = %d\n", n); + continue; + } - /* round to 8 octet boundary */ - shouldbesize = (shouldbesize + 7) & ~7; + shouldbesize = (CTL_HEADER_LEN + count + 3) & ~3; - if (n & 0x3) { - printf("Packet not padded, size = %d\n", n); - } if ((maclen = n - shouldbesize) >= MIN_MAC_LEN) { - printf( - "Packet shows signs of authentication (total %d, data %d, mac %d)\n", - n, shouldbesize, maclen); - lpkt = (u_long *)&rpkt; - printf("%08lx %08lx %08lx %08lx %08lx %08lx\n", - (u_long)ntohl(lpkt[(n - maclen)/sizeof(u_long) - 3]), - (u_long)ntohl(lpkt[(n - maclen)/sizeof(u_long) - 2]), - (u_long)ntohl(lpkt[(n - maclen)/sizeof(u_long) - 1]), - (u_long)ntohl(lpkt[(n - maclen)/sizeof(u_long)]), - (u_long)ntohl(lpkt[(n - maclen)/sizeof(u_long) + 1]), - (u_long)ntohl(lpkt[(n - maclen)/sizeof(u_long) + 2])); - key = ntohl(lpkt[(n - maclen) / sizeof(u_long)]); - printf("Authenticated with keyid %lu\n", (u_long)key); - if (key != 0 && key != info_auth_keyid) { - printf("We don't know that key\n"); - } else { - if (authdecrypt(key, (u_int32 *)&rpkt, - n - maclen, maclen)) { - printf("Auth okay!\n"); + if (n < shouldbesize) { + printf("Response packet claims %u octets " + "payload, above %d received\n", + count, + n - CTL_HEADER_LEN + ); + return ERR_INCOMPLETE; + } + + if (debug >= 3 && shouldbesize > n) { + u_int32 key; + u_int32 *lpkt; + int maclen; + + /* + * Usually we ignore authentication, but for debugging purposes + * we watch it here. + */ + /* round to 8 octet boundary */ + shouldbesize = (shouldbesize + 7) & ~7; + + maclen = n - shouldbesize; + if (maclen >= MIN_MAC_LEN) { + printf( + "Packet shows signs of authentication (total %d, data %d, mac %d)\n", + n, shouldbesize, maclen); + lpkt = (u_int32 *)&rpkt; + printf("%08lx %08lx %08lx %08lx %08lx %08lx\n", + (u_long)ntohl(lpkt[(n - maclen)/sizeof(u_int32) - 3]), + (u_long)ntohl(lpkt[(n - maclen)/sizeof(u_int32) - 2]), + (u_long)ntohl(lpkt[(n - maclen)/sizeof(u_int32) - 1]), + (u_long)ntohl(lpkt[(n - maclen)/sizeof(u_int32)]), + (u_long)ntohl(lpkt[(n - maclen)/sizeof(u_int32) + 1]), + (u_long)ntohl(lpkt[(n - maclen)/sizeof(u_int32) + 2])); + key = ntohl(lpkt[(n - maclen) / sizeof(u_int32)]); + printf("Authenticated with keyid %lu\n", (u_long)key); + if (key != 0 && key != info_auth_keyid) { + printf("We don't know that key\n"); } else { - printf("Auth failed!\n"); + if (authdecrypt(key, (u_int32 *)&rpkt, + n - maclen, maclen)) { + printf("Auth okay!\n"); + } else { + printf("Auth failed!\n"); + } } } } - } - if (debug >= 2) - printf("Got packet, size = %d\n", n); - if (count > (u_short)(n-CTL_HEADER_LEN)) { - if (debug) - printf( - "Received count of %d octets, data in packet is %d\n", - count, n-CTL_HEADER_LEN); - goto again; - } - if (count == 0 && CTL_ISMORE(rpkt.r_m_e_op)) { - if (debug) - printf("Received count of 0 in non-final fragment\n"); - goto again; - } - if (offset + count > sizeof(pktdata)) { - if (debug) - printf("Offset %d, count %d, too big for buffer\n", - offset, count); - return ERR_TOOMUCH; - } - if (seenlastfrag && !CTL_ISMORE(rpkt.r_m_e_op)) { - if (debug) - printf("Received second last fragment packet\n"); - goto again; - } + if (debug >= 2) + printf("Got packet, size = %d\n", n); + if ((int)count > (n - CTL_HEADER_LEN)) { + if (debug) + printf("Received count of %d octets, " + "data in packet is %d\n", + count, n-CTL_HEADER_LEN); + continue; + } + if (count == 0 && CTL_ISMORE(rpkt.r_m_e_op)) { + if (debug) + printf("Received count of 0 in non-final fragment\n"); + continue; + } + if (offset + count > sizeof(pktdata)) { + if (debug) + printf("Offset %d, count %d, too big for buffer\n", + offset, count); + return ERR_TOOMUCH; + } + if (seenlastfrag && !CTL_ISMORE(rpkt.r_m_e_op)) { + if (debug) + printf("Received second last fragment packet\n"); + continue; + } - /* - * So far, so good. Record this fragment, making sure it doesn't - * overlap anything. - */ - if (debug >= 2) - printf("Packet okay\n");; + /* + * So far, so good. Record this fragment, making sure it doesn't + * overlap anything. + */ + if (debug >= 2) + printf("Packet okay\n");; + + if (numfrags > (MAXFRAGS - 1)) { + if (debug) + printf("Number of fragments exceeds maximum %d\n", + MAXFRAGS - 1); + return ERR_TOOMUCH; + } - if (numfrags == MAXFRAGS) { - if (debug) - printf("Number of fragments exceeds maximum\n"); - return ERR_TOOMUCH; - } - - for (n = 0; n < numfrags; n++) { - if (offset == offsets[n]) - goto again; /* duplicate */ - if (offset < offsets[n]) - break; - } - - if ((u_short)(n > 0 && offsets[n-1] + counts[n-1]) > offset) - goto overlap; - if (n < numfrags && (u_short)(offset + count) > offsets[n]) - goto overlap; - - { - register int i; - - for (i = numfrags; i > n; i--) { - offsets[i] = offsets[i-1]; - counts[i] = counts[i-1]; + /* + * Find the position for the fragment relative to any + * previously received. + */ + for (f = 0; + f < numfrags && offsets[f] < offset; + f++) { + /* empty body */ ; } - } - offsets[n] = offset; - counts[n] = count; - numfrags++; - /* - * Got that stuffed in right. Figure out if this was the last. - * Record status info out of the last packet. - */ - if (!CTL_ISMORE(rpkt.r_m_e_op)) { - seenlastfrag = 1; - if (rstatus != 0) - *rstatus = ntohs(rpkt.status); - } + if (f < numfrags && offset == offsets[f]) { + if (debug) + printf("duplicate %u octets at %u ignored, prior %u at %u\n", + count, offset, counts[f], + offsets[f]); + continue; + } - /* - * Copy the data into the data buffer. - */ - memmove((char *)pktdata + offset, (char *)rpkt.data, count); + if (f > 0 && (offsets[f-1] + counts[f-1]) > offset) { + if (debug) + printf("received frag at %u overlaps with %u octet frag at %u\n", + offset, counts[f-1], + offsets[f-1]); + continue; + } - /* - * If we've seen the last fragment, look for holes in the sequence. - * If there aren't any, we're done. - */ - if (seenlastfrag && offsets[0] == 0) { - for (n = 1; n < numfrags; n++) { - if (offsets[n-1] + counts[n-1] != offsets[n]) - break; + if (f < numfrags && (offset + count) > offsets[f]) { + if (debug) + printf("received %u octet frag at %u overlaps with frag at %u\n", + count, offset, offsets[f]); + continue; } - if (n == numfrags) { - *rsize = offsets[numfrags-1] + counts[numfrags-1]; - return 0; + + for (ff = numfrags; ff > f; ff--) { + offsets[ff] = offsets[ff-1]; + counts[ff] = counts[ff-1]; } - } - goto again; + offsets[f] = offset; + counts[f] = count; + numfrags++; - overlap: - /* - * Print debugging message about overlapping fragments - */ - if (debug) - printf("Overlapping fragments returned in response\n"); - goto again; -} + /* + * Got that stuffed in right. Figure out if this was the last. + * Record status info out of the last packet. + */ + if (!CTL_ISMORE(rpkt.r_m_e_op)) { + seenlastfrag = 1; + if (rstatus != 0) + *rstatus = ntohs(rpkt.status); + } + + /* + * Copy the data into the data buffer. + */ + memcpy((char *)pktdata + offset, rpkt.data, count); + + /* + * If we've seen the last fragment, look for holes in the sequence. + * If there aren't any, we're done. + */ + if (seenlastfrag && offsets[0] == 0) { + for (f = 1; f < numfrags; f++) + if (offsets[f-1] + counts[f-1] != + offsets[f]) + break; + if (f == numfrags) { + *rsize = offsets[f-1] + counts[f-1]; + if (debug) + fprintf(stderr, + "%u packets reassembled into response\n", + numfrags); + return 0; + } + } + } /* giant for (;;) collecting response packets */ +} /* getresponse() */ /* @@ -1174,15 +1205,18 @@ sendrequest( ) { struct ntp_control qpkt; - int pktsize; + int pktsize; + u_long key_id; + char * pass; + int maclen; /* * Check to make sure the data will fit in one packet */ if (qsize > CTL_MAX_DATA_LEN) { - (void) fprintf(stderr, - "***Internal error! qsize (%d) too large\n", - qsize); + fprintf(stderr, + "***Internal error! qsize (%d) too large\n", + qsize); return 1; } @@ -1197,19 +1231,18 @@ sendrequest( qpkt.offset = 0; qpkt.count = htons((u_short)qsize); + pktsize = CTL_HEADER_LEN; + /* - * If we have data, copy it in and pad it out to a 64 - * bit boundary. + * If we have data, copy and pad it out to a 32-bit boundary. */ if (qsize > 0) { - memmove((char *)qpkt.data, qdata, (unsigned)qsize); - pktsize = qsize + CTL_HEADER_LEN; - while (pktsize & (sizeof(u_long) - 1)) { + memcpy(qpkt.data, qdata, (size_t)qsize); + pktsize += qsize; + while (pktsize & (sizeof(u_int32) - 1)) { qpkt.data[qsize++] = 0; pktsize++; } - } else { - pktsize = CTL_HEADER_LEN; } /* @@ -1217,76 +1250,167 @@ sendrequest( * we're going to have to think about it a little. */ if (!auth && !always_auth) { - return sendpkt((char *)&qpkt, pktsize); - } else { - const char *pass = "\0"; - int maclen = 0; - u_long my_keyid; + return sendpkt(&qpkt, pktsize); + } - /* - * Pad out packet to a multiple of 8 octets to be sure - * receiver can handle it. - */ - while (pktsize & 7) { - qpkt.data[qsize++] = 0; - pktsize++; - } + /* + * Pad out packet to a multiple of 8 octets to be sure + * receiver can handle it. + */ + while (pktsize & 7) { + qpkt.data[qsize++] = 0; + pktsize++; + } - /* - * Get the keyid and the password if we don't have one. - */ - if (info_auth_keyid == 0) { - int u_keyid = getkeyid("Keyid: "); - if (u_keyid == 0 || u_keyid > NTP_MAXKEY) { - (void) fprintf(stderr, - "Invalid key identifier\n"); - return 1; - } - info_auth_keyid = u_keyid; + /* + * Get the keyid and the password if we don't have one. + */ + if (info_auth_keyid == 0) { + key_id = getkeyid("Keyid: "); + if (key_id == 0 || key_id > NTP_MAXKEY) { + fprintf(stderr, + "Invalid key identifier\n"); + return 1; } - if (!authistrusted(info_auth_keyid)) { - pass = getpass("MD5 Password: "); - if (*pass == '\0') { - (void) fprintf(stderr, - "Invalid password\n"); - return (1); - } + info_auth_keyid = key_id; + } + if (!authistrusted(info_auth_keyid)) { + pass = getpass_keytype(info_auth_keytype); + if ('\0' == pass[0]) { + fprintf(stderr, "Invalid password\n"); + return 1; } - authusekey(info_auth_keyid, info_auth_keytype, (const u_char *)pass); + authusekey(info_auth_keyid, info_auth_keytype, + (u_char *)pass); authtrust(info_auth_keyid, 1); + } - /* - * Stick the keyid in the packet where - * cp currently points. Cp should be aligned - * properly. Then do the encryptions. - */ - my_keyid = htonl(info_auth_keyid); - memcpy(&qpkt.data[qsize], &my_keyid, sizeof my_keyid); - maclen = authencrypt(info_auth_keyid, (u_int32 *)&qpkt, - pktsize); - if (maclen == 0) { - (void) fprintf(stderr, "Key not found\n"); - return (1); - } - return sendpkt((char *)&qpkt, pktsize + maclen); + /* + * Do the encryption. + */ + maclen = authencrypt(info_auth_keyid, (void *)&qpkt, pktsize); + if (!maclen) { + fprintf(stderr, "Key not found\n"); + return 1; + } else if ((size_t)maclen != (info_auth_hashlen + sizeof(keyid_t))) { + fprintf(stderr, + "%d octet MAC, %lu expected with %lu octet digest\n", + maclen, (u_long)(info_auth_hashlen + sizeof(keyid_t)), + (u_long)info_auth_hashlen); + return 1; } - /*NOTREACHED*/ + + return sendpkt((char *)&qpkt, pktsize + maclen); } /* - * doquery - send a request and process the response + * show_error_msg - display the error text for a mode 6 error response. + */ +void +show_error_msg( + int m6resp, + associd_t associd + ) +{ + if (numhosts > 1) + fprintf(stderr, "server=%s ", currenthost); + + switch(m6resp) { + + case CERR_BADFMT: + fprintf(stderr, + "***Server reports a bad format request packet\n"); + break; + + case CERR_PERMISSION: + fprintf(stderr, + "***Server disallowed request (authentication?)\n"); + break; + + case CERR_BADOP: + fprintf(stderr, + "***Server reports a bad opcode in request\n"); + break; + + case CERR_BADASSOC: + fprintf(stderr, + "***Association ID %d unknown to server\n", + associd); + break; + + case CERR_UNKNOWNVAR: + fprintf(stderr, + "***A request variable unknown to the server\n"); + break; + + case CERR_BADVALUE: + fprintf(stderr, + "***Server indicates a request variable was bad\n"); + break; + + case ERR_UNSPEC: + fprintf(stderr, + "***Server returned an unspecified error\n"); + break; + + case ERR_TIMEOUT: + fprintf(stderr, "***Request timed out\n"); + break; + + case ERR_INCOMPLETE: + fprintf(stderr, + "***Response from server was incomplete\n"); + break; + + case ERR_TOOMUCH: + fprintf(stderr, + "***Buffer size exceeded for returned data\n"); + break; + + default: + fprintf(stderr, + "***Server returns unknown error code %d\n", + m6resp); + } +} + +/* + * doquery - send a request and process the response, displaying + * error messages for any error responses. */ int doquery( int opcode, - int associd, + associd_t associd, int auth, int qsize, char *qdata, u_short *rstatus, int *rsize, - char **rdata + const char **rdata + ) +{ + return doqueryex(opcode, associd, auth, qsize, qdata, rstatus, + rsize, rdata, FALSE); +} + + +/* + * doqueryex - send a request and process the response, optionally + * displaying error messages for any error responses. + */ +int +doqueryex( + int opcode, + associd_t associd, + int auth, + int qsize, + char *qdata, + u_short *rstatus, + int *rsize, + const char **rdata, + int quiet ) { int res; @@ -1296,7 +1420,7 @@ doquery( * Check to make sure host is open */ if (!havehost) { - (void) fprintf(stderr, "***No host open, use `host' command\n"); + fprintf(stderr, "***No host open, use `host' command\n"); return -1; } @@ -1309,7 +1433,7 @@ doquery( */ res = sendrequest(opcode, associd, auth, qsize, qdata); if (res != 0) - return res; + return res; /* * Get the response. If we got a standard error, print a message @@ -1328,94 +1452,40 @@ doquery( done = 1; goto again; } - if (numhosts > 1) - (void) fprintf(stderr, "server=%s ", currenthost); - switch(res) { - case CERR_BADFMT: - (void) fprintf(stderr, - "***Server reports a bad format request packet\n"); - break; - case CERR_PERMISSION: - (void) fprintf(stderr, - "***Server disallowed request (authentication?)\n"); - break; - case CERR_BADOP: - (void) fprintf(stderr, - "***Server reports a bad opcode in request\n"); - break; - case CERR_BADASSOC: - (void) fprintf(stderr, - "***Association ID %d unknown to server\n",associd); - break; - case CERR_UNKNOWNVAR: - (void) fprintf(stderr, - "***A request variable unknown to the server\n"); - break; - case CERR_BADVALUE: - (void) fprintf(stderr, - "***Server indicates a request variable was bad\n"); - break; - case ERR_UNSPEC: - (void) fprintf(stderr, - "***Server returned an unspecified error\n"); - break; - case ERR_TIMEOUT: - (void) fprintf(stderr, "***Request timed out\n"); - break; - case ERR_INCOMPLETE: - (void) fprintf(stderr, - "***Response from server was incomplete\n"); - break; - case ERR_TOOMUCH: - (void) fprintf(stderr, - "***Buffer size exceeded for returned data\n"); - break; - default: - (void) fprintf(stderr, - "***Server returns unknown error code %d\n", res); - break; - } + if (!quiet) + show_error_msg(res, associd); + } return res; } +#ifndef BUILD_AS_LIB /* * getcmds - read commands from the standard input and execute them */ static void getcmds(void) { -#if defined(HAVE_LIBREADLINE) || defined(HAVE_LIBEDIT) - char *line; - - for (;;) { - if ((line = readline(interactive?prompt:"")) == NULL) return; - if (*line) add_history(line); - docmd(line); - free(line); - } -#else /* not (HAVE_LIBREADLINE || HAVE_LIBEDIT) */ - char line[MAXLINE]; - - for (;;) { - if (interactive) { -#ifdef VMS /* work around a problem with mixing stdout & stderr */ - fputs("",stdout); -#endif - (void) fputs(prompt, stderr); - (void) fflush(stderr); - } + char * line; + int count; - if (fgets(line, sizeof line, stdin) == NULL) - return; + ntp_readline_init(interactive ? prompt : NULL); + + for (;;) { + line = ntp_readline(&count); + if (NULL == line) + break; + docmd(line); + free(line); + } - docmd(line); - } -#endif /* not (HAVE_LIBREADLINE || HAVE_LIBEDIT) */ + ntp_readline_uninit(); } +#endif /* !BUILD_AS_LIB */ -#ifndef SYS_WINNT /* Under NT cannot handle SIGINT, WIN32 spawns a handler */ + +#if !defined(SYS_WINNT) && !defined(BUILD_AS_LIB) /* * abortcmd - catch interrupts and abort the current command */ @@ -1430,8 +1500,10 @@ abortcmd( (void) fflush(stderr); if (jump) longjmp(interrupt_buf, 1); } -#endif /* SYS_WINNT */ +#endif /* !SYS_WINNT && !BUILD_AS_LIB */ + +#ifndef BUILD_AS_LIB /* * docmd - decode the command line and execute a command */ @@ -1482,9 +1554,9 @@ docmd( break; } if ((xcmd->arg[i] & OPT) && (*tokens[i+1] == '>')) - break; + break; if (!getarg(tokens[i+1], (int)xcmd->arg[i], &pcmd.argval[i])) - return; + return; pcmd.nargs++; } @@ -1493,9 +1565,9 @@ docmd( char *fname; if (*(tokens[i]+1) != '\0') - fname = tokens[i]+1; + fname = tokens[i]+1; else if ((i+1) < ntok) - fname = tokens[i+1]; + fname = tokens[i+1]; else { (void) fprintf(stderr, "***No file for redirect\n"); return; @@ -1527,7 +1599,13 @@ docmd( /* * tokenize - turn a command line into tokens + * + * SK: Modified to allow a quoted string + * + * HMS: If the first character of the first token is a ':' then (after + * eating inter-token whitespace) the 2nd token is the rest of the line. */ + static void tokenize( const char *line, @@ -1543,84 +1621,44 @@ tokenize( cp = line; for (*ntok = 0; *ntok < MAXTOKENS; (*ntok)++) { tokens[*ntok] = sp; + + /* Skip inter-token whitespace */ while (ISSPACE(*cp)) cp++; + + /* If we're at EOL we're done */ if (ISEOL(*cp)) break; - do { - *sp++ = *cp++; - } while (!ISSPACE(*cp) && !ISEOL(*cp)); - - *sp++ = '\0'; - } -} - - - -/* - * findcmd - find a command in a command description table - */ -static int -findcmd( - register char *str, - struct xcmd *clist1, - struct xcmd *clist2, - struct xcmd **cmd - ) -{ - register struct xcmd *cl; - register int clen; - int nmatch; - struct xcmd *nearmatch = NULL; - struct xcmd *clist; - clen = strlen(str); - nmatch = 0; - if (clist1 != 0) - clist = clist1; - else if (clist2 != 0) - clist = clist2; - else - return 0; + /* If this is the 2nd token and the first token begins + * with a ':', then just grab to EOL. + */ - again: - for (cl = clist; cl->keyword != 0; cl++) { - /* do a first character check, for efficiency */ - if (*str != *(cl->keyword)) - continue; - if (strncmp(str, cl->keyword, (unsigned)clen) == 0) { - /* - * Could be extact match, could be approximate. - * Is exact if the length of the keyword is the - * same as the str. - */ - if (*((cl->keyword) + clen) == '\0') { - *cmd = cl; - return 1; - } - nmatch++; - nearmatch = cl; + if (*ntok == 1 && tokens[0][0] == ':') { + do { + *sp++ = *cp++; + } while (!ISEOL(*cp)); } - } - /* - * See if there is more to do. If so, go again. Sorry about the - * goto, too much looking at BSD sources... - */ - if (clist == clist1 && clist2 != 0) { - clist = clist2; - goto again; - } + /* Check if this token begins with a double quote. + * If yes, continue reading till the next double quote + */ + else if (*cp == '\"') { + ++cp; + do { + *sp++ = *cp++; + } while ((*cp != '\"') && !ISEOL(*cp)); + /* HMS: a missing closing " should be an error */ + } + else { + do { + *sp++ = *cp++; + } while ((*cp != '\"') && !ISSPACE(*cp) && !ISEOL(*cp)); + /* HMS: Why check for a " in the previous line? */ + } - /* - * If we got extactly 1 near match, use it, else return number - * of matches. - */ - if (nmatch == 1) { - *cmd = nearmatch; - return 1; + *sp++ = '\0'; } - return nmatch; } @@ -1714,6 +1752,74 @@ getarg( return 1; } +#endif /* !BUILD_AS_LIB */ + + +/* + * findcmd - find a command in a command description table + */ +static int +findcmd( + register char *str, + struct xcmd *clist1, + struct xcmd *clist2, + struct xcmd **cmd + ) +{ + register struct xcmd *cl; + register int clen; + int nmatch; + struct xcmd *nearmatch = NULL; + struct xcmd *clist; + + clen = strlen(str); + nmatch = 0; + if (clist1 != 0) + clist = clist1; + else if (clist2 != 0) + clist = clist2; + else + return 0; + + again: + for (cl = clist; cl->keyword != 0; cl++) { + /* do a first character check, for efficiency */ + if (*str != *(cl->keyword)) + continue; + if (strncmp(str, cl->keyword, (unsigned)clen) == 0) { + /* + * Could be extact match, could be approximate. + * Is exact if the length of the keyword is the + * same as the str. + */ + if (*((cl->keyword) + clen) == '\0') { + *cmd = cl; + return 1; + } + nmatch++; + nearmatch = cl; + } + } + + /* + * See if there is more to do. If so, go again. Sorry about the + * goto, too much looking at BSD sources... + */ + if (clist == clist1 && clist2 != 0) { + clist = clist2; + goto again; + } + + /* + * If we got extactly 1 near match, use it, else return number + * of matches. + */ + if (nmatch == 1) { + *cmd = nearmatch; + return 1; + } + return nmatch; +} /* @@ -1723,41 +1829,47 @@ getarg( int getnetnum( const char *hname, - struct sockaddr_storage *num, + sockaddr_u *num, char *fullhost, int af ) { - int sockaddr_len; struct addrinfo hints, *ai = NULL; - sockaddr_len = (af == AF_INET) - ? sizeof(struct sockaddr_in) - : sizeof(struct sockaddr_in6); - memset((char *)&hints, 0, sizeof(struct addrinfo)); + ZERO(hints); hints.ai_flags = AI_CANONNAME; #ifdef AI_ADDRCONFIG hints.ai_flags |= AI_ADDRCONFIG; #endif - /* decodenetnum works with addresses only */ + /* + * decodenetnum only works with addresses, but handles syntax + * that getaddrinfo doesn't: [2001::1]:1234 + */ if (decodenetnum(hname, num)) { - if (fullhost != 0) { - getnameinfo((struct sockaddr *)num, sockaddr_len, - fullhost, sizeof(fullhost), NULL, 0, - NI_NUMERICHOST); - } + if (fullhost != NULL) + getnameinfo(&num->sa, SOCKLEN(num), fullhost, + LENHOSTNAME, NULL, 0, 0); return 1; } else if (getaddrinfo(hname, "ntp", &hints, &ai) == 0) { - memmove((char *)num, ai->ai_addr, ai->ai_addrlen); - if (ai->ai_canonname != 0) - (void) strcpy(fullhost, ai->ai_canonname); + NTP_INSIST(sizeof(*num) >= ai->ai_addrlen); + memcpy(num, ai->ai_addr, ai->ai_addrlen); + if (fullhost != NULL) { + if (ai->ai_canonname != NULL) { + strncpy(fullhost, ai->ai_canonname, + LENHOSTNAME); + fullhost[LENHOSTNAME - 1] = '\0'; + } else { + getnameinfo(&num->sa, SOCKLEN(num), + fullhost, LENHOSTNAME, NULL, + 0, 0); + } + } return 1; - } else { - (void) fprintf(stderr, "***Can't find host %s\n", hname); - return 0; } - /*NOTREACHED*/ + fprintf(stderr, "***Can't find host %s\n", hname); + + return 0; } /* @@ -1766,14 +1878,42 @@ getnetnum( */ char * nntohost( - struct sockaddr_storage *netnum + sockaddr_u *netnum + ) +{ + return nntohost_col(netnum, LIB_BUFLENGTH - 1, FALSE); +} + + +/* + * nntohost_col - convert network number to host name in fixed width. + * This routine enforces the showhostnames setting. + * When displaying hostnames longer than the width, + * the first part of the hostname is displayed. When + * displaying numeric addresses longer than the width, + * Such as IPv6 addresses, the caller decides whether + * the first or last of the numeric address is used. + */ +char * +nntohost_col( + sockaddr_u * addr, + size_t width, + int preserve_lowaddrbits ) { - if (!showhostnames) - return stoa(netnum); - if ((netnum->ss_family == AF_INET) && ISREFCLOCKADR(netnum)) - return refnumtoa(netnum); - return socktohost(netnum); + const char * out; + + if (!showhostnames) { + if (preserve_lowaddrbits) + out = trunc_left(stoa(addr), width); + else + out = trunc_right(stoa(addr), width); + } else if (ISREFCLOCKADR(addr)) { + out = refnumtoa(addr); + } else { + out = trunc_right(socktohost(addr), width); + } + return out; } @@ -1913,24 +2053,26 @@ decodets( l_fp *lfp ) { + char *cp; + char buf[30]; + size_t b; + /* * If it starts with a 0x, decode as hex. */ if (*str == '0' && (*(str+1) == 'x' || *(str+1) == 'X')) - return hextolfp(str+2, lfp); + return hextolfp(str+2, lfp); /* * If it starts with a '"', try it as an RT-11 date. */ if (*str == '"') { - register char *cp = str+1; - register char *bp; - char buf[30]; - - bp = buf; - while (*cp != '"' && *cp != '\0' && bp < &buf[29]) - *bp++ = *cp++; - *bp = '\0'; + cp = str + 1; + b = 0; + while ('"' != *cp && '\0' != *cp && + b < COUNTOF(buf) - 1) + buf[b++] = *cp++; + buf[b] = '\0'; return rtdatetolfp(buf, lfp); } @@ -1939,14 +2081,15 @@ decodets( * about heuristics! */ if ((*str >= 'A' && *str <= 'F') || (*str >= 'a' && *str <= 'f')) - return hextolfp(str, lfp); + return hextolfp(str, lfp); /* * Try it as a decimal. If this fails, try as an unquoted * RT-11 date. This code should go away eventually. */ if (atolfp(str, lfp)) - return 1; + return 1; + return rtdatetolfp(str, lfp); } @@ -1975,8 +2118,8 @@ decodeint( { if (*str == '0') { if (*(str+1) == 'x' || *(str+1) == 'X') - return hextoint(str+2, val); - return octtoint(str, val); + return hextoint(str+2, (u_long *)val); + return octtoint(str, (u_long *)val); } return atoint(str, val); } @@ -2051,61 +2194,55 @@ help( FILE *fp ) { - struct xcmd *xcp; + struct xcmd *xcp = NULL; /* quiet warning */ char *cmd; const char *list[100]; - int word, words; - int row, rows; - int col, cols; + size_t word, words; + size_t row, rows; + size_t col, cols; + size_t length; if (pcmd->nargs == 0) { words = 0; - for (xcp = builtins; xcp->keyword != 0; xcp++) { + for (xcp = builtins; xcp->keyword != NULL; xcp++) { if (*(xcp->keyword) != '?') - list[words++] = xcp->keyword; + list[words++] = xcp->keyword; } - for (xcp = opcmds; xcp->keyword != 0; xcp++) - list[words++] = xcp->keyword; + for (xcp = opcmds; xcp->keyword != NULL; xcp++) + list[words++] = xcp->keyword; - qsort( -#ifdef QSORT_USES_VOID_P - (void *) -#else - (char *) -#endif - (list), (size_t)(words), sizeof(char *), helpsort); + qsort((void *)list, (size_t)words, sizeof(list[0]), + helpsort); col = 0; for (word = 0; word < words; word++) { - int length = strlen(list[word]); - if (col < length) { - col = length; - } + length = strlen(list[word]); + col = max(col, length); } cols = SCREENWIDTH / ++col; - rows = (words + cols - 1) / cols; + rows = (words + cols - 1) / cols; - (void) fprintf(fp, "ntpq commands:\n"); + fprintf(fp, "ntpq commands:\n"); for (row = 0; row < rows; row++) { - for (word = row; word < words; word += rows) { - (void) fprintf(fp, "%-*.*s", col, col-1, list[word]); - } - (void) fprintf(fp, "\n"); - } + for (word = row; word < words; word += rows) + fprintf(fp, "%-*.*s", col, col-1, + list[word]); + fprintf(fp, "\n"); + } } else { cmd = pcmd->argval[0].string; words = findcmd(cmd, builtins, opcmds, &xcp); if (words == 0) { - (void) fprintf(stderr, - "Command `%s' is unknown\n", cmd); + fprintf(stderr, + "Command `%s' is unknown\n", cmd); return; } else if (words >= 2) { - (void) fprintf(stderr, - "Command `%s' is ambiguous\n", cmd); + fprintf(stderr, + "Command `%s' is ambiguous\n", cmd); return; } - (void) fprintf(fp, "function: %s\n", xcp->comment); + fprintf(fp, "function: %s\n", xcp->comment); printusage(xcp, fp); } } @@ -2114,29 +2251,18 @@ help( /* * helpsort - do hostname qsort comparisons */ -#ifdef QSORT_USES_VOID_P static int helpsort( const void *t1, const void *t2 ) { - char const * const * name1 = (char const * const *)t1; - char const * const * name2 = (char const * const *)t2; + const char * const * name1 = t1; + const char * const * name2 = t2; return strcmp(*name1, *name2); } -#else -static int -helpsort( - char **name1, - char **name2 - ) -{ - return strcmp(*name1, *name2); -} -#endif /* * printusage - print usage information for a command @@ -2172,11 +2298,11 @@ timeout( int val; if (pcmd->nargs == 0) { - val = tvout.tv_sec * 1000 + tvout.tv_usec / 1000; + val = (int)tvout.tv_sec * 1000 + tvout.tv_usec / 1000; (void) fprintf(fp, "primary timeout %d ms\n", val); } else { tvout.tv_sec = pcmd->argval[0].uval / 1000; - tvout.tv_usec = (pcmd->argval[0].uval - (tvout.tv_sec * 1000)) + tvout.tv_usec = (pcmd->argval[0].uval - ((long)tvout.tv_sec * 1000)) * 1000; } } @@ -2229,9 +2355,10 @@ host( if (pcmd->nargs == 0) { if (havehost) - (void) fprintf(fp, "current host is %s\n", currenthost); + (void) fprintf(fp, "current host is %s\n", + currenthost); else - (void) fprintf(fp, "no current host\n"); + (void) fprintf(fp, "no current host\n"); return; } @@ -2245,7 +2372,8 @@ host( else { if (havehost) (void) fprintf(fp, - "current host remains %s\n", currenthost); + "current host remains %s\n", + currenthost); else (void) fprintf(fp, "still no current host\n"); return; @@ -2257,10 +2385,11 @@ host( numassoc = 0; } else { if (havehost) - (void) fprintf(fp, - "current host remains %s\n", currenthost); + (void) fprintf(fp, + "current host remains %s\n", + currenthost); else - (void) fprintf(fp, "still no current host\n"); + (void) fprintf(fp, "still no current host\n"); } } @@ -2310,21 +2439,34 @@ keytype( FILE *fp ) { - if (pcmd->nargs == 0) - fprintf(fp, "keytype is %s\n", - (info_auth_keytype == KEY_TYPE_MD5) ? "MD5" : "???"); - else - switch (*(pcmd->argval[0].string)) { - case 'm': - case 'M': - info_auth_keytype = KEY_TYPE_MD5; - break; + const char * digest_name; + size_t digest_len; + int key_type; + + if (!pcmd->nargs) { + fprintf(fp, "keytype is %s with %lu octet digests\n", + keytype_name(info_auth_keytype), + (u_long)info_auth_hashlen); + return; + } - default: - fprintf(fp, "keytype must be 'md5'\n"); - } -} + digest_name = pcmd->argval[0].string; + digest_len = 0; + key_type = keytype_from_text(digest_name, &digest_len); + if (!key_type) { + fprintf(fp, "keytype must be 'md5'%s\n", +#ifdef OPENSSL + " or a digest type provided by OpenSSL"); +#else + ""); +#endif + return; + } + + info_auth_keytype = key_type; + info_auth_hashlen = digest_len; +} /* @@ -2347,13 +2489,17 @@ passwd( } info_auth_keyid = u_keyid; } - pass = getpass("MD5 Password: "); - if (*pass == '\0') - (void) fprintf(fp, "Password unchanged\n"); + if (pcmd->nargs >= 1) + pass = pcmd->argval[0].string; else { - authusekey(info_auth_keyid, info_auth_keytype, (u_char *)pass); - authtrust(info_auth_keyid, 1); + pass = getpass_keytype(info_auth_keytype); + if ('\0' == pass[0]) { + fprintf(fp, "Password unchanged\n"); + return; + } } + authusekey(info_auth_keyid, info_auth_keytype, (u_char *)pass); + authtrust(info_auth_keyid, 1); } @@ -2562,29 +2708,28 @@ getkeyid( const char *keyprompt ) { - register char *p; - register int c; + int c; FILE *fi; char pbuf[20]; + size_t i; + size_t ilim; #ifndef SYS_WINNT if ((fi = fdopen(open("/dev/tty", 2), "r")) == NULL) #else - if ((fi = _fdopen((int)GetStdHandle(STD_INPUT_HANDLE), "r")) == NULL) + if ((fi = _fdopen(open("CONIN$", _O_TEXT), "r")) == NULL) #endif /* SYS_WINNT */ fi = stdin; - else + else setbuf(fi, (char *)NULL); fprintf(stderr, "%s", keyprompt); fflush(stderr); - for (p=pbuf; (c = getc(fi))!='\n' && c!=EOF;) { - if (p < &pbuf[18]) - *p++ = (char)c; - } - *p = '\0'; + for (i = 0, ilim = COUNTOF(pbuf) - 1; + i < ilim && (c = getc(fi)) != '\n' && c != EOF; + ) + pbuf[i++] = (char)c; + pbuf[i] = '\0'; if (fi != stdin) - fclose(fi); - if (strcmp(pbuf, "0") == 0) - return 0; + fclose(fi); return (u_long) atoi(pbuf); } @@ -2596,82 +2741,93 @@ getkeyid( */ static void atoascii( - int length, - char *data, - char *outdata + const char *in, + size_t in_octets, + char *out, + size_t out_octets ) { - register u_char *cp; - register u_char *ocp; - register u_char c; - - if (!data) - { - *outdata = '\0'; + register const u_char * pchIn; + const u_char * pchInLimit; + register u_char * pchOut; + register u_char c; + + pchIn = (const u_char *)in; + pchInLimit = pchIn + in_octets; + pchOut = (u_char *)out; + + if (NULL == pchIn) { + if (0 < out_octets) + *pchOut = '\0'; return; } - ocp = (u_char *)outdata; - for (cp = (u_char *)data; cp < (u_char *)data + length; cp++) { - c = *cp; - if (c == '\0') - break; - if (c == '\0') - break; - if (c > 0177) { - *ocp++ = 'M'; - *ocp++ = '-'; - c &= 0177; - } +#define ONEOUT(c) \ +do { \ + if (0 == --out_octets) { \ + *pchOut = '\0'; \ + return; \ + } \ + *pchOut++ = (c); \ +} while (0) - if (c < ' ') { - *ocp++ = '^'; - *ocp++ = (u_char)(c + '@'); - } else if (c == 0177) { - *ocp++ = '^'; - *ocp++ = '?'; - } else { - *ocp++ = c; + for ( ; pchIn < pchInLimit; pchIn++) { + c = *pchIn; + if ('\0' == c) + break; + if (c & 0x80) { + ONEOUT('M'); + ONEOUT('-'); + c &= 0x7f; } - if (ocp >= ((u_char *)outdata + length - 4)) - break; + if (c < ' ') { + ONEOUT('^'); + ONEOUT((u_char)(c + '@')); + } else if (0x7f == c) { + ONEOUT('^'); + ONEOUT('?'); + } else + ONEOUT(c); } - *ocp++ = '\0'; -} + ONEOUT('\0'); +#undef ONEOUT +} /* * makeascii - print possibly ascii data using the character * transformations that cat -v uses. */ -static void +void makeascii( int length, - char *data, + const char *data, FILE *fp ) { - register u_char *cp; - register int c; + const u_char *data_u_char; + const u_char *cp; + int c; + + data_u_char = (const u_char *)data; - for (cp = (u_char *)data; cp < (u_char *)data + length; cp++) { + for (cp = data_u_char; cp < data_u_char + length; cp++) { c = (int)*cp; - if (c > 0177) { + if (c & 0x80) { putc('M', fp); putc('-', fp); - c &= 0177; + c &= 0x7f; } if (c < ' ') { putc('^', fp); - putc(c+'@', fp); - } else if (c == 0177) { + putc(c + '@', fp); + } else if (0x7f == c) { putc('^', fp); putc('?', fp); - } else { + } else putc(c, fp); - } } } @@ -2692,6 +2848,62 @@ asciize( /* + * truncate string to fit clipping excess at end. + * "too long" -> "too l" + * Used for hostnames. + */ +char * +trunc_right( + const char * src, + size_t width + ) +{ + size_t sl; + char * out; + + + sl = strlen(src); + if (sl > width && LIB_BUFLENGTH - 1 > width && width > 0) { + LIB_GETBUF(out); + memcpy(out, src, width); + out[width] = '\0'; + + return out; + } + + return src; +} + + +/* + * truncate string to fit by preserving right side and using '_' to hint + * "too long" -> "_long" + * Used for local IPv6 addresses, where low bits differentiate. + */ +char * +trunc_left( + const char * src, + size_t width + ) +{ + size_t sl; + char * out; + + + sl = strlen(src); + if (sl > width && LIB_BUFLENGTH - 1 > width && width > 1) { + LIB_GETBUF(out); + out[0] = '_'; + memcpy(&out[1], &src[sl + 1 - width], width); + + return out; + } + + return src; +} + + +/* * Some circular buffer space */ #define CBLEN 80 @@ -2706,15 +2918,15 @@ int nextcb = 0; int nextvar( int *datalen, - char **datap, + const char **datap, char **vname, char **vvalue ) { - register char *cp; - register char *np; - register char *cpend; - register char *npend; /* character after last */ + const char *cp; + char *np; + const char *cpend; + char *npend; /* character after last */ int quoted = 0; static char name[MAXVARLEN]; static char value[MAXVALLEN]; @@ -2726,9 +2938,9 @@ nextvar( * Space past commas and white space */ while (cp < cpend && (*cp == ',' || isspace((int)*cp))) - cp++; + cp++; if (cp == cpend) - return 0; + return 0; /* * Copy name until we hit a ',', an '=', a '\r' or a '\n'. Backspace @@ -2837,16 +3049,17 @@ findvar( void printvars( int length, - char *data, + const char *data, int status, int sttype, + int quiet, FILE *fp ) { if (rawmode) - rawprint(sttype, length, data, status, fp); + rawprint(sttype, length, data, status, quiet, fp); else - cookedprint(sttype, length, data, status, fp); + cookedprint(sttype, length, data, status, quiet, fp); } @@ -2857,13 +3070,14 @@ static void rawprint( int datatype, int length, - char *data, + const char *data, int status, + int quiet, FILE *fp ) { - register char *cp; - register char *cpend; + const char *cp; + const char *cpend; /* * Essentially print the data as is. We reformat unprintables, though. @@ -2871,7 +3085,8 @@ rawprint( cp = data; cpend = data + length; - (void) fprintf(fp, "status=0x%04x,\n", status); + if (!quiet) + (void) fprintf(fp, "status=0x%04x,\n", status); while (cp < cpend) { if (*cp == '\r') { @@ -2880,13 +3095,12 @@ rawprint( * \n, supress this, else pretty print it. Otherwise * just output the character. */ - if (cp == (cpend-1) || *(cp+1) != '\n') + if (cp == (cpend - 1) || *(cp + 1) != '\n') makeascii(1, cp, fp); - } else if (isspace((int)*cp) || isprint((int)*cp)) { + } else if (isspace(*cp) || isprint(*cp)) putc(*cp, fp); - } else { + else makeascii(1, cp, fp); - } cp++; } } @@ -2920,32 +3134,27 @@ output( char *value ) { - int lenname; - int lenvalue; + size_t len; - lenname = strlen(name); - lenvalue = strlen(value); + /* strlen of "name=value" */ + len = strlen(name) + 1 + strlen(value); if (out_chars != 0) { - putc(',', fp); - out_chars++; - out_linecount++; - if ((out_linecount + lenname + lenvalue + 3) > MAXOUTLINE) { - putc('\n', fp); - out_chars++; + out_chars += 2; + if ((out_linecount + len + 2) > MAXOUTLINE) { + fputs(",\n", fp); out_linecount = 0; } else { - putc(' ', fp); - out_chars++; - out_linecount++; + fputs(", ", fp); + out_linecount += 2; } } fputs(name, fp); putc('=', fp); fputs(value, fp); - out_chars += lenname + 1 + lenvalue; - out_linecount += lenname + 1 + lenvalue; + out_chars += len; + out_linecount += len; } @@ -2958,7 +3167,7 @@ endoutput( ) { if (out_chars != 0) - putc('\n', fp); + putc('\n', fp); } @@ -3012,33 +3221,44 @@ tstflags( u_long val ) { - register char *cb, *s; + register char *cp, *s; + size_t cb; register int i; register const char *sep; sep = ""; i = 0; - s = cb = &circ_buf[nextcb][0]; + s = cp = circ_buf[nextcb]; if (++nextcb >= NUMCB) - nextcb = 0; + nextcb = 0; + cb = sizeof(circ_buf[0]); - sprintf(cb, "%02lx", val); - cb += strlen(cb); + snprintf(cp, cb, "%02lx", val); + cp += strlen(cp); + cb -= strlen(cp); if (!val) { - strcat(cb, " ok"); - cb += strlen(cb); + strncat(cp, " ok", cb); + cp += strlen(cp); + cb -= strlen(cp); } else { - *cb++ = ' '; - for (i = 0; i < 13; i++) { + if (cb) { + *cp++ = ' '; + cb--; + } + for (i = 0; i < COUNTOF(tstflagnames); i++) { if (val & 0x1) { - sprintf(cb, "%s%s", sep, tstflagnames[i]); + snprintf(cp, cb, "%s%s", sep, + tstflagnames[i]); sep = ", "; - cb += strlen(cb); + cp += strlen(cp); + cb -= strlen(cp); } val >>= 1; } } - *cb = '\0'; + if (cb) + *cp = '\0'; + return s; } @@ -3049,8 +3269,9 @@ static void cookedprint( int datatype, int length, - char *data, + const char *data, int status, + int quiet, FILE *fp ) { @@ -3062,28 +3283,30 @@ cookedprint( struct ctl_var *varlist; l_fp lfp; long ival; - struct sockaddr_storage hval; + sockaddr_u hval; u_long uval; l_fp lfparr[8]; int narr; switch (datatype) { - case TYPE_PEER: + case TYPE_PEER: varlist = peer_var; break; - case TYPE_SYS: + case TYPE_SYS: varlist = sys_var; break; - case TYPE_CLOCK: + case TYPE_CLOCK: varlist = clock_var; break; - default: - (void) fprintf(stderr, "Unknown datatype(0x%x) in cookedprint\n", datatype); + default: + fprintf(stderr, "Unknown datatype(0x%x) in cookedprint\n", + datatype); return; } - (void) fprintf(fp, "status=%04x %s,\n", status, - statustoa(datatype, status)); + if (!quiet) + fprintf(fp, "status=%04x %s,\n", status, + statustoa(datatype, status)); startoutput(); while (nextvar(&length, &data, &name, &value)) { @@ -3154,8 +3377,7 @@ cookedprint( case RF: if (decodenetnum(value, &hval)) { - if ((hval.ss_family == AF_INET) && - ISREFCLOCKADR(&hval)) + if (ISREFCLOCKADR(&hval)) output(fp, name, refnumtoa(&hval)); else @@ -3226,8 +3448,8 @@ cookedprint( char bv[401]; int len; - atoascii(400, name, bn); - atoascii(400, value, bv); + atoascii(name, MAXVARLEN, bn, sizeof(bn)); + atoascii(value, MAXVARLEN, bv, sizeof(bv)); if (output_raw != '*') { len = strlen(bv); bv[len] = output_raw; @@ -3247,47 +3469,59 @@ void sortassoc(void) { if (numassoc > 1) - qsort( -#ifdef QSORT_USES_VOID_P - (void *) -#else - (char *) -#endif - assoc_cache, (size_t)numassoc, - sizeof(struct association), assoccmp); + qsort((void *)assoc_cache, (size_t)numassoc, + sizeof(assoc_cache[0]), assoccmp); } /* * assoccmp - compare two associations */ -#ifdef QSORT_USES_VOID_P static int assoccmp( const void *t1, const void *t2 ) { - const struct association *ass1 = (const struct association *)t1; - const struct association *ass2 = (const struct association *)t2; + const struct association *ass1 = t1; + const struct association *ass2 = t2; if (ass1->assid < ass2->assid) - return -1; + return -1; if (ass1->assid > ass2->assid) - return 1; + return 1; return 0; } -#else -static int -assoccmp( - struct association *ass1, - struct association *ass2 + + +/* + * ntpq_custom_opt_handler - autoopts handler for -c and -p + * + * By default, autoopts loses the relative order of -c and -p options + * on the command line. This routine replaces the default handler for + * those routines and builds a list of commands to execute preserving + * the order. + */ +void +ntpq_custom_opt_handler( + tOptions *pOptions, + tOptDesc *pOptDesc ) { - if (ass1->assid < ass2->assid) - return -1; - if (ass1->assid > ass2->assid) - return 1; - return 0; + switch (pOptDesc->optValue) { + + default: + fprintf(stderr, + "ntpq_custom_opt_handler unexpected option '%c' (%d)\n", + pOptDesc->optValue, pOptDesc->optValue); + exit(-1); + + case 'c': + ADDCMD(pOptDesc->pzLastArg); + break; + + case 'p': + ADDCMD("peers"); + break; + } } -#endif /* not QSORT_USES_VOID_P */ |