Home | History | Annotate | Line # | Download | only in c++tools
      1 /* C++ modules.  Experimental!
      2    Copyright (C) 2018-2022 Free Software Foundation, Inc.
      3    Written by Nathan Sidwell <nathan (at) acm.org> while at FaceBook
      4 
      5    This file is part of GCC.
      6 
      7    GCC is free software; you can redistribute it and/or modify it
      8    under the terms of the GNU General Public License as published by
      9    the Free Software Foundation; either version 3, or (at your option)
     10    any later version.
     11 
     12    GCC is distributed in the hope that it will be useful, but
     13    WITHOUT ANY WARRANTY; without even the implied warranty of
     14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     15    General Public License for more details.
     16 
     17 You should have received a copy of the GNU General Public License
     18 along with GCC; see the file COPYING3.  If not see
     19 <http://www.gnu.org/licenses/>.  */
     20 
     21 #include "config.h"
     22 #include "resolver.h"
     23 
     24 // C++
     25 #include <set>
     26 #include <vector>
     27 #include <map>
     28 // C
     29 #include <csignal>
     30 #include <cstring>
     31 #include <cstdarg>
     32 #include <cstdlib>
     33 // OS
     34 #include <unistd.h>
     35 #include <sys/types.h>
     36 #include <sys/stat.h>
     37 #include <fcntl.h>
     38 
     39 // Network
     40 /* Include network stuff first.  Excitingly OSX10.14 uses bcmp here, which
     41    we poison later!  */
     42 #if defined (HAVE_AF_UNIX) || defined (HAVE_AF_INET6)
     43 /* socket, bind, listen, accept{4}  */
     44 # define NETWORKING 1
     45 # include <sys/socket.h>
     46 # ifdef HAVE_AF_UNIX
     47 /* sockaddr_un  */
     48 #  include <sys/un.h>
     49 # endif
     50 # include <netinet/in.h>
     51 # ifdef HAVE_AF_INET6
     52 /* sockaddr_in6, getaddrinfo, freeaddrinfo, gai_sterror, ntohs, htons.  */
     53 #  include <netdb.h>
     54 # endif
     55 #ifdef HAVE_INET_NTOP
     56 /* inet_ntop.  */
     57 #include <arpa/inet.h>
     58 #endif
     59 #endif
     60 #ifndef HAVE_AF_INET6
     61 # define gai_strerror(X) ""
     62 #endif
     63 
     64 #ifndef AI_NUMERICSERV
     65 #define AI_NUMERICSERV 0
     66 #endif
     67 
     68 #include <getopt.h>
     69 
     70 // Select or epoll
     71 #if NETWORKING
     72 #ifdef HAVE_EPOLL
     73 /* epoll_create, epoll_ctl, epoll_pwait  */
     74 #include <sys/epoll.h>
     75 #endif
     76 #if defined (HAVE_PSELECT) || defined (HAVE_SELECT)
     77 /* pselect or select  */
     78 #include <sys/select.h>
     79 #endif
     80 #endif
     81 
     82 // GCC
     83 #include "version.h"
     84 #include "ansidecl.h"
     85 #define HAVE_DECL_BASENAME 1 /* See comment in gcc/configure.ac.  */
     86 #include "libiberty.h"
     87 
     88 #if !HOST_HAS_O_CLOEXEC
     89 #define O_CLOEXEC 0
     90 #endif
     91 
     92 #ifndef IS_DIR_SEPARATOR
     93 #define IS_DIR_SEPARATOR(C) ((C) == '/')
     94 #endif
     95 #ifndef DIR_SEPARATOR
     96 #define DIR_SEPARATOR '/'
     97 #endif
     98 
     99 /* Imported from libcpp/system.h
    100    Use gcc_assert(EXPR) to test invariants.  */
    101 #if ENABLE_ASSERT_CHECKING
    102 #define gcc_assert(EXPR)                                                \
    103    ((void)(!(EXPR) ? fancy_abort (__FILE__, __LINE__, __FUNCTION__), 0 : 0))
    104 #elif (GCC_VERSION >= 4005)
    105 #define gcc_assert(EXPR)                                                \
    106   ((void)(__builtin_expect (!(EXPR), 0) ? __builtin_unreachable (), 0 : 0))
    107 #else
    108 /* Include EXPR, so that unused variable warnings do not occur.  */
    109 #define gcc_assert(EXPR) ((void)(0 && (EXPR)))
    110 #endif
    111 
    112 /* Use gcc_unreachable() to mark unreachable locations (like an
    113    unreachable default case of a switch.  Do not use gcc_assert(0).  */
    114 #if (GCC_VERSION >= 4005) && !ENABLE_ASSERT_CHECKING
    115 #define gcc_unreachable() __builtin_unreachable ()
    116 #else
    117 #define gcc_unreachable() (fancy_abort (__FILE__, __LINE__, __FUNCTION__))
    118 #endif
    119 
    120 
    121 #if NETWORKING
    122 struct netmask {
    123   in6_addr addr;
    124   unsigned bits;
    125 
    126   netmask (const in6_addr &a, unsigned b)
    127   {
    128     if (b > sizeof (in6_addr) * 8)
    129       b = sizeof (in6_addr) * 8;
    130     bits = b;
    131     unsigned byte = (b + 7) / 8;
    132     unsigned ix = 0;
    133     for (ix = 0; ix < byte; ix++)
    134       addr.s6_addr[ix] = a.s6_addr[ix];
    135     for (; ix != sizeof (in6_addr); ix++)
    136       addr.s6_addr[ix] = 0;
    137     if (b & 3)
    138       addr.s6_addr[b/7] &= (255 << 8) >> (b & 3);
    139   }
    140 
    141   bool includes (const in6_addr &a) const
    142   {
    143     unsigned byte = bits / 8;
    144     for (unsigned ix = 0; ix != byte; ix++)
    145       if (addr.s6_addr[ix] != a.s6_addr[ix])
    146 	return false;
    147     if (bits & 3)
    148       if ((addr.s6_addr[byte] ^ a.s6_addr[byte]) >> (8 - (bits & 3)))
    149 	return false;
    150     return true;
    151   }
    152 };
    153 
    154 /* Netmask comparison.  */
    155 struct netmask_cmp {
    156   bool operator() (const netmask &a, const netmask &b) const
    157   {
    158     if (a.bits != b.bits)
    159       return a.bits < b.bits;
    160     for (unsigned ix = 0; ix != sizeof (in6_addr); ix++)
    161       if (a.addr.s6_addr[ix] != b.addr.s6_addr[ix])
    162 	return a.addr.s6_addr[ix] < b.addr.s6_addr[ix];
    163     return false;
    164   }
    165 };
    166 
    167 typedef std::set<netmask, netmask_cmp> netmask_set_t;
    168 typedef std::vector<netmask> netmask_vec_t;
    169 #endif
    170 
    171 const char *progname;
    172 
    173 /* Speak thoughts out loud.  */
    174 static bool flag_noisy = false;
    175 
    176 /* One and done.  */
    177 static bool flag_one = false;
    178 
    179 /* Serialize connections.  */
    180 static bool flag_sequential = false;
    181 
    182 /* Fallback to default if map file is unrewarding.  */
    183 static bool flag_map = false;
    184 
    185 /* Fallback to xlate if map file is unrewarding.  */
    186 static bool flag_xlate = false;
    187 
    188 /* Root binary directory.  */
    189 static const char *flag_root = "gcm.cache";
    190 
    191 #if NETWORKING
    192 static netmask_set_t netmask_set;
    193 
    194 static netmask_vec_t accept_addrs;
    195 #endif
    196 
    197 /* Strip out the source directory from FILE.  */
    198 
    199 static const char *
    200 trim_src_file (const char *file)
    201 {
    202   static const char me[] = __FILE__;
    203   unsigned pos = 0;
    204 
    205   while (file[pos] == me[pos] && me[pos])
    206     pos++;
    207   while (pos && !IS_DIR_SEPARATOR (me[pos-1]))
    208     pos--;
    209 
    210   return file + pos;
    211 }
    212 
    213 /* Die screaming.  */
    214 
    215 void ATTRIBUTE_NORETURN ATTRIBUTE_PRINTF_1 ATTRIBUTE_COLD
    216 internal_error (const char *fmt, ...)
    217 {
    218   fprintf (stderr, "%s:Internal error ", progname);
    219   va_list args;
    220 
    221   va_start (args, fmt);
    222   vfprintf (stderr, fmt, args);
    223   va_end (args);
    224   fprintf (stderr, "\n");
    225 
    226   exit (2);
    227 }
    228 
    229 /* Hooked to from gcc_assert & gcc_unreachable.  */
    230 
    231 #if ENABLE_ASSERT_CHECKING
    232 void ATTRIBUTE_NORETURN ATTRIBUTE_COLD
    233 fancy_abort (const char *file, int line, const char *func)
    234 {
    235   internal_error ("in %s, at %s:%d", func, trim_src_file (file), line);
    236 }
    237 #endif
    238 
    239 /* Exploded on a signal.  */
    240 
    241 static void ATTRIBUTE_NORETURN ATTRIBUTE_COLD
    242 crash_signal (int sig)
    243 {
    244   signal (sig, SIG_DFL);
    245   // strsignal is not portable :(
    246   internal_error ("signal %d", sig);
    247 }
    248 
    249 /* A fatal error of some kind.  */
    250 
    251 static void ATTRIBUTE_NORETURN ATTRIBUTE_COLD ATTRIBUTE_PRINTF_1
    252 error (const char *msg, ...)
    253 {
    254   fprintf (stderr, "%s:error: ", progname);
    255   va_list args;
    256 
    257   va_start (args, msg);
    258   vfprintf (stderr, msg, args);
    259   va_end (args);
    260   fprintf (stderr, "\n");
    261 
    262   exit (1);
    263 }
    264 
    265 #if NETWORKING
    266 /* Progress messages to the user.  */
    267 static bool ATTRIBUTE_PRINTF_1 ATTRIBUTE_COLD
    268 noisy (const char *fmt, ...)
    269 {
    270   fprintf (stderr, "%s:", progname);
    271   va_list args;
    272   va_start (args, fmt);
    273   vfprintf (stderr, fmt, args);
    274   va_end (args);
    275   fprintf (stderr, "\n");
    276 
    277   return false;
    278 }
    279 #endif
    280 
    281 /* More messages to the user.  */
    282 
    283 static void ATTRIBUTE_PRINTF_2
    284 fnotice (FILE *file, const char *fmt, ...)
    285 {
    286   va_list args;
    287 
    288   va_start (args, fmt);
    289   vfprintf (file, fmt, args);
    290   va_end (args);
    291 }
    292 
    293 static void ATTRIBUTE_NORETURN
    294 print_usage (int error_p)
    295 {
    296   FILE *file = error_p ? stderr : stdout;
    297   int status = error_p ? 1 : 0;
    298 
    299   fnotice (file, "Usage: %s [OPTION...] [CONNECTION] [MAPPINGS...] \n\n",
    300 	   progname);
    301   fnotice (file, "C++ Module Mapper.\n\n");
    302   fnotice (file, "  -a, --accept     Netmask to accept from\n");
    303   fnotice (file, "  -f, --fallback   Use fallback for missing mappings\n");
    304   fnotice (file, "  -h, --help       Print this help, then exit\n");
    305   fnotice (file, "  -n, --noisy      Print progress messages\n");
    306   fnotice (file, "  -1, --one        One connection and then exit\n");
    307   fnotice (file, "  -r, --root DIR   Root compiled module directory\n");
    308   fnotice (file, "  -s, --sequential Process connections sequentially\n");
    309   fnotice (file, "  -v, --version    Print version number, then exit\n");
    310   fnotice (file, "Send SIGTERM(%d) to terminate\n", SIGTERM);
    311   fnotice (file, "\nFor bug reporting instructions, please see:\n%s.\n",
    312 	   bug_report_url);
    313   exit (status);
    314 }
    315 
    316 /* Print version information and exit.  */
    317 
    318 static void ATTRIBUTE_NORETURN
    319 print_version (void)
    320 {
    321   fnotice (stdout, "%s %s%s\n", progname, pkgversion_string, version_string);
    322   fprintf (stdout, "Copyright %s 2018-2022 Free Software Foundation, Inc.\n",
    323 	   ("(C)"));
    324   fnotice (stdout,
    325 	   ("This is free software; see the source for copying conditions.\n"
    326 	    "There is NO warranty; not even for MERCHANTABILITY or \n"
    327 	    "FITNESS FOR A PARTICULAR PURPOSE.\n\n"));
    328   exit (0);
    329 }
    330 
    331 /* ARG is a netmask to accept from.  Add it to the table.  Return
    332    false if we fail to resolve it.  */
    333 
    334 static bool
    335 accept_from (char *arg ATTRIBUTE_UNUSED)
    336 {
    337   bool ok = true;
    338 #if HAVE_AF_INET6
    339   unsigned bits = sizeof (in6_addr) * 8;
    340   char *slash = strrchr (arg, '/');
    341   if (slash)
    342     {
    343       *slash = 0;
    344       if (slash[1])
    345 	{
    346 	  char *endp;
    347 	  bits = strtoul (slash + 1, &endp, 0);
    348 	}
    349     }
    350 
    351   addrinfo hints;
    352 
    353   hints.ai_flags = AI_NUMERICSERV;
    354   hints.ai_family = AF_INET6;
    355   hints.ai_socktype = SOCK_STREAM;
    356   hints.ai_protocol = 0;
    357   hints.ai_addrlen = 0;
    358   hints.ai_addr = NULL;
    359   hints.ai_canonname = NULL;
    360   hints.ai_next = NULL;
    361 
    362   struct addrinfo *addrs = NULL;
    363   /* getaddrinfo requires either hostname or servname to be non-null, so that we must
    364      set a port number (to cover the case that the string passed contains just /NN).
    365      Use an arbitrary in-range port number, but avoiding "0" which triggers a bug on
    366      some BSD variants.  */
    367   if (int e = getaddrinfo (slash == arg ? NULL : arg, "1", &hints, &addrs))
    368     {
    369       noisy ("cannot resolve '%s': %s", arg, gai_strerror (e));
    370       ok = false;
    371     }
    372   else
    373     for (addrinfo *next = addrs; next; next = next->ai_next)
    374       if (next->ai_family == AF_INET6)
    375 	{
    376 	  netmask mask (((const sockaddr_in6 *)next->ai_addr)->sin6_addr, bits);
    377 	  netmask_set.insert (mask);
    378 	}
    379   freeaddrinfo (addrs);
    380 #endif
    381   return ok;
    382 }
    383 
    384 /* Process args, return index to first non-arg.  */
    385 
    386 static int
    387 process_args (int argc, char **argv)
    388 {
    389   static const struct option options[] =
    390     {
    391      { "accept", required_argument, NULL, 'a' },
    392      { "help",	no_argument,	NULL, 'h' },
    393      { "map",   no_argument,	NULL, 'm' },
    394      { "noisy",	no_argument,	NULL, 'n' },
    395      { "one",	no_argument,	NULL, '1' },
    396      { "root",	required_argument, NULL, 'r' },
    397      { "sequential", no_argument, NULL, 's' },
    398      { "translate",no_argument,	NULL, 't' },
    399      { "version", no_argument,	NULL, 'v' },
    400      { 0, 0, 0, 0 }
    401     };
    402   int opt;
    403   bool bad_accept = false;
    404   const char *opts = "a:fhmn1r:stv";
    405   while ((opt = getopt_long (argc, argv, opts, options, NULL)) != -1)
    406     {
    407       switch (opt)
    408 	{
    409 	case 'a':
    410 	  if (!accept_from (optarg))
    411 	    bad_accept = true;
    412 	  break;
    413 	case 'h':
    414 	  print_usage (false);
    415 	  /* print_usage will exit.  */
    416 	case 'f': // deprecated alias
    417 	case 'm':
    418 	  flag_map = true;
    419 	  break;
    420 	case 'n':
    421 	  flag_noisy = true;
    422 	  break;
    423 	case '1':
    424 	  flag_one = true;
    425 	  break;
    426 	case 'r':
    427 	  flag_root = optarg;
    428 	  break;
    429 	case 's':
    430 	  flag_sequential = true;
    431 	  break;
    432 	case 't':
    433 	  flag_xlate = true;
    434 	  break;
    435 	case 'v':
    436 	  print_version ();
    437 	  /* print_version will exit.  */
    438 	default:
    439 	  print_usage (true);
    440 	  /* print_usage will exit.  */
    441 	}
    442     }
    443 
    444   if (bad_accept)
    445     error ("failed to resolve all accept addresses");
    446 
    447   return optind;
    448 }
    449 
    450 #if NETWORKING
    451 
    452 /* Manipulate the EPOLL state, or do nothing, if there is epoll.  */
    453 
    454 #ifdef HAVE_EPOLL
    455 static inline void
    456 do_epoll_ctl (int epoll_fd, int code, int event, int fd, unsigned data)
    457 {
    458   epoll_event ev;
    459   ev.events = event;
    460   ev.data.u32 = data;
    461   if (epoll_ctl (epoll_fd, code, fd, &ev))
    462     {
    463       noisy ("epoll_ctl error:%s", xstrerror (errno));
    464       gcc_unreachable ();
    465     }
    466 }
    467 #define my_epoll_ctl(EFD,C,EV,FD,CL) \
    468   ((EFD) >= 0 ? do_epoll_ctl (EFD,C,EV,FD,CL) : (void)0)
    469 #else
    470 #define my_epoll_ctl(EFD,C,EV,FD,CL) ((void)(EFD), (void)(FD), (void)(CL))
    471 #endif
    472 
    473 /* We increment this to tell the server to shut down.  */
    474 static volatile int term = false;
    475 static volatile int kill_sock_fd = -1;
    476 #if !defined (HAVE_PSELECT) && defined (HAVE_SELECT)
    477 static int term_pipe[2] = {-1, -1};
    478 #else
    479 #define term_pipe ((int *)NULL)
    480 #endif
    481 
    482 /* A terminate signal.  Shutdown gracefully.  */
    483 
    484 static void
    485 term_signal (int sig)
    486 {
    487   signal (sig, term_signal);
    488   term = term + 1;
    489   if (term_pipe && term_pipe[1] >= 0)
    490     write (term_pipe[1], &term_pipe[1], 1);
    491 }
    492 
    493 /* A kill signal.  Shutdown immediately.  */
    494 
    495 static void
    496 kill_signal (int sig)
    497 {
    498   signal (sig, SIG_DFL);
    499   int sock_fd = kill_sock_fd;
    500   if (sock_fd >= 0)
    501     close (sock_fd);
    502   exit (2);
    503 }
    504 
    505 bool process_server (Cody::Server *server, unsigned slot, int epoll_fd)
    506 {
    507   switch (server->GetDirection ())
    508     {
    509     case Cody::Server::READING:
    510       if (int err = server->Read ())
    511 	return !(err == EINTR || err == EAGAIN);
    512       server->ProcessRequests ();
    513       server->PrepareToWrite ();
    514       break;
    515 
    516     case Cody::Server::WRITING:
    517       if (int err = server->Write ())
    518 	return !(err == EINTR || err == EAGAIN);
    519       server->PrepareToRead ();
    520       break;
    521 
    522     default:
    523       // We should never get here
    524       return true;
    525     }
    526 
    527   // We've changed direction, so update epoll
    528   gcc_assert (server->GetFDRead () == server->GetFDWrite ());
    529   my_epoll_ctl (epoll_fd, EPOLL_CTL_MOD,
    530 		server->GetDirection () == Cody::Server::READING
    531 		? EPOLLIN : EPOLLOUT, server->GetFDRead (), slot + 1);
    532 
    533   return false;
    534 }
    535 
    536 void close_server (Cody::Server *server, int epoll_fd)
    537 {
    538   my_epoll_ctl (epoll_fd, EPOLL_CTL_DEL, EPOLLIN, server->GetFDRead (), 0);
    539 
    540   close (server->GetFDRead ());
    541 
    542   delete server;
    543 }
    544 
    545 int open_server (bool ip6, int sock_fd)
    546 {
    547   sockaddr_in6 addr;
    548   socklen_t addr_len = sizeof (addr);
    549 
    550 #ifdef HAVE_ACCEPT4
    551   int client_fd = accept4 (sock_fd, ip6 ? (sockaddr *)&addr : nullptr,
    552 			   &addr_len, SOCK_NONBLOCK);
    553 #else
    554   int client_fd = accept (sock_fd, ip6 ? (sockaddr *)&addr : nullptr, &addr_len);
    555 #endif
    556   if (client_fd < 0)
    557     {
    558       error ("cannot accept: %s", xstrerror (errno));
    559       flag_one = true;
    560     }
    561   else if (ip6)
    562     {
    563       const char *str = NULL;
    564 #if HAVE_INET_NTOP
    565       char name[INET6_ADDRSTRLEN];
    566       str = inet_ntop (addr.sin6_family, &addr.sin6_addr, name, sizeof (name));
    567 #endif
    568       if (!accept_addrs.empty ())
    569 	{
    570 	  netmask_vec_t::iterator e = accept_addrs.end ();
    571 	  for (netmask_vec_t::iterator i = accept_addrs.begin ();
    572 	       i != e; ++i)
    573 	    if (i->includes (addr.sin6_addr))
    574 	      goto present;
    575 	  close (client_fd);
    576 	  client_fd = -1;
    577 	  noisy ("Rejecting connection from disallowed source '%s'",
    578 		 str ? str : "");
    579 	present:;
    580 	}
    581       if (client_fd >= 0)
    582 	flag_noisy && noisy ("Accepting connection from '%s'", str ? str : "");
    583     }
    584 
    585   return client_fd;
    586 }
    587 
    588 /* A server listening on bound socket SOCK_FD.  */
    589 
    590 static void
    591 server (bool ipv6, int sock_fd, module_resolver *resolver)
    592 {
    593   int epoll_fd = -1;
    594 
    595   signal (SIGTERM, term_signal);
    596 #ifdef HAVE_EPOLL
    597   epoll_fd = epoll_create (1);
    598 #endif
    599   if (epoll_fd >= 0)
    600     my_epoll_ctl (epoll_fd, EPOLL_CTL_ADD, EPOLLIN, sock_fd, 0);
    601 
    602 #if defined (HAVE_EPOLL) || defined (HAVE_PSELECT) || defined (HAVE_SELECT)
    603   sigset_t mask;
    604   {
    605     sigset_t block;
    606     sigemptyset (&block);
    607     sigaddset (&block, SIGTERM);
    608     sigprocmask (SIG_BLOCK, &block, &mask);
    609   }
    610 #endif
    611 
    612 #ifdef HAVE_EPOLL
    613   const unsigned max_events = 20;
    614   epoll_event events[max_events];
    615 #endif
    616 #if defined (HAVE_PSELECT) || defined (HAVE_SELECT)
    617   fd_set readers, writers;
    618 #endif
    619   if (term_pipe)
    620     pipe (term_pipe);
    621 
    622   // We need stable references to servers, so this array can contain nulls
    623   std::vector<Cody::Server *> connections;
    624   unsigned live = 0;
    625   while (sock_fd >= 0 || live)
    626     {
    627       /* Wait for one or more events.  */
    628       bool eintr = false;
    629       int event_count;
    630 
    631       if (epoll_fd >= 0)
    632 	{
    633 #ifdef HAVE_EPOLL
    634 	  event_count = epoll_pwait (epoll_fd, events, max_events, -1, &mask);
    635 #endif
    636 	}
    637       else
    638 	{
    639 #if defined (HAVE_PSELECT) || defined (HAVE_SELECT)
    640 	  FD_ZERO (&readers);
    641 	  FD_ZERO (&writers);
    642 
    643 	  unsigned limit = 0;
    644 	  if (sock_fd >= 0
    645 	      && !(term || (live && (flag_one || flag_sequential))))
    646 	    {
    647 	      FD_SET (sock_fd, &readers);
    648 	      limit = sock_fd + 1;
    649 	    }
    650 
    651 	  if (term_pipe && term_pipe[0] >= 0)
    652 	    {
    653 	      FD_SET (term_pipe[0], &readers);
    654 	      if (unsigned (term_pipe[0]) >= limit)
    655 		limit = term_pipe[0] + 1;
    656 	    }
    657 
    658 	  for (auto iter = connections.begin ();
    659 	       iter != connections.end (); ++iter)
    660 	    if (auto *server = *iter)
    661 	      {
    662 		int fd = -1;
    663 		switch (server->GetDirection ())
    664 		  {
    665 		  case Cody::Server::READING:
    666 		    fd = server->GetFDRead ();
    667 		    FD_SET (fd, &readers);
    668 		    break;
    669 		  case Cody::Server::WRITING:
    670 		    fd = server->GetFDWrite ();
    671 		    FD_SET (fd, &writers);
    672 		    break;
    673 		  default:
    674 		    break;
    675 		  }
    676 
    677 		if (fd >= 0 && limit <= unsigned (fd))
    678 		  limit = fd + 1;
    679 	      }
    680 
    681 #ifdef HAVE_PSELECT
    682 	  event_count = pselect (limit, &readers, &writers, NULL, NULL, &mask);
    683 #else
    684 	  event_count = select (limit, &readers, &writers, NULL, NULL);
    685 #endif
    686 	  if (term_pipe && FD_ISSET (term_pipe[0], &readers))
    687 	    {
    688 	      /* Fake up an interrupted system call.  */
    689 	      event_count = -1;
    690 	      errno = EINTR;
    691 	    }
    692 #endif
    693 	}
    694 
    695       if (event_count < 0)
    696 	{
    697 	  // Error in waiting
    698 	  if (errno == EINTR)
    699 	    {
    700 	      flag_noisy && noisy ("Interrupted wait");
    701 	      eintr = true;
    702 	    }
    703 	  else
    704 	    error ("cannot %s: %s", epoll_fd >= 0 ? "epoll_wait"
    705 #ifdef HAVE_PSELECT
    706 		   : "pselect",
    707 #else
    708 		   : "select",
    709 #endif
    710 		   xstrerror (errno));
    711 	  event_count = 0;
    712 	}
    713 
    714       auto iter = connections.begin ();
    715       while (event_count--)
    716 	{
    717 	  // Process an event
    718 	  int active = -2;
    719 
    720 	  if (epoll_fd >= 0)
    721 	    {
    722 #ifdef HAVE_EPOLL
    723 	      /* See PR c++/88664 for why a temporary is used.  */
    724 	      unsigned data = events[event_count].data.u32;
    725 	      active = int (data) - 1;
    726 #endif
    727 	    }
    728 	  else
    729 	    {
    730 	      for (; iter != connections.end (); ++iter)
    731 		if (auto *server = *iter)
    732 		  {
    733 		    bool found = false;
    734 		    switch (server->GetDirection ())
    735 		      {
    736 #if defined (HAVE_PSELECT) || defined (HAVE_SELECT)
    737 		      case Cody::Server::READING:
    738 			found = FD_ISSET (server->GetFDRead (), &readers);
    739 			break;
    740 		      case Cody::Server::WRITING:
    741 			found = FD_ISSET (server->GetFDWrite (), &writers);
    742 			break;
    743 #endif
    744 		      default:
    745 			break;
    746 		      }
    747 
    748 		    if (found)
    749 		      {
    750 			active = iter - connections.begin ();
    751 			++iter;
    752 			break;
    753 		      }
    754 		  }
    755 
    756 #if defined (HAVE_PSELECT) || defined (HAVE_SELECT)
    757 	      if (active < 0 && sock_fd >= 0 && FD_ISSET (sock_fd, &readers))
    758 		active = -1;
    759 #endif
    760 	    }
    761 
    762 	  if (active >= 0)
    763 	    {
    764 	      // Do the action
    765 	      auto *server = connections[active];
    766 	      if (process_server (server, active, epoll_fd))
    767 		{
    768 		  connections[active] = nullptr;
    769 		  close_server (server, epoll_fd);
    770 		  live--;
    771 		  if (flag_sequential)
    772 		    my_epoll_ctl (epoll_fd, EPOLL_CTL_ADD, EPOLLIN, sock_fd, 0);
    773 		}
    774 	    }
    775 	  else if (active == -1 && !eintr)
    776 	    {
    777 	      // New connection
    778 	      int fd = open_server (ipv6, sock_fd);
    779 	      if (fd >= 0)
    780 		{
    781 #if !defined (HAVE_ACCEPT4) \
    782   && (defined (HAVE_EPOLL) || defined (HAVE_PSELECT) || defined (HAVE_SELECT))
    783 		  int flags = fcntl (fd, F_GETFL, 0);
    784 		  fcntl (fd, F_SETFL, flags | O_NONBLOCK);
    785 #endif
    786 		  auto *server = new Cody::Server (resolver, fd);
    787 
    788 		  unsigned slot = connections.size ();
    789 		  if (live == slot)
    790 		    connections.push_back (server);
    791 		  else
    792 		    for (auto iter = connections.begin (); ; ++iter)
    793 		      if (!*iter)
    794 			{
    795 			  *iter = server;
    796 			  slot = iter - connections.begin ();
    797 			  break;
    798 			}
    799 		  live++;
    800 		  my_epoll_ctl (epoll_fd, EPOLL_CTL_ADD, EPOLLIN, fd, slot + 1);
    801 		}
    802 	    }
    803 
    804 	  if (sock_fd >= 0
    805 	      && (term || (live && (flag_one || flag_sequential))))
    806 	    {
    807 	      /* Stop paying attention to sock_fd.  */
    808 	      my_epoll_ctl (epoll_fd, EPOLL_CTL_DEL, EPOLLIN, sock_fd, 0);
    809 	      if (flag_one || term)
    810 		{
    811 		  close (sock_fd);
    812 		  sock_fd = -1;
    813 		}
    814 	    }
    815 	}
    816     }
    817 #if defined (HAVE_EPOLL) || defined (HAVE_PSELECT) || defined (HAVE_SELECT)
    818   /* Restore the signal mask.  */
    819   sigprocmask (SIG_SETMASK, &mask, NULL);
    820 #endif
    821 
    822   gcc_assert (sock_fd < 0);
    823   if (epoll_fd >= 0)
    824     close (epoll_fd);
    825 
    826   if (term_pipe && term_pipe[0] >= 0)
    827     {
    828       close (term_pipe[0]);
    829       close (term_pipe[1]);
    830     }
    831 }
    832 
    833 #endif
    834 
    835 static int maybe_parse_socket (std::string &option, module_resolver *r)
    836 {
    837   /* Local or ipv6 address.  */
    838   auto last = option.find_last_of ('?');
    839   if (last != option.npos)
    840     {
    841       r->set_ident (option.c_str () + last + 1);
    842       option.erase (last);
    843     }
    844   int fd = -2;
    845   char const *errmsg = nullptr;
    846 
    847   /* Does it look like a socket?  */
    848   if (option[0] == '=')
    849     {
    850       /* A local socket.  */
    851 #if CODY_NETWORKING
    852       fd = Cody::ListenLocal (&errmsg, option.c_str () + 1);
    853 #endif
    854     }
    855   else
    856     {
    857       auto colon = option.find_last_of (':');
    858       if (colon != option.npos)
    859 	{
    860 	  /* Try a hostname:port address.  */
    861 	  char const *cptr = option.c_str () + colon;
    862 	  char *endp;
    863 	  unsigned port = strtoul (cptr + 1, &endp, 10);
    864 
    865 	  if (port && endp != cptr + 1 && !*endp)
    866 	    {
    867 	      /* Ends in ':number', treat as ipv6 domain socket.  */
    868 	      option.erase (colon);
    869 #if CODY_NETWORKING
    870 	      fd = Cody::ListenInet6 (&errmsg, option.c_str (), port);
    871 #endif
    872 	    }
    873 	}
    874     }
    875 
    876   if (errmsg)
    877     error ("failed to open socket: %s", errmsg);
    878 
    879   return fd;
    880 }
    881 
    882 int
    883 main (int argc, char *argv[])
    884 {
    885   const char *p = argv[0] + strlen (argv[0]);
    886   while (p != argv[0] && !IS_DIR_SEPARATOR (p[-1]))
    887     --p;
    888   progname = p;
    889 
    890 #ifdef SIGSEGV
    891   signal (SIGSEGV, crash_signal);
    892 #endif
    893 #ifdef SIGILL
    894   signal (SIGILL, crash_signal);
    895 #endif
    896 #ifdef SIGBUS
    897   signal (SIGBUS, crash_signal);
    898 #endif
    899 #ifdef SIGABRT
    900   signal (SIGABRT, crash_signal);
    901 #endif
    902 #ifdef SIGFPE
    903   signal (SIGFPE, crash_signal);
    904 #endif
    905 #ifdef SIGPIPE
    906   /* Ignore sigpipe, so read/write get an error.  */
    907   signal (SIGPIPE, SIG_IGN);
    908 #endif
    909 #if NETWORKING
    910 #ifdef SIGINT
    911   signal (SIGINT, kill_signal);
    912 #endif
    913 #endif
    914 
    915   int argno = process_args (argc, argv);
    916 
    917   std::string name;
    918   int sock_fd = -1; /* Socket fd, otherwise stdin/stdout.  */
    919   module_resolver r (flag_map, flag_xlate);
    920 
    921   if (argno != argc)
    922     {
    923       name = argv[argno];
    924       sock_fd = maybe_parse_socket (name, &r);
    925       if (!name.empty ())
    926 	argno++;
    927     }
    928 
    929   if (argno != argc)
    930     for (; argno != argc; argno++)
    931       {
    932 	std::string option = argv[argno];
    933 	char const *prefix = nullptr;
    934 	auto ident = option.find_last_of ('?');
    935 	if (ident != option.npos)
    936 	  {
    937 	    prefix = option.c_str () + ident + 1;
    938 	    option[ident] = 0;
    939 	  }
    940 	int fd = open (option.c_str (), O_RDONLY | O_CLOEXEC);
    941 	int err = 0;
    942 	if (fd < 0)
    943 	  err = errno;
    944 	else
    945 	  {
    946 	    err = r.read_tuple_file (fd, prefix, false);
    947 	    close (fd);
    948 	  }
    949 
    950 	if (err)
    951 	  error ("failed reading '%s': %s", option.c_str (), xstrerror (err));
    952       }
    953   else
    954     r.set_default_map (true);
    955 
    956   if (flag_root)
    957     r.set_repo (flag_root);
    958 
    959 #ifdef HAVE_AF_INET6
    960   netmask_set_t::iterator end = netmask_set.end ();
    961   for (netmask_set_t::iterator iter = netmask_set.begin ();
    962        iter != end; ++iter)
    963     {
    964       netmask_vec_t::iterator e = accept_addrs.end ();
    965       for (netmask_vec_t::iterator i = accept_addrs.begin (); i != e; ++i)
    966 	if (i->includes (iter->addr))
    967 	  goto present;
    968       accept_addrs.push_back (*iter);
    969     present:;
    970     }
    971 #endif
    972 
    973 #if NETWORKING
    974   if (sock_fd >= 0)
    975     {
    976       server (name[0] != '=', sock_fd, &r);
    977       if (name[0] == '=')
    978 	unlink (name.c_str () + 1);
    979     }
    980   else
    981 #endif
    982     {
    983       auto server = Cody::Server (&r, 0, 1);
    984 
    985       int err = 0;
    986       for (;;)
    987 	{
    988 	  server.PrepareToRead ();
    989 	  while ((err = server.Read ()))
    990 	    {
    991 	      if (err == EINTR || err == EAGAIN)
    992 		continue;
    993 	      goto done;
    994 	    }
    995 
    996 	  server.ProcessRequests ();
    997 
    998 	  server.PrepareToWrite ();
    999 	  while ((err = server.Write ()))
   1000 	    {
   1001 	      if (err == EINTR || err == EAGAIN)
   1002 		continue;
   1003 	      goto done;
   1004 	    }
   1005 	}
   1006     done:;
   1007       if (err > 0)
   1008 	error ("communication error:%s", xstrerror (err));
   1009     }
   1010 
   1011   return 0;
   1012 }
   1013