ada: output.adb: fix newline being inserted when buffer is full
[official-gcc.git] / gcc / cp / mapper-client.cc
blob8e331c0e8969faa70c1acec36d43964b87260b27
1 /* C++ modules. Experimental!
2 Copyright (C) 2017-2022 Free Software Foundation, Inc.
3 Written by Nathan Sidwell <nathan@acm.org> while at FaceBook
5 This file is part of GCC.
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.
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.
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/>. */
21 #include "config.h"
22 #if defined (__unix__)
23 // Solaris11's socket header used bcopy, which we poison. cody.hh
24 // will include it later under the above check
25 #include <sys/socket.h>
26 #endif
27 #define INCLUDE_STRING
28 #define INCLUDE_VECTOR
29 #define INCLUDE_MAP
30 #define INCLUDE_MEMORY
31 #include "system.h"
33 #include "line-map.h"
34 #include "diagnostic-core.h"
35 #include "mapper-client.h"
36 #include "intl.h"
38 #include "../../c++tools/resolver.h"
40 #if !HOST_HAS_O_CLOEXEC
41 #define O_CLOEXEC 0
42 #endif
44 module_client::module_client (pex_obj *p, int fd_from, int fd_to)
45 : Client (fd_from, fd_to), pex (p)
49 static module_client *
50 spawn_mapper_program (char const **errmsg, std::string &name,
51 char const *full_program_name)
53 /* Split writable at white-space. No space-containing args for
54 you! */
55 // At most every other char could be an argument
56 char **argv = new char *[name.size () / 2 + 2];
57 unsigned arg_no = 0;
58 char *str = new char[name.size ()];
59 memcpy (str, name.c_str () + 1, name.size ());
61 for (auto ptr = str; ; ++ptr)
63 while (*ptr == ' ')
64 ptr++;
65 if (!*ptr)
66 break;
68 if (!arg_no)
70 /* @name means look in the compiler's install dir. */
71 if (ptr[0] == '@')
72 ptr++;
73 else
74 full_program_name = nullptr;
77 argv[arg_no++] = ptr;
78 while (*ptr && *ptr != ' ')
79 ptr++;
80 if (!*ptr)
81 break;
82 *ptr = 0;
84 argv[arg_no] = nullptr;
86 auto *pex = pex_init (PEX_USE_PIPES, progname, NULL);
87 FILE *to = pex_input_pipe (pex, false);
88 name = argv[0];
89 if (!to)
90 *errmsg = "connecting input";
91 else
93 int flags = PEX_SEARCH;
95 if (full_program_name)
97 /* Prepend the invoking path, if the mapper is a simple
98 file name. */
99 size_t dir_len = progname - full_program_name;
100 std::string argv0;
101 argv0.reserve (dir_len + name.size ());
102 argv0.append (full_program_name, dir_len).append (name);
103 name = std::move (argv0);
104 argv[0] = const_cast <char *> (name.c_str ());
105 flags = 0;
107 int err;
108 *errmsg = pex_run (pex, flags, argv[0], argv, NULL, NULL, &err);
110 delete[] str;
111 delete[] argv;
113 int fd_from = -1, fd_to = -1;
114 if (!*errmsg)
116 FILE *from = pex_read_output (pex, false);
117 if (from && (fd_to = dup (fileno (to))) >= 0)
118 fd_from = fileno (from);
119 else
120 *errmsg = "connecting output";
121 fclose (to);
124 if (*errmsg)
126 pex_free (pex);
127 return nullptr;
130 return new module_client (pex, fd_from, fd_to);
133 module_client *
134 module_client::open_module_client (location_t loc, const char *o,
135 void (*set_repo) (const char *),
136 char const *full_program_name)
138 module_client *c = nullptr;
139 std::string ident;
140 std::string name;
141 char const *errmsg = nullptr;
142 unsigned line = 0;
144 if (o && o[0])
146 /* Maybe a local or ipv6 address. */
147 name = o;
148 auto last = name.find_last_of ('?');
149 if (last != name.npos)
151 ident = name.substr (last + 1);
152 name.erase (last);
155 if (name.size ())
157 switch (name[0])
159 case '<':
160 // <from>to or <>fromto, or <>
162 size_t pos = name.find ('>', 1);
163 if (pos == std::string::npos)
164 pos = name.size ();
165 std::string from (name, 1, pos - 1);
166 std::string to;
167 if (pos != name.size ())
168 to.append (name, pos + 1, std::string::npos);
170 int fd_from = -1, fd_to = -1;
171 if (from.empty () && to.empty ())
173 fd_from = fileno (stdin);
174 fd_to = fileno (stdout);
176 else
178 char *ptr;
179 if (!from.empty ())
181 /* Sadly str::stoul is not portable. */
182 const char *cstr = from.c_str ();
183 fd_from = strtoul (cstr, &ptr, 10);
184 if (*ptr)
186 /* Not a number -- a named pipe. */
187 int dir = to.empty ()
188 ? O_RDWR | O_CLOEXEC : O_RDONLY | O_CLOEXEC;
189 fd_from = open (cstr, dir);
191 if (to.empty ())
192 fd_to = fd_from;
195 if (!from.empty () && fd_from < 0)
197 else if (to.empty ())
199 else
201 const char *cstr = to.c_str ();
202 fd_to = strtoul (cstr, &ptr, 10);
203 if (*ptr)
205 /* Not a number, a named pipe. */
206 int dir = from.empty ()
207 ? O_RDWR | O_CLOEXEC : O_WRONLY | O_CLOEXEC;
208 fd_to = open (cstr, dir);
209 if (fd_to < 0)
210 close (fd_from);
212 if (from.empty ())
213 fd_from = fd_to;
217 if (fd_from < 0 || fd_to < 0)
218 errmsg = "opening";
219 else
220 c = new module_client (fd_from, fd_to);
222 break;
224 case '=':
225 // =localsocket
227 int fd = -1;
228 #if CODY_NETWORKING
229 fd = Cody::OpenLocal (&errmsg, name.c_str () + 1);
230 #else
231 errmsg = "disabled";
232 #endif
233 if (fd >= 0)
234 c = new module_client (fd, fd);
236 break;
238 case '|':
239 // |program and args
240 c = spawn_mapper_program (&errmsg, name, full_program_name);
241 break;
243 default:
244 // file or hostname:port
246 auto colon = name.find_last_of (':');
247 if (colon != name.npos)
249 char const *cptr = name.c_str () + colon;
250 char *endp;
251 unsigned port = strtoul (cptr + 1, &endp, 10);
253 if (port && endp != cptr + 1 && !*endp)
255 name[colon] = 0;
256 int fd = -1;
257 #if CODY_NETWORKING
258 fd = Cody::OpenInet6 (&errmsg, name.c_str (), port);
259 #else
260 errmsg = "disabled";
261 #endif
262 name[colon] = ':';
264 if (fd >= 0)
265 c = new module_client (fd, fd);
270 break;
275 if (!c)
277 // Make a default in-process client
278 bool file = !errmsg && !name.empty ();
279 auto r = new module_resolver (!file, true);
281 if (file)
283 int fd = open (name.c_str (), O_RDONLY | O_CLOEXEC);
284 if (fd < 0)
285 errmsg = "opening";
286 else
288 if (int l = r->read_tuple_file (fd, ident, false))
290 if (l > 0)
291 line = l;
292 errmsg = "reading";
295 close (fd);
298 else
299 r->set_repo ("gcm.cache");
301 auto *s = new Cody::Server (r);
302 c = new module_client (s);
305 #ifdef SIGPIPE
306 if (!c->IsDirect ())
307 /* We need to ignore sig pipe for a while. */
308 c->sigpipe = signal (SIGPIPE, SIG_IGN);
309 #endif
311 if (errmsg)
312 error_at (loc, line ? G_("failed %s mapper %qs line %u")
313 : G_("failed %s mapper %qs"), errmsg, name.c_str (), line);
315 // now wave hello!
316 c->Cork ();
317 c->Connect (std::string ("GCC"), ident);
318 c->ModuleRepo ();
319 auto packets = c->Uncork ();
321 auto &connect = packets[0];
322 if (connect.GetCode () == Cody::Client::PC_CONNECT)
323 c->flags = Cody::Flags (connect.GetInteger ());
324 else if (connect.GetCode () == Cody::Client::PC_ERROR)
325 error_at (loc, "failed mapper handshake %s", connect.GetString ().c_str ());
327 auto &repo = packets[1];
328 if (repo.GetCode () == Cody::Client::PC_PATHNAME)
329 set_repo (repo.GetString ().c_str ());
331 return c;
334 void
335 module_client::close_module_client (location_t loc, module_client *mapper)
337 if (mapper->IsDirect ())
339 auto *s = mapper->GetServer ();
340 auto *r = s->GetResolver ();
341 delete s;
342 delete r;
344 else
346 if (mapper->pex)
348 int fd_write = mapper->GetFDWrite ();
349 if (fd_write >= 0)
350 close (fd_write);
352 int status;
353 pex_get_status (mapper->pex, 1, &status);
355 pex_free (mapper->pex);
356 mapper->pex = NULL;
358 if (WIFSIGNALED (status))
359 error_at (loc, "mapper died by signal %s",
360 strsignal (WTERMSIG (status)));
361 else if (WIFEXITED (status) && WEXITSTATUS (status) != 0)
362 error_at (loc, "mapper exit status %d",
363 WEXITSTATUS (status));
365 else
367 int fd_read = mapper->GetFDRead ();
368 close (fd_read);
371 #ifdef SIGPIPE
372 // Restore sigpipe
373 if (mapper->sigpipe != SIG_IGN)
374 signal (SIGPIPE, mapper->sigpipe);
375 #endif
378 delete mapper;