1 /* Output to stdout / stderr for GNU make
2 Copyright (C) 2013-2022 Free Software Foundation, Inc.
3 This file is part of GNU Make.
4
5 GNU Make is free software; you can redistribute it and/or modify it under the
6 terms of the GNU General Public License as published by the Free Software
7 Foundation; either version 3 of the License, or (at your option) any later
8 version.
9
10 GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY
11 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
12 A PARTICULAR PURPOSE. See the GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License along with
15 this program. If not, see <https://www.gnu.org/licenses/>. */
16
17 #include "makeint.h"
18 #include "os.h"
19 #include "output.h"
20
21 /* GNU make no longer supports pre-ANSI89 environments. */
22
23 #include <assert.h>
24 #include <stdio.h>
25 #include <stdarg.h>
26
27 #ifdef HAVE_UNISTD_H
28 # include <unistd.h>
29 #endif
30
31 #ifdef HAVE_FCNTL_H
32 # include <fcntl.h>
33 #else
34 # include <sys/file.h>
35 #endif
36
37 #ifdef WINDOWS32
38 # include <windows.h>
39 # include <io.h>
40 # include "sub_proc.h"
41 #endif /* WINDOWS32 */
42
43 struct output *output_context = NULL;
44 unsigned int stdio_traced = 0;
45
46 #define OUTPUT_NONE (-1)
47
48 #define OUTPUT_ISSET(_out) ((_out)->out >= 0 || (_out)->err >= 0)
49
50 /* Write a string to the current STDOUT or STDERR. */
51 static void
52 _outputs (struct output *out, int is_err, const char *msg)
53 {
54 FILE *f;
55
56 if (out && out->syncout)
57 {
58 int fd = is_err ? out->err : out->out;
59 if (fd != OUTPUT_NONE)
60 {
61 size_t len = strlen (msg);
62 int r;
63 EINTRLOOP (r, lseek (fd, 0, SEEK_END));
64 writebuf (fd, msg, len);
65 return;
66 }
67 }
68
69 f = is_err ? stderr : stdout;
70 fputs (msg, f);
71 fflush (f);
72 }
73
74 /* Write a message indicating that we've just entered or
75 left (according to ENTERING) the current directory. */
76
77 static int
78 log_working_directory (int entering)
79 {
80 static char *buf = NULL;
81 static size_t len = 0;
82 size_t need;
83 const char *fmt;
84 char *p;
85
86 /* Get enough space for the longest possible output. */
87 need = strlen (program) + INTSTR_LENGTH + 2 + 1;
88 if (starting_directory)
89 need += strlen (starting_directory);
90
91 /* Use entire sentences to give the translators a fighting chance. */
92 if (makelevel == 0)
93 if (starting_directory == 0)
94 if (entering)
95 fmt = _("%s: Entering an unknown directory\n");
96 else
97 fmt = _("%s: Leaving an unknown directory\n");
98 else
99 if (entering)
100 fmt = _("%s: Entering directory '%s'\n");
101 else
102 fmt = _("%s: Leaving directory '%s'\n");
103 else
104 if (starting_directory == 0)
105 if (entering)
106 fmt = _("%s[%u]: Entering an unknown directory\n");
107 else
108 fmt = _("%s[%u]: Leaving an unknown directory\n");
109 else
110 if (entering)
111 fmt = _("%s[%u]: Entering directory '%s'\n");
112 else
113 fmt = _("%s[%u]: Leaving directory '%s'\n");
114
115 need += strlen (fmt);
116
117 if (need > len)
118 {
119 buf = xrealloc (buf, need);
120 len = need;
121 }
122
123 p = buf;
124 if (print_data_base_flag)
125 {
126 *(p++) = '#';
127 *(p++) = ' ';
128 }
129
130 if (makelevel == 0)
131 if (starting_directory == 0)
132 sprintf (p, fmt , program);
133 else
134 sprintf (p, fmt, program, starting_directory);
135 else if (starting_directory == 0)
136 sprintf (p, fmt, program, makelevel);
137 else
138 sprintf (p, fmt, program, makelevel, starting_directory);
139
140 _outputs (NULL, 0, buf);
141
142 return 1;
143 }
144
145
146 #ifndef NO_OUTPUT_SYNC
147
148 /* Support routine for output_sync() */
149 static void
150 pump_from_tmp (int from, FILE *to)
151 {
152 static char buffer[8192];
153
154 #ifdef WINDOWS32
155 int prev_mode;
156
157 /* "from" is opened by open_tmpfd, which does it in binary mode, so
158 we need the mode of "to" to match that. */
159 prev_mode = _setmode (fileno (to), _O_BINARY);
160 #endif
161
162 if (lseek (from, 0, SEEK_SET) == -1)
163 perror ("lseek()");
164
165 while (1)
166 {
167 int len;
168 EINTRLOOP (len, read (from, buffer, sizeof (buffer)));
169 if (len < 0)
170 perror ("read()");
171 if (len <= 0)
172 break;
173 if (fwrite (buffer, len, 1, to) < 1)
174 {
175 perror ("fwrite()");
176 break;
177 }
178 fflush (to);
179 }
180
181 #ifdef WINDOWS32
182 /* Switch "to" back to its original mode, so that log messages by
183 Make have the same EOL format as without --output-sync. */
184 _setmode (fileno (to), prev_mode);
185 #endif
186 }
187
188 /* Returns a file descriptor to a temporary file, that will be automatically
189 deleted on exit. */
190 int
191 output_tmpfd (void)
192 {
193 int fd = get_tmpfd (NULL);
194 fd_set_append (fd);
195 return fd;
196 }
197
198 /* Adds file descriptors to the child structure to support output_sync; one
199 for stdout and one for stderr as long as they are open. If stdout and
200 stderr share a device they can share a temp file too.
201 Will reset output_sync on error. */
202 static void
203 setup_tmpfile (struct output *out)
204 {
205 static unsigned int in_setup = 0;
206 unsigned int io_state;
207
208 /* If something fails during setup we might recurse back into this function
209 while writing errors. Make sure we don't do so infinitely. */
210 if (in_setup)
211 return;
212 in_setup = 1;
213
214 io_state = check_io_state ();
215
216 if (NONE_SET (io_state, IO_STDOUT_OK|IO_STDERR_OK))
217 {
218 /* This is probably useless since stdout/stderr aren't working. */
219 perror_with_name ("output-sync suppressed: ", "stderr");
220 goto error;
221 }
222
223 if (ANY_SET (io_state, IO_STDOUT_OK))
224 {
225 int fd = output_tmpfd ();
226 if (fd < 0)
227 goto error;
228 fd_noinherit (fd);
229 out->out = fd;
230 }
231
232 if (ANY_SET (io_state, IO_STDERR_OK))
233 {
234 if (out->out != OUTPUT_NONE && ANY_SET (io_state, IO_COMBINED_OUTERR))
235 out->err = out->out;
236 else
237 {
238 int fd = output_tmpfd ();
239 if (fd < 0)
240 goto error;
241 fd_noinherit (fd);
242 out->err = fd;
243 }
244 }
245
246 in_setup = 0;
247 return;
248
249 /* If we failed to create a temp file, disable output sync going forward. */
250 error:
251 output_close (out);
252 output_sync = OUTPUT_SYNC_NONE;
253 osync_clear ();
254 in_setup = 0;
255 }
256
257 /* Synchronize the output of jobs in -j mode to keep the results of
258 each job together. This is done by holding the results in temp files,
259 one for stdout and potentially another for stderr, and only releasing
260 them to "real" stdout/stderr when a semaphore can be obtained. */
261
262 void
263 output_dump (struct output *out)
264 {
265 #define FD_NOT_EMPTY(_f) ((_f) != OUTPUT_NONE && lseek ((_f), 0, SEEK_END) > 0)
266
267 int outfd_not_empty = FD_NOT_EMPTY (out->out);
268 int errfd_not_empty = FD_NOT_EMPTY (out->err);
269
270 if (outfd_not_empty || errfd_not_empty)
271 {
272 int traced = 0;
273
274 /* Try to acquire the semaphore. If it fails, dump the output
275 unsynchronized; still better than silently discarding it.
276 We want to keep this lock for as little time as possible. */
277 if (!osync_acquire ())
278 {
279 O (error, NILF,
280 _("warning: Cannot acquire output lock, disabling output sync."));
281 osync_clear ();
282 }
283
284 /* Log the working directory for this dump. */
285 if (print_directory && output_sync != OUTPUT_SYNC_RECURSE)
286 traced = log_working_directory (1);
287
288 if (outfd_not_empty)
289 pump_from_tmp (out->out, stdout);
290 if (errfd_not_empty && out->err != out->out)
291 pump_from_tmp (out->err, stderr);
292
293 if (traced)
294 log_working_directory (0);
295
296 /* Exit the critical section. */
297 osync_release ();
298
299 /* Truncate and reset the output, in case we use it again. */
300 if (out->out != OUTPUT_NONE)
301 {
302 int e;
303 lseek (out->out, 0, SEEK_SET);
304 EINTRLOOP (e, ftruncate (out->out, 0));
305 }
306 if (out->err != OUTPUT_NONE && out->err != out->out)
307 {
308 int e;
309 lseek (out->err, 0, SEEK_SET);
310 EINTRLOOP (e, ftruncate (out->err, 0));
311 }
312 }
313 }
314 #endif /* NO_OUTPUT_SYNC */
315
316
317 void
318 output_init (struct output *out)
319 {
320 if (out)
321 {
322 out->out = out->err = OUTPUT_NONE;
323 out->syncout = !!output_sync;
324 return;
325 }
326
327 /* Force stdout/stderr into append mode (if they are files) to ensure
328 parallel jobs won't lose output due to overlapping writes. */
329 fd_set_append (fileno (stdout));
330 fd_set_append (fileno (stderr));
331 }
332
333 void
334 output_close (struct output *out)
335 {
336 if (! out)
337 {
338 if (stdio_traced)
339 log_working_directory (0);
340 return;
341 }
342
343 #ifndef NO_OUTPUT_SYNC
344 output_dump (out);
345 #endif
346
347 if (out->out >= 0)
348 close (out->out);
349 if (out->err >= 0 && out->err != out->out)
350 close (out->err);
351
352 output_init (out);
353 }
354
355 /* We're about to generate output: be sure it's set up. */
356 void
357 output_start (void)
358 {
359 #ifndef NO_OUTPUT_SYNC
360 /* If we're syncing output make sure the temporary file is set up. */
361 if (output_context && output_context->syncout)
362 if (! OUTPUT_ISSET(output_context))
363 setup_tmpfile (output_context);
364 #endif
365
366 /* If we're not syncing this output per-line or per-target, make sure we emit
367 the "Entering..." message where appropriate. */
368 if (output_sync == OUTPUT_SYNC_NONE || output_sync == OUTPUT_SYNC_RECURSE)
369 if (! stdio_traced && print_directory)
370 stdio_traced = log_working_directory (1);
371 }
372
373 void
374 outputs (int is_err, const char *msg)
375 {
376 if (! msg || *msg == '\0')
377 return;
378
379 output_start ();
380
381 _outputs (output_context, is_err, msg);
382 }
383
384
385 static struct fmtstring
386 {
387 char *buffer;
388 size_t size;
389 } fmtbuf = { NULL, 0 };
390
391 static char *
392 get_buffer (size_t need)
393 {
394 /* Make sure we have room. NEED includes space for \0. */
395 if (need > fmtbuf.size)
396 {
397 fmtbuf.size += need * 2;
398 fmtbuf.buffer = xrealloc (fmtbuf.buffer, fmtbuf.size);
399 }
400
401 fmtbuf.buffer[need-1] = '\0';
402
403 return fmtbuf.buffer;
404 }
405
406 /* Print a message on stdout. */
407
408 void
409 message (int prefix, size_t len, const char *fmt, ...)
410 {
411 va_list args;
412 char *start;
413 char *p;
414
415 len += strlen (fmt) + strlen (program) + INTSTR_LENGTH + 4 + 1 + 1;
416 start = p = get_buffer (len);
417
418 if (prefix)
419 {
420 if (makelevel == 0)
421 sprintf (p, "%s: ", program);
422 else
423 sprintf (p, "%s[%u]: ", program, makelevel);
424 p += strlen (p);
425 }
426
427 va_start (args, fmt);
428 vsprintf (p, fmt, args);
429 va_end (args);
430
431 strcat (p, "\n");
432
433 assert (start[len-1] == '\0');
434 outputs (0, start);
435 }
436
437 /* Print an error message. */
438
439 void
440 error (const floc *flocp, size_t len, const char *fmt, ...)
441 {
442 va_list args;
443 char *start;
444 char *p;
445
446 len += (strlen (fmt) + strlen (program)
447 + (flocp && flocp->filenm ? strlen (flocp->filenm) : 0)
448 + INTSTR_LENGTH + 4 + 1 + 1);
449 start = p = get_buffer (len);
450
451 if (flocp && flocp->filenm)
452 sprintf (p, "%s:%lu: ", flocp->filenm, flocp->lineno + flocp->offset);
453 else if (makelevel == 0)
454 sprintf (p, "%s: ", program);
455 else
456 sprintf (p, "%s[%u]: ", program, makelevel);
457 p += strlen (p);
458
459 va_start (args, fmt);
460 vsprintf (p, fmt, args);
461 va_end (args);
462
463 strcat (p, "\n");
464
465 assert (start[len-1] == '\0');
466 outputs (1, start);
467 }
468
469 /* Print an error message and exit. */
470
471 void
472 fatal (const floc *flocp, size_t len, const char *fmt, ...)
473 {
474 va_list args;
475 const char *stop = _(". Stop.\n");
476 char *start;
477 char *p;
478
479 len += (strlen (fmt) + strlen (program)
480 + (flocp && flocp->filenm ? strlen (flocp->filenm) : 0)
481 + INTSTR_LENGTH + 8 + strlen (stop) + 1);
482 start = p = get_buffer (len);
483
484 if (flocp && flocp->filenm)
485 sprintf (p, "%s:%lu: *** ", flocp->filenm, flocp->lineno + flocp->offset);
486 else if (makelevel == 0)
487 sprintf (p, "%s: *** ", program);
488 else
489 sprintf (p, "%s[%u]: *** ", program, makelevel);
490 p += strlen (p);
491
492 va_start (args, fmt);
493 vsprintf (p, fmt, args);
494 va_end (args);
495
496 strcat (p, stop);
497
498 assert (start[len-1] == '\0');
499 outputs (1, start);
500
501 die (MAKE_FAILURE);
502 }
503
504 /* Print an error message from errno. */
505
506 void
507 perror_with_name (const char *str, const char *name)
508 {
509 const char *err = strerror (errno);
510 OSSS (error, NILF, _("%s%s: %s"), str, name, err);
511 }
512
513 /* Print an error message from errno and exit. */
514
515 void
516 pfatal_with_name (const char *name)
517 {
518 const char *err = strerror (errno);
519 OSS (fatal, NILF, _("%s: %s"), name, err);
520
521 /* NOTREACHED */
522 }
523
524 /* Print a message about out of memory (not using more heap) and exit.
525 Our goal here is to be sure we don't try to allocate more memory, which
526 means we don't want to use string translations or normal cleanup. */
527
528 void
529 out_of_memory ()
530 {
531 writebuf (FD_STDOUT, program, strlen (program));
532 writebuf (FD_STDOUT, STRING_SIZE_TUPLE (": *** virtual memory exhausted\n"));
533 exit (MAKE_FAILURE);
534 }