Annotation of embedaddon/ntp/ntpq/ntpq.c, revision 1.1

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

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>