Line | Branch | Exec | Source |
---|---|---|---|
1 | #include <errno.h> | ||
2 | #include <poll.h> | ||
3 | #include <stddef.h> | ||
4 | #include <stdio.h> | ||
5 | #include <string.h> | ||
6 | #include <unistd.h> | ||
7 | #include "spawn.h" | ||
8 | #include "command/error.h" | ||
9 | #include "regexp.h" | ||
10 | #include "terminal/mode.h" | ||
11 | #include "util/debug.h" | ||
12 | #include "util/fd.h" | ||
13 | #include "util/fork-exec.h" | ||
14 | #include "util/str-util.h" | ||
15 | #include "util/strtonum.h" | ||
16 | #include "util/xmalloc.h" | ||
17 | #include "util/xreadwrite.h" | ||
18 | #include "util/xstdio.h" | ||
19 | |||
20 | ✗ | static void handle_error_msg(const Compiler *c, MessageArray *msgs, char *str) | |
21 | { | ||
22 | ✗ | if (str[0] == '\0' || str[0] == '\n') { | |
23 | return; | ||
24 | } | ||
25 | |||
26 | ✗ | size_t str_len = str_replace_byte(str, '\t', ' '); | |
27 | ✗ | if (str[str_len - 1] == '\n') { | |
28 | ✗ | str[--str_len] = '\0'; | |
29 | } | ||
30 | |||
31 | ✗ | for (size_t i = 0, n = c->error_formats.count; i < n; i++) { | |
32 | ✗ | const ErrorFormat *p = c->error_formats.ptrs[i]; | |
33 | ✗ | regmatch_t m[ERRORFMT_CAPTURE_MAX]; | |
34 | ✗ | if (!regexp_exec(&p->re, str, str_len, ARRAYLEN(m), m, 0)) { | |
35 | ✗ | continue; | |
36 | } | ||
37 | ✗ | if (p->ignore) { | |
38 | ✗ | return; | |
39 | } | ||
40 | |||
41 | ✗ | int mi = (int)p->capture_index[ERRFMT_MESSAGE]; | |
42 | ✗ | if (m[mi].rm_so < 0) { | |
43 | ✗ | mi = 0; | |
44 | } | ||
45 | |||
46 | ✗ | Message *msg = new_message(str + m[mi].rm_so, m[mi].rm_eo - m[mi].rm_so); | |
47 | ✗ | msg->loc = new_file_location(NULL, 0, 0, 0); | |
48 | |||
49 | ✗ | int fi = (int)p->capture_index[ERRFMT_FILE]; | |
50 | ✗ | if (fi >= 0 && m[fi].rm_so >= 0) { | |
51 | ✗ | msg->loc->filename = xstrslice(str, m[fi].rm_so, m[fi].rm_eo); | |
52 | |||
53 | ✗ | unsigned long *const ptrs[] = { | |
54 | ✗ | [ERRFMT_LINE] = &msg->loc->line, | |
55 | ✗ | [ERRFMT_COLUMN] = &msg->loc->column, | |
56 | }; | ||
57 | |||
58 | ✗ | static_assert(ARRAYLEN(ptrs) == 3); | |
59 | ✗ | static_assert(ERRFMT_LINE == 1); | |
60 | ✗ | static_assert(ERRFMT_COLUMN == 2); | |
61 | |||
62 | ✗ | for (size_t j = ERRFMT_LINE; j < ARRAYLEN(ptrs); j++) { | |
63 | ✗ | int ci = (int)p->capture_index[j]; | |
64 | ✗ | if (ci >= 0 && m[ci].rm_so >= 0) { | |
65 | ✗ | size_t len = m[ci].rm_eo - m[ci].rm_so; | |
66 | ✗ | unsigned long val; | |
67 | ✗ | if (len == buf_parse_ulong(str + m[ci].rm_so, len, &val)) { | |
68 | ✗ | *ptrs[j] = val; | |
69 | } | ||
70 | } | ||
71 | } | ||
72 | } | ||
73 | |||
74 | ✗ | add_message(msgs, msg); | |
75 | ✗ | return; | |
76 | } | ||
77 | |||
78 | ✗ | add_message(msgs, new_message(str, str_len)); | |
79 | } | ||
80 | |||
81 | ✗ | static void read_errors(const Compiler *c, MessageArray *msgs, int fd, bool quiet) | |
82 | { | ||
83 | ✗ | FILE *f = fdopen(fd, "r"); | |
84 | ✗ | if (unlikely(!f)) { | |
85 | ✗ | return; | |
86 | } | ||
87 | char line[4096]; | ||
88 | ✗ | while (xfgets(line, sizeof(line), f)) { | |
89 | ✗ | if (!quiet) { | |
90 | ✗ | xfputs(line, stderr); | |
91 | } | ||
92 | ✗ | handle_error_msg(c, msgs, line); | |
93 | } | ||
94 | ✗ | fclose(f); | |
95 | } | ||
96 | |||
97 | 11 | static void handle_piped_data(int f[3], SpawnContext *ctx) | |
98 | { | ||
99 | 11 | BUG_ON(f[0] < 0 && f[1] < 0 && f[2] < 0); | |
100 | 11 | BUG_ON(f[0] >= 0 && f[0] <= 2); | |
101 | 11 | BUG_ON(f[1] >= 0 && f[1] <= 2); | |
102 | 11 | BUG_ON(f[2] >= 0 && f[2] <= 2); | |
103 | |||
104 |
2/2✓ Branch 0 (12→13) taken 5 times.
✓ Branch 1 (12→16) taken 6 times.
|
11 | if (ctx->input.length == 0) { |
105 | 5 | xclose(f[0]); | |
106 | 5 | f[0] = -1; | |
107 |
4/4✓ Branch 0 (14→15) taken 2 times.
✓ Branch 1 (14→16) taken 3 times.
✓ Branch 2 (15→16) taken 1 times.
✓ Branch 3 (15→63) taken 1 times.
|
5 | if (f[1] < 0 && f[2] < 0) { |
108 | return; | ||
109 | } | ||
110 | } | ||
111 | |||
112 | 10 | struct pollfd fds[] = { | |
113 | 10 | {.fd = f[0], .events = POLLOUT}, | |
114 | {.fd = f[1], .events = POLLIN}, | ||
115 | {.fd = f[2], .events = POLLIN}, | ||
116 | }; | ||
117 | |||
118 | 10 | size_t wlen = 0; | |
119 | 26 | while (1) { | |
120 |
1/2✗ Branch 0 (19→20) not taken.
✓ Branch 1 (19→38) taken 26 times.
|
26 | if (unlikely(poll(fds, ARRAYLEN(fds), -1) < 0)) { |
121 | ✗ | if (errno == EINTR) { | |
122 | ✗ | continue; | |
123 | } | ||
124 | ✗ | error_msg_errno(ctx->ebuf, "poll"); | |
125 | ✗ | return; | |
126 | } | ||
127 | |||
128 |
2/2✓ Branch 0 (38→24) taken 52 times.
✓ Branch 1 (38→39) taken 26 times.
|
78 | for (size_t i = 0; i < ARRAYLEN(ctx->outputs); i++) { |
129 | 52 | struct pollfd *pfd = fds + i + 1; | |
130 |
2/2✓ Branch 0 (24→25) taken 11 times.
✓ Branch 1 (24→37) taken 41 times.
|
52 | if (pfd->revents & POLLIN) { |
131 | 11 | String *output = &ctx->outputs[i]; | |
132 | 11 | char *buf = string_reserve_space(output, 4096); | |
133 | 11 | ssize_t rc = xread(pfd->fd, buf, output->alloc - output->len); | |
134 |
1/2✗ Branch 0 (27→28) not taken.
✓ Branch 1 (27→30) taken 11 times.
|
11 | if (unlikely(rc < 0)) { |
135 | ✗ | error_msg_errno(ctx->ebuf, "read"); | |
136 | ✗ | return; | |
137 | } | ||
138 |
1/2✗ Branch 0 (30→31) not taken.
✓ Branch 1 (30→36) taken 11 times.
|
11 | if (rc == 0) { // EOF |
139 | ✗ | if (xclose(pfd->fd)) { | |
140 | ✗ | error_msg_errno(ctx->ebuf, "close"); | |
141 | ✗ | return; | |
142 | } | ||
143 | ✗ | pfd->fd = -1; | |
144 | ✗ | continue; | |
145 | } | ||
146 | 11 | output->len += rc; | |
147 | } | ||
148 | } | ||
149 | |||
150 |
2/2✓ Branch 0 (39→40) taken 4 times.
✓ Branch 1 (39→50) taken 22 times.
|
26 | if (fds[0].revents & POLLOUT) { |
151 | 4 | ssize_t rc = xwrite(fds[0].fd, ctx->input.data + wlen, ctx->input.length - wlen); | |
152 |
1/2✗ Branch 0 (41→42) not taken.
✓ Branch 1 (41→44) taken 4 times.
|
4 | if (unlikely(rc < 0)) { |
153 | ✗ | error_msg_errno(ctx->ebuf, "write"); | |
154 | ✗ | return; | |
155 | } | ||
156 | 4 | wlen += (size_t) rc; | |
157 |
1/2✓ Branch 0 (44→45) taken 4 times.
✗ Branch 1 (44→50) not taken.
|
4 | if (wlen == ctx->input.length) { |
158 |
1/2✗ Branch 0 (46→47) not taken.
✓ Branch 1 (46→49) taken 4 times.
|
4 | if (xclose(fds[0].fd)) { |
159 | ✗ | error_msg_errno(ctx->ebuf, "close"); | |
160 | ✗ | return; | |
161 | } | ||
162 | 4 | fds[0].fd = -1; | |
163 | } | ||
164 | } | ||
165 | |||
166 | 26 | size_t active_fds = ARRAYLEN(fds); | |
167 |
2/2✓ Branch 0 (61→51) taken 78 times.
✓ Branch 1 (61→62) taken 26 times.
|
104 | for (size_t i = 0; i < ARRAYLEN(fds); i++) { |
168 | 78 | int rev = fds[i].revents; | |
169 |
3/4✓ Branch 0 (51→52) taken 41 times.
✓ Branch 1 (51→53) taken 37 times.
✗ Branch 2 (52→53) not taken.
✓ Branch 3 (52→54) taken 41 times.
|
78 | if (fds[i].fd < 0 || rev & POLLNVAL) { |
170 | 37 | fds[i].fd = -1; | |
171 | 37 | active_fds--; | |
172 | 37 | continue; | |
173 | } | ||
174 |
3/4✓ Branch 0 (54→55) taken 41 times.
✗ Branch 1 (54→56) not taken.
✓ Branch 2 (55→56) taken 16 times.
✓ Branch 3 (55→60) taken 25 times.
|
41 | if (rev & POLLERR || (rev & (POLLHUP | POLLIN)) == POLLHUP) { |
175 |
1/2✗ Branch 0 (57→58) not taken.
✓ Branch 1 (57→59) taken 16 times.
|
16 | if (xclose(fds[i].fd)) { |
176 | ✗ | error_msg_errno(ctx->ebuf, "close"); | |
177 | } | ||
178 | 16 | fds[i].fd = -1; | |
179 | 16 | active_fds--; | |
180 | } | ||
181 | } | ||
182 |
2/2✓ Branch 0 (62→17) taken 16 times.
✓ Branch 1 (62→63) taken 10 times.
|
26 | if (active_fds == 0) { |
183 | return; | ||
184 | } | ||
185 | } | ||
186 | } | ||
187 | |||
188 | 36 | static int open_dev_null(ErrorBuffer *ebuf, int flags) | |
189 | { | ||
190 | 36 | int fd = xopen("/dev/null", flags | O_CLOEXEC, 0); | |
191 |
1/2✗ Branch 0 (3→4) not taken.
✓ Branch 1 (3→5) taken 36 times.
|
36 | if (unlikely(fd < 0)) { |
192 | ✗ | error_msg_errno(ebuf, "Error opening /dev/null"); | |
193 | } | ||
194 | 36 | return fd; | |
195 | } | ||
196 | |||
197 | ✗ | static int handle_child_error(ErrorBuffer *ebuf, pid_t pid) | |
198 | { | ||
199 | ✗ | int ret = wait_child(pid); | |
200 | ✗ | if (ret < 0) { | |
201 | ✗ | error_msg_errno(ebuf, "waitpid"); | |
202 | ✗ | } else if (ret >= 256) { | |
203 | ✗ | int sig = ret >> 8; | |
204 | ✗ | const char *str = strsignal(sig); | |
205 | ✗ | error_msg(ebuf, "Child received signal %d (%s)", sig, str ? str : "??"); | |
206 | ✗ | } else if (ret) { | |
207 | ✗ | error_msg(ebuf, "Child returned %d", ret); | |
208 | } | ||
209 | ✗ | return ret; | |
210 | } | ||
211 | |||
212 | 1 | static void exec_error(SpawnContext *ctx) | |
213 | { | ||
214 | 1 | error_msg(ctx->ebuf, "Unable to exec '%s': %s", ctx->argv[0], strerror(errno)); | |
215 | 1 | } | |
216 | |||
217 | ✗ | bool spawn_compiler(SpawnContext *ctx, const Compiler *c, MessageArray *msgs, bool read_stdout) | |
218 | { | ||
219 | ✗ | BUG_ON(!ctx->argv); | |
220 | ✗ | BUG_ON(!ctx->argv[0]); | |
221 | ✗ | BUG_ON(!ctx->ebuf); | |
222 | |||
223 | ✗ | int fd[3]; | |
224 | ✗ | fd[0] = open_dev_null(ctx->ebuf, O_RDONLY); | |
225 | ✗ | if (fd[0] < 0) { | |
226 | return false; | ||
227 | } | ||
228 | |||
229 | ✗ | int dev_null = open_dev_null(ctx->ebuf, O_WRONLY); | |
230 | ✗ | if (dev_null < 0) { | |
231 | ✗ | xclose(fd[0]); | |
232 | ✗ | return false; | |
233 | } | ||
234 | |||
235 | ✗ | int p[2]; | |
236 | ✗ | if (xpipe2(p, O_CLOEXEC) != 0) { | |
237 | ✗ | error_msg_errno(ctx->ebuf, "pipe"); | |
238 | ✗ | xclose(dev_null); | |
239 | ✗ | xclose(fd[0]); | |
240 | ✗ | return false; | |
241 | } | ||
242 | |||
243 | ✗ | bool quiet = ctx->quiet; | |
244 | ✗ | if (read_stdout) { | |
245 | ✗ | fd[1] = p[1]; | |
246 | ✗ | fd[2] = quiet ? dev_null : 2; | |
247 | } else { | ||
248 | ✗ | fd[1] = quiet ? dev_null : 1; | |
249 | ✗ | fd[2] = p[1]; | |
250 | } | ||
251 | |||
252 | ✗ | pid_t pid = fork_exec(ctx->argv, NULL, fd, quiet); | |
253 | ✗ | if (pid == -1) { | |
254 | ✗ | exec_error(ctx); | |
255 | ✗ | xclose(p[1]); | |
256 | } else { | ||
257 | // Must close write end of the pipe before read_errors() or | ||
258 | // the read end never gets EOF! | ||
259 | ✗ | xclose(p[1]); | |
260 | ✗ | read_errors(c, msgs, p[0], quiet); | |
261 | ✗ | handle_child_error(ctx->ebuf, pid); | |
262 | } | ||
263 | |||
264 | ✗ | xclose(p[0]); | |
265 | ✗ | xclose(dev_null); | |
266 | ✗ | xclose(fd[0]); | |
267 | ✗ | return (pid != -1); | |
268 | } | ||
269 | |||
270 | // Close fd only if valid (positive) and not stdin/stdout/stderr | ||
271 | 204 | static int safe_xclose(int fd) | |
272 | { | ||
273 |
2/2✓ Branch 0 (2→3) taken 77 times.
✓ Branch 1 (2→4) taken 127 times.
|
204 | return (fd > STDERR_FILENO) ? xclose(fd) : 0; |
274 | } | ||
275 | |||
276 | 74 | static void safe_xclose_all(int fds[], size_t nr_fds) | |
277 | { | ||
278 |
2/2✓ Branch 0 (5→3) taken 204 times.
✓ Branch 1 (5→6) taken 74 times.
|
278 | for (size_t i = 0; i < nr_fds; i++) { |
279 | 204 | safe_xclose(fds[i]); | |
280 | 204 | fds[i] = -1; | |
281 | } | ||
282 | 74 | } | |
283 | |||
284 | 18 | UNITTEST { | |
285 | 18 | int fds[] = {-2, -3, -4}; | |
286 | 18 | safe_xclose_all(fds, 2); | |
287 | 18 | BUG_ON(fds[0] != -1); | |
288 | 18 | BUG_ON(fds[1] != -1); | |
289 | 18 | BUG_ON(fds[2] != -4); | |
290 | 18 | safe_xclose_all(fds, 3); | |
291 | 18 | BUG_ON(fds[2] != -1); | |
292 | 18 | } | |
293 | |||
294 | 19 | int spawn(SpawnContext *ctx) | |
295 | { | ||
296 | 19 | BUG_ON(!ctx->argv); | |
297 | 19 | BUG_ON(!ctx->argv[0]); | |
298 | 19 | BUG_ON(!ctx->ebuf); | |
299 | |||
300 | 19 | int child_fds[3] = {-1, -1, -1}; | |
301 | 19 | int parent_fds[3] = {-1, -1, -1}; | |
302 | 19 | bool quiet = ctx->quiet; | |
303 | 19 | size_t nr_pipes = 0; | |
304 | |||
305 |
2/2✓ Branch 0 (35→9) taken 57 times.
✓ Branch 1 (35→36) taken 19 times.
|
76 | for (size_t i = 0; i < ARRAYLEN(child_fds); i++) { |
306 |
3/4✓ Branch 0 (9→10) taken 30 times.
✓ Branch 1 (9→12) taken 6 times.
✓ Branch 2 (9→15) taken 21 times.
✗ Branch 3 (9→33) not taken.
|
57 | switch (ctx->actions[i]) { |
307 | 30 | case SPAWN_TTY: | |
308 |
1/2✗ Branch 0 (10→11) not taken.
✓ Branch 1 (10→12) taken 30 times.
|
30 | if (!quiet) { |
309 | ✗ | child_fds[i] = i; | |
310 | ✗ | break; | |
311 | } | ||
312 | // Fallthrough | ||
313 | case SPAWN_NULL: | ||
314 | 36 | child_fds[i] = open_dev_null(ctx->ebuf, O_RDWR); | |
315 |
1/2✗ Branch 0 (13→14) not taken.
✓ Branch 1 (13→34) taken 36 times.
|
36 | if (child_fds[i] < 0) { |
316 | ✗ | goto error; | |
317 | } | ||
318 | break; | ||
319 | 21 | case SPAWN_PIPE: { | |
320 | 21 | int p[2]; | |
321 |
1/2✗ Branch 0 (16→17) not taken.
✓ Branch 1 (16→19) taken 21 times.
|
21 | if (xpipe2(p, O_CLOEXEC) != 0) { |
322 | ✗ | error_msg_errno(ctx->ebuf, "pipe"); | |
323 | ✗ | goto error; | |
324 | } | ||
325 | 21 | BUG_ON(p[0] <= STDERR_FILENO); | |
326 | 21 | BUG_ON(p[1] <= STDERR_FILENO); | |
327 |
2/2✓ Branch 0 (23→24) taken 5 times.
✓ Branch 1 (23→25) taken 16 times.
|
21 | child_fds[i] = i ? p[1] : p[0]; |
328 |
2/2✓ Branch 0 (25→26) taken 5 times.
✓ Branch 1 (25→27) taken 16 times.
|
21 | parent_fds[i] = i ? p[0] : p[1]; |
329 |
1/2✗ Branch 0 (28→29) not taken.
✓ Branch 1 (28→31) taken 21 times.
|
21 | if (!fd_set_nonblock(parent_fds[i], true)) { |
330 | ✗ | error_msg_errno(ctx->ebuf, "fcntl"); | |
331 | ✗ | goto error; | |
332 | } | ||
333 | 21 | nr_pipes++; | |
334 | 21 | break; | |
335 | } | ||
336 | ✗ | default: | |
337 | − | BUG("unhandled action type"); | |
338 | goto error; | ||
339 | } | ||
340 | } | ||
341 | |||
342 | 19 | pid_t pid = fork_exec(ctx->argv, ctx->env, child_fds, quiet); | |
343 |
2/2✓ Branch 0 (37→38) taken 1 times.
✓ Branch 1 (37→40) taken 18 times.
|
19 | if (pid == -1) { |
344 | 1 | exec_error(ctx); | |
345 | 1 | goto error; | |
346 | } | ||
347 | |||
348 | 18 | safe_xclose_all(child_fds, ARRAYLEN(child_fds)); | |
349 |
2/2✓ Branch 0 (41→42) taken 11 times.
✓ Branch 1 (41→43) taken 7 times.
|
18 | if (nr_pipes > 0) { |
350 | 11 | handle_piped_data(parent_fds, ctx); | |
351 | } | ||
352 | |||
353 | 18 | safe_xclose_all(parent_fds, ARRAYLEN(parent_fds)); | |
354 | 18 | int err = wait_child(pid); | |
355 |
1/2✗ Branch 0 (45→46) not taken.
✓ Branch 1 (45→50) taken 18 times.
|
18 | if (err < 0) { |
356 | ✗ | error_msg_errno(ctx->ebuf, "waitpid"); | |
357 | } | ||
358 | |||
359 | return err; | ||
360 | |||
361 | 1 | error: | |
362 | 1 | safe_xclose_all(child_fds, ARRAYLEN(child_fds)); | |
363 | 1 | safe_xclose_all(parent_fds, ARRAYLEN(parent_fds)); | |
364 | 1 | return -1; | |
365 | } | ||
366 |