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