"Fossies" - the Fresh Open Source Software Archive

Member "chrony-3.5/client.c" (10 May 2019, 92893 Bytes) of package /linux/misc/chrony-3.5.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "client.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 3.4_vs_3.5.

    1 /*
    2   chronyd/chronyc - Programs for keeping computer clocks accurate.
    3 
    4  **********************************************************************
    5  * Copyright (C) Richard P. Curnow  1997-2003
    6  * Copyright (C) Lonnie Abelbeck  2016, 2018
    7  * Copyright (C) Miroslav Lichvar  2009-2018
    8  * 
    9  * This program is free software; you can redistribute it and/or modify
   10  * it under the terms of version 2 of the GNU General Public License as
   11  * published by the Free Software Foundation.
   12  * 
   13  * This program is distributed in the hope that it will be useful, but
   14  * WITHOUT ANY WARRANTY; without even the implied warranty of
   15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   16  * General Public License for more details.
   17  * 
   18  * You should have received a copy of the GNU General Public License along
   19  * with this program; if not, write to the Free Software Foundation, Inc.,
   20  * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
   21  * 
   22  **********************************************************************
   23 
   24   =======================================================================
   25 
   26   Command line client for configuring the daemon and obtaining status
   27   from it whilst running.
   28   */
   29 
   30 #include "config.h"
   31 
   32 #include "sysincl.h"
   33 
   34 #include "array.h"
   35 #include "candm.h"
   36 #include "logging.h"
   37 #include "memory.h"
   38 #include "nameserv.h"
   39 #include "getdate.h"
   40 #include "cmdparse.h"
   41 #include "pktlength.h"
   42 #include "util.h"
   43 
   44 #ifdef FEAT_READLINE
   45 #ifdef USE_EDITLINE
   46 #include <editline/readline.h>
   47 #else
   48 #include <readline/readline.h>
   49 #include <readline/history.h>
   50 #endif
   51 #endif
   52 
   53 /* ================================================== */
   54 
   55 union sockaddr_all {
   56   struct sockaddr_in in4;
   57 #ifdef FEAT_IPV6
   58   struct sockaddr_in6 in6;
   59 #endif
   60   struct sockaddr_un un;
   61   struct sockaddr sa;
   62 };
   63 
   64 static ARR_Instance sockaddrs;
   65 
   66 static int sock_fd = -1;
   67 
   68 static int quit = 0;
   69 
   70 static int on_terminal = 0;
   71 
   72 static int no_dns = 0;
   73 
   74 static int csv_mode = 0;
   75 
   76 /* ================================================== */
   77 /* Log a message. This is a minimalistic replacement of the logging.c
   78    implementation to avoid linking with it and other modules. */
   79 
   80 int log_debug_enabled = 0;
   81 
   82 void LOG_Message(LOG_Severity severity,
   83 #if DEBUG > 0
   84                  int line_number, const char *filename, const char *function_name,
   85 #endif
   86                  const char *format, ...)
   87 {
   88   va_list ap;
   89 
   90   va_start(ap, format);
   91   vfprintf(stderr, format, ap);
   92   putc('\n', stderr);
   93   va_end(ap);
   94 }
   95 
   96 /* ================================================== */
   97 /* Read a single line of commands from standard input */
   98 
   99 #ifdef FEAT_READLINE
  100 static char **command_name_completion(const char *text, int start, int end);
  101 #endif
  102 
  103 static char *
  104 read_line(void)
  105 {
  106   static char line[2048];
  107   static const char *prompt = "chronyc> ";
  108 
  109   if (on_terminal) {
  110 #ifdef FEAT_READLINE
  111     char *cmd;
  112 
  113     rl_attempted_completion_function = command_name_completion;
  114     rl_basic_word_break_characters = " \t\n\r";
  115 
  116     /* save line only if not empty */
  117     cmd = readline(prompt);
  118     if( cmd == NULL ) return( NULL );
  119     
  120     /* user pressed return */
  121     if( *cmd != '\0' ) {
  122       strncpy(line, cmd, sizeof(line) - 1);
  123       line[sizeof(line) - 1] = '\0';
  124       add_history(cmd);
  125       /* free the buffer allocated by readline */
  126       Free(cmd);
  127     } else {
  128       /* simulate the user has entered an empty line */
  129       *line = '\0';
  130     }
  131     return( line );
  132 #else
  133     printf("%s", prompt);
  134     fflush(stdout);
  135 #endif
  136   }
  137   if (fgets(line, sizeof(line), stdin)) {
  138     return line;
  139   } else {
  140     return NULL;
  141   }
  142   
  143 }
  144 
  145 /* ================================================== */
  146 
  147 static ARR_Instance
  148 get_sockaddrs(const char *hostnames, int port)
  149 {
  150   ARR_Instance addrs;
  151   char *hostname, *s1, *s2;
  152   IPAddr ip_addrs[DNS_MAX_ADDRESSES];
  153   union sockaddr_all *addr;
  154   int i;
  155 
  156   addrs = ARR_CreateInstance(sizeof (union sockaddr_all));
  157   s1 = Strdup(hostnames);
  158 
  159   /* Parse the comma-separated list of hostnames */
  160   for (hostname = s1; hostname && *hostname; hostname = s2) {
  161     s2 = strchr(hostname, ',');
  162     if (s2)
  163       *s2++ = '\0';
  164 
  165     /* hostname starting with / is considered a path of Unix domain socket */
  166     if (hostname[0] == '/') {
  167       addr = (union sockaddr_all *)ARR_GetNewElement(addrs);
  168       if (snprintf(addr->un.sun_path, sizeof (addr->un.sun_path), "%s", hostname) >=
  169           sizeof (addr->un.sun_path))
  170         LOG_FATAL("Unix socket path too long");
  171       addr->un.sun_family = AF_UNIX;
  172     } else {
  173       if (DNS_Name2IPAddress(hostname, ip_addrs, DNS_MAX_ADDRESSES) != DNS_Success) {
  174         DEBUG_LOG("Could not get IP address for %s", hostname);
  175         continue;
  176       }
  177 
  178       for (i = 0; i < DNS_MAX_ADDRESSES && ip_addrs[i].family != IPADDR_UNSPEC; i++) {
  179         addr = (union sockaddr_all *)ARR_GetNewElement(addrs);
  180         UTI_IPAndPortToSockaddr(&ip_addrs[i], port, (struct sockaddr *)addr);
  181         DEBUG_LOG("Resolved %s to %s", hostname, UTI_IPToString(&ip_addrs[i]));
  182       }
  183     }
  184   }
  185 
  186   Free(s1);
  187   return addrs;
  188 }
  189 
  190 /* ================================================== */
  191 /* Initialise the socket used to talk to the daemon */
  192 
  193 static int
  194 prepare_socket(union sockaddr_all *addr)
  195 {
  196   socklen_t addr_len;
  197   char *dir;
  198 
  199   switch (addr->sa.sa_family) {
  200     case AF_UNIX:
  201       addr_len = sizeof (addr->un);
  202       break;
  203     case AF_INET:
  204       addr_len = sizeof (addr->in4);
  205       break;
  206 #ifdef FEAT_IPV6
  207     case AF_INET6:
  208       addr_len = sizeof (addr->in6);
  209       break;
  210 #endif
  211     default:
  212       assert(0);
  213   }
  214 
  215   sock_fd = socket(addr->sa.sa_family, SOCK_DGRAM, 0);
  216 
  217   if (sock_fd < 0) {
  218     DEBUG_LOG("Could not create socket : %s", strerror(errno));
  219     return 0;
  220   }
  221 
  222   if (addr->sa.sa_family == AF_UNIX) {
  223     struct sockaddr_un sa_un;
  224 
  225     /* Construct path of our socket.  Use the same directory as the server
  226        socket and include our process ID to allow multiple chronyc instances
  227        running at the same time. */
  228     dir = UTI_PathToDir(addr->un.sun_path);
  229     if (snprintf(sa_un.sun_path, sizeof (sa_un.sun_path),
  230                  "%s/chronyc.%d.sock", dir, (int)getpid()) >= sizeof (sa_un.sun_path))
  231       LOG_FATAL("Unix socket path too long");
  232     Free(dir);
  233 
  234     sa_un.sun_family = AF_UNIX;
  235     unlink(sa_un.sun_path);
  236 
  237     /* Bind the socket to the path */
  238     if (bind(sock_fd, (struct sockaddr *)&sa_un, sizeof (sa_un)) < 0) {
  239       DEBUG_LOG("Could not bind socket : %s", strerror(errno));
  240       return 0;
  241     }
  242 
  243     /* Allow server without root privileges to send replies to our socket */
  244     if (chmod(sa_un.sun_path, 0666) < 0) {
  245       DEBUG_LOG("Could not change socket permissions : %s", strerror(errno));
  246       return 0;
  247     }
  248   }
  249 
  250   if (connect(sock_fd, &addr->sa, addr_len) < 0) {
  251     DEBUG_LOG("Could not connect socket : %s", strerror(errno));
  252     return 0;
  253   }
  254 
  255   return 1;
  256 }
  257 
  258 /* ================================================== */
  259 
  260 static void
  261 close_io(void)
  262 {
  263   union sockaddr_all addr;
  264   socklen_t addr_len = sizeof (addr);
  265 
  266   if (sock_fd < 0)
  267     return;
  268 
  269   /* Remove our Unix domain socket */
  270   if (getsockname(sock_fd, &addr.sa, &addr_len) < 0)
  271     LOG_FATAL("getsockname() failed : %s", strerror(errno));
  272   if (addr_len <= sizeof (addr) && addr_len > sizeof (addr.sa.sa_family) &&
  273       addr.sa.sa_family == AF_UNIX)
  274     unlink(addr.un.sun_path);
  275 
  276   close(sock_fd);
  277   sock_fd = -1;
  278 }
  279 
  280 /* ================================================== */
  281 
  282 static int
  283 open_io(void)
  284 {
  285   static unsigned int address_index = 0;
  286   union sockaddr_all *addr;
  287 
  288   /* If a socket is already opened, close it and try the next address */
  289   if (sock_fd >= 0) {
  290     close_io();
  291     address_index++;
  292   }
  293 
  294   /* Find an address for which a socket can be opened and connected */
  295   for (; address_index < ARR_GetSize(sockaddrs); address_index++) {
  296     addr = (union sockaddr_all *)ARR_GetElement(sockaddrs, address_index);
  297     DEBUG_LOG("Opening connection to %s", UTI_SockaddrToString(&addr->sa));
  298 
  299     if (prepare_socket(addr))
  300       return 1;
  301 
  302     close_io();
  303   }
  304 
  305   return 0;
  306 }
  307 
  308 /* ================================================== */
  309 
  310 static void
  311 bits_to_mask(int bits, int family, IPAddr *mask)
  312 {
  313   int i;
  314 
  315   mask->family = family;
  316   switch (family) {
  317     case IPADDR_INET4:
  318       if (bits > 32 || bits < 0)
  319         bits = 32;
  320       if (bits > 0) {
  321         mask->addr.in4 = -1;
  322         mask->addr.in4 <<= 32 - bits;
  323       } else {
  324         mask->addr.in4 = 0;
  325       }
  326       break;
  327     case IPADDR_INET6:
  328       if (bits > 128 || bits < 0)
  329         bits = 128;
  330       for (i = 0; i < bits / 8; i++)
  331         mask->addr.in6[i] = 0xff;
  332       if (i < 16)
  333         mask->addr.in6[i++] = (0xff << (8 - bits % 8)) & 0xff;
  334       for (; i < 16; i++)
  335         mask->addr.in6[i] = 0x0;
  336       break;
  337     default:
  338       assert(0);
  339   }
  340 }
  341 
  342 /* ================================================== */
  343 
  344 static int
  345 read_mask_address(char *line, IPAddr *mask, IPAddr *address)
  346 {
  347   unsigned int bits;
  348   char *p, *q;
  349 
  350   p = line;
  351   if (!*p) {
  352     mask->family = address->family = IPADDR_UNSPEC;
  353     return 1;
  354   } else {
  355     q = strchr(p, '/');
  356     if (q) {
  357       *q++ = 0;
  358       if (UTI_StringToIP(p, mask)) {
  359         p = q;
  360         if (UTI_StringToIP(p, address)) {
  361           if (address->family == mask->family)
  362             return 1;
  363         } else if (sscanf(p, "%u", &bits) == 1) {
  364           *address = *mask;
  365           bits_to_mask(bits, address->family, mask);
  366           return 1;
  367         }
  368       }
  369     } else {
  370       if (DNS_Name2IPAddress(p, address, 1) == DNS_Success) {
  371         bits_to_mask(-1, address->family, mask);
  372         return 1;
  373       } else {
  374         LOG(LOGS_ERR, "Could not get address for hostname");
  375         return 0;
  376       }
  377     }
  378   }
  379 
  380   LOG(LOGS_ERR, "Invalid syntax for mask/address");
  381   return 0;
  382 }
  383 
  384 /* ================================================== */
  385 
  386 static int
  387 process_cmd_offline(CMD_Request *msg, char *line)
  388 {
  389   IPAddr mask, address;
  390   int ok;
  391 
  392   if (read_mask_address(line, &mask, &address)) {
  393     UTI_IPHostToNetwork(&mask, &msg->data.offline.mask);
  394     UTI_IPHostToNetwork(&address, &msg->data.offline.address);
  395     msg->command = htons(REQ_OFFLINE);
  396     ok = 1;
  397   } else {
  398     ok = 0;
  399   }
  400 
  401   return ok;
  402 
  403 }
  404 
  405 /* ================================================== */
  406 
  407 
  408 static int
  409 process_cmd_online(CMD_Request *msg, char *line)
  410 {
  411   IPAddr mask, address;
  412   int ok;
  413 
  414   if (read_mask_address(line, &mask, &address)) {
  415     UTI_IPHostToNetwork(&mask, &msg->data.online.mask);
  416     UTI_IPHostToNetwork(&address, &msg->data.online.address);
  417     msg->command = htons(REQ_ONLINE);
  418     ok = 1;
  419   } else {
  420     ok = 0;
  421   }
  422 
  423   return ok;
  424 
  425 }
  426 
  427 /* ================================================== */
  428 
  429 static void
  430 process_cmd_onoffline(CMD_Request *msg, char *line)
  431 {
  432   msg->command = htons(REQ_ONOFFLINE);
  433 }
  434 
  435 /* ================================================== */
  436 
  437 static int
  438 read_address_integer(char *line, IPAddr *address, int *value)
  439 {
  440   char *hostname;
  441   int ok = 0;
  442 
  443   hostname = line;
  444   line = CPS_SplitWord(line);
  445 
  446   if (sscanf(line, "%d", value) != 1) {
  447     LOG(LOGS_ERR, "Invalid syntax for address value");
  448     ok = 0;
  449   } else {
  450     if (DNS_Name2IPAddress(hostname, address, 1) != DNS_Success) {
  451       LOG(LOGS_ERR, "Could not get address for hostname");
  452       ok = 0;
  453     } else {
  454       ok = 1;
  455     }
  456   }
  457 
  458   return ok;
  459 
  460 }
  461 
  462 
  463 /* ================================================== */
  464 
  465 static int
  466 read_address_double(char *line, IPAddr *address, double *value)
  467 {
  468   char *hostname;
  469   int ok = 0;
  470 
  471   hostname = line;
  472   line = CPS_SplitWord(line);
  473 
  474   if (sscanf(line, "%lf", value) != 1) {
  475     LOG(LOGS_ERR, "Invalid syntax for address value");
  476     ok = 0;
  477   } else {
  478     if (DNS_Name2IPAddress(hostname, address, 1) != DNS_Success) {
  479       LOG(LOGS_ERR, "Could not get address for hostname");
  480       ok = 0;
  481     } else {
  482       ok = 1;
  483     }
  484   }
  485 
  486   return ok;
  487 
  488 }
  489 
  490 
  491 /* ================================================== */
  492 
  493 static int
  494 process_cmd_minpoll(CMD_Request *msg, char *line)
  495 {
  496   IPAddr address;
  497   int minpoll;
  498   int ok;
  499   
  500   if (read_address_integer(line, &address, &minpoll)) {
  501     UTI_IPHostToNetwork(&address, &msg->data.modify_minpoll.address);
  502     msg->data.modify_minpoll.new_minpoll = htonl(minpoll);
  503     msg->command = htons(REQ_MODIFY_MINPOLL);
  504     ok = 1;
  505   } else {
  506     ok = 0;
  507   }
  508 
  509   return ok;
  510 
  511 }
  512 
  513 /* ================================================== */
  514 
  515 static int
  516 process_cmd_maxpoll(CMD_Request *msg, char *line)
  517 {
  518   IPAddr address;
  519   int maxpoll;
  520   int ok;
  521   
  522   if (read_address_integer(line, &address, &maxpoll)) {
  523     UTI_IPHostToNetwork(&address, &msg->data.modify_maxpoll.address);
  524     msg->data.modify_maxpoll.new_maxpoll = htonl(maxpoll);
  525     msg->command = htons(REQ_MODIFY_MAXPOLL);
  526     ok = 1;
  527   } else {
  528     ok = 0;
  529   }
  530 
  531   return ok;
  532 
  533 }
  534 
  535 /* ================================================== */
  536 
  537 static int
  538 process_cmd_maxdelay(CMD_Request *msg, char *line)
  539 {
  540   IPAddr address;
  541   double max_delay;
  542   int ok;
  543   
  544   if (read_address_double(line, &address, &max_delay)) {
  545     UTI_IPHostToNetwork(&address, &msg->data.modify_maxdelay.address);
  546     msg->data.modify_maxdelay.new_max_delay = UTI_FloatHostToNetwork(max_delay);
  547     msg->command = htons(REQ_MODIFY_MAXDELAY);
  548     ok = 1;
  549   } else {
  550     ok = 0;
  551   }
  552 
  553   return ok;
  554 
  555 }
  556 
  557 /* ================================================== */
  558 
  559 static int
  560 process_cmd_maxdelaydevratio(CMD_Request *msg, char *line)
  561 {
  562   IPAddr address;
  563   double max_delay_dev_ratio;
  564   int ok;
  565   
  566   if (read_address_double(line, &address, &max_delay_dev_ratio)) {
  567     UTI_IPHostToNetwork(&address, &msg->data.modify_maxdelaydevratio.address);
  568     msg->data.modify_maxdelayratio.new_max_delay_ratio = UTI_FloatHostToNetwork(max_delay_dev_ratio);
  569     msg->command = htons(REQ_MODIFY_MAXDELAYDEVRATIO);
  570     ok = 1;
  571   } else {
  572     ok = 0;
  573   }
  574 
  575   return ok;
  576 
  577 }
  578 
  579 /* ================================================== */
  580 
  581 static int
  582 process_cmd_maxdelayratio(CMD_Request *msg, char *line)
  583 {
  584   IPAddr address;
  585   double max_delay_ratio;
  586   int ok;
  587   
  588   if (read_address_double(line, &address, &max_delay_ratio)) {
  589     UTI_IPHostToNetwork(&address, &msg->data.modify_maxdelayratio.address);
  590     msg->data.modify_maxdelayratio.new_max_delay_ratio = UTI_FloatHostToNetwork(max_delay_ratio);
  591     msg->command = htons(REQ_MODIFY_MAXDELAYRATIO);
  592     ok = 1;
  593   } else {
  594     ok = 0;
  595   }
  596 
  597   return ok;
  598 
  599 }
  600 
  601 /* ================================================== */
  602 
  603 static int
  604 process_cmd_minstratum(CMD_Request *msg, char *line)
  605 {
  606   IPAddr address;
  607   int min_stratum;
  608   int ok;
  609   
  610   if (read_address_integer(line, &address, &min_stratum)) {
  611     UTI_IPHostToNetwork(&address, &msg->data.modify_minstratum.address);
  612     msg->data.modify_minstratum.new_min_stratum = htonl(min_stratum);
  613     msg->command = htons(REQ_MODIFY_MINSTRATUM);
  614     ok = 1;
  615   } else {
  616     ok = 0;
  617   }
  618 
  619   return ok;
  620 
  621 }
  622 
  623 /* ================================================== */
  624 
  625 static int
  626 process_cmd_polltarget(CMD_Request *msg, char *line)
  627 {
  628   IPAddr address;
  629   int poll_target;
  630   int ok;
  631   
  632   if (read_address_integer(line, &address, &poll_target)) {
  633     UTI_IPHostToNetwork(&address, &msg->data.modify_polltarget.address);
  634     msg->data.modify_polltarget.new_poll_target = htonl(poll_target);
  635     msg->command = htons(REQ_MODIFY_POLLTARGET);
  636     ok = 1;
  637   } else {
  638     ok = 0;
  639   }
  640 
  641   return ok;
  642 
  643 }
  644 
  645 /* ================================================== */
  646 
  647 static int
  648 process_cmd_maxupdateskew(CMD_Request *msg, char *line)
  649 {
  650   int ok;
  651   double new_max_update_skew;
  652   
  653   if (sscanf(line, "%lf", &new_max_update_skew) == 1) {
  654     msg->data.modify_maxupdateskew.new_max_update_skew = UTI_FloatHostToNetwork(new_max_update_skew);
  655     msg->command = htons(REQ_MODIFY_MAXUPDATESKEW);
  656     ok = 1;
  657   } else {
  658     ok = 0;
  659   }
  660 
  661   return ok;
  662 
  663 }
  664 
  665 /* ================================================== */
  666 
  667 static void
  668 process_cmd_dump(CMD_Request *msg, char *line)
  669 {
  670   msg->command = htons(REQ_DUMP);
  671   msg->data.dump.pad = htonl(0);
  672 }
  673 
  674 /* ================================================== */
  675 
  676 static void
  677 process_cmd_writertc(CMD_Request *msg, char *line)
  678 {
  679   msg->command = htons(REQ_WRITERTC);
  680 }
  681 
  682 /* ================================================== */
  683 
  684 static void
  685 process_cmd_trimrtc(CMD_Request *msg, char *line)
  686 {
  687   msg->command = htons(REQ_TRIMRTC);
  688 }
  689 
  690 /* ================================================== */
  691 
  692 static void
  693 process_cmd_cyclelogs(CMD_Request *msg, char *line)
  694 {
  695   msg->command = htons(REQ_CYCLELOGS);
  696 }
  697 
  698 /* ================================================== */
  699 
  700 static int
  701 process_cmd_burst(CMD_Request *msg, char *line)
  702 {
  703   int n_good_samples, n_total_samples;
  704   char *s1, *s2;
  705   IPAddr address, mask;
  706 
  707   s1 = line;
  708   s2 = CPS_SplitWord(s1);
  709   CPS_SplitWord(s2);
  710 
  711   if (sscanf(s1, "%d/%d", &n_good_samples, &n_total_samples) != 2) {
  712     LOG(LOGS_ERR, "Invalid syntax for burst command");
  713     return 0;
  714   }
  715 
  716   mask.family = address.family = IPADDR_UNSPEC;
  717   if (*s2 && !read_mask_address(s2, &mask, &address)) {
  718     return 0;
  719   }
  720 
  721   msg->command = htons(REQ_BURST);
  722   msg->data.burst.n_good_samples = ntohl(n_good_samples);
  723   msg->data.burst.n_total_samples = ntohl(n_total_samples);
  724 
  725   UTI_IPHostToNetwork(&mask, &msg->data.burst.mask);
  726   UTI_IPHostToNetwork(&address, &msg->data.burst.address);
  727 
  728   return 1;
  729 }
  730 
  731 /* ================================================== */
  732 
  733 static int
  734 process_cmd_local(CMD_Request *msg, char *line)
  735 {
  736   int on_off, stratum = 0, orphan = 0;
  737   double distance = 0.0;
  738 
  739   if (!strcmp(line, "off")) {
  740     on_off = 0;
  741   } else if (CPS_ParseLocal(line, &stratum, &orphan, &distance)) {
  742     on_off = 1;
  743   } else {
  744     LOG(LOGS_ERR, "Invalid syntax for local command");
  745     return 0;
  746   }
  747 
  748   msg->command = htons(REQ_LOCAL2);
  749   msg->data.local.on_off = htonl(on_off);
  750   msg->data.local.stratum = htonl(stratum);
  751   msg->data.local.distance = UTI_FloatHostToNetwork(distance);
  752   msg->data.local.orphan = htonl(orphan);
  753 
  754   return 1;
  755 }
  756 
  757 /* ================================================== */
  758 
  759 static int
  760 process_cmd_manual(CMD_Request *msg, const char *line)
  761 {
  762   const char *p;
  763 
  764   p = line;
  765 
  766   if (!strcmp(p, "off")) {
  767     msg->data.manual.option = htonl(0);
  768   } else if (!strcmp(p, "on")) {
  769     msg->data.manual.option = htonl(1);
  770   } else if (!strcmp(p, "reset")) {
  771     msg->data.manual.option = htonl(2);
  772   } else {
  773     LOG(LOGS_ERR, "Invalid syntax for manual command");
  774     return 0;
  775   }
  776   msg->command = htons(REQ_MANUAL);
  777 
  778   return 1;
  779 }
  780 
  781 /* ================================================== */
  782 
  783 static int
  784 parse_allow_deny(CMD_Request *msg, char *line)
  785 {
  786   unsigned long a, b, c, d;
  787   int n, specified_subnet_bits;
  788   IPAddr ip;
  789   char *p;
  790   
  791   p = line;
  792   if (!*p) {
  793     /* blank line - applies to all addresses */
  794     ip.family = IPADDR_UNSPEC;
  795     UTI_IPHostToNetwork(&ip, &msg->data.allow_deny.ip);
  796     msg->data.allow_deny.subnet_bits = htonl(0);
  797   } else {
  798     char *slashpos;
  799     slashpos = strchr(p, '/');
  800     if (slashpos) *slashpos = 0;
  801     
  802     n = 0;
  803     if (!UTI_StringToIP(p, &ip) &&
  804         (n = sscanf(p, "%lu.%lu.%lu.%lu", &a, &b, &c, &d)) <= 0) {
  805 
  806       /* Try to parse as the name of a machine */
  807       if (slashpos || DNS_Name2IPAddress(p, &ip, 1) != DNS_Success) {
  808         LOG(LOGS_ERR, "Could not read address");
  809         return 0;
  810       } else {
  811         UTI_IPHostToNetwork(&ip, &msg->data.allow_deny.ip);
  812         if (ip.family == IPADDR_INET6)
  813           msg->data.allow_deny.subnet_bits = htonl(128);
  814         else
  815           msg->data.allow_deny.subnet_bits = htonl(32);
  816       }        
  817     } else {
  818       
  819       if (n == 0) {
  820         if (ip.family == IPADDR_INET6)
  821           msg->data.allow_deny.subnet_bits = htonl(128);
  822         else
  823           msg->data.allow_deny.subnet_bits = htonl(32);
  824       } else {
  825         ip.family = IPADDR_INET4;
  826 
  827         a &= 0xff;
  828         b &= 0xff;
  829         c &= 0xff;
  830         d &= 0xff;
  831         
  832         switch (n) {
  833           case 1:
  834             ip.addr.in4 = htonl((a<<24));
  835             msg->data.allow_deny.subnet_bits = htonl(8);
  836             break;
  837           case 2:
  838             ip.addr.in4 = htonl((a<<24) | (b<<16));
  839             msg->data.allow_deny.subnet_bits = htonl(16);
  840             break;
  841           case 3:
  842             ip.addr.in4 = htonl((a<<24) | (b<<16) | (c<<8));
  843             msg->data.allow_deny.subnet_bits = htonl(24);
  844             break;
  845           case 4:
  846             ip.addr.in4 = htonl((a<<24) | (b<<16) | (c<<8) | d);
  847             msg->data.allow_deny.subnet_bits = htonl(32);
  848             break;
  849           default:
  850             assert(0);
  851         }
  852       }
  853 
  854       UTI_IPHostToNetwork(&ip, &msg->data.allow_deny.ip);
  855 
  856       if (slashpos) {
  857         n = sscanf(slashpos+1, "%d", &specified_subnet_bits);
  858         if (n == 1) {
  859           msg->data.allow_deny.subnet_bits = htonl(specified_subnet_bits);
  860         } else {
  861           LOG(LOGS_WARN, "Warning: badly formatted subnet size, using %d",
  862               (int)ntohl(msg->data.allow_deny.subnet_bits));
  863         }
  864       } 
  865     }
  866   }
  867   return 1;
  868 }
  869 
  870 /* ================================================== */
  871 
  872 static int
  873 process_cmd_allow(CMD_Request *msg, char *line)
  874 {
  875   int status;
  876   msg->command = htons(REQ_ALLOW);
  877   status = parse_allow_deny(msg, line);
  878   return status;
  879 }
  880 
  881 /* ================================================== */
  882 
  883 static int
  884 process_cmd_allowall(CMD_Request *msg, char *line)
  885 {
  886   int status;
  887   msg->command = htons(REQ_ALLOWALL);
  888   status = parse_allow_deny(msg, line);
  889   return status;
  890 }
  891 
  892 /* ================================================== */
  893 
  894 static int
  895 process_cmd_deny(CMD_Request *msg, char *line)
  896 {
  897   int status;
  898   msg->command = htons(REQ_DENY);
  899   status = parse_allow_deny(msg, line);
  900   return status;
  901 }
  902 
  903 /* ================================================== */
  904 
  905 static int
  906 process_cmd_denyall(CMD_Request *msg, char *line)
  907 {
  908   int status;
  909   msg->command = htons(REQ_DENYALL);
  910   status = parse_allow_deny(msg, line);
  911   return status;
  912 }
  913 
  914 /* ================================================== */
  915 
  916 static int
  917 process_cmd_cmdallow(CMD_Request *msg, char *line)
  918 {
  919   int status;
  920   msg->command = htons(REQ_CMDALLOW);
  921   status = parse_allow_deny(msg, line);
  922   return status;
  923 }
  924 
  925 /* ================================================== */
  926 
  927 static int
  928 process_cmd_cmdallowall(CMD_Request *msg, char *line)
  929 {
  930   int status;
  931   msg->command = htons(REQ_CMDALLOWALL);
  932   status = parse_allow_deny(msg, line);
  933   return status;
  934 }
  935 
  936 /* ================================================== */
  937 
  938 static int
  939 process_cmd_cmddeny(CMD_Request *msg, char *line)
  940 {
  941   int status;
  942   msg->command = htons(REQ_CMDDENY);
  943   status = parse_allow_deny(msg, line);
  944   return status;
  945 }
  946 
  947 /* ================================================== */
  948 
  949 static int
  950 process_cmd_cmddenyall(CMD_Request *msg, char *line)
  951 {
  952   int status;
  953   msg->command = htons(REQ_CMDDENYALL);
  954   status = parse_allow_deny(msg, line);
  955   return status;
  956 }
  957 
  958 /* ================================================== */
  959 
  960 static int
  961 accheck_getaddr(char *line, IPAddr *addr)
  962 {
  963   unsigned long a, b, c, d;
  964   IPAddr ip;
  965   char *p;
  966   p = line;
  967   if (!*p) {
  968     return 0;
  969   } else {
  970     if (sscanf(p, "%lu.%lu.%lu.%lu", &a, &b, &c, &d) == 4) {
  971       addr->family = IPADDR_INET4;
  972       addr->addr.in4 = (a<<24) | (b<<16) | (c<<8) | d;
  973       return 1;
  974     } else {
  975       if (DNS_Name2IPAddress(p, &ip, 1) != DNS_Success) {
  976         return 0;
  977       } else {
  978         *addr = ip;
  979         return 1;
  980       }
  981     }
  982   }
  983 }
  984 
  985 /* ================================================== */
  986 
  987 static int
  988 process_cmd_accheck(CMD_Request *msg, char *line)
  989 {
  990   IPAddr ip;
  991   msg->command = htons(REQ_ACCHECK);
  992   if (accheck_getaddr(line, &ip)) {
  993     UTI_IPHostToNetwork(&ip, &msg->data.ac_check.ip);
  994     return 1;
  995   } else {    
  996     LOG(LOGS_ERR, "Could not read address");
  997     return 0;
  998   }
  999 }
 1000 
 1001 /* ================================================== */
 1002 
 1003 static int
 1004 process_cmd_cmdaccheck(CMD_Request *msg, char *line)
 1005 {
 1006   IPAddr ip;
 1007   msg->command = htons(REQ_CMDACCHECK);
 1008   if (accheck_getaddr(line, &ip)) {
 1009     UTI_IPHostToNetwork(&ip, &msg->data.ac_check.ip);
 1010     return 1;
 1011   } else {    
 1012     LOG(LOGS_ERR, "Could not read address");
 1013     return 0;
 1014   }
 1015 }
 1016 
 1017 /* ================================================== */
 1018 
 1019 static void
 1020 process_cmd_dfreq(CMD_Request *msg, char *line)
 1021 {
 1022   double dfreq;
 1023   msg->command = htons(REQ_DFREQ);
 1024   if (sscanf(line, "%lf", &dfreq) == 1) {
 1025     msg->data.dfreq.dfreq = UTI_FloatHostToNetwork(dfreq);
 1026   } else {
 1027     msg->data.dfreq.dfreq = UTI_FloatHostToNetwork(0.0);
 1028   }
 1029 }
 1030 
 1031 /* ================================================== */
 1032 
 1033 static void
 1034 cvt_to_sec_usec(double x, long *sec, long *usec) {
 1035   long s, us;
 1036   s = (long) x;
 1037   us = (long)(0.5 + 1.0e6 * (x - (double) s));
 1038   while (us >= 1000000) {
 1039     us -= 1000000;
 1040     s += 1;
 1041   }
 1042   while (us < 0) {
 1043     us += 1000000;
 1044     s -= 1;
 1045   }
 1046   
 1047   *sec = s;
 1048   *usec = us;
 1049 }
 1050 
 1051 /* ================================================== */
 1052 
 1053 static void
 1054 process_cmd_doffset(CMD_Request *msg, char *line)
 1055 {
 1056   double doffset;
 1057   long sec, usec;
 1058   msg->command = htons(REQ_DOFFSET);
 1059   if (sscanf(line, "%lf", &doffset) == 1) {
 1060     cvt_to_sec_usec(doffset, &sec, &usec);
 1061     msg->data.doffset.sec = htonl(sec);
 1062     msg->data.doffset.usec = htonl(usec);
 1063   } else {
 1064     msg->data.doffset.sec = htonl(0);
 1065     msg->data.doffset.usec = htonl(0);
 1066   }
 1067 }
 1068 
 1069 /* ================================================== */
 1070 
 1071 static int
 1072 process_cmd_add_server_or_peer(CMD_Request *msg, char *line)
 1073 {
 1074   CPS_NTP_Source data;
 1075   IPAddr ip_addr;
 1076   int result = 0, status;
 1077   const char *opt_name;
 1078   
 1079   status = CPS_ParseNTPSourceAdd(line, &data);
 1080   switch (status) {
 1081     case 0:
 1082       LOG(LOGS_ERR, "Invalid syntax for add command");
 1083       break;
 1084     default:
 1085       if (DNS_Name2IPAddress(data.name, &ip_addr, 1) != DNS_Success) {
 1086         LOG(LOGS_ERR, "Invalid host/IP address");
 1087         break;
 1088       }
 1089 
 1090       opt_name = NULL;
 1091       if (opt_name) {
 1092         LOG(LOGS_ERR, "%s can't be set in chronyc", opt_name);
 1093         break;
 1094       }
 1095 
 1096       msg->data.ntp_source.port = htonl((unsigned long) data.port);
 1097       UTI_IPHostToNetwork(&ip_addr, &msg->data.ntp_source.ip_addr);
 1098       msg->data.ntp_source.minpoll = htonl(data.params.minpoll);
 1099       msg->data.ntp_source.maxpoll = htonl(data.params.maxpoll);
 1100       msg->data.ntp_source.presend_minpoll = htonl(data.params.presend_minpoll);
 1101       msg->data.ntp_source.min_stratum = htonl(data.params.min_stratum);
 1102       msg->data.ntp_source.poll_target = htonl(data.params.poll_target);
 1103       msg->data.ntp_source.version = htonl(data.params.version);
 1104       msg->data.ntp_source.max_sources = htonl(data.params.max_sources);
 1105       msg->data.ntp_source.min_samples = htonl(data.params.min_samples);
 1106       msg->data.ntp_source.max_samples = htonl(data.params.max_samples);
 1107       msg->data.ntp_source.authkey = htonl(data.params.authkey);
 1108       msg->data.ntp_source.max_delay = UTI_FloatHostToNetwork(data.params.max_delay);
 1109       msg->data.ntp_source.max_delay_ratio = UTI_FloatHostToNetwork(data.params.max_delay_ratio);
 1110       msg->data.ntp_source.max_delay_dev_ratio =
 1111         UTI_FloatHostToNetwork(data.params.max_delay_dev_ratio);
 1112       msg->data.ntp_source.min_delay = UTI_FloatHostToNetwork(data.params.min_delay);
 1113       msg->data.ntp_source.asymmetry = UTI_FloatHostToNetwork(data.params.asymmetry);
 1114       msg->data.ntp_source.offset = UTI_FloatHostToNetwork(data.params.offset);
 1115       msg->data.ntp_source.flags = htonl(
 1116           (data.params.connectivity == SRC_ONLINE ? REQ_ADDSRC_ONLINE : 0) |
 1117           (data.params.auto_offline ? REQ_ADDSRC_AUTOOFFLINE : 0) |
 1118           (data.params.iburst ? REQ_ADDSRC_IBURST : 0) |
 1119           (data.params.interleaved ? REQ_ADDSRC_INTERLEAVED : 0) |
 1120           (data.params.burst ? REQ_ADDSRC_BURST : 0) |
 1121           (data.params.sel_options & SRC_SELECT_PREFER ? REQ_ADDSRC_PREFER : 0) |
 1122           (data.params.sel_options & SRC_SELECT_NOSELECT ? REQ_ADDSRC_NOSELECT : 0) |
 1123           (data.params.sel_options & SRC_SELECT_TRUST ? REQ_ADDSRC_TRUST : 0) |
 1124           (data.params.sel_options & SRC_SELECT_REQUIRE ? REQ_ADDSRC_REQUIRE : 0));
 1125       msg->data.ntp_source.filter_length = htonl(data.params.filter_length);
 1126       memset(msg->data.ntp_source.reserved, 0, sizeof (msg->data.ntp_source.reserved));
 1127 
 1128       result = 1;
 1129 
 1130       break;
 1131   }
 1132 
 1133   return result;
 1134 }
 1135 
 1136 /* ================================================== */
 1137 
 1138 static int
 1139 process_cmd_add_server(CMD_Request *msg, char *line)
 1140 {
 1141   msg->command = htons(REQ_ADD_SERVER3);
 1142   return process_cmd_add_server_or_peer(msg, line);
 1143 }
 1144 
 1145 /* ================================================== */
 1146 
 1147 static int
 1148 process_cmd_add_peer(CMD_Request *msg, char *line)
 1149 {
 1150   msg->command = htons(REQ_ADD_PEER3);
 1151   return process_cmd_add_server_or_peer(msg, line);
 1152 }
 1153 
 1154 /* ================================================== */
 1155 
 1156 static int
 1157 process_cmd_delete(CMD_Request *msg, char *line)
 1158 {
 1159   char *hostname;
 1160   int ok = 0;
 1161   IPAddr address;
 1162 
 1163   msg->command = htons(REQ_DEL_SOURCE);
 1164   hostname = line;
 1165   CPS_SplitWord(line);
 1166 
 1167   if (!*hostname) {
 1168     LOG(LOGS_ERR, "Invalid syntax for address");
 1169     ok = 0;
 1170   } else {
 1171     if (DNS_Name2IPAddress(hostname, &address, 1) != DNS_Success) {
 1172       LOG(LOGS_ERR, "Could not get address for hostname");
 1173       ok = 0;
 1174     } else {
 1175       UTI_IPHostToNetwork(&address, &msg->data.del_source.ip_addr);
 1176       ok = 1;
 1177     }
 1178   }
 1179 
 1180   return ok;
 1181   
 1182 }
 1183 
 1184 /* ================================================== */
 1185 
 1186 static void
 1187 give_help(void)
 1188 {
 1189   int line, len;
 1190   const char *s, cols[] =
 1191     "System clock:\0\0"
 1192     "tracking\0Display system time information\0"
 1193     "makestep\0Correct clock by stepping immediately\0"
 1194     "makestep <threshold> <updates>\0Configure automatic clock stepping\0"
 1195     "maxupdateskew <skew>\0Modify maximum valid skew to update frequency\0"
 1196     "waitsync [<max-tries> [<max-correction> [<max-skew> [<interval>]]]]\0"
 1197                           "Wait until synchronised in specified limits\0"
 1198     "\0\0"
 1199     "Time sources:\0\0"
 1200     "sources [-v]\0Display information about current sources\0"
 1201     "sourcestats [-v]\0Display statistics about collected measurements\0"
 1202     "reselect\0Force reselecting synchronisation source\0"
 1203     "reselectdist <dist>\0Modify reselection distance\0"
 1204     "\0\0"
 1205     "NTP sources:\0\0"
 1206     "activity\0Check how many NTP sources are online/offline\0"
 1207     "ntpdata [<address>]\0Display information about last valid measurement\0"
 1208     "add server <address> [options]\0Add new NTP server\0"
 1209     "add peer <address> [options]\0Add new NTP peer\0"
 1210     "delete <address>\0Remove server or peer\0"
 1211     "burst <n-good>/<n-max> [<mask>/<address>]\0Start rapid set of measurements\0"
 1212     "maxdelay <address> <delay>\0Modify maximum valid sample delay\0"
 1213     "maxdelayratio <address> <ratio>\0Modify maximum valid delay/minimum ratio\0"
 1214     "maxdelaydevratio <address> <ratio>\0Modify maximum valid delay/deviation ratio\0"
 1215     "minpoll <address> <poll>\0Modify minimum polling interval\0"
 1216     "maxpoll <address> <poll>\0Modify maximum polling interval\0"
 1217     "minstratum <address> <stratum>\0Modify minimum stratum\0"
 1218     "offline [<mask>/<address>]\0Set sources in subnet to offline status\0"
 1219     "online [<mask>/<address>]\0Set sources in subnet to online status\0"
 1220     "onoffline\0Set all sources to online or offline status\0"
 1221     "\0according to network configuration\0"
 1222     "polltarget <address> <target>\0Modify poll target\0"
 1223     "refresh\0Refresh IP addresses\0"
 1224     "\0\0"
 1225     "Manual time input:\0\0"
 1226     "manual off|on|reset\0Disable/enable/reset settime command\0"
 1227     "manual list\0Show previous settime entries\0"
 1228     "manual delete <index>\0Delete previous settime entry\0"
 1229     "settime <time>\0Set daemon time\0"
 1230     "\0(e.g. Sep 25, 2015 16:30:05 or 16:30:05)\0"
 1231     "\0\0NTP access:\0\0"
 1232     "accheck <address>\0Check whether address is allowed\0"
 1233     "clients\0Report on clients that have accessed the server\0"
 1234     "serverstats\0Display statistics of the server\0"
 1235     "allow [<subnet>]\0Allow access to subnet as a default\0"
 1236     "allow all [<subnet>]\0Allow access to subnet and all children\0"
 1237     "deny [<subnet>]\0Deny access to subnet as a default\0"
 1238     "deny all [<subnet>]\0Deny access to subnet and all children\0"
 1239     "local [options]\0Serve time even when not synchronised\0"
 1240     "local off\0Don't serve time when not synchronised\0"
 1241     "smoothtime reset|activate\0Reset/activate time smoothing\0"
 1242     "smoothing\0Display current time smoothing state\0"
 1243     "\0\0"
 1244     "Monitoring access:\0\0"
 1245     "cmdaccheck <address>\0Check whether address is allowed\0"
 1246     "cmdallow [<subnet>]\0Allow access to subnet as a default\0"
 1247     "cmdallow all [<subnet>]\0Allow access to subnet and all children\0"
 1248     "cmddeny [<subnet>]\0Deny access to subnet as a default\0"
 1249     "cmddeny all [<subnet>]\0Deny access to subnet and all children\0"
 1250     "\0\0"
 1251     "Real-time clock:\0\0"
 1252     "rtcdata\0Print current RTC performance parameters\0"
 1253     "trimrtc\0Correct RTC relative to system clock\0"
 1254     "writertc\0Save RTC performance parameters to file\0"
 1255     "\0\0"
 1256     "Other daemon commands:\0\0"
 1257     "cyclelogs\0Close and re-open log files\0"
 1258     "dump\0Dump all measurements to save files\0"
 1259     "rekey\0Re-read keys from key file\0"
 1260     "shutdown\0Stop daemon\0"
 1261     "\0\0"
 1262     "Client commands:\0\0"
 1263     "dns -n|+n\0Disable/enable resolving IP addresses to hostnames\0"
 1264     "dns -4|-6|-46\0Resolve hostnames only to IPv4/IPv6/both addresses\0"
 1265     "timeout <milliseconds>\0Set initial response timeout\0"
 1266     "retries <retries>\0Set maximum number of retries\0"
 1267     "keygen [<id> [<type> [<bits>]]]\0Generate key for key file\0"
 1268     "exit|quit\0Leave the program\0"
 1269     "help\0Generate this help\0"
 1270     "\0";
 1271 
 1272   /* Indent the second column */
 1273   for (s = cols, line = 0; s < cols + sizeof (cols); s += len + 1, line++) {
 1274     len = strlen(s);
 1275     printf(line % 2 == 0 ? (len >= 28 ? "%s\n%28s" : "%-28s%s") : "%s%s\n",
 1276            s, "");
 1277   }
 1278 }
 1279 
 1280 /* ================================================== */
 1281 /* Tab-completion when editline/readline is available */
 1282 
 1283 #ifdef FEAT_READLINE
 1284 
 1285 enum {
 1286   TAB_COMPLETE_BASE_CMDS,
 1287   TAB_COMPLETE_ADD_OPTS,
 1288   TAB_COMPLETE_MANUAL_OPTS,
 1289   TAB_COMPLETE_SOURCES_OPTS,
 1290   TAB_COMPLETE_SOURCESTATS_OPTS,
 1291   TAB_COMPLETE_MAX_INDEX
 1292 };
 1293 
 1294 static int tab_complete_index;
 1295 
 1296 static char *
 1297 command_name_generator(const char *text, int state)
 1298 {
 1299   const char *name, **names[TAB_COMPLETE_MAX_INDEX];
 1300   const char *base_commands[] = {
 1301     "accheck", "activity", "add", "allow", "burst",
 1302     "clients", "cmdaccheck", "cmdallow", "cmddeny", "cyclelogs", "delete",
 1303     "deny", "dns", "dump", "exit", "help", "keygen", "local", "makestep",
 1304     "manual", "maxdelay", "maxdelaydevratio", "maxdelayratio", "maxpoll",
 1305     "maxupdateskew", "minpoll", "minstratum", "ntpdata", "offline", "online", "onoffline",
 1306     "polltarget", "quit", "refresh", "rekey", "reselect", "reselectdist",
 1307     "retries", "rtcdata", "serverstats", "settime", "shutdown", "smoothing",
 1308     "smoothtime", "sources", "sourcestats",
 1309     "timeout", "tracking", "trimrtc", "waitsync", "writertc",
 1310     NULL
 1311   };
 1312   const char *add_options[] = { "peer", "server", NULL };
 1313   const char *manual_options[] = { "on", "off", "delete", "list", "reset", NULL };
 1314   const char *sources_options[] = { "-v", NULL };
 1315   const char *sourcestats_options[] = { "-v", NULL };
 1316   static int list_index, len;
 1317 
 1318   names[TAB_COMPLETE_BASE_CMDS] = base_commands;
 1319   names[TAB_COMPLETE_ADD_OPTS] = add_options;
 1320   names[TAB_COMPLETE_MANUAL_OPTS] = manual_options;
 1321   names[TAB_COMPLETE_SOURCES_OPTS] = sources_options;
 1322   names[TAB_COMPLETE_SOURCESTATS_OPTS] = sourcestats_options;
 1323 
 1324   if (!state) {
 1325     list_index = 0;
 1326     len = strlen(text);
 1327   }
 1328 
 1329   while ((name = names[tab_complete_index][list_index++])) {
 1330     if (strncmp(name, text, len) == 0) {
 1331       return strdup(name);
 1332     }
 1333   }
 1334 
 1335   return NULL;
 1336 }
 1337 
 1338 /* ================================================== */
 1339 
 1340 static char **
 1341 command_name_completion(const char *text, int start, int end)
 1342 {
 1343   char first[32];
 1344 
 1345   snprintf(first, MIN(sizeof (first), start + 1), "%s", rl_line_buffer);
 1346   rl_attempted_completion_over = 1;
 1347 
 1348   if (!strcmp(first, "add ")) {
 1349     tab_complete_index = TAB_COMPLETE_ADD_OPTS;
 1350   } else if (!strcmp(first, "manual ")) {
 1351     tab_complete_index = TAB_COMPLETE_MANUAL_OPTS;
 1352   } else if (!strcmp(first, "sources ")) {
 1353     tab_complete_index = TAB_COMPLETE_SOURCES_OPTS;
 1354   } else if (!strcmp(first, "sourcestats ")) {
 1355     tab_complete_index = TAB_COMPLETE_SOURCESTATS_OPTS;
 1356   } else if (first[0] == '\0') {
 1357     tab_complete_index = TAB_COMPLETE_BASE_CMDS;
 1358   } else {
 1359     return NULL;
 1360   }
 1361 
 1362   return rl_completion_matches(text, command_name_generator);
 1363 }
 1364 #endif
 1365 
 1366 /* ================================================== */
 1367 
 1368 static int max_retries = 2;
 1369 static int initial_timeout = 1000;
 1370 static int proto_version = PROTO_VERSION_NUMBER;
 1371 
 1372 /* This is the core protocol module.  Complete particular fields in
 1373    the outgoing packet, send it, wait for a response, handle retries,
 1374    etc.  Returns a Boolean indicating whether the protocol was
 1375    successful or not.*/
 1376 
 1377 static int
 1378 submit_request(CMD_Request *request, CMD_Reply *reply)
 1379 {
 1380   int select_status;
 1381   int recv_status;
 1382   int read_length;
 1383   int command_length;
 1384   int padding_length;
 1385   struct timespec ts_now, ts_start;
 1386   struct timeval tv;
 1387   int n_attempts, new_attempt;
 1388   double timeout;
 1389   fd_set rdfd;
 1390 
 1391   request->pkt_type = PKT_TYPE_CMD_REQUEST;
 1392   request->res1 = 0;
 1393   request->res2 = 0;
 1394   request->pad1 = 0;
 1395   request->pad2 = 0;
 1396 
 1397   n_attempts = 0;
 1398   new_attempt = 1;
 1399 
 1400   do {
 1401     if (gettimeofday(&tv, NULL))
 1402       return 0;
 1403 
 1404     if (new_attempt) {
 1405       new_attempt = 0;
 1406 
 1407       if (n_attempts > max_retries)
 1408         return 0;
 1409 
 1410       UTI_TimevalToTimespec(&tv, &ts_start);
 1411 
 1412       UTI_GetRandomBytes(&request->sequence, sizeof (request->sequence));
 1413       request->attempt = htons(n_attempts);
 1414       request->version = proto_version;
 1415       command_length = PKL_CommandLength(request);
 1416       padding_length = PKL_CommandPaddingLength(request);
 1417       assert(command_length > 0 && command_length > padding_length);
 1418 
 1419       n_attempts++;
 1420 
 1421       /* Zero the padding to not send any uninitialized data */
 1422       memset(((char *)request) + command_length - padding_length, 0, padding_length);
 1423 
 1424       if (sock_fd < 0) {
 1425         DEBUG_LOG("No socket to send request");
 1426         return 0;
 1427       }
 1428 
 1429       if (send(sock_fd, (void *)request, command_length, 0) < 0) {
 1430         DEBUG_LOG("Could not send %d bytes : %s", command_length, strerror(errno));
 1431         return 0;
 1432       }
 1433 
 1434       DEBUG_LOG("Sent %d bytes", command_length);
 1435     }
 1436 
 1437     UTI_TimevalToTimespec(&tv, &ts_now);
 1438 
 1439     /* Check if the clock wasn't stepped back */
 1440     if (UTI_CompareTimespecs(&ts_now, &ts_start) < 0)
 1441       ts_start = ts_now;
 1442 
 1443     timeout = initial_timeout / 1000.0 * (1U << (n_attempts - 1)) -
 1444               UTI_DiffTimespecsToDouble(&ts_now, &ts_start);
 1445     DEBUG_LOG("Timeout %f seconds", timeout);
 1446 
 1447     /* Avoid calling select() with an invalid timeout */
 1448     if (timeout <= 0.0) {
 1449       new_attempt = 1;
 1450       continue;
 1451     }
 1452 
 1453     UTI_DoubleToTimeval(timeout, &tv);
 1454 
 1455     FD_ZERO(&rdfd);
 1456     FD_SET(sock_fd, &rdfd);
 1457 
 1458     if (quit)
 1459       return 0;
 1460 
 1461     select_status = select(sock_fd + 1, &rdfd, NULL, NULL, &tv);
 1462 
 1463     if (select_status < 0) {
 1464       DEBUG_LOG("select failed : %s", strerror(errno));
 1465       return 0;
 1466     } else if (select_status == 0) {
 1467       /* Timeout must have elapsed, try a resend? */
 1468       new_attempt = 1;
 1469     } else {
 1470       recv_status = recv(sock_fd, (void *)reply, sizeof(CMD_Reply), 0);
 1471       
 1472       if (recv_status < 0) {
 1473         /* If we get connrefused here, it suggests the sendto is
 1474            going to a dead port */
 1475         DEBUG_LOG("Could not receive : %s", strerror(errno));
 1476         new_attempt = 1;
 1477       } else {
 1478         DEBUG_LOG("Received %d bytes", recv_status);
 1479         
 1480         read_length = recv_status;
 1481         
 1482         /* Check if the header is valid */
 1483         if (read_length < offsetof(CMD_Reply, data) ||
 1484             (reply->version != proto_version &&
 1485              !(reply->version >= PROTO_VERSION_MISMATCH_COMPAT_CLIENT &&
 1486                ntohs(reply->status) == STT_BADPKTVERSION)) ||
 1487             reply->pkt_type != PKT_TYPE_CMD_REPLY ||
 1488             reply->res1 != 0 ||
 1489             reply->res2 != 0 ||
 1490             reply->command != request->command ||
 1491             reply->sequence != request->sequence) {
 1492           DEBUG_LOG("Invalid reply");
 1493           continue;
 1494         }
 1495         
 1496 #if PROTO_VERSION_NUMBER == 6
 1497         /* Protocol version 5 is similar to 6 except there is no padding.
 1498            If a version 5 reply with STT_BADPKTVERSION is received,
 1499            switch our version and try again. */
 1500         if (proto_version == PROTO_VERSION_NUMBER &&
 1501             reply->version == PROTO_VERSION_NUMBER - 1) {
 1502           proto_version = PROTO_VERSION_NUMBER - 1;
 1503           n_attempts--;
 1504           new_attempt = 1;
 1505           continue;
 1506         }
 1507 #else
 1508 #error unknown compatibility with PROTO_VERSION - 1
 1509 #endif
 1510 
 1511         /* Check that the packet contains all data it is supposed to have.
 1512            Unknown responses will always pass this test as their expected
 1513            length is zero. */
 1514         if (read_length < PKL_ReplyLength(reply)) {
 1515           DEBUG_LOG("Reply too short");
 1516           new_attempt = 1;
 1517           continue;
 1518         }
 1519 
 1520         /* Good packet received, print out results */
 1521         DEBUG_LOG("Reply cmd=%d reply=%d stat=%d",
 1522                   ntohs(reply->command), ntohs(reply->reply), ntohs(reply->status));
 1523         break;
 1524       }
 1525     }
 1526   } while (1);
 1527 
 1528   return 1;
 1529 }
 1530 
 1531 /* ================================================== */
 1532 
 1533 static int
 1534 request_reply(CMD_Request *request, CMD_Reply *reply, int requested_reply, int verbose)
 1535 {
 1536   int status;
 1537 
 1538   while (!submit_request(request, reply)) {
 1539     /* Try connecting to other addresses before giving up */
 1540     if (open_io())
 1541       continue;
 1542     printf("506 Cannot talk to daemon\n");
 1543     return 0;
 1544   }
 1545 
 1546   status = ntohs(reply->status);
 1547         
 1548   if (verbose || status != STT_SUCCESS) {
 1549     switch (status) {
 1550       case STT_SUCCESS:
 1551         printf("200 OK");
 1552         break;
 1553       case STT_ACCESSALLOWED:
 1554         printf("208 Access allowed");
 1555         break;
 1556       case STT_ACCESSDENIED:
 1557         printf("209 Access denied");
 1558         break;
 1559       case STT_FAILED:
 1560         printf("500 Failure");
 1561         break;
 1562       case STT_UNAUTH:
 1563         printf("501 Not authorised");
 1564         break;
 1565       case STT_INVALID:
 1566         printf("502 Invalid command");
 1567         break;
 1568       case STT_NOSUCHSOURCE:
 1569         printf("503 No such source");
 1570         break;
 1571       case STT_INVALIDTS:
 1572         printf("504 Duplicate or stale logon detected");
 1573         break;
 1574       case STT_NOTENABLED:
 1575         printf("505 Facility not enabled in daemon");
 1576         break;
 1577       case STT_BADSUBNET:
 1578         printf("507 Bad subnet");
 1579         break;
 1580       case STT_NOHOSTACCESS:
 1581         printf("510 No command access from this host");
 1582         break;
 1583       case STT_SOURCEALREADYKNOWN:
 1584         printf("511 Source already present");
 1585         break;
 1586       case STT_TOOMANYSOURCES:
 1587         printf("512 Too many sources present");
 1588         break;
 1589       case STT_NORTC:
 1590         printf("513 RTC driver not running");
 1591         break;
 1592       case STT_BADRTCFILE:
 1593         printf("514 Can't write RTC parameters");
 1594         break;
 1595       case STT_INVALIDAF:
 1596         printf("515 Invalid address family");
 1597         break;
 1598       case STT_BADSAMPLE:
 1599         printf("516 Sample index out of range");
 1600         break;
 1601       case STT_BADPKTVERSION:
 1602         printf("517 Protocol version mismatch");
 1603         break;
 1604       case STT_BADPKTLENGTH:
 1605         printf("518 Packet length mismatch");
 1606         break;
 1607       case STT_INACTIVE:
 1608         printf("519 Client logging is not active in the daemon");
 1609         break;
 1610       default:
 1611         printf("520 Got unexpected error from daemon");
 1612     }
 1613     printf("\n");
 1614   }
 1615   
 1616   if (status != STT_SUCCESS &&
 1617       status != STT_ACCESSALLOWED && status != STT_ACCESSDENIED) {
 1618     return 0;
 1619   } 
 1620 
 1621   if (ntohs(reply->reply) != requested_reply) {
 1622     printf("508 Bad reply from daemon\n");
 1623     return 0;
 1624   }
 1625 
 1626   /* Make sure an unknown response was not requested */
 1627   assert(PKL_ReplyLength(reply));
 1628 
 1629   return 1;
 1630 }
 1631 
 1632 /* ================================================== */
 1633 
 1634 static void
 1635 print_seconds(unsigned long s)
 1636 {
 1637   unsigned long d;
 1638 
 1639   if (s == (uint32_t)-1) {
 1640     printf("   -");
 1641   } else if (s < 1200) {
 1642     printf("%4lu", s);
 1643   } else if (s < 36000) {
 1644     printf("%3lum", s / 60);
 1645   } else if (s < 345600) {
 1646     printf("%3luh", s / 3600);
 1647   } else {
 1648     d = s / 86400;
 1649     if (d > 999) {
 1650       printf("%3luy", d / 365);
 1651     } else {
 1652       printf("%3lud", d);
 1653     }
 1654   }
 1655 }
 1656 
 1657 /* ================================================== */
 1658 
 1659 static void
 1660 print_nanoseconds(double s)
 1661 {
 1662   s = fabs(s);
 1663 
 1664   if (s < 9999.5e-9) {
 1665     printf("%4.0fns", s * 1e9);
 1666   } else if (s < 9999.5e-6) {
 1667     printf("%4.0fus", s * 1e6);
 1668   } else if (s < 9999.5e-3) {
 1669     printf("%4.0fms", s * 1e3);
 1670   } else if (s < 999.5) {
 1671     printf("%5.1fs", s);
 1672   } else if (s < 99999.5) {
 1673     printf("%5.0fs", s);
 1674   } else if (s < 99999.5 * 60) {
 1675     printf("%5.0fm", s / 60);
 1676   } else if (s < 99999.5 * 3600) {
 1677     printf("%5.0fh", s / 3600);
 1678   } else if (s < 99999.5 * 3600 * 24) {
 1679     printf("%5.0fd", s / (3600 * 24));
 1680   } else {
 1681     printf("%5.0fy", s / (3600 * 24 * 365));
 1682   }
 1683 }
 1684 
 1685 /* ================================================== */
 1686 
 1687 static void
 1688 print_signed_nanoseconds(double s)
 1689 {
 1690   double x;
 1691 
 1692   x = fabs(s);
 1693 
 1694   if (x < 9999.5e-9) {
 1695     printf("%+5.0fns", s * 1e9);
 1696   } else if (x < 9999.5e-6) {
 1697     printf("%+5.0fus", s * 1e6);
 1698   } else if (x < 9999.5e-3) {
 1699     printf("%+5.0fms", s * 1e3);
 1700   } else if (x < 999.5) {
 1701     printf("%+6.1fs", s);
 1702   } else if (x < 99999.5) {
 1703     printf("%+6.0fs", s);
 1704   } else if (x < 99999.5 * 60) {
 1705     printf("%+6.0fm", s / 60);
 1706   } else if (x < 99999.5 * 3600) {
 1707     printf("%+6.0fh", s / 3600);
 1708   } else if (x < 99999.5 * 3600 * 24) {
 1709     printf("%+6.0fd", s / (3600 * 24));
 1710   } else {
 1711     printf("%+6.0fy", s / (3600 * 24 * 365));
 1712   }
 1713 }
 1714 
 1715 /* ================================================== */
 1716 
 1717 static void
 1718 print_freq_ppm(double f)
 1719 {
 1720   if (fabs(f) < 99999.5) {
 1721     printf("%10.3f", f);
 1722   } else {
 1723     printf("%10.0f", f);
 1724   }
 1725 }
 1726 
 1727 /* ================================================== */
 1728 
 1729 static void
 1730 print_signed_freq_ppm(double f)
 1731 {
 1732   if (fabs(f) < 99999.5) {
 1733     printf("%+10.3f", f);
 1734   } else {
 1735     printf("%+10.0f", f);
 1736   }
 1737 }
 1738 
 1739 /* ================================================== */
 1740 
 1741 static void
 1742 print_clientlog_interval(int rate)
 1743 {
 1744   if (rate >= 127) {
 1745     printf(" -");
 1746   } else {
 1747     printf("%2d", rate);
 1748   }
 1749 }
 1750 
 1751 /* ================================================== */
 1752 
 1753 static void
 1754 print_header(const char *header)
 1755 {
 1756   int len;
 1757 
 1758   if (csv_mode)
 1759     return;
 1760 
 1761   printf("%s\n", header);
 1762 
 1763   len = strlen(header);
 1764   while (len--)
 1765     printf("=");
 1766   printf("\n");
 1767 }
 1768 
 1769 /* ================================================== */
 1770 
 1771 #define REPORT_END 0x1234
 1772 
 1773 /* Print a report. The syntax of the format is similar to printf(), but not all
 1774    specifiers are supported and some are different! */
 1775 
 1776 static void
 1777 print_report(const char *format, ...)
 1778 {
 1779   char buf[256];
 1780   va_list ap;
 1781   int i, field, sign, width, prec, spec;
 1782   const char *string;
 1783   unsigned long long_uinteger;
 1784   unsigned int uinteger;
 1785   int integer;
 1786   struct timespec *ts;
 1787   struct tm *tm;
 1788   double dbl;
 1789 
 1790   va_start(ap, format);
 1791 
 1792   for (field = 0; ; field++) {
 1793     /* Search for text between format specifiers and print it
 1794        if not in the CSV mode */
 1795     for (i = 0; i < sizeof (buf) && format[i] != '%' && format[i] != '\0'; i++)
 1796       buf[i] = format[i];
 1797 
 1798     if (i >= sizeof (buf))
 1799       break;
 1800 
 1801     buf[i] = '\0';
 1802 
 1803     if (!csv_mode)
 1804       printf("%s", buf);
 1805 
 1806     if (format[i] == '\0' || format[i + 1] == '\0')
 1807       break;
 1808 
 1809     format += i + 1;
 1810 
 1811     sign = 0;
 1812     width = 0;
 1813     prec = 5;
 1814 
 1815     if (*format == '+' || *format == '-') {
 1816       sign = 1;
 1817       format++;
 1818     }
 1819 
 1820     if (isdigit((unsigned char)*format)) {
 1821       width = atoi(format);
 1822       while (isdigit((unsigned char)*format))
 1823         format++;
 1824     }
 1825 
 1826     if (*format == '.') {
 1827       format++;
 1828       prec = atoi(format);
 1829       while (isdigit((unsigned char)*format))
 1830         format++;
 1831     }
 1832 
 1833     spec = *format;
 1834     format++;
 1835 
 1836     /* Disable human-readable formatting in the CSV mode */
 1837     if (csv_mode) {
 1838       sign = width = 0;
 1839 
 1840       if (field > 0)
 1841         printf(",");
 1842 
 1843       switch (spec) {
 1844         case 'C':
 1845           spec = 'd';
 1846           break;
 1847         case 'F':
 1848         case 'P':
 1849           prec = 3;
 1850           spec = 'f';
 1851           break;
 1852         case 'O':
 1853         case 'S':
 1854           prec = 9;
 1855           spec = 'f';
 1856           break;
 1857         case 'I':
 1858           spec = 'U';
 1859           break;
 1860         case 'T':
 1861           spec = 'V';
 1862           break;
 1863       }
 1864     }
 1865 
 1866     switch (spec) {
 1867       case 'B': /* boolean */
 1868         integer = va_arg(ap, int);
 1869         printf("%s", integer ? "Yes" : "No");
 1870         break;
 1871       case 'C': /* clientlog interval */
 1872         integer = va_arg(ap, int);
 1873         print_clientlog_interval(integer);
 1874         break;
 1875       case 'F': /* absolute frequency in ppm with fast/slow keyword */
 1876       case 'O': /* absolute offset in seconds with fast/slow keyword */
 1877         dbl = va_arg(ap, double);
 1878         printf("%*.*f %s %s", width, prec, fabs(dbl),
 1879                spec == 'O' ? "seconds" : "ppm",
 1880                (dbl > 0.0) ^ (spec != 'O') ? "slow" : "fast");
 1881         break;
 1882       case 'I': /* interval with unit */
 1883         long_uinteger = va_arg(ap, unsigned long);
 1884         print_seconds(long_uinteger);
 1885         break;
 1886       case 'L': /* leap status */
 1887         integer = va_arg(ap, int);
 1888         switch (integer) {
 1889           case LEAP_Normal:
 1890             string = "Normal";
 1891             break;
 1892           case LEAP_InsertSecond:
 1893             string = "Insert second";
 1894             break;
 1895           case LEAP_DeleteSecond:
 1896             string = "Delete second";
 1897             break;
 1898           case LEAP_Unsynchronised:
 1899             string = "Not synchronised";
 1900             break;
 1901           default:
 1902             string = "Invalid";
 1903             break;
 1904         }
 1905         printf("%s", string);
 1906         break;
 1907       case 'M': /* NTP mode */
 1908         integer = va_arg(ap, int);
 1909         switch (integer) {
 1910           case MODE_ACTIVE:
 1911             string = "Symmetric active";
 1912             break;
 1913           case MODE_PASSIVE:
 1914             string = "Symmetric passive";
 1915             break;
 1916           case MODE_SERVER:
 1917             string = "Server";
 1918             break;
 1919           default:
 1920             string = "Invalid";
 1921             break;
 1922         }
 1923         printf("%s", string);
 1924         break;
 1925       case 'N': /* Timestamp source */
 1926         integer = va_arg(ap, int);
 1927         switch (integer) {
 1928           case 'D':
 1929             string = "Daemon";
 1930             break;
 1931           case 'K':
 1932             string = "Kernel";
 1933             break;
 1934           case 'H':
 1935             string = "Hardware";
 1936             break;
 1937           default:
 1938             string = "Invalid";
 1939             break;
 1940         }
 1941         printf("%s", string);
 1942         break;
 1943       case 'P': /* frequency in ppm */
 1944         dbl = va_arg(ap, double);
 1945         if (sign)
 1946           print_signed_freq_ppm(dbl);
 1947         else
 1948           print_freq_ppm(dbl);
 1949         break;
 1950       case 'R': /* reference ID in hexdecimal */
 1951         long_uinteger = va_arg(ap, unsigned long);
 1952         printf("%08lX", long_uinteger);
 1953         break;
 1954       case 'S': /* offset with unit */
 1955         dbl = va_arg(ap, double);
 1956         if (sign)
 1957           print_signed_nanoseconds(dbl);
 1958         else
 1959           print_nanoseconds(dbl);
 1960         break;
 1961       case 'T': /* timespec as date and time in UTC */
 1962         ts = va_arg(ap, struct timespec *);
 1963         tm = gmtime(&ts->tv_sec);
 1964         if (!tm)
 1965           break;
 1966         strftime(buf, sizeof (buf), "%a %b %d %T %Y", tm);
 1967         printf("%s", buf);
 1968         break;
 1969       case 'U': /* unsigned long in decimal */
 1970         long_uinteger = va_arg(ap, unsigned long);
 1971         printf("%*lu", width, long_uinteger);
 1972         break;
 1973       case 'V': /* timespec as seconds since epoch */
 1974         ts = va_arg(ap, struct timespec *);
 1975         printf("%s", UTI_TimespecToString(ts));
 1976         break;
 1977       case 'b': /* unsigned int in binary */
 1978         uinteger = va_arg(ap, unsigned int);
 1979         for (i = prec - 1; i >= 0; i--)
 1980           printf("%c", uinteger & 1U << i ? '1' : '0');
 1981         break;
 1982 
 1983       /* Classic printf specifiers */
 1984       case 'c': /* character */
 1985         integer = va_arg(ap, int);
 1986         printf("%c", integer);
 1987         break;
 1988       case 'd': /* signed int in decimal */
 1989         integer = va_arg(ap, int);
 1990         printf("%*d", width, integer);
 1991         break;
 1992       case 'f': /* double */
 1993         dbl = va_arg(ap, double);
 1994         printf(sign ? "%+*.*f" : "%*.*f", width, prec, dbl);
 1995         break;
 1996       case 'o': /* unsigned int in octal */
 1997         uinteger = va_arg(ap, unsigned int);
 1998         printf("%*o", width, uinteger);
 1999         break;
 2000       case 's': /* string */
 2001         string = va_arg(ap, const char *);
 2002         if (sign)
 2003           printf("%-*s", width, string);
 2004         else
 2005           printf("%*s", width, string);
 2006         break;
 2007       case 'u': /* unsigned int in decimal */
 2008         uinteger = va_arg(ap, unsigned int);
 2009         printf("%*u", width, uinteger);
 2010         break;
 2011     }
 2012   }
 2013 
 2014   /* Require terminating argument to catch bad type conversions */
 2015   if (va_arg(ap, int) != REPORT_END)
 2016     assert(0);
 2017 
 2018   va_end(ap);
 2019 
 2020   if (csv_mode)
 2021     printf("\n");
 2022 }
 2023 
 2024 /* ================================================== */
 2025 
 2026 static void
 2027 print_info_field(const char *format, ...)
 2028 {
 2029   va_list ap;
 2030 
 2031   if (csv_mode)
 2032     return;
 2033 
 2034   va_start(ap, format);
 2035   vprintf(format, ap);
 2036   va_end(ap);
 2037 }
 2038 
 2039 /* ================================================== */
 2040 
 2041 static void
 2042 format_name(char *buf, int size, int trunc_dns, int ref, uint32_t ref_id,
 2043             IPAddr *ip_addr)
 2044 {
 2045   if (ref) {
 2046     snprintf(buf, size, "%s", UTI_RefidToString(ref_id));
 2047   } else if (no_dns || csv_mode) {
 2048     snprintf(buf, size, "%s", UTI_IPToString(ip_addr));
 2049   } else {
 2050     DNS_IPAddress2Name(ip_addr, buf, size);
 2051     if (trunc_dns > 0 && strlen(buf) > trunc_dns) {
 2052       buf[trunc_dns - 1] = '>';
 2053       buf[trunc_dns] = '\0';
 2054     }
 2055   }
 2056 }
 2057 
 2058 /* ================================================== */
 2059 
 2060 static int
 2061 check_for_verbose_flag(char *line)
 2062 {
 2063   if (!csv_mode && !strcmp(line, "-v"))
 2064     return 1;
 2065   return 0;
 2066 }
 2067 
 2068 /* ================================================== */
 2069 
 2070 static int
 2071 process_cmd_sources(char *line)
 2072 {
 2073   CMD_Request request;
 2074   CMD_Reply reply;
 2075   IPAddr ip_addr;
 2076   uint32_t i, mode, n_sources;
 2077   char name[50], mode_ch, state_ch;
 2078   int verbose;
 2079 
 2080   /* Check whether to output verbose headers */
 2081   verbose = check_for_verbose_flag(line);
 2082   
 2083   request.command = htons(REQ_N_SOURCES);
 2084   if (!request_reply(&request, &reply, RPY_N_SOURCES, 0))
 2085     return 0;
 2086 
 2087   n_sources = ntohl(reply.data.n_sources.n_sources);
 2088   print_info_field("210 Number of sources = %lu\n", (unsigned long)n_sources);
 2089 
 2090   if (verbose) {
 2091     printf("\n");
 2092     printf("  .-- Source mode  '^' = server, '=' = peer, '#' = local clock.\n");
 2093     printf(" / .- Source state '*' = current synced, '+' = combined , '-' = not combined,\n");
 2094     printf("| /   '?' = unreachable, 'x' = time may be in error, '~' = time too variable.\n");
 2095     printf("||                                                 .- xxxx [ yyyy ] +/- zzzz\n");
 2096     printf("||      Reachability register (octal) -.           |  xxxx = adjusted offset,\n");
 2097     printf("||      Log2(Polling interval) --.      |          |  yyyy = measured offset,\n");
 2098     printf("||                                \\     |          |  zzzz = estimated error.\n");
 2099     printf("||                                 |    |           \\\n");
 2100   }
 2101 
 2102   print_header("MS Name/IP address         Stratum Poll Reach LastRx Last sample               ");
 2103 
 2104   /*           "MS NNNNNNNNNNNNNNNNNNNNNNNNNNN  SS  PP   RRR  RRRR  SSSSSSS[SSSSSSS] +/- SSSSSS" */
 2105 
 2106   for (i = 0; i < n_sources; i++) {
 2107     request.command = htons(REQ_SOURCE_DATA);
 2108     request.data.source_data.index = htonl(i);
 2109     if (!request_reply(&request, &reply, RPY_SOURCE_DATA, 0))
 2110       return 0;
 2111 
 2112     mode = ntohs(reply.data.source_data.mode);
 2113     UTI_IPNetworkToHost(&reply.data.source_data.ip_addr, &ip_addr);
 2114     format_name(name, sizeof (name), 25,
 2115                 mode == RPY_SD_MD_REF && ip_addr.family == IPADDR_INET4,
 2116                 ip_addr.addr.in4, &ip_addr);
 2117 
 2118     switch (mode) {
 2119       case RPY_SD_MD_CLIENT:
 2120         mode_ch = '^';
 2121         break;
 2122       case RPY_SD_MD_PEER:
 2123         mode_ch = '=';
 2124         break;
 2125       case RPY_SD_MD_REF:
 2126         mode_ch = '#';
 2127         break;
 2128       default:
 2129         mode_ch = ' ';
 2130     }
 2131 
 2132     switch (ntohs(reply.data.source_data.state)) {
 2133       case RPY_SD_ST_SYNC:
 2134         state_ch = '*';
 2135         break;
 2136       case RPY_SD_ST_UNREACH:
 2137         state_ch = '?';
 2138         break;
 2139       case RPY_SD_ST_FALSETICKER:
 2140         state_ch = 'x';
 2141         break;
 2142       case RPY_SD_ST_JITTERY:
 2143         state_ch = '~';
 2144         break;
 2145       case RPY_SD_ST_CANDIDATE:
 2146         state_ch = '+';
 2147         break;
 2148       case RPY_SD_ST_OUTLIER:
 2149         state_ch = '-';
 2150         break;
 2151       default:
 2152         state_ch = ' ';
 2153     }
 2154 
 2155     switch (ntohs(reply.data.source_data.flags)) {
 2156       default:
 2157         break;
 2158     }
 2159 
 2160     print_report("%c%c %-27s  %2d  %2d   %3o  %I  %+S[%+S] +/- %S\n",
 2161                  mode_ch, state_ch, name,
 2162                  ntohs(reply.data.source_data.stratum),
 2163                  (int16_t)ntohs(reply.data.source_data.poll),
 2164                  ntohs(reply.data.source_data.reachability),
 2165                  (unsigned long)ntohl(reply.data.source_data.since_sample),
 2166                  UTI_FloatNetworkToHost(reply.data.source_data.latest_meas),
 2167                  UTI_FloatNetworkToHost(reply.data.source_data.orig_latest_meas),
 2168                  UTI_FloatNetworkToHost(reply.data.source_data.latest_meas_err),
 2169                  REPORT_END);
 2170   }
 2171 
 2172   return 1;
 2173 }
 2174 
 2175 /* ================================================== */
 2176 
 2177 static int
 2178 process_cmd_sourcestats(char *line)
 2179 {
 2180   CMD_Request request;
 2181   CMD_Reply reply;
 2182   uint32_t i, n_sources;
 2183   int verbose = 0;
 2184   char name[50];
 2185   IPAddr ip_addr;
 2186 
 2187   verbose = check_for_verbose_flag(line);
 2188 
 2189   request.command = htons(REQ_N_SOURCES);
 2190   if (!request_reply(&request, &reply, RPY_N_SOURCES, 0))
 2191     return 0;
 2192 
 2193   n_sources = ntohl(reply.data.n_sources.n_sources);
 2194   print_info_field("210 Number of sources = %lu\n", (unsigned long)n_sources);
 2195 
 2196   if (verbose) {
 2197     printf("                             .- Number of sample points in measurement set.\n");
 2198     printf("                            /    .- Number of residual runs with same sign.\n");
 2199     printf("                           |    /    .- Length of measurement set (time).\n");
 2200     printf("                           |   |    /      .- Est. clock freq error (ppm).\n");
 2201     printf("                           |   |   |      /           .- Est. error in freq.\n");
 2202     printf("                           |   |   |     |           /         .- Est. offset.\n");
 2203     printf("                           |   |   |     |          |          |   On the -.\n");
 2204     printf("                           |   |   |     |          |          |   samples. \\\n");
 2205     printf("                           |   |   |     |          |          |             |\n");
 2206   }
 2207 
 2208   print_header("Name/IP Address            NP  NR  Span  Frequency  Freq Skew  Offset  Std Dev");
 2209 
 2210   /*           "NNNNNNNNNNNNNNNNNNNNNNNNN  NP  NR  SSSS FFFFFFFFFF SSSSSSSSSS  SSSSSSS  SSSSSS" */
 2211 
 2212   for (i = 0; i < n_sources; i++) {
 2213     request.command = htons(REQ_SOURCESTATS);
 2214     request.data.source_data.index = htonl(i);
 2215     if (!request_reply(&request, &reply, RPY_SOURCESTATS, 0))
 2216       return 0;
 2217 
 2218     UTI_IPNetworkToHost(&reply.data.sourcestats.ip_addr, &ip_addr);
 2219     format_name(name, sizeof (name), 25, ip_addr.family == IPADDR_UNSPEC,
 2220                 ntohl(reply.data.sourcestats.ref_id), &ip_addr);
 2221 
 2222     print_report("%-25s %3U %3U  %I %+P %P  %+S  %S\n",
 2223                  name,
 2224                  (unsigned long)ntohl(reply.data.sourcestats.n_samples),
 2225                  (unsigned long)ntohl(reply.data.sourcestats.n_runs),
 2226                  (unsigned long)ntohl(reply.data.sourcestats.span_seconds),
 2227                  UTI_FloatNetworkToHost(reply.data.sourcestats.resid_freq_ppm),
 2228                  UTI_FloatNetworkToHost(reply.data.sourcestats.skew_ppm),
 2229                  UTI_FloatNetworkToHost(reply.data.sourcestats.est_offset),
 2230                  UTI_FloatNetworkToHost(reply.data.sourcestats.sd),
 2231                  REPORT_END);
 2232   }
 2233 
 2234   return 1;
 2235 }
 2236 
 2237 /* ================================================== */
 2238 
 2239 static int
 2240 process_cmd_tracking(char *line)
 2241 {
 2242   CMD_Request request;
 2243   CMD_Reply reply;
 2244   IPAddr ip_addr;
 2245   uint32_t ref_id;
 2246   char name[50];
 2247   struct timespec ref_time;
 2248   
 2249   request.command = htons(REQ_TRACKING);
 2250   if (!request_reply(&request, &reply, RPY_TRACKING, 0))
 2251     return 0;
 2252 
 2253   ref_id = ntohl(reply.data.tracking.ref_id);
 2254 
 2255   UTI_IPNetworkToHost(&reply.data.tracking.ip_addr, &ip_addr);
 2256   format_name(name, sizeof (name), sizeof (name),
 2257               ip_addr.family == IPADDR_UNSPEC, ref_id, &ip_addr);
 2258 
 2259   UTI_TimespecNetworkToHost(&reply.data.tracking.ref_time, &ref_time);
 2260 
 2261   print_report("Reference ID    : %R (%s)\n"
 2262                "Stratum         : %u\n"
 2263                "Ref time (UTC)  : %T\n"
 2264                "System time     : %.9O of NTP time\n"
 2265                "Last offset     : %+.9f seconds\n"
 2266                "RMS offset      : %.9f seconds\n"
 2267                "Frequency       : %.3F\n"
 2268                "Residual freq   : %+.3f ppm\n"
 2269                "Skew            : %.3f ppm\n"
 2270                "Root delay      : %.9f seconds\n"
 2271                "Root dispersion : %.9f seconds\n"
 2272                "Update interval : %.1f seconds\n"
 2273                "Leap status     : %L\n",
 2274                (unsigned long)ref_id, name,
 2275                ntohs(reply.data.tracking.stratum),
 2276                &ref_time,
 2277                UTI_FloatNetworkToHost(reply.data.tracking.current_correction),
 2278                UTI_FloatNetworkToHost(reply.data.tracking.last_offset),
 2279                UTI_FloatNetworkToHost(reply.data.tracking.rms_offset),
 2280                UTI_FloatNetworkToHost(reply.data.tracking.freq_ppm),
 2281                UTI_FloatNetworkToHost(reply.data.tracking.resid_freq_ppm),
 2282                UTI_FloatNetworkToHost(reply.data.tracking.skew_ppm),
 2283                UTI_FloatNetworkToHost(reply.data.tracking.root_delay),
 2284                UTI_FloatNetworkToHost(reply.data.tracking.root_dispersion),
 2285                UTI_FloatNetworkToHost(reply.data.tracking.last_update_interval),
 2286                ntohs(reply.data.tracking.leap_status), REPORT_END);
 2287 
 2288   return 1;
 2289 }
 2290 
 2291 /* ================================================== */
 2292 
 2293 static int
 2294 process_cmd_ntpdata(char *line)
 2295 {
 2296   CMD_Request request;
 2297   CMD_Reply reply;
 2298   IPAddr remote_addr, local_addr;
 2299   struct timespec ref_time;
 2300   uint32_t i, n_sources;
 2301   uint16_t mode;
 2302   int specified_addr;
 2303 
 2304   if (*line) {
 2305     specified_addr = 1;
 2306     n_sources = 1;
 2307   } else {
 2308     specified_addr = 0;
 2309     request.command = htons(REQ_N_SOURCES);
 2310     if (!request_reply(&request, &reply, RPY_N_SOURCES, 0))
 2311       return 0;
 2312     n_sources = ntohl(reply.data.n_sources.n_sources);
 2313   }
 2314 
 2315   for (i = 0; i < n_sources; i++) {
 2316     if (specified_addr) {
 2317       if (DNS_Name2IPAddress(line, &remote_addr, 1) != DNS_Success) {
 2318         LOG(LOGS_ERR, "Could not get address for hostname");
 2319         return 0;
 2320       }
 2321     } else {
 2322       request.command = htons(REQ_SOURCE_DATA);
 2323       request.data.source_data.index = htonl(i);
 2324       if (!request_reply(&request, &reply, RPY_SOURCE_DATA, 0))
 2325         return 0;
 2326 
 2327       mode = ntohs(reply.data.source_data.mode);
 2328       if (mode != RPY_SD_MD_CLIENT && mode != RPY_SD_MD_PEER)
 2329         continue;
 2330 
 2331       UTI_IPNetworkToHost(&reply.data.source_data.ip_addr, &remote_addr);
 2332     }
 2333 
 2334     request.command = htons(REQ_NTP_DATA);
 2335     UTI_IPHostToNetwork(&remote_addr, &request.data.ntp_data.ip_addr);
 2336     if (!request_reply(&request, &reply, RPY_NTP_DATA, 0))
 2337       return 0;
 2338 
 2339     UTI_IPNetworkToHost(&reply.data.ntp_data.remote_addr, &remote_addr);
 2340     UTI_IPNetworkToHost(&reply.data.ntp_data.local_addr, &local_addr);
 2341     UTI_TimespecNetworkToHost(&reply.data.ntp_data.ref_time, &ref_time);
 2342 
 2343     if (!specified_addr && !csv_mode)
 2344       printf("\n");
 2345 
 2346     print_report("Remote address  : %s (%R)\n"
 2347                  "Remote port     : %u\n"
 2348                  "Local address   : %s (%R)\n"
 2349                  "Leap status     : %L\n"
 2350                  "Version         : %u\n"
 2351                  "Mode            : %M\n"
 2352                  "Stratum         : %u\n"
 2353                  "Poll interval   : %d (%.0f seconds)\n"
 2354                  "Precision       : %d (%.9f seconds)\n"
 2355                  "Root delay      : %.6f seconds\n"
 2356                  "Root dispersion : %.6f seconds\n"
 2357                  "Reference ID    : %R (%s)\n"
 2358                  "Reference time  : %T\n"
 2359                  "Offset          : %+.9f seconds\n"
 2360                  "Peer delay      : %.9f seconds\n"
 2361                  "Peer dispersion : %.9f seconds\n"
 2362                  "Response time   : %.9f seconds\n"
 2363                  "Jitter asymmetry: %+.2f\n"
 2364                  "NTP tests       : %.3b %.3b %.4b\n"
 2365                  "Interleaved     : %B\n"
 2366                  "Authenticated   : %B\n"
 2367                  "TX timestamping : %N\n"
 2368                  "RX timestamping : %N\n"
 2369                  "Total TX        : %U\n"
 2370                  "Total RX        : %U\n"
 2371                  "Total valid RX  : %U\n",
 2372                  UTI_IPToString(&remote_addr), (unsigned long)UTI_IPToRefid(&remote_addr),
 2373                  ntohs(reply.data.ntp_data.remote_port),
 2374                  UTI_IPToString(&local_addr), (unsigned long)UTI_IPToRefid(&local_addr),
 2375                  reply.data.ntp_data.leap, reply.data.ntp_data.version,
 2376                  reply.data.ntp_data.mode, reply.data.ntp_data.stratum,
 2377                  reply.data.ntp_data.poll, UTI_Log2ToDouble(reply.data.ntp_data.poll),
 2378                  reply.data.ntp_data.precision, UTI_Log2ToDouble(reply.data.ntp_data.precision),
 2379                  UTI_FloatNetworkToHost(reply.data.ntp_data.root_delay),
 2380                  UTI_FloatNetworkToHost(reply.data.ntp_data.root_dispersion),
 2381                  (unsigned long)ntohl(reply.data.ntp_data.ref_id),
 2382                  reply.data.ntp_data.stratum <= 1 ?
 2383                    UTI_RefidToString(ntohl(reply.data.ntp_data.ref_id)) : "",
 2384                  &ref_time,
 2385                  UTI_FloatNetworkToHost(reply.data.ntp_data.offset),
 2386                  UTI_FloatNetworkToHost(reply.data.ntp_data.peer_delay),
 2387                  UTI_FloatNetworkToHost(reply.data.ntp_data.peer_dispersion),
 2388                  UTI_FloatNetworkToHost(reply.data.ntp_data.response_time),
 2389                  UTI_FloatNetworkToHost(reply.data.ntp_data.jitter_asymmetry),
 2390                  ntohs(reply.data.ntp_data.flags) >> 7,
 2391                  ntohs(reply.data.ntp_data.flags) >> 4,
 2392                  ntohs(reply.data.ntp_data.flags),
 2393                  ntohs(reply.data.ntp_data.flags) & RPY_NTP_FLAG_INTERLEAVED,
 2394                  ntohs(reply.data.ntp_data.flags) & RPY_NTP_FLAG_AUTHENTICATED,
 2395                  reply.data.ntp_data.tx_tss_char, reply.data.ntp_data.rx_tss_char,
 2396                  (unsigned long)ntohl(reply.data.ntp_data.total_tx_count),
 2397                  (unsigned long)ntohl(reply.data.ntp_data.total_rx_count),
 2398                  (unsigned long)ntohl(reply.data.ntp_data.total_valid_count),
 2399                  REPORT_END);
 2400   }
 2401 
 2402   return 1;
 2403 }
 2404 
 2405 /* ================================================== */
 2406 
 2407 static int
 2408 process_cmd_serverstats(char *line)
 2409 {
 2410   CMD_Request request;
 2411   CMD_Reply reply;
 2412 
 2413   request.command = htons(REQ_SERVER_STATS);
 2414   if (!request_reply(&request, &reply, RPY_SERVER_STATS, 0))
 2415     return 0;
 2416 
 2417   print_report("NTP packets received       : %U\n"
 2418                "NTP packets dropped        : %U\n"
 2419                "Command packets received   : %U\n"
 2420                "Command packets dropped    : %U\n"
 2421                "Client log records dropped : %U\n",
 2422                (unsigned long)ntohl(reply.data.server_stats.ntp_hits),
 2423                (unsigned long)ntohl(reply.data.server_stats.ntp_drops),
 2424                (unsigned long)ntohl(reply.data.server_stats.cmd_hits),
 2425                (unsigned long)ntohl(reply.data.server_stats.cmd_drops),
 2426                (unsigned long)ntohl(reply.data.server_stats.log_drops),
 2427                REPORT_END);
 2428 
 2429   return 1;
 2430 }
 2431 
 2432 /* ================================================== */
 2433 
 2434 static int
 2435 process_cmd_smoothing(char *line)
 2436 {
 2437   CMD_Request request;
 2438   CMD_Reply reply;
 2439   uint32_t flags;
 2440 
 2441   request.command = htons(REQ_SMOOTHING);
 2442   if (!request_reply(&request, &reply, RPY_SMOOTHING, 0))
 2443     return 0;
 2444 
 2445   flags = ntohl(reply.data.smoothing.flags);
 2446 
 2447   print_report("Active         : %B %s\n"
 2448                "Offset         : %+.9f seconds\n"
 2449                "Frequency      : %+.6f ppm\n"
 2450                "Wander         : %+.6f ppm per second\n"
 2451                "Last update    : %.1f seconds ago\n"
 2452                "Remaining time : %.1f seconds\n",
 2453                !!(flags & RPY_SMT_FLAG_ACTIVE),
 2454                flags & RPY_SMT_FLAG_LEAPONLY ? "(leap second only)" : "",
 2455                UTI_FloatNetworkToHost(reply.data.smoothing.offset),
 2456                UTI_FloatNetworkToHost(reply.data.smoothing.freq_ppm),
 2457                UTI_FloatNetworkToHost(reply.data.smoothing.wander_ppm),
 2458                UTI_FloatNetworkToHost(reply.data.smoothing.last_update_ago),
 2459                UTI_FloatNetworkToHost(reply.data.smoothing.remaining_time),
 2460                REPORT_END);
 2461 
 2462   return 1;
 2463 }
 2464 
 2465 /* ================================================== */
 2466 
 2467 static int
 2468 process_cmd_smoothtime(CMD_Request *msg, const char *line)
 2469 {
 2470   if (!strcmp(line, "reset")) {
 2471     msg->data.smoothtime.option = htonl(REQ_SMOOTHTIME_RESET);
 2472   } else if (!strcmp(line, "activate")) {
 2473     msg->data.smoothtime.option = htonl(REQ_SMOOTHTIME_ACTIVATE);
 2474   } else {
 2475     LOG(LOGS_ERR, "Invalid syntax for smoothtime command");
 2476     return 0;
 2477   }
 2478 
 2479   msg->command = htons(REQ_SMOOTHTIME);
 2480 
 2481   return 1;
 2482 }
 2483 
 2484 /* ================================================== */
 2485 
 2486 static int
 2487 process_cmd_rtcreport(char *line)
 2488 {
 2489   CMD_Request request;
 2490   CMD_Reply reply;
 2491   struct timespec ref_time;
 2492   
 2493   request.command = htons(REQ_RTCREPORT);
 2494   if (!request_reply(&request, &reply, RPY_RTC, 0))
 2495     return 0;
 2496 
 2497   UTI_TimespecNetworkToHost(&reply.data.rtc.ref_time, &ref_time);
 2498 
 2499   print_report("RTC ref time (UTC) : %T\n"
 2500                "Number of samples  : %u\n"
 2501                "Number of runs     : %u\n"
 2502                "Sample span period : %I\n"
 2503                "RTC is fast by     : %12.6f seconds\n"
 2504                "RTC gains time at  : %9.3f ppm\n",
 2505                &ref_time,
 2506                ntohs(reply.data.rtc.n_samples),
 2507                ntohs(reply.data.rtc.n_runs),
 2508                (unsigned long)ntohl(reply.data.rtc.span_seconds),
 2509                UTI_FloatNetworkToHost(reply.data.rtc.rtc_seconds_fast),
 2510                UTI_FloatNetworkToHost(reply.data.rtc.rtc_gain_rate_ppm),
 2511                REPORT_END);
 2512 
 2513   return 1;
 2514 }
 2515 
 2516 /* ================================================== */
 2517 
 2518 static int
 2519 process_cmd_clients(char *line)
 2520 {
 2521   CMD_Request request;
 2522   CMD_Reply reply;
 2523   IPAddr ip;
 2524   uint32_t i, n_clients, next_index, n_indices;
 2525   RPY_ClientAccesses_Client *client;
 2526   char name[50];
 2527 
 2528   next_index = 0;
 2529 
 2530   print_header("Hostname                      NTP   Drop Int IntL Last     Cmd   Drop Int  Last");
 2531 
 2532   while (1) {
 2533     request.command = htons(REQ_CLIENT_ACCESSES_BY_INDEX2);
 2534     request.data.client_accesses_by_index.first_index = htonl(next_index);
 2535     request.data.client_accesses_by_index.n_clients = htonl(MAX_CLIENT_ACCESSES);
 2536 
 2537     if (!request_reply(&request, &reply, RPY_CLIENT_ACCESSES_BY_INDEX2, 0))
 2538       return 0;
 2539 
 2540     n_clients = ntohl(reply.data.client_accesses_by_index.n_clients);
 2541     n_indices = ntohl(reply.data.client_accesses_by_index.n_indices);
 2542 
 2543     for (i = 0; i < n_clients && i < MAX_CLIENT_ACCESSES; i++) {
 2544       client = &reply.data.client_accesses_by_index.clients[i];
 2545 
 2546       UTI_IPNetworkToHost(&client->ip, &ip);
 2547 
 2548       /* UNSPEC means the record could not be found in the daemon's tables.
 2549          We shouldn't ever generate this case, but ignore it if we do. */
 2550       if (ip.family == IPADDR_UNSPEC)
 2551         continue;
 2552 
 2553       format_name(name, sizeof (name), 25, 0, 0, &ip);
 2554 
 2555       print_report("%-25s  %6U  %5U  %C  %C  %I  %6U  %5U  %C  %I\n",
 2556                    name,
 2557                    (unsigned long)ntohl(client->ntp_hits),
 2558                    (unsigned long)ntohl(client->ntp_drops),
 2559                    client->ntp_interval,
 2560                    client->ntp_timeout_interval,
 2561                    (unsigned long)ntohl(client->last_ntp_hit_ago),
 2562                    (unsigned long)ntohl(client->cmd_hits),
 2563                    (unsigned long)ntohl(client->cmd_drops),
 2564                    client->cmd_interval,
 2565                    (unsigned long)ntohl(client->last_cmd_hit_ago),
 2566                    REPORT_END);
 2567     }
 2568 
 2569     /* Set the next index to probe based on what the server tells us */
 2570     next_index = ntohl(reply.data.client_accesses_by_index.next_index);
 2571 
 2572     if (next_index >= n_indices || n_clients < MAX_CLIENT_ACCESSES)
 2573       break;
 2574   }
 2575 
 2576   return 1;
 2577 }
 2578 
 2579 
 2580 /* ================================================== */
 2581 /* Process the manual list command */
 2582 static int
 2583 process_cmd_manual_list(const char *line)
 2584 {
 2585   CMD_Request request;
 2586   CMD_Reply reply;
 2587   uint32_t i, n_samples;
 2588   RPY_ManualListSample *sample;
 2589   struct timespec when;
 2590 
 2591   request.command = htons(REQ_MANUAL_LIST);
 2592   if (!request_reply(&request, &reply, RPY_MANUAL_LIST2, 0))
 2593     return 0;
 2594 
 2595   n_samples = ntohl(reply.data.manual_list.n_samples);
 2596   print_info_field("210 n_samples = %lu\n", (unsigned long)n_samples);
 2597 
 2598   print_header("#    Date     Time(UTC)    Slewed   Original   Residual");
 2599 
 2600   for (i = 0; i < n_samples && i < MAX_MANUAL_LIST_SAMPLES; i++) {
 2601     sample = &reply.data.manual_list.samples[i];
 2602     UTI_TimespecNetworkToHost(&sample->when, &when);
 2603 
 2604     print_report("%2d %s %10.2f %10.2f %10.2f\n",
 2605                  i, UTI_TimeToLogForm(when.tv_sec),
 2606                  UTI_FloatNetworkToHost(sample->slewed_offset),
 2607                  UTI_FloatNetworkToHost(sample->orig_offset),
 2608                  UTI_FloatNetworkToHost(sample->residual),
 2609                  REPORT_END);
 2610   }
 2611 
 2612   return 1;
 2613 }
 2614 
 2615 /* ================================================== */
 2616 
 2617 static int
 2618 process_cmd_manual_delete(CMD_Request *msg, const char *line)
 2619 {
 2620   int index;
 2621 
 2622   if (sscanf(line, "%d", &index) != 1) {
 2623     LOG(LOGS_ERR, "Bad syntax for manual delete command");
 2624     return 0;
 2625   }
 2626 
 2627   msg->command = htons(REQ_MANUAL_DELETE);
 2628   msg->data.manual_delete.index = htonl(index);
 2629   return 1;
 2630 }
 2631 
 2632 /* ================================================== */
 2633 
 2634 static int
 2635 process_cmd_settime(char *line)
 2636 {
 2637   struct timespec ts;
 2638   time_t now, new_time;
 2639   CMD_Request request;
 2640   CMD_Reply reply;
 2641   double dfreq_ppm, new_afreq_ppm;
 2642   double offset;
 2643 
 2644   now = time(NULL);
 2645   new_time = get_date(line, &now);
 2646 
 2647   if (new_time == -1) {
 2648     printf("510 - Could not parse date string\n");
 2649   } else {
 2650     ts.tv_sec = new_time;
 2651     ts.tv_nsec = 0;
 2652     UTI_TimespecHostToNetwork(&ts, &request.data.settime.ts);
 2653     request.command = htons(REQ_SETTIME);
 2654     if (request_reply(&request, &reply, RPY_MANUAL_TIMESTAMP2, 1)) {
 2655           offset = UTI_FloatNetworkToHost(reply.data.manual_timestamp.offset);
 2656           dfreq_ppm = UTI_FloatNetworkToHost(reply.data.manual_timestamp.dfreq_ppm);
 2657           new_afreq_ppm = UTI_FloatNetworkToHost(reply.data.manual_timestamp.new_afreq_ppm);
 2658           printf("Clock was %.2f seconds fast.  Frequency change = %.2fppm, new frequency = %.2fppm\n",
 2659               offset, dfreq_ppm, new_afreq_ppm);
 2660           return 1;
 2661     }
 2662   }
 2663   return 0;
 2664 }
 2665 
 2666 /* ================================================== */
 2667 
 2668 static void
 2669 process_cmd_rekey(CMD_Request *msg, char *line)
 2670 {
 2671   msg->command = htons(REQ_REKEY);
 2672 }
 2673 
 2674 /* ================================================== */
 2675 
 2676 static int
 2677 process_cmd_makestep(CMD_Request *msg, char *line)
 2678 {
 2679   int limit;
 2680   double threshold;
 2681 
 2682   if (*line) {
 2683     if (sscanf(line, "%lf %d", &threshold, &limit) != 2) {
 2684       LOG(LOGS_ERR, "Bad syntax for makestep command");
 2685       return 0;
 2686     }
 2687     msg->command = htons(REQ_MODIFY_MAKESTEP);
 2688     msg->data.modify_makestep.limit = htonl(limit);
 2689     msg->data.modify_makestep.threshold = UTI_FloatHostToNetwork(threshold);
 2690   } else {
 2691     msg->command = htons(REQ_MAKESTEP);
 2692   }
 2693 
 2694   return 1;
 2695 }
 2696 
 2697 /* ================================================== */
 2698 
 2699 static int
 2700 process_cmd_activity(const char *line)
 2701 {
 2702   CMD_Request request;
 2703   CMD_Reply reply;
 2704 
 2705   request.command = htons(REQ_ACTIVITY);
 2706   if (!request_reply(&request, &reply, RPY_ACTIVITY, 0))
 2707     return 0;
 2708 
 2709   print_info_field("200 OK\n");
 2710 
 2711   print_report("%U sources online\n"
 2712                "%U sources offline\n"
 2713                "%U sources doing burst (return to online)\n"
 2714                "%U sources doing burst (return to offline)\n"
 2715                "%U sources with unknown address\n",
 2716                (unsigned long)ntohl(reply.data.activity.online),
 2717                (unsigned long)ntohl(reply.data.activity.offline),
 2718                (unsigned long)ntohl(reply.data.activity.burst_online),
 2719                (unsigned long)ntohl(reply.data.activity.burst_offline),
 2720                (unsigned long)ntohl(reply.data.activity.unresolved),
 2721                REPORT_END);
 2722 
 2723   return 1;
 2724 }
 2725 
 2726 /* ================================================== */
 2727 
 2728 static int
 2729 process_cmd_reselectdist(CMD_Request *msg, char *line)
 2730 {
 2731   double dist;
 2732   int ok;
 2733   msg->command = htons(REQ_RESELECTDISTANCE);
 2734   if (sscanf(line, "%lf", &dist) == 1) {
 2735     msg->data.reselect_distance.distance = UTI_FloatHostToNetwork(dist);
 2736     ok = 1;
 2737   } else {
 2738     ok = 0;
 2739   }
 2740   return ok;
 2741 }
 2742 
 2743 /* ================================================== */
 2744 
 2745 static void
 2746 process_cmd_reselect(CMD_Request *msg, char *line)
 2747 {
 2748   msg->command = htons(REQ_RESELECT);
 2749 }
 2750 
 2751 /* ================================================== */
 2752 
 2753 static void
 2754 process_cmd_refresh(CMD_Request *msg, char *line)
 2755 {
 2756   msg->command = htons(REQ_REFRESH);
 2757 }
 2758 
 2759 /* ================================================== */
 2760 
 2761 static void
 2762 process_cmd_shutdown(CMD_Request *msg, char *line)
 2763 {
 2764   msg->command = htons(REQ_SHUTDOWN);
 2765 }
 2766 
 2767 /* ================================================== */
 2768 
 2769 static int
 2770 process_cmd_waitsync(char *line)
 2771 {
 2772   CMD_Request request;
 2773   CMD_Reply reply;
 2774   IPAddr ip_addr;
 2775   uint32_t ref_id;
 2776   double correction, skew_ppm, max_correction, max_skew_ppm, interval;
 2777   int ret = 0, max_tries, i;
 2778   struct timeval timeout;
 2779 
 2780   max_tries = 0;
 2781   max_correction = 0.0;
 2782   max_skew_ppm = 0.0;
 2783   interval = 10.0;
 2784 
 2785   if (sscanf(line, "%d %lf %lf %lf", &max_tries, &max_correction, &max_skew_ppm, &interval))
 2786     ;
 2787 
 2788   /* Don't allow shorter interval than 0.1 seconds */
 2789   if (interval < 0.1)
 2790     interval = 0.1;
 2791 
 2792   request.command = htons(REQ_TRACKING);
 2793 
 2794   for (i = 1; ; i++) {
 2795     if (request_reply(&request, &reply, RPY_TRACKING, 0)) {
 2796       ref_id = ntohl(reply.data.tracking.ref_id);
 2797       UTI_IPNetworkToHost(&reply.data.tracking.ip_addr, &ip_addr);
 2798 
 2799       correction = UTI_FloatNetworkToHost(reply.data.tracking.current_correction);
 2800       correction = fabs(correction);
 2801       skew_ppm = UTI_FloatNetworkToHost(reply.data.tracking.skew_ppm);
 2802 
 2803       print_report("try: %d, refid: %R, correction: %.9f, skew: %.3f\n",
 2804                    i, (unsigned long)ref_id, correction, skew_ppm, REPORT_END);
 2805 
 2806       if ((ip_addr.family != IPADDR_UNSPEC ||
 2807            (ref_id != 0 && ref_id != 0x7f7f0101L /* LOCAL refid */)) &&
 2808           (max_correction == 0.0 || correction <= max_correction) &&
 2809           (max_skew_ppm == 0.0 || skew_ppm <= max_skew_ppm)) {
 2810         ret = 1;
 2811       }
 2812     }
 2813 
 2814     if (!ret && (!max_tries || i < max_tries) && !quit) {
 2815       UTI_DoubleToTimeval(interval, &timeout);
 2816       if (select(0, NULL, NULL, NULL, &timeout))
 2817         break;
 2818     } else {
 2819       break;
 2820     }
 2821   }
 2822   return ret;
 2823 }
 2824 
 2825 /* ================================================== */
 2826 
 2827 static int
 2828 process_cmd_dns(const char *line)
 2829 {
 2830   if (!strcmp(line, "-46")) {
 2831     DNS_SetAddressFamily(IPADDR_UNSPEC);
 2832   } else if (!strcmp(line, "-4")) {
 2833     DNS_SetAddressFamily(IPADDR_INET4);
 2834   } else if (!strcmp(line, "-6")) {
 2835     DNS_SetAddressFamily(IPADDR_INET6);
 2836   } else if (!strcmp(line, "-n")) {
 2837     no_dns = 1;
 2838   } else if (!strcmp(line, "+n")) {
 2839     no_dns = 0;
 2840   } else {
 2841     LOG(LOGS_ERR, "Unrecognized dns command");
 2842     return 0;
 2843   }
 2844   return 1;
 2845 }
 2846 
 2847 /* ================================================== */
 2848 
 2849 static int
 2850 process_cmd_timeout(const char *line)
 2851 {
 2852   int timeout;
 2853 
 2854   timeout = atoi(line);
 2855   if (timeout < 100) {
 2856     LOG(LOGS_ERR, "Timeout %d is too short", timeout);
 2857     return 0;
 2858   }
 2859   initial_timeout = timeout;
 2860   return 1;
 2861 }
 2862 
 2863 /* ================================================== */
 2864 
 2865 static int
 2866 process_cmd_retries(const char *line)
 2867 {
 2868   int retries;
 2869 
 2870   retries = atoi(line);
 2871   if (retries < 0 || retries > 30) {
 2872     LOG(LOGS_ERR, "Invalid maximum number of retries");
 2873     return 0;
 2874   }
 2875   max_retries = retries;
 2876   return 1;
 2877 }
 2878 
 2879 /* ================================================== */
 2880 
 2881 static int
 2882 process_cmd_keygen(char *line)
 2883 {
 2884   char hash_name[17];
 2885   unsigned char key[512];
 2886   unsigned int i, length, id = 1, bits = 160;
 2887 
 2888 #ifdef FEAT_SECHASH
 2889   snprintf(hash_name, sizeof (hash_name), "SHA1");
 2890 #else
 2891   snprintf(hash_name, sizeof (hash_name), "MD5");
 2892 #endif
 2893 
 2894   if (sscanf(line, "%u %16s %u", &id, hash_name, &bits))
 2895     ;
 2896 
 2897   length = CLAMP(10, (bits + 7) / 8, sizeof (key));
 2898   if (HSH_GetHashId(hash_name) < 0) {
 2899     LOG(LOGS_ERR, "Unknown hash function %s", hash_name);
 2900     return 0;
 2901   }
 2902 
 2903   UTI_GetRandomBytesUrandom(key, length);
 2904 
 2905   printf("%u %s HEX:", id, hash_name);
 2906   for (i = 0; i < length; i++)
 2907     printf("%02hhX", key[i]);
 2908   printf("\n");
 2909 
 2910   return 1;
 2911 }
 2912 
 2913 /* ================================================== */
 2914 
 2915 static int
 2916 process_line(char *line)
 2917 {
 2918   char *command;
 2919   int do_normal_submit;
 2920   int ret;
 2921   CMD_Request tx_message;
 2922   CMD_Reply rx_message;
 2923 
 2924   ret = 0;
 2925 
 2926   do_normal_submit = 1;
 2927 
 2928   CPS_NormalizeLine(line);
 2929 
 2930   if (!*line) {
 2931     fflush(stderr);
 2932     fflush(stdout);
 2933     return 1;
 2934   };
 2935 
 2936   command = line;
 2937   line = CPS_SplitWord(line);
 2938 
 2939   if (!strcmp(command, "accheck")) {
 2940     do_normal_submit = process_cmd_accheck(&tx_message, line);
 2941   } else if (!strcmp(command, "activity")) {
 2942     do_normal_submit = 0;
 2943     ret = process_cmd_activity(line);
 2944   } else if (!strcmp(command, "add") && !strncmp(line, "peer", 4)) {
 2945     do_normal_submit = process_cmd_add_peer(&tx_message, CPS_SplitWord(line));
 2946   } else if (!strcmp(command, "add") && !strncmp(line, "server", 6)) {
 2947     do_normal_submit = process_cmd_add_server(&tx_message, CPS_SplitWord(line));
 2948   } else if (!strcmp(command, "allow")) {
 2949     if (!strncmp(line, "all", 3)) {
 2950       do_normal_submit = process_cmd_allowall(&tx_message, CPS_SplitWord(line));
 2951     } else {
 2952       do_normal_submit = process_cmd_allow(&tx_message, line);
 2953     }
 2954   } else if (!strcmp(command, "burst")) {
 2955     do_normal_submit = process_cmd_burst(&tx_message, line);
 2956   } else if (!strcmp(command, "clients")) {
 2957     ret = process_cmd_clients(line);
 2958     do_normal_submit = 0;
 2959   } else if (!strcmp(command, "cmdaccheck")) {
 2960     do_normal_submit = process_cmd_cmdaccheck(&tx_message, line);
 2961   } else if (!strcmp(command, "cmdallow")) {
 2962     if (!strncmp(line, "all", 3)) {
 2963       do_normal_submit = process_cmd_cmdallowall(&tx_message, CPS_SplitWord(line));
 2964     } else {
 2965       do_normal_submit = process_cmd_cmdallow(&tx_message, line);
 2966     }
 2967   } else if (!strcmp(command, "cmddeny")) {
 2968     if (!strncmp(line, "all", 3)) {
 2969       line = CPS_SplitWord(line);
 2970       do_normal_submit = process_cmd_cmddenyall(&tx_message, line);
 2971     } else {
 2972       do_normal_submit = process_cmd_cmddeny(&tx_message, line);
 2973     }
 2974   } else if (!strcmp(command, "cyclelogs")) {
 2975     process_cmd_cyclelogs(&tx_message, line);
 2976   } else if (!strcmp(command, "delete")) {
 2977     do_normal_submit = process_cmd_delete(&tx_message, line);
 2978   } else if (!strcmp(command, "deny")) {
 2979     if (!strncmp(line, "all", 3)) {
 2980       do_normal_submit = process_cmd_denyall(&tx_message, CPS_SplitWord(line));
 2981     } else {
 2982       do_normal_submit = process_cmd_deny(&tx_message, line);
 2983     }
 2984   } else if (!strcmp(command, "dfreq")) {
 2985     process_cmd_dfreq(&tx_message, line);
 2986   } else if (!strcmp(command, "dns")) {
 2987     ret = process_cmd_dns(line);
 2988     do_normal_submit = 0;
 2989   } else if (!strcmp(command, "doffset")) {
 2990     process_cmd_doffset(&tx_message, line);
 2991   } else if (!strcmp(command, "dump")) {
 2992     process_cmd_dump(&tx_message, line);
 2993   } else if (!strcmp(command, "exit")) {
 2994     do_normal_submit = 0;
 2995     quit = 1;
 2996     ret = 1;
 2997   } else if (!strcmp(command, "help")) {
 2998     do_normal_submit = 0;
 2999     give_help();
 3000     ret = 1;
 3001   } else if (!strcmp(command, "keygen")) {
 3002     ret = process_cmd_keygen(line);
 3003     do_normal_submit = 0;
 3004   } else if (!strcmp(command, "local")) {
 3005     do_normal_submit = process_cmd_local(&tx_message, line);
 3006   } else if (!strcmp(command, "makestep")) {
 3007     do_normal_submit = process_cmd_makestep(&tx_message, line);
 3008   } else if (!strcmp(command, "manual")) {
 3009     if (!strncmp(line, "list", 4)) {
 3010       do_normal_submit = 0;
 3011       ret = process_cmd_manual_list(CPS_SplitWord(line));
 3012     } else if (!strncmp(line, "delete", 6)) {
 3013       do_normal_submit = process_cmd_manual_delete(&tx_message, CPS_SplitWord(line));
 3014     } else {
 3015       do_normal_submit = process_cmd_manual(&tx_message, line);
 3016     }
 3017   } else if (!strcmp(command, "maxdelay")) {
 3018     do_normal_submit = process_cmd_maxdelay(&tx_message, line);
 3019   } else if (!strcmp(command, "maxdelaydevratio")) {
 3020     do_normal_submit = process_cmd_maxdelaydevratio(&tx_message, line);
 3021   } else if (!strcmp(command, "maxdelayratio")) {
 3022     do_normal_submit = process_cmd_maxdelayratio(&tx_message, line);
 3023   } else if (!strcmp(command, "maxpoll")) {
 3024     do_normal_submit = process_cmd_maxpoll(&tx_message, line);
 3025   } else if (!strcmp(command, "maxupdateskew")) {
 3026     do_normal_submit = process_cmd_maxupdateskew(&tx_message, line);
 3027   } else if (!strcmp(command, "minpoll")) {
 3028     do_normal_submit = process_cmd_minpoll(&tx_message, line);
 3029   } else if (!strcmp(command, "minstratum")) {
 3030     do_normal_submit = process_cmd_minstratum(&tx_message, line);
 3031   } else if (!strcmp(command, "ntpdata")) {
 3032     do_normal_submit = 0;
 3033     ret = process_cmd_ntpdata(line);
 3034   } else if (!strcmp(command, "offline")) {
 3035     do_normal_submit = process_cmd_offline(&tx_message, line);
 3036   } else if (!strcmp(command, "online")) {
 3037     do_normal_submit = process_cmd_online(&tx_message, line);
 3038   } else if (!strcmp(command, "onoffline")) {
 3039     process_cmd_onoffline(&tx_message, line);
 3040   } else if (!strcmp(command, "polltarget")) {
 3041     do_normal_submit = process_cmd_polltarget(&tx_message, line);
 3042   } else if (!strcmp(command, "quit")) {
 3043     do_normal_submit = 0;
 3044     quit = 1;
 3045     ret = 1;
 3046   } else if (!strcmp(command, "refresh")) {
 3047     process_cmd_refresh(&tx_message, line);
 3048   } else if (!strcmp(command, "rekey")) {
 3049     process_cmd_rekey(&tx_message, line);
 3050   } else if (!strcmp(command, "reselect")) {
 3051     process_cmd_reselect(&tx_message, line);
 3052   } else if (!strcmp(command, "reselectdist")) {
 3053     do_normal_submit = process_cmd_reselectdist(&tx_message, line);
 3054   } else if (!strcmp(command, "retries")) {
 3055     ret = process_cmd_retries(line);
 3056     do_normal_submit = 0;
 3057   } else if (!strcmp(command, "rtcdata")) {
 3058     do_normal_submit = 0;
 3059     ret = process_cmd_rtcreport(line);
 3060   } else if (!strcmp(command, "serverstats")) {
 3061     do_normal_submit = 0;
 3062     ret = process_cmd_serverstats(line);
 3063   } else if (!strcmp(command, "settime")) {
 3064     do_normal_submit = 0;
 3065     ret = process_cmd_settime(line);
 3066   } else if (!strcmp(command, "shutdown")) {
 3067     process_cmd_shutdown(&tx_message, line);
 3068   } else if (!strcmp(command, "smoothing")) {
 3069     do_normal_submit = 0;
 3070     ret = process_cmd_smoothing(line);
 3071   } else if (!strcmp(command, "smoothtime")) {
 3072     do_normal_submit = process_cmd_smoothtime(&tx_message, line);
 3073   } else if (!strcmp(command, "sources")) {
 3074     do_normal_submit = 0;
 3075     ret = process_cmd_sources(line);
 3076   } else if (!strcmp(command, "sourcestats")) {
 3077     do_normal_submit = 0;
 3078     ret = process_cmd_sourcestats(line);
 3079   } else if (!strcmp(command, "timeout")) {
 3080     ret = process_cmd_timeout(line);
 3081     do_normal_submit = 0;
 3082   } else if (!strcmp(command, "tracking")) {
 3083     ret = process_cmd_tracking(line);
 3084     do_normal_submit = 0;
 3085   } else if (!strcmp(command, "trimrtc")) {
 3086     process_cmd_trimrtc(&tx_message, line);
 3087   } else if (!strcmp(command, "waitsync")) {
 3088     ret = process_cmd_waitsync(line);
 3089     do_normal_submit = 0;
 3090   } else if (!strcmp(command, "writertc")) {
 3091     process_cmd_writertc(&tx_message, line);
 3092   } else if (!strcmp(command, "authhash") ||
 3093              !strcmp(command, "password")) {
 3094     /* Warn, but don't return error to not break scripts */
 3095     LOG(LOGS_WARN, "Authentication is no longer supported");
 3096     do_normal_submit = 0;
 3097     ret = 1;
 3098   } else {
 3099     LOG(LOGS_ERR, "Unrecognized command");
 3100     do_normal_submit = 0;
 3101   }
 3102     
 3103   if (do_normal_submit) {
 3104     ret = request_reply(&tx_message, &rx_message, RPY_NULL, 1);
 3105   }
 3106   fflush(stderr);
 3107   fflush(stdout);
 3108   return ret;
 3109 }
 3110 
 3111 /* ================================================== */
 3112 
 3113 static int
 3114 process_args(int argc, char **argv, int multi)
 3115 {
 3116   int total_length, i, ret = 0;
 3117   char *line;
 3118 
 3119   total_length = 0;
 3120   for(i=0; i<argc; i++) {
 3121     total_length += strlen(argv[i]) + 1;
 3122   }
 3123 
 3124   line = (char *) Malloc((2 + total_length) * sizeof(char));
 3125 
 3126   for (i = 0; i < argc; i++) {
 3127     line[0] = '\0';
 3128     if (multi) {
 3129       strcat(line, argv[i]);
 3130     } else {
 3131       for (; i < argc; i++) {
 3132         strcat(line, argv[i]);
 3133         if (i + 1 < argc)
 3134           strcat(line, " ");
 3135       }
 3136     }
 3137 
 3138     ret = process_line(line);
 3139     if (!ret || quit)
 3140       break;
 3141   }
 3142 
 3143   Free(line);
 3144 
 3145   return ret;
 3146 }
 3147 
 3148 /* ================================================== */
 3149 
 3150 static void
 3151 signal_handler(int signum)
 3152 {
 3153   quit = 1;
 3154 }
 3155 
 3156 /* ================================================== */
 3157 
 3158 static void
 3159 display_gpl(void)
 3160 {
 3161     printf("chrony version %s\n"
 3162            "Copyright (C) 1997-2003, 2007, 2009-2019 Richard P. Curnow and others\n"
 3163            "chrony comes with ABSOLUTELY NO WARRANTY.  This is free software, and\n"
 3164            "you are welcome to redistribute it under certain conditions.  See the\n"
 3165            "GNU General Public License version 2 for details.\n\n",
 3166            CHRONY_VERSION);
 3167 }
 3168 
 3169 /* ================================================== */
 3170 
 3171 static void
 3172 print_help(const char *progname)
 3173 {
 3174       printf("Usage: %s [-h HOST] [-p PORT] [-n] [-c] [-d] [-4|-6] [-m] [COMMAND]\n",
 3175              progname);
 3176 }
 3177 
 3178 /* ================================================== */
 3179 
 3180 static void
 3181 print_version(void)
 3182 {
 3183       printf("chronyc (chrony) version %s (%s)\n", CHRONY_VERSION, CHRONYC_FEATURES);
 3184 }
 3185 
 3186 /* ================================================== */
 3187 
 3188 int
 3189 main(int argc, char **argv)
 3190 {
 3191   char *line;
 3192   const char *progname = argv[0];
 3193   const char *hostnames = NULL;
 3194   int opt, ret = 1, multi = 0, family = IPADDR_UNSPEC;
 3195   int port = DEFAULT_CANDM_PORT;
 3196 
 3197   /* Parse (undocumented) long command-line options */
 3198   for (optind = 1; optind < argc; optind++) {
 3199     if (!strcmp("--help", argv[optind])) {
 3200       print_help(progname);
 3201       return 0;
 3202     } else if (!strcmp("--version", argv[optind])) {
 3203       print_version();
 3204       return 0;
 3205     }
 3206   }
 3207 
 3208   optind = 1;
 3209 
 3210   /* Parse short command-line options */
 3211   while ((opt = getopt(argc, argv, "+46acdf:h:mnp:v")) != -1) {
 3212     switch (opt) {
 3213       case '4':
 3214       case '6':
 3215         family = opt == '4' ? IPADDR_INET4 : IPADDR_INET6;
 3216         break;
 3217       case 'a':
 3218       case 'f':
 3219         /* For compatibility only */
 3220         break;
 3221       case 'c':
 3222         csv_mode = 1;
 3223         break;
 3224       case 'd':
 3225         log_debug_enabled = 1;
 3226         break;
 3227       case 'h':
 3228         hostnames = optarg;
 3229         break;
 3230       case 'm':
 3231         multi = 1;
 3232         break;
 3233       case 'n':
 3234         no_dns = 1;
 3235         break;
 3236       case 'p':
 3237         port = atoi(optarg);
 3238         break;
 3239       case 'v':
 3240         print_version();
 3241         return 0;
 3242       default:
 3243         print_help(progname);
 3244         return 1;
 3245     }
 3246   }
 3247 
 3248   if (isatty(0) && isatty(1) && isatty(2)) {
 3249     on_terminal = 1;
 3250   }
 3251 
 3252   if (on_terminal && optind == argc) {
 3253     display_gpl();
 3254   }
 3255   
 3256   DNS_SetAddressFamily(family);
 3257 
 3258   if (!hostnames) {
 3259     hostnames = DEFAULT_COMMAND_SOCKET",127.0.0.1,::1";
 3260   }
 3261 
 3262   UTI_SetQuitSignalsHandler(signal_handler, 0);
 3263 
 3264   sockaddrs = get_sockaddrs(hostnames, port);
 3265 
 3266   if (!open_io())
 3267     LOG_FATAL("Could not open connection to daemon");
 3268 
 3269   if (optind < argc) {
 3270     ret = process_args(argc - optind, argv + optind, multi);
 3271   } else {
 3272     do {
 3273       line = read_line();
 3274       if (line && !quit) {
 3275         ret = process_line(line);
 3276       }else {
 3277     /* supply the final '\n' when user exits via ^D */
 3278         if( on_terminal ) printf("\n");
 3279       }
 3280     } while (line && !quit);
 3281   }
 3282 
 3283   close_io();
 3284 
 3285   ARR_DestroyInstance(sockaddrs);
 3286 
 3287   return !ret;
 3288 }
 3289 
 3290