Home | History | Annotate | Line # | Download | only in cp
      1  1.1  mrg /* C++ modules.  Experimental!
      2  1.1  mrg    Copyright (C) 2017-2022 Free Software Foundation, Inc.
      3  1.1  mrg    Written by Nathan Sidwell <nathan (at) acm.org> while at FaceBook
      4  1.1  mrg 
      5  1.1  mrg    This file is part of GCC.
      6  1.1  mrg 
      7  1.1  mrg    GCC is free software; you can redistribute it and/or modify it
      8  1.1  mrg    under the terms of the GNU General Public License as published by
      9  1.1  mrg    the Free Software Foundation; either version 3, or (at your option)
     10  1.1  mrg    any later version.
     11  1.1  mrg 
     12  1.1  mrg    GCC is distributed in the hope that it will be useful, but
     13  1.1  mrg    WITHOUT ANY WARRANTY; without even the implied warranty of
     14  1.1  mrg    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     15  1.1  mrg    General Public License for more details.
     16  1.1  mrg 
     17  1.1  mrg You should have received a copy of the GNU General Public License
     18  1.1  mrg along with GCC; see the file COPYING3.  If not see
     19  1.1  mrg <http://www.gnu.org/licenses/>.  */
     20  1.1  mrg 
     21  1.1  mrg #include "config.h"
     22  1.1  mrg #if defined (__unix__)
     23  1.1  mrg // Solaris11's socket header used bcopy, which we poison.  cody.hh
     24  1.1  mrg // will include it later under the above check
     25  1.1  mrg #include <sys/socket.h>
     26  1.1  mrg #endif
     27  1.1  mrg #define INCLUDE_STRING
     28  1.1  mrg #define INCLUDE_VECTOR
     29  1.1  mrg #define INCLUDE_MAP
     30  1.1  mrg #define INCLUDE_MEMORY
     31  1.1  mrg #include "system.h"
     32  1.1  mrg 
     33  1.1  mrg #include "line-map.h"
     34  1.1  mrg #include "diagnostic-core.h"
     35  1.1  mrg #include "mapper-client.h"
     36  1.1  mrg #include "intl.h"
     37  1.1  mrg 
     38  1.1  mrg #include "../../c++tools/resolver.h"
     39  1.1  mrg 
     40  1.1  mrg #if !HOST_HAS_O_CLOEXEC
     41  1.1  mrg #define O_CLOEXEC 0
     42  1.1  mrg #endif
     43  1.1  mrg 
     44  1.1  mrg module_client::module_client (pex_obj *p, int fd_from, int fd_to)
     45  1.1  mrg   : Client (fd_from, fd_to), pex (p)
     46  1.1  mrg {
     47  1.1  mrg }
     48  1.1  mrg 
     49  1.1  mrg static module_client *
     50  1.1  mrg spawn_mapper_program (char const **errmsg, std::string &name,
     51  1.1  mrg 		      char const *full_program_name)
     52  1.1  mrg {
     53  1.1  mrg   /* Split writable at white-space.  No space-containing args for
     54  1.1  mrg      you!  */
     55  1.1  mrg   // At most every other char could be an argument
     56  1.1  mrg   char **argv = new char *[name.size () / 2 + 2];
     57  1.1  mrg   unsigned arg_no = 0;
     58  1.1  mrg   char *str = new char[name.size ()];
     59  1.1  mrg   memcpy (str, name.c_str () + 1, name.size ());
     60  1.1  mrg 
     61  1.1  mrg   for (auto ptr = str; ; ++ptr)
     62  1.1  mrg     {
     63  1.1  mrg       while (*ptr == ' ')
     64  1.1  mrg 	ptr++;
     65  1.1  mrg       if (!*ptr)
     66  1.1  mrg 	break;
     67  1.1  mrg 
     68  1.1  mrg       if (!arg_no)
     69  1.1  mrg 	{
     70  1.1  mrg 	  /* @name means look in the compiler's install dir.  */
     71  1.1  mrg 	  if (ptr[0] == '@')
     72  1.1  mrg 	    ptr++;
     73  1.1  mrg 	  else
     74  1.1  mrg 	    full_program_name = nullptr;
     75  1.1  mrg 	}
     76  1.1  mrg 
     77  1.1  mrg       argv[arg_no++] = ptr;
     78  1.1  mrg       while (*ptr && *ptr != ' ')
     79  1.1  mrg 	ptr++;
     80  1.1  mrg       if (!*ptr)
     81  1.1  mrg 	break;
     82  1.1  mrg       *ptr = 0;
     83  1.1  mrg     }
     84  1.1  mrg   argv[arg_no] = nullptr;
     85  1.1  mrg 
     86  1.1  mrg   auto *pex = pex_init (PEX_USE_PIPES, progname, NULL);
     87  1.1  mrg   FILE *to = pex_input_pipe (pex, false);
     88  1.1  mrg   name = argv[0];
     89  1.1  mrg   if (!to)
     90  1.1  mrg     *errmsg = "connecting input";
     91  1.1  mrg   else
     92  1.1  mrg     {
     93  1.1  mrg       int flags = PEX_SEARCH;
     94  1.1  mrg 
     95  1.1  mrg       if (full_program_name)
     96  1.1  mrg 	{
     97  1.1  mrg 	  /* Prepend the invoking path, if the mapper is a simple
     98  1.1  mrg 	     file name.  */
     99  1.1  mrg 	  size_t dir_len = progname - full_program_name;
    100  1.1  mrg 	  std::string argv0;
    101  1.1  mrg 	  argv0.reserve (dir_len + name.size ());
    102  1.1  mrg 	  argv0.append (full_program_name, dir_len).append (name);
    103  1.1  mrg 	  name = std::move (argv0);
    104  1.1  mrg 	  argv[0] = const_cast <char *> (name.c_str ());
    105  1.1  mrg 	  flags = 0;
    106  1.1  mrg 	}
    107  1.1  mrg       int err;
    108  1.1  mrg       *errmsg = pex_run (pex, flags, argv[0], argv, NULL, NULL, &err);
    109  1.1  mrg     }
    110  1.1  mrg   delete[] str;
    111  1.1  mrg   delete[] argv;
    112  1.1  mrg 
    113  1.1  mrg   int fd_from = -1, fd_to = -1;
    114  1.1  mrg   if (!*errmsg)
    115  1.1  mrg     {
    116  1.1  mrg       FILE *from = pex_read_output (pex, false);
    117  1.1  mrg       if (from && (fd_to = dup (fileno (to))) >= 0)
    118  1.1  mrg 	fd_from = fileno (from);
    119  1.1  mrg       else
    120  1.1  mrg 	*errmsg = "connecting output";
    121  1.1  mrg       fclose (to);
    122  1.1  mrg     }
    123  1.1  mrg 
    124  1.1  mrg   if (*errmsg)
    125  1.1  mrg     {
    126  1.1  mrg       pex_free (pex);
    127  1.1  mrg       return nullptr;
    128  1.1  mrg     }
    129  1.1  mrg 
    130  1.1  mrg   return new module_client (pex, fd_from, fd_to);
    131  1.1  mrg }
    132  1.1  mrg 
    133  1.1  mrg module_client *
    134  1.1  mrg module_client::open_module_client (location_t loc, const char *o,
    135  1.1  mrg 				   void (*set_repo) (const char *),
    136  1.1  mrg 				   char const *full_program_name)
    137  1.1  mrg {
    138  1.1  mrg   module_client *c = nullptr;
    139  1.1  mrg   std::string ident;
    140  1.1  mrg   std::string name;
    141  1.1  mrg   char const *errmsg = nullptr;
    142  1.1  mrg   unsigned line = 0;
    143  1.1  mrg 
    144  1.1  mrg   if (o && o[0])
    145  1.1  mrg     {
    146  1.1  mrg       /* Maybe a local or ipv6 address.  */
    147  1.1  mrg       name = o;
    148  1.1  mrg       auto last = name.find_last_of ('?');
    149  1.1  mrg       if (last != name.npos)
    150  1.1  mrg 	{
    151  1.1  mrg 	  ident = name.substr (last + 1);
    152  1.1  mrg 	  name.erase (last);
    153  1.1  mrg 	}
    154  1.1  mrg 
    155  1.1  mrg       if (name.size ())
    156  1.1  mrg 	{
    157  1.1  mrg 	  switch (name[0])
    158  1.1  mrg 	    {
    159  1.1  mrg 	    case '<':
    160  1.1  mrg 	      // <from>to or <>fromto, or <>
    161  1.1  mrg 	      {
    162  1.1  mrg 		size_t pos = name.find ('>', 1);
    163  1.1  mrg 		if (pos == std::string::npos)
    164  1.1  mrg 		  pos = name.size ();
    165  1.1  mrg 		std::string from (name, 1, pos - 1);
    166  1.1  mrg 		std::string to;
    167  1.1  mrg 		if (pos != name.size ())
    168  1.1  mrg 		  to.append (name, pos + 1, std::string::npos);
    169  1.1  mrg 
    170  1.1  mrg 		int fd_from = -1, fd_to = -1;
    171  1.1  mrg 		if (from.empty () && to.empty ())
    172  1.1  mrg 		  {
    173  1.1  mrg 		    fd_from = fileno (stdin);
    174  1.1  mrg 		    fd_to = fileno (stdout);
    175  1.1  mrg 		  }
    176  1.1  mrg 		else
    177  1.1  mrg 		  {
    178  1.1  mrg 		    char *ptr;
    179  1.1  mrg 		    if (!from.empty ())
    180  1.1  mrg 		      {
    181  1.1  mrg 			/* Sadly str::stoul is not portable.  */
    182  1.1  mrg 			const char *cstr = from.c_str ();
    183  1.1  mrg 			fd_from = strtoul (cstr, &ptr, 10);
    184  1.1  mrg 			if (*ptr)
    185  1.1  mrg 			  {
    186  1.1  mrg 			    /* Not a number -- a named pipe.  */
    187  1.1  mrg 			    int dir = to.empty ()
    188  1.1  mrg 			      ? O_RDWR | O_CLOEXEC : O_RDONLY | O_CLOEXEC;
    189  1.1  mrg 			    fd_from = open (cstr, dir);
    190  1.1  mrg 			  }
    191  1.1  mrg 			if (to.empty ())
    192  1.1  mrg 			  fd_to = fd_from;
    193  1.1  mrg 		      }
    194  1.1  mrg 
    195  1.1  mrg 		    if (!from.empty () && fd_from < 0)
    196  1.1  mrg 		      ;
    197  1.1  mrg 		    else if (to.empty ())
    198  1.1  mrg 		      ;
    199  1.1  mrg 		    else
    200  1.1  mrg 		      {
    201  1.1  mrg 			const char *cstr = to.c_str ();
    202  1.1  mrg 			fd_to = strtoul (cstr, &ptr, 10);
    203  1.1  mrg 			if (*ptr)
    204  1.1  mrg 			  {
    205  1.1  mrg 			    /* Not a number, a named pipe.  */
    206  1.1  mrg 			    int dir = from.empty ()
    207  1.1  mrg 			      ? O_RDWR | O_CLOEXEC : O_WRONLY | O_CLOEXEC;
    208  1.1  mrg 			    fd_to = open (cstr, dir);
    209  1.1  mrg 			    if (fd_to < 0)
    210  1.1  mrg 			      close (fd_from);
    211  1.1  mrg 			  }
    212  1.1  mrg 			if (from.empty ())
    213  1.1  mrg 			  fd_from = fd_to;
    214  1.1  mrg 		      }
    215  1.1  mrg 		  }
    216  1.1  mrg 
    217  1.1  mrg 		if (fd_from < 0 || fd_to < 0)
    218  1.1  mrg 		  errmsg = "opening";
    219  1.1  mrg 		else
    220  1.1  mrg 		  c = new module_client (fd_from, fd_to);
    221  1.1  mrg 	      }
    222  1.1  mrg 	      break;
    223  1.1  mrg 
    224  1.1  mrg 	    case '=':
    225  1.1  mrg 	      // =localsocket
    226  1.1  mrg 	      {
    227  1.1  mrg 		int fd = -1;
    228  1.1  mrg #if CODY_NETWORKING
    229  1.1  mrg 		fd = Cody::OpenLocal (&errmsg, name.c_str () + 1);
    230  1.1  mrg #endif
    231  1.1  mrg 		if (fd >= 0)
    232  1.1  mrg 		  c = new module_client (fd, fd);
    233  1.1  mrg 	      }
    234  1.1  mrg 	      break;
    235  1.1  mrg 
    236  1.1  mrg 	    case '|':
    237  1.1  mrg 	      // |program and args
    238  1.1  mrg 	      c = spawn_mapper_program (&errmsg, name, full_program_name);
    239  1.1  mrg 	      break;
    240  1.1  mrg 
    241  1.1  mrg 	    default:
    242  1.1  mrg 	      // file or hostname:port
    243  1.1  mrg 	      {
    244  1.1  mrg 		auto colon = name.find_last_of (':');
    245  1.1  mrg 		if (colon != name.npos)
    246  1.1  mrg 		  {
    247  1.1  mrg 		    char const *cptr = name.c_str () + colon;
    248  1.1  mrg 		    char *endp;
    249  1.1  mrg 		    unsigned port = strtoul (cptr + 1, &endp, 10);
    250  1.1  mrg 
    251  1.1  mrg 		    if (port && endp != cptr + 1 && !*endp)
    252  1.1  mrg 		      {
    253  1.1  mrg 			name[colon] = 0;
    254  1.1  mrg 			int fd = -1;
    255  1.1  mrg #if CODY_NETWORKING
    256  1.1  mrg 			fd = Cody::OpenInet6 (&errmsg, name.c_str (), port);
    257  1.1  mrg #endif
    258  1.1  mrg 			name[colon] = ':';
    259  1.1  mrg 
    260  1.1  mrg 			if (fd >= 0)
    261  1.1  mrg 			  c = new module_client (fd, fd);
    262  1.1  mrg 		      }
    263  1.1  mrg 		  }
    264  1.1  mrg 
    265  1.1  mrg 	      }
    266  1.1  mrg 	      break;
    267  1.1  mrg 	    }
    268  1.1  mrg 	}
    269  1.1  mrg     }
    270  1.1  mrg 
    271  1.1  mrg   if (!c)
    272  1.1  mrg     {
    273  1.1  mrg       // Make a default in-process client
    274  1.1  mrg       bool file = !errmsg && !name.empty ();
    275  1.1  mrg       auto r = new module_resolver (!file, true);
    276  1.1  mrg 
    277  1.1  mrg       if (file)
    278  1.1  mrg 	{
    279  1.1  mrg 	int fd = open (name.c_str (), O_RDONLY | O_CLOEXEC);
    280  1.1  mrg 	if (fd < 0)
    281  1.1  mrg 	  errmsg = "opening";
    282  1.1  mrg 	else
    283  1.1  mrg 	  {
    284  1.1  mrg 	    if (int l = r->read_tuple_file (fd, ident, false))
    285  1.1  mrg 	      {
    286  1.1  mrg 		if (l > 0)
    287  1.1  mrg 		  line = l;
    288  1.1  mrg 		errmsg = "reading";
    289  1.1  mrg 	      }
    290  1.1  mrg 
    291  1.1  mrg 	    close (fd);
    292  1.1  mrg 	  }
    293  1.1  mrg 	}
    294  1.1  mrg       else
    295  1.1  mrg 	r->set_repo ("gcm.cache");
    296  1.1  mrg 
    297  1.1  mrg       auto *s = new Cody::Server (r);
    298  1.1  mrg       c = new module_client (s);
    299  1.1  mrg     }
    300  1.1  mrg 
    301  1.1  mrg #ifdef SIGPIPE
    302  1.1  mrg   if (!c->IsDirect ())
    303  1.1  mrg     /* We need to ignore sig pipe for a while.  */
    304  1.1  mrg     c->sigpipe = signal (SIGPIPE, SIG_IGN);
    305  1.1  mrg #endif
    306  1.1  mrg 
    307  1.1  mrg   if (errmsg)
    308  1.1  mrg     error_at (loc, line ? G_("failed %s mapper %qs line %u")
    309  1.1  mrg 	      : G_("failed %s mapper %qs"), errmsg, name.c_str (), line);
    310  1.1  mrg 
    311  1.1  mrg   // now wave hello!
    312  1.1  mrg   c->Cork ();
    313  1.1  mrg   c->Connect (std::string ("GCC"), ident);
    314  1.1  mrg   c->ModuleRepo ();
    315  1.1  mrg   auto packets = c->Uncork ();
    316  1.1  mrg 
    317  1.1  mrg   auto &connect = packets[0];
    318  1.1  mrg   if (connect.GetCode () == Cody::Client::PC_CONNECT)
    319  1.1  mrg     c->flags = Cody::Flags (connect.GetInteger ());
    320  1.1  mrg   else if (connect.GetCode () == Cody::Client::PC_ERROR)
    321  1.1  mrg     error_at (loc, "failed mapper handshake %s", connect.GetString ().c_str ());
    322  1.1  mrg 
    323  1.1  mrg   auto &repo = packets[1];
    324  1.1  mrg   if (repo.GetCode () == Cody::Client::PC_PATHNAME)
    325  1.1  mrg     set_repo (repo.GetString ().c_str ());
    326  1.1  mrg 
    327  1.1  mrg   return c;
    328  1.1  mrg }
    329  1.1  mrg 
    330  1.1  mrg void
    331  1.1  mrg module_client::close_module_client (location_t loc, module_client *mapper)
    332  1.1  mrg {
    333  1.1  mrg   if (mapper->IsDirect ())
    334  1.1  mrg     {
    335  1.1  mrg       auto *s = mapper->GetServer ();
    336  1.1  mrg       auto *r = s->GetResolver ();
    337  1.1  mrg       delete s;
    338  1.1  mrg       delete r;
    339  1.1  mrg     }
    340  1.1  mrg   else
    341  1.1  mrg     {
    342  1.1  mrg       if (mapper->pex)
    343  1.1  mrg 	{
    344  1.1  mrg 	  int fd_write = mapper->GetFDWrite ();
    345  1.1  mrg 	  if (fd_write >= 0)
    346  1.1  mrg 	    close (fd_write);
    347  1.1  mrg 
    348  1.1  mrg 	  int status;
    349  1.1  mrg 	  pex_get_status (mapper->pex, 1, &status);
    350  1.1  mrg 
    351  1.1  mrg 	  pex_free (mapper->pex);
    352  1.1  mrg 	  mapper->pex = NULL;
    353  1.1  mrg 
    354  1.1  mrg 	  if (WIFSIGNALED (status))
    355  1.1  mrg 	    error_at (loc, "mapper died by signal %s",
    356  1.1  mrg 		      strsignal (WTERMSIG (status)));
    357  1.1  mrg 	  else if (WIFEXITED (status) && WEXITSTATUS (status) != 0)
    358  1.1  mrg 	    error_at (loc, "mapper exit status %d",
    359  1.1  mrg 		      WEXITSTATUS (status));
    360  1.1  mrg 	}
    361  1.1  mrg       else
    362  1.1  mrg 	{
    363  1.1  mrg 	  int fd_read = mapper->GetFDRead ();
    364  1.1  mrg 	  close (fd_read);
    365  1.1  mrg 	}
    366  1.1  mrg 
    367  1.1  mrg #ifdef SIGPIPE
    368  1.1  mrg       // Restore sigpipe
    369  1.1  mrg       if (mapper->sigpipe != SIG_IGN)
    370  1.1  mrg 	signal (SIGPIPE, mapper->sigpipe);
    371  1.1  mrg #endif
    372  1.1  mrg     }
    373  1.1  mrg 
    374  1.1  mrg   delete mapper;
    375  1.1  mrg }
    376