1 /*        $NetBSD: job.c,v 1.500 2025/05/03 08:18:33 rillig Exp $     */
2 
3 /*
4  * Copyright (c) 1988, 1989, 1990 The Regents of the University of California.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to Berkeley by
8  * Adam de Boor.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  * 3. Neither the name of the University nor the names of its contributors
19  *    may be used to endorse or promote products derived from this software
20  *    without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32  * SUCH DAMAGE.
33  */
34 
35 /*
36  * Copyright (c) 1988, 1989 by Adam de Boor
37  * Copyright (c) 1989 by Berkeley Softworks
38  * All rights reserved.
39  *
40  * This code is derived from software contributed to Berkeley by
41  * Adam de Boor.
42  *
43  * Redistribution and use in source and binary forms, with or without
44  * modification, are permitted provided that the following conditions
45  * are met:
46  * 1. Redistributions of source code must retain the above copyright
47  *    notice, this list of conditions and the following disclaimer.
48  * 2. Redistributions in binary form must reproduce the above copyright
49  *    notice, this list of conditions and the following disclaimer in the
50  *    documentation and/or other materials provided with the distribution.
51  * 3. All advertising materials mentioning features or use of this software
52  *    must display the following acknowledgement:
53  *        This product includes software developed by the University of
54  *        California, Berkeley and its contributors.
55  * 4. Neither the name of the University nor the names of its contributors
56  *    may be used to endorse or promote products derived from this software
57  *    without specific prior written permission.
58  *
59  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
60  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
61  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
62  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
63  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
64  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
65  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
66  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
67  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
68  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
69  * SUCH DAMAGE.
70  */
71 
72 /*
73  * Create child processes and collect their output.
74  *
75  * Interface:
76  *        Job_Init  Called to initialize this module. In addition,
77  *                            the .BEGIN target is made, including all of its
78  *                            dependencies before this function returns.
79  *                            Hence, the makefiles must have been parsed
80  *                            before this function is called.
81  *
82  *        Job_End             Clean up any memory used.
83  *
84  *        Job_Make  Start the creation of the given target.
85  *
86  *        Job_CatchChildren
87  *                            Check for and handle the termination of any children.
88  *
89  *        Job_CatchOutput
90  *                            Print any output the child processes have produced.
91  *
92  *        Job_ParseShell      Given a special dependency line with target '.SHELL',
93  *                            define the shell that is used for the creation
94  *                            commands in jobs mode.
95  *
96  *        Job_Finish          Make the .END target. Should only be called when the
97  *                            job table is empty.
98  *
99  *        Job_AbortAll        Abort all currently running jobs. Do not handle
100  *                            output or do anything for the jobs, just kill them.
101  *                            Should only be called in an emergency.
102  *
103  *        Job_CheckCommands
104  *                            Verify that the commands for a target are
105  *                            ok. Provide them if necessary and possible.
106  *
107  *        Job_Touch Update a target without really updating it.
108  *
109  *        Job_Wait  Wait for all currently-running jobs to finish.
110  */
111 
112 #include <sys/types.h>
113 #include <sys/stat.h>
114 #include <sys/time.h>
115 #include <sys/wait.h>
116 
117 #include <errno.h>
118 #ifndef USE_SELECT
119 #include <poll.h>
120 #endif
121 #include <signal.h>
122 #include <utime.h>
123 
124 #include "make.h"
125 #include "dir.h"
126 #include "job.h"
127 #ifdef USE_META
128 # include "meta.h"
129 #endif
130 #include "pathnames.h"
131 #include "trace.h"
132 
133 /*        "@(#)job.c          8.2 (Berkeley) 3/19/94"       */
134 MAKE_RCSID("$NetBSD: job.c,v 1.500 2025/05/03 08:18:33 rillig Exp $");
135 
136 
137 #ifdef USE_SELECT
138 /*
139  * Emulate poll() in terms of select().  This is not a complete
140  * emulation but it is sufficient for make's purposes.
141  */
142 
143 #define poll emul_poll
144 #define pollfd emul_pollfd
145 
146 struct emul_pollfd {
147           int fd;
148           short events;
149           short revents;
150 };
151 
152 #define POLLIN                0x0001
153 #define POLLOUT               0x0004
154 
155 int emul_poll(struct pollfd *, int, int);
156 #endif
157 
158 /*
159  * The POLL_MSEC constant determines the maximum number of milliseconds spent
160  * in poll before coming out to see if a child has finished.
161  */
162 #define POLL_MSEC   5000
163 
164 struct pollfd;
165 
166 
167 typedef enum JobStatus {
168           JOB_ST_FREE         = 0,      /* Job is available */
169           JOB_ST_SET_UP       = 1,      /* Job is allocated but otherwise invalid */
170           /* XXX: What about the 2? */
171           JOB_ST_RUNNING      = 3,      /* Job is running, pid valid */
172           JOB_ST_FINISHED     = 4       /* Job is done (ie after SIGCHLD) */
173 } JobStatus;
174 
175 /*
176  * A Job manages the shell commands that are run to create a single target.
177  * Each job is run in a separate subprocess by a shell.  Several jobs can run
178  * in parallel.
179  *
180  * The shell commands for the target are written to a temporary file,
181  * then the shell is run with the temporary file as stdin, and the output
182  * of that shell is captured via a pipe.
183  *
184  * When a job is finished, Make_Update updates all parents of the node
185  * that was just remade, marking them as ready to be made next if all
186  * other dependencies are finished as well.
187  */
188 struct Job {
189           /* The process ID of the shell running the commands */
190           int pid;
191 
192           /* The target the child is making */
193           GNode *node;
194 
195           /*
196            * If one of the shell commands is "...", all following commands are
197            * delayed until the .END node is made.  This list node points to the
198            * first of these commands, if any.
199            */
200           StringListNode *tailCmds;
201 
202           /* This is where the shell commands go. */
203           FILE *cmdFILE;
204 
205           int exit_status;    /* from wait4() in signal handler */
206 
207           JobStatus status;
208 
209           bool suspended;
210 
211           /* Ignore non-zero exits */
212           bool ignerr;
213           /* Output the command before or instead of running it. */
214           bool echo;
215           /* Target is a special one. */
216           bool special;
217 
218           int inPipe;                   /* Pipe for reading output from job */
219           int outPipe;                  /* Pipe for writing control commands */
220           struct pollfd *inPollfd; /* pollfd associated with inPipe */
221 
222 #define JOB_BUFSIZE 1024
223           /* Buffer for storing the output of the job, line by line. */
224           char outBuf[JOB_BUFSIZE + 1];
225           size_t curPos;                /* Current position in outBuf. */
226 
227 #ifdef USE_META
228           struct BuildMon bm;
229 #endif
230 };
231 
232 
233 /*
234  * A shell defines how the commands are run.  All commands for a target are
235  * written into a single file, which is then given to the shell to execute
236  * the commands from it.  The commands are written to the file using a few
237  * templates for echo control and error control.
238  *
239  * The name of the shell is the basename for the predefined shells, such as
240  * "sh", "csh", "bash".  For custom shells, it is the full pathname, and its
241  * basename is used to select the type of shell; the longest match wins.
242  * So /usr/pkg/bin/bash has type sh, /usr/local/bin/tcsh has type csh.
243  *
244  * The echoing of command lines is controlled using hasEchoCtl, echoOff,
245  * echoOn, noPrint and noPrintLen.  When echoOff is executed by the shell, it
246  * still outputs something, but this something is not interesting, therefore
247  * it is filtered out using noPrint and noPrintLen.
248  *
249  * The error checking for individual commands is controlled using hasErrCtl,
250  * errOn, errOff and runChkTmpl.
251  *
252  * In case a shell doesn't have error control, echoTmpl is a printf template
253  * for echoing the command, should echoing be on; runIgnTmpl is another
254  * printf template for executing the command while ignoring the return
255  * status. Finally runChkTmpl is a printf template for running the command and
256  * causing the shell to exit on error. If any of these strings are empty when
257  * hasErrCtl is false, the command will be executed anyway as is, and if it
258  * causes an error, so be it. Any templates set up to echo the command will
259  * escape any '$ ` \ "' characters in the command string to avoid unwanted
260  * shell code injection, the escaped command is safe to use in double quotes.
261  *
262  * The command-line flags "echo" and "exit" also control the behavior.  The
263  * "echo" flag causes the shell to start echoing commands right away.  The
264  * "exit" flag causes the shell to exit when an error is detected in one of
265  * the commands.
266  */
267 typedef struct Shell {
268 
269           /*
270            * The name of the shell. For Bourne and C shells, this is used only
271            * to find the shell description when used as the single source of a
272            * .SHELL target. For user-defined shells, this is the full path of
273            * the shell.
274            */
275           const char *name;
276 
277           bool hasEchoCtl;    /* whether both echoOff and echoOn are there */
278           const char *echoOff;          /* command to turn echoing off */
279           const char *echoOn; /* command to turn echoing back on */
280           const char *noPrint;          /* text to skip when printing output from the
281                                          * shell. This is usually the same as echoOff */
282           size_t noPrintLen;  /* length of noPrint command */
283 
284           bool hasErrCtl;               /* whether error checking can be controlled
285                                          * for individual commands */
286           const char *errOn;  /* command to turn on error checking */
287           const char *errOff; /* command to turn off error checking */
288 
289           const char *echoTmpl;         /* template to echo a command */
290           const char *runIgnTmpl;       /* template to run a command without error
291                                          * checking */
292           const char *runChkTmpl;       /* template to run a command with error
293                                          * checking */
294 
295           /*
296            * A string literal that results in a newline character when it
297            * occurs outside of any 'quote' or "quote" characters.
298            */
299           const char *newline;
300           char commentChar;   /* character used by shell for comment lines */
301 
302           const char *echoFlag;         /* shell flag to echo commands */
303           const char *errFlag;          /* shell flag to exit on error */
304 } Shell;
305 
306 typedef struct CommandFlags {
307           /* Whether to echo the command before or instead of running it. */
308           bool echo;
309 
310           /* Run the command even in -n or -N mode. */
311           bool always;
312 
313           /*
314            * true if we turned error checking off before writing the command to
315            * the commands file and need to turn it back on
316            */
317           bool ignerr;
318 } CommandFlags;
319 
320 /*
321  * Write shell commands to a file.
322  *
323  * TODO: keep track of whether commands are echoed.
324  * TODO: keep track of whether error checking is active.
325  */
326 typedef struct ShellWriter {
327           FILE *f;
328 
329           /* we've sent 'set -x' */
330           bool xtraced;
331 
332 } ShellWriter;
333 
334 /* error handling variables */
335 static int job_errors = 0;    /* number of errors reported */
336 static enum {                           /* Why is the make aborting? */
337           ABORT_NONE,
338           ABORT_ERROR,                  /* Aborted because of an error */
339           ABORT_INTERRUPT,    /* Aborted because it was interrupted */
340           ABORT_WAIT                    /* Waiting for jobs to finish */
341 } aborting = ABORT_NONE;
342 #define JOB_TOKENS "+EI+"     /* Token to requeue for each abort state */
343 
344 static const char aborting_name[][6] = { "NONE", "ERROR", "INTR", "WAIT" };
345 
346 /* Tracks the number of tokens currently "out" to build jobs. */
347 int jobTokensRunning = 0;
348 
349 /*
350  * Descriptions for various shells.
351  *
352  * The build environment may set DEFSHELL_INDEX to one of
353  * DEFSHELL_INDEX_SH, DEFSHELL_INDEX_KSH, or DEFSHELL_INDEX_CSH, to
354  * select one of the predefined shells as the default shell.
355  *
356  * Alternatively, the build environment may set DEFSHELL_CUSTOM to the
357  * name or the full path of a sh-compatible shell, which will be used as
358  * the default shell.
359  *
360  * ".SHELL" lines in Makefiles can choose the default shell from the
361  * set defined here, or add additional shells.
362  */
363 
364 #ifdef DEFSHELL_CUSTOM
365 #define DEFSHELL_INDEX_CUSTOM 0
366 #define DEFSHELL_INDEX_SH     1
367 #define DEFSHELL_INDEX_KSH    2
368 #define DEFSHELL_INDEX_CSH    3
369 #else
370 #define DEFSHELL_INDEX_SH     0
371 #define DEFSHELL_INDEX_KSH    1
372 #define DEFSHELL_INDEX_CSH    2
373 #endif
374 
375 #ifndef DEFSHELL_INDEX
376 #define DEFSHELL_INDEX 0      /* DEFSHELL_INDEX_CUSTOM or DEFSHELL_INDEX_SH */
377 #endif
378 
379 static Shell shells[] = {
380 #ifdef DEFSHELL_CUSTOM
381     /*
382      * An sh-compatible shell with a non-standard name.
383      *
384      * Keep this in sync with the "sh" description below, but avoid
385      * non-portable features that might not be supplied by all
386      * sh-compatible shells.
387      */
388     {
389           DEFSHELL_CUSTOM,    /* .name */
390           false,                        /* .hasEchoCtl */
391           "",                           /* .echoOff */
392           "",                           /* .echoOn */
393           "",                           /* .noPrint */
394           0,                            /* .noPrintLen */
395           false,                        /* .hasErrCtl */
396           "",                           /* .errOn */
397           "",                           /* .errOff */
398           "echo \"%s\"\n",    /* .echoTmpl */
399           "%s\n",                       /* .runIgnTmpl */
400           "{ %s \n} || exit $?\n", /* .runChkTmpl */
401           "'\n'",                       /* .newline */
402           '#',                          /* .commentChar */
403           "",                           /* .echoFlag */
404           "",                           /* .errFlag */
405     },
406 #endif /* DEFSHELL_CUSTOM */
407     /*
408      * SH description. Echo control is also possible and, under
409      * sun UNIX anyway, one can even control error checking.
410      */
411     {
412           "sh",                         /* .name */
413           false,                        /* .hasEchoCtl */
414           "",                           /* .echoOff */
415           "",                           /* .echoOn */
416           "",                           /* .noPrint */
417           0,                            /* .noPrintLen */
418           false,                        /* .hasErrCtl */
419           "",                           /* .errOn */
420           "",                           /* .errOff */
421           "echo \"%s\"\n",    /* .echoTmpl */
422           "%s\n",                       /* .runIgnTmpl */
423           "{ %s \n} || exit $?\n", /* .runChkTmpl */
424           "'\n'",                       /* .newline */
425           '#',                          /* .commentChar*/
426 #if defined(MAKE_NATIVE) && defined(__NetBSD__)
427           /* XXX: -q is not really echoFlag, it's more like noEchoInSysFlag. */
428           "q",                          /* .echoFlag */
429 #else
430           "",                           /* .echoFlag */
431 #endif
432           "",                           /* .errFlag */
433     },
434     /*
435      * KSH description.
436      */
437     {
438           "ksh",                        /* .name */
439           true,                         /* .hasEchoCtl */
440           "set +v",           /* .echoOff */
441           "set -v",           /* .echoOn */
442           "set +v",           /* .noPrint */
443           6,                            /* .noPrintLen */
444           false,                        /* .hasErrCtl */
445           "",                           /* .errOn */
446           "",                           /* .errOff */
447           "echo \"%s\"\n",    /* .echoTmpl */
448           "%s\n",                       /* .runIgnTmpl */
449           "{ %s \n} || exit $?\n", /* .runChkTmpl */
450           "'\n'",                       /* .newline */
451           '#',                          /* .commentChar */
452           "v",                          /* .echoFlag */
453           "",                           /* .errFlag */
454     },
455     /*
456      * CSH description. The csh can do echo control by playing
457      * with the setting of the 'echo' shell variable. Sadly,
458      * however, it is unable to do error control nicely.
459      */
460     {
461           "csh",                        /* .name */
462           true,                         /* .hasEchoCtl */
463           "unset verbose",    /* .echoOff */
464           "set verbose",                /* .echoOn */
465           "unset verbose",    /* .noPrint */
466           13,                           /* .noPrintLen */
467           false,                        /* .hasErrCtl */
468           "",                           /* .errOn */
469           "",                           /* .errOff */
470           "echo \"%s\"\n",    /* .echoTmpl */
471           "csh -c \"%s || exit 0\"\n", /* .runIgnTmpl */
472           "",                           /* .runChkTmpl */
473           "'\\\n'",           /* .newline */
474           '#',                          /* .commentChar */
475           "v",                          /* .echoFlag */
476           "e",                          /* .errFlag */
477     }
478 };
479 
480 /*
481  * This is the shell to which we pass all commands in the Makefile.
482  * It is set by the Job_ParseShell function.
483  */
484 static Shell *shell = &shells[DEFSHELL_INDEX];
485 char *shellPath;              /* full pathname of executable image */
486 const char *shellName = NULL; /* last component of shellPath */
487 char *shellErrFlag = NULL;
488 static char *shell_freeIt = NULL; /* Allocated memory for custom .SHELL */
489 
490 
491 static Job *job_table;                  /* The structures that describe them */
492 static Job *job_table_end;    /* job_table + maxJobs */
493 static bool wantToken;
494 static bool lurking_children = false;
495 static bool make_suspended = false; /* Whether we've seen a SIGTSTP (etc) */
496 
497 /*
498  * Set of descriptors of pipes connected to
499  * the output channels of children
500  */
501 static struct pollfd *fds = NULL;
502 static Job **jobByFdIndex = NULL;
503 static nfds_t fdsLen = 0;
504 static void watchfd(Job *);
505 static void clearfd(Job *);
506 
507 static char *targPrefix = NULL;         /* To identify a job change in the output. */
508 static Job tokenPoolJob;      /* token wait pseudo-job */
509 
510 static Job childExitJob;      /* child exit pseudo-job */
511 #define CHILD_EXIT "."
512 #define DO_JOB_RESUME "R"
513 
514 enum {
515           npseudojobs = 2               /* number of pseudo-jobs */
516 };
517 
518 static sigset_t caught_signals;         /* Set of signals we handle */
519 static volatile sig_atomic_t caught_sigchld;
520 
521 static void CollectOutput(Job *, bool);
522 static void JobInterrupt(bool, int) MAKE_ATTR_DEAD;
523 static void JobRestartJobs(void);
524 static void JobSigReset(void);
525 
526 static void
SwitchOutputTo(GNode * gn)527 SwitchOutputTo(GNode *gn)
528 {
529           /* The node for which output was most recently produced. */
530           static GNode *lastNode = NULL;
531 
532           if (gn == lastNode)
533                     return;
534           lastNode = gn;
535 
536           if (opts.maxJobs != 1 && targPrefix != NULL && targPrefix[0] != '\0')
537                     (void)fprintf(stdout, "%s %s ---\n", targPrefix, gn->name);
538 }
539 
540 static unsigned
nfds_per_job(void)541 nfds_per_job(void)
542 {
543 #if defined(USE_FILEMON) && !defined(USE_FILEMON_DEV)
544           if (useMeta)
545                     return 2;
546 #endif
547           return 1;
548 }
549 
550 void
Job_FlagsToString(const Job * job,char * buf,size_t bufsize)551 Job_FlagsToString(const Job *job, char *buf, size_t bufsize)
552 {
553           snprintf(buf, bufsize, "%c%c%c",
554               job->ignerr ? 'i' : '-',
555               !job->echo ? 's' : '-',
556               job->special ? 'S' : '-');
557 }
558 
559 #ifdef USE_META
560 struct BuildMon *
Job_BuildMon(Job * job)561 Job_BuildMon(Job *job)
562 {
563           return &job->bm;
564 }
565 #endif
566 
567 GNode *
Job_Node(Job * job)568 Job_Node(Job *job)
569 {
570           return job->node;
571 }
572 
573 int
Job_Pid(Job * job)574 Job_Pid(Job *job)
575 {
576           return job->pid;
577 }
578 
579 static void
DumpJobs(const char * where)580 DumpJobs(const char *where)
581 {
582           Job *job;
583           char flags[4];
584 
585           debug_printf("job table @ %s\n", where);
586           for (job = job_table; job < job_table_end; job++) {
587                     Job_FlagsToString(job, flags, sizeof flags);
588                     debug_printf("job %d, status %d, flags %s, pid %d\n",
589                         (int)(job - job_table), job->status, flags, job->pid);
590           }
591 }
592 
593 /*
594  * Delete the target of a failed, interrupted, or otherwise
595  * unsuccessful job unless inhibited by .PRECIOUS.
596  */
597 static void
JobDeleteTarget(GNode * gn)598 JobDeleteTarget(GNode *gn)
599 {
600           const char *file;
601 
602           if (gn->type & OP_JOIN)
603                     return;
604           if (gn->type & OP_PHONY)
605                     return;
606           if (GNode_IsPrecious(gn))
607                     return;
608           if (opts.noExecute)
609                     return;
610 
611           file = GNode_Path(gn);
612           if (unlink_file(file) == 0)
613                     Error("*** %s removed", file);
614 }
615 
616 /* Lock the jobs table and the jobs therein. */
617 static void
JobsTable_Lock(sigset_t * omaskp)618 JobsTable_Lock(sigset_t *omaskp)
619 {
620           if (sigprocmask(SIG_BLOCK, &caught_signals, omaskp) != 0)
621                     Punt("JobsTable_Lock: sigprocmask: %s", strerror(errno));
622 }
623 
624 /* Unlock the jobs table and the jobs therein. */
625 static void
JobsTable_Unlock(sigset_t * omaskp)626 JobsTable_Unlock(sigset_t *omaskp)
627 {
628           (void)sigprocmask(SIG_SETMASK, omaskp, NULL);
629 }
630 
631 static void
SetNonblocking(int fd)632 SetNonblocking(int fd)
633 {
634           int flags = fcntl(fd, F_GETFL, 0);
635           if (flags == -1)
636                     Punt("SetNonblocking.get: %s", strerror(errno));
637           flags |= O_NONBLOCK;
638           if (fcntl(fd, F_SETFL, flags) == -1)
639                     Punt("SetNonblocking.set: %s", strerror(errno));
640 }
641 
642 static void
JobCreatePipe(Job * job,int minfd)643 JobCreatePipe(Job *job, int minfd)
644 {
645           int i;
646           int pipe_fds[2];
647 
648           if (pipe(pipe_fds) == -1)
649                     Punt("Cannot create pipe: %s", strerror(errno));
650 
651           for (i = 0; i < 2; i++) {
652                     /* Avoid using low-numbered fds */
653                     int fd = fcntl(pipe_fds[i], F_DUPFD, minfd);
654                     if (fd != -1) {
655                               close(pipe_fds[i]);
656                               pipe_fds[i] = fd;
657                     }
658           }
659 
660           job->inPipe = pipe_fds[0];
661           job->outPipe = pipe_fds[1];
662 
663           if (fcntl(job->inPipe, F_SETFD, FD_CLOEXEC) == -1)
664                     Punt("Cannot set close-on-exec: %s", strerror(errno));
665           if (fcntl(job->outPipe, F_SETFD, FD_CLOEXEC) == -1)
666                     Punt("Cannot set close-on-exec: %s", strerror(errno));
667 
668           /*
669            * We mark the input side of the pipe non-blocking; we poll(2) the
670            * pipe when we're waiting for a job token, but we might lose the
671            * race for the token when a new one becomes available, so the read
672            * from the pipe should not block.
673            */
674           SetNonblocking(job->inPipe);
675 }
676 
677 /* Pass the signal to each running job. */
678 static void
JobCondPassSig(int signo)679 JobCondPassSig(int signo)
680 {
681           Job *job;
682 
683           DEBUG1(JOB, "JobCondPassSig(%d) called.\n", signo);
684 
685           for (job = job_table; job < job_table_end; job++) {
686                     if (job->status != JOB_ST_RUNNING)
687                               continue;
688                     DEBUG2(JOB, "JobCondPassSig passing signal %d to child %d.\n",
689                         signo, job->pid);
690                     KILLPG(job->pid, signo);
691           }
692 }
693 
694 /*
695  * SIGCHLD handler.
696  *
697  * Sends a token on the child exit pipe to wake us up from select()/poll().
698  */
699 static void
JobChildSig(int signo MAKE_ATTR_UNUSED)700 JobChildSig(int signo MAKE_ATTR_UNUSED)
701 {
702           caught_sigchld = 1;
703           while (write(childExitJob.outPipe, CHILD_EXIT, 1) == -1 &&
704                  errno == EAGAIN)
705                     continue;
706 }
707 
708 
709 /* Resume all stopped jobs. */
710 static void
JobContinueSig(int signo MAKE_ATTR_UNUSED)711 JobContinueSig(int signo MAKE_ATTR_UNUSED)
712 {
713           /*
714            * Defer sending SIGCONT to our stopped children until we return
715            * from the signal handler.
716            */
717           while (write(childExitJob.outPipe, DO_JOB_RESUME, 1) == -1 &&
718                  errno == EAGAIN)
719                     continue;
720 }
721 
722 /*
723  * Pass a signal on to all jobs, then resend to ourselves.
724  * We die by the same signal.
725  */
726 MAKE_ATTR_DEAD static void
JobPassSig_int(int signo)727 JobPassSig_int(int signo)
728 {
729           /* Run .INTERRUPT target then exit */
730           JobInterrupt(true, signo);
731 }
732 
733 /*
734  * Pass a signal on to all jobs, then resend to ourselves.
735  * We die by the same signal.
736  */
737 MAKE_ATTR_DEAD static void
JobPassSig_term(int signo)738 JobPassSig_term(int signo)
739 {
740           /* Dont run .INTERRUPT target then exit */
741           JobInterrupt(false, signo);
742 }
743 
744 static void
JobPassSig_suspend(int signo)745 JobPassSig_suspend(int signo)
746 {
747           sigset_t nmask, omask;
748           struct sigaction act;
749 
750           /* Suppress job started/continued messages */
751           make_suspended = true;
752 
753           /* Pass the signal onto every job */
754           JobCondPassSig(signo);
755 
756           /*
757            * Send ourselves the signal now we've given the message to everyone
758            * else. Note we block everything else possible while we're getting
759            * the signal. This ensures that all our jobs get continued when we
760            * wake up before we take any other signal.
761            */
762           sigfillset(&nmask);
763           sigdelset(&nmask, signo);
764           (void)sigprocmask(SIG_SETMASK, &nmask, &omask);
765 
766           act.sa_handler = SIG_DFL;
767           sigemptyset(&act.sa_mask);
768           act.sa_flags = 0;
769           (void)sigaction(signo, &act, NULL);
770 
771           DEBUG1(JOB, "JobPassSig_suspend passing signal %d to self.\n", signo);
772 
773           (void)kill(getpid(), signo);
774 
775           /*
776            * We've been continued.
777            *
778            * A whole host of signals is going to happen!
779            * SIGCHLD for any processes that actually suspended themselves.
780            * SIGCHLD for any processes that exited while we were asleep.
781            * The SIGCONT that actually caused us to wake up.
782            *
783            * Since we defer passing the SIGCONT on to our children until
784            * the main processing loop, we can be sure that all the SIGCHLD
785            * events will have happened by then - and that the waitpid() will
786            * collect the child 'suspended' events.
787            * For correct sequencing we just need to ensure we process the
788            * waitpid() before passing on the SIGCONT.
789            *
790            * In any case nothing else is needed here.
791            */
792 
793           /* Restore handler and signal mask */
794           act.sa_handler = JobPassSig_suspend;
795           (void)sigaction(signo, &act, NULL);
796           (void)sigprocmask(SIG_SETMASK, &omask, NULL);
797 }
798 
799 static Job *
JobFindPid(int pid,JobStatus status,bool isJobs)800 JobFindPid(int pid, JobStatus status, bool isJobs)
801 {
802           Job *job;
803 
804           for (job = job_table; job < job_table_end; job++) {
805                     if (job->status == status && job->pid == pid)
806                               return job;
807           }
808           if (DEBUG(JOB) && isJobs)
809                     DumpJobs("no pid");
810           return NULL;
811 }
812 
813 /* Parse leading '@', '-' and '+', which control the exact execution mode. */
814 static void
ParseCommandFlags(char ** pp,CommandFlags * out_cmdFlags)815 ParseCommandFlags(char **pp, CommandFlags *out_cmdFlags)
816 {
817           char *p = *pp;
818           out_cmdFlags->echo = true;
819           out_cmdFlags->ignerr = false;
820           out_cmdFlags->always = false;
821 
822           for (;;) {
823                     if (*p == '@')
824                               out_cmdFlags->echo = DEBUG(LOUD);
825                     else if (*p == '-')
826                               out_cmdFlags->ignerr = true;
827                     else if (*p == '+')
828                               out_cmdFlags->always = true;
829                     else if (!ch_isspace(*p))
830                               /* Ignore whitespace for compatibility with GNU make */
831                               break;
832                     p++;
833           }
834 
835           *pp = p;
836 }
837 
838 /* Escape a string for a double-quoted string literal in sh, csh and ksh. */
839 static char *
EscapeShellDblQuot(const char * cmd)840 EscapeShellDblQuot(const char *cmd)
841 {
842           size_t i, j;
843 
844           /* Worst that could happen is every char needs escaping. */
845           char *esc = bmake_malloc(strlen(cmd) * 2 + 1);
846           for (i = 0, j = 0; cmd[i] != '\0'; i++, j++) {
847                     if (cmd[i] == '$' || cmd[i] == '`' || cmd[i] == '\\' ||
848                         cmd[i] == '"')
849                               esc[j++] = '\\';
850                     esc[j] = cmd[i];
851           }
852           esc[j] = '\0';
853 
854           return esc;
855 }
856 
857 static void
ShellWriter_WriteFmt(ShellWriter * wr,const char * fmt,const char * arg)858 ShellWriter_WriteFmt(ShellWriter *wr, const char *fmt, const char *arg)
859 {
860           DEBUG1(JOB, fmt, arg);
861 
862           (void)fprintf(wr->f, fmt, arg);
863           if (wr->f == stdout)
864                     (void)fflush(wr->f);
865 }
866 
867 static void
ShellWriter_WriteLine(ShellWriter * wr,const char * line)868 ShellWriter_WriteLine(ShellWriter *wr, const char *line)
869 {
870           ShellWriter_WriteFmt(wr, "%s\n", line);
871 }
872 
873 static void
ShellWriter_EchoOff(ShellWriter * wr)874 ShellWriter_EchoOff(ShellWriter *wr)
875 {
876           if (shell->hasEchoCtl)
877                     ShellWriter_WriteLine(wr, shell->echoOff);
878 }
879 
880 static void
ShellWriter_EchoCmd(ShellWriter * wr,const char * escCmd)881 ShellWriter_EchoCmd(ShellWriter *wr, const char *escCmd)
882 {
883           ShellWriter_WriteFmt(wr, shell->echoTmpl, escCmd);
884 }
885 
886 static void
ShellWriter_EchoOn(ShellWriter * wr)887 ShellWriter_EchoOn(ShellWriter *wr)
888 {
889           if (shell->hasEchoCtl)
890                     ShellWriter_WriteLine(wr, shell->echoOn);
891 }
892 
893 static void
ShellWriter_TraceOn(ShellWriter * wr)894 ShellWriter_TraceOn(ShellWriter *wr)
895 {
896           if (!wr->xtraced) {
897                     ShellWriter_WriteLine(wr, "set -x");
898                     wr->xtraced = true;
899           }
900 }
901 
902 static void
ShellWriter_ErrOff(ShellWriter * wr,bool echo)903 ShellWriter_ErrOff(ShellWriter *wr, bool echo)
904 {
905           if (echo)
906                     ShellWriter_EchoOff(wr);
907           ShellWriter_WriteLine(wr, shell->errOff);
908           if (echo)
909                     ShellWriter_EchoOn(wr);
910 }
911 
912 static void
ShellWriter_ErrOn(ShellWriter * wr,bool echo)913 ShellWriter_ErrOn(ShellWriter *wr, bool echo)
914 {
915           if (echo)
916                     ShellWriter_EchoOff(wr);
917           ShellWriter_WriteLine(wr, shell->errOn);
918           if (echo)
919                     ShellWriter_EchoOn(wr);
920 }
921 
922 /*
923  * The shell has no built-in error control, so emulate error control by
924  * enclosing each shell command in a template like "{ %s \n } || exit $?"
925  * (configurable per shell).
926  */
927 static void
JobWriteSpecialsEchoCtl(Job * job,ShellWriter * wr,CommandFlags * inout_cmdFlags,const char * escCmd,const char ** inout_cmdTemplate)928 JobWriteSpecialsEchoCtl(Job *job, ShellWriter *wr, CommandFlags *inout_cmdFlags,
929                               const char *escCmd, const char **inout_cmdTemplate)
930 {
931           /* XXX: Why is the whole job modified at this point? */
932           job->ignerr = true;
933 
934           if (job->echo && inout_cmdFlags->echo) {
935                     ShellWriter_EchoOff(wr);
936                     ShellWriter_EchoCmd(wr, escCmd);
937 
938                     /*
939                      * Leave echoing off so the user doesn't see the commands
940                      * for toggling the error checking.
941                      */
942                     inout_cmdFlags->echo = false;
943           }
944           *inout_cmdTemplate = shell->runIgnTmpl;
945 
946           /*
947            * The template runIgnTmpl already takes care of ignoring errors,
948            * so pretend error checking is still on.
949            * XXX: What effects does this have, and why is it necessary?
950            */
951           inout_cmdFlags->ignerr = false;
952 }
953 
954 static void
JobWriteSpecials(Job * job,ShellWriter * wr,const char * escCmd,bool run,CommandFlags * inout_cmdFlags,const char ** inout_cmdTemplate)955 JobWriteSpecials(Job *job, ShellWriter *wr, const char *escCmd, bool run,
956                      CommandFlags *inout_cmdFlags, const char **inout_cmdTemplate)
957 {
958           if (!run)
959                     inout_cmdFlags->ignerr = false;
960           else if (shell->hasErrCtl)
961                     ShellWriter_ErrOff(wr, job->echo && inout_cmdFlags->echo);
962           else if (shell->runIgnTmpl != NULL && shell->runIgnTmpl[0] != '\0') {
963                     JobWriteSpecialsEchoCtl(job, wr, inout_cmdFlags, escCmd,
964                         inout_cmdTemplate);
965           } else
966                     inout_cmdFlags->ignerr = false;
967 }
968 
969 /*
970  * Write a shell command to the job's commands file, to be run later.
971  *
972  * If the command starts with '@' and neither the -s nor the -n flag was
973  * given to make, stick a shell-specific echoOff command in the script.
974  *
975  * If the command starts with '-' and the shell has no error control (none
976  * of the predefined shells has that), ignore errors for the entire job.
977  *
978  * XXX: Why ignore errors for the entire job?  This is even documented in the
979  * manual page, but without any rationale since there is no known rationale.
980  *
981  * XXX: The manual page says the '-' "affects the entire job", but that's not
982  * accurate.  The '-' does not affect the commands before the '-'.
983  *
984  * If the command is just "...", skip all further commands of this job.  These
985  * commands are attached to the .END node instead and will be run by
986  * Job_Finish after all other targets have been made.
987  */
988 static void
JobWriteCommand(Job * job,ShellWriter * wr,StringListNode * ln,const char * ucmd)989 JobWriteCommand(Job *job, ShellWriter *wr, StringListNode *ln, const char *ucmd)
990 {
991           bool run;
992 
993           CommandFlags cmdFlags;
994           /* Template for writing a command to the shell file */
995           const char *cmdTemplate;
996           char *xcmd;                   /* The expanded command */
997           char *xcmdStart;
998           char *escCmd;                 /* xcmd escaped to be used in double quotes */
999 
1000           run = GNode_ShouldExecute(job->node);
1001 
1002           xcmd = Var_SubstInTarget(ucmd, job->node);
1003           /* TODO: handle errors */
1004           xcmdStart = xcmd;
1005 
1006           cmdTemplate = "%s\n";
1007 
1008           ParseCommandFlags(&xcmd, &cmdFlags);
1009 
1010           /* The '+' command flag overrides the -n or -N options. */
1011           if (cmdFlags.always && !run) {
1012                     /*
1013                      * We're not actually executing anything...
1014                      * but this one needs to be - use compat mode just for it.
1015                      */
1016                     (void)Compat_RunCommand(ucmd, job->node, ln);
1017                     free(xcmdStart);
1018                     return;
1019           }
1020 
1021           /*
1022            * If the shell doesn't have error control, the alternate echoing
1023            * will be done (to avoid showing additional error checking code)
1024            * and this needs some characters escaped.
1025            */
1026           escCmd = shell->hasErrCtl ? NULL : EscapeShellDblQuot(xcmd);
1027 
1028           if (!cmdFlags.echo) {
1029                     if (job->echo && run && shell->hasEchoCtl)
1030                               ShellWriter_EchoOff(wr);
1031                     else if (shell->hasErrCtl)
1032                               cmdFlags.echo = true;
1033           }
1034 
1035           if (cmdFlags.ignerr) {
1036                     JobWriteSpecials(job, wr, escCmd, run, &cmdFlags, &cmdTemplate);
1037           } else {
1038 
1039                     /*
1040                      * If errors are being checked and the shell doesn't have
1041                      * error control but does supply an runChkTmpl template, then
1042                      * set up commands to run through it.
1043                      */
1044 
1045                     if (!shell->hasErrCtl && shell->runChkTmpl != NULL &&
1046                         shell->runChkTmpl[0] != '\0') {
1047                               if (job->echo && cmdFlags.echo) {
1048                                         ShellWriter_EchoOff(wr);
1049                                         ShellWriter_EchoCmd(wr, escCmd);
1050                                         cmdFlags.echo = false;
1051                               }
1052                               /*
1053                                * If it's a comment line or blank, avoid the possible
1054                                * syntax error generated by "{\n} || exit $?".
1055                                */
1056                               cmdTemplate = escCmd[0] == shell->commentChar ||
1057                                               escCmd[0] == '\0'
1058                                   ? shell->runIgnTmpl
1059                                   : shell->runChkTmpl;
1060                               cmdFlags.ignerr = false;
1061                     }
1062           }
1063 
1064           if (DEBUG(SHELL) && strcmp(shellName, "sh") == 0)
1065                     ShellWriter_TraceOn(wr);
1066 
1067           ShellWriter_WriteFmt(wr, cmdTemplate, xcmd);
1068           free(xcmdStart);
1069           free(escCmd);
1070 
1071           if (cmdFlags.ignerr)
1072                     ShellWriter_ErrOn(wr, cmdFlags.echo && job->echo);
1073 
1074           if (!cmdFlags.echo)
1075                     ShellWriter_EchoOn(wr);
1076 }
1077 
1078 /*
1079  * Write all commands to the shell file that is later executed.
1080  *
1081  * The special command "..." stops writing and saves the remaining commands
1082  * to be executed later, when the target '.END' is made.
1083  *
1084  * Return whether at least one command was written to the shell file.
1085  */
1086 static bool
JobWriteCommands(Job * job)1087 JobWriteCommands(Job *job)
1088 {
1089           StringListNode *ln;
1090           bool seen = false;
1091           ShellWriter wr;
1092 
1093           wr.f = job->cmdFILE;
1094           wr.xtraced = false;
1095 
1096           for (ln = job->node->commands.first; ln != NULL; ln = ln->next) {
1097                     const char *cmd = ln->datum;
1098 
1099                     if (strcmp(cmd, "...") == 0) {
1100                               job->node->type |= OP_SAVE_CMDS;
1101                               job->tailCmds = ln->next;
1102                               break;
1103                     }
1104 
1105                     JobWriteCommand(job, &wr, ln, ln->datum);
1106                     seen = true;
1107           }
1108 
1109           return seen;
1110 }
1111 
1112 /*
1113  * Save the delayed commands (those after '...'), to be executed later in
1114  * the '.END' node, when everything else is done.
1115  */
1116 static void
JobSaveCommands(Job * job)1117 JobSaveCommands(Job *job)
1118 {
1119           StringListNode *ln;
1120 
1121           for (ln = job->tailCmds; ln != NULL; ln = ln->next) {
1122                     const char *cmd = ln->datum;
1123                     char *expanded_cmd;
1124                     /*
1125                      * XXX: This Var_Subst is only intended to expand the dynamic
1126                      * variables such as .TARGET, .IMPSRC.  It is not intended to
1127                      * expand the other variables as well; see deptgt-end.mk.
1128                      */
1129                     expanded_cmd = Var_SubstInTarget(cmd, job->node);
1130                     /* TODO: handle errors */
1131                     Lst_Append(&Targ_GetEndNode()->commands, expanded_cmd);
1132                     Parse_RegisterCommand(expanded_cmd);
1133           }
1134 }
1135 
1136 
1137 /* Called to close both input and output pipes when a job is finished. */
1138 static void
JobClosePipes(Job * job)1139 JobClosePipes(Job *job)
1140 {
1141           clearfd(job);
1142           (void)close(job->outPipe);
1143           job->outPipe = -1;
1144 
1145           CollectOutput(job, true);
1146           (void)close(job->inPipe);
1147           job->inPipe = -1;
1148 }
1149 
1150 static void
DebugFailedJob(const Job * job)1151 DebugFailedJob(const Job *job)
1152 {
1153           const StringListNode *ln;
1154 
1155           if (!DEBUG(ERROR))
1156                     return;
1157 
1158           debug_printf("\n");
1159           debug_printf("*** Failed target: %s\n", job->node->name);
1160           debug_printf("*** In directory: %s\n", curdir);
1161           debug_printf("*** Failed commands:\n");
1162           for (ln = job->node->commands.first; ln != NULL; ln = ln->next) {
1163                     const char *cmd = ln->datum;
1164                     debug_printf("\t%s\n", cmd);
1165 
1166                     if (strchr(cmd, '$') != NULL) {
1167                               char *xcmd = Var_Subst(cmd, job->node, VARE_EVAL);
1168                               debug_printf("\t=> %s\n", xcmd);
1169                               free(xcmd);
1170                     }
1171           }
1172 }
1173 
1174 static void
JobFinishDoneExitedError(Job * job,int * inout_status)1175 JobFinishDoneExitedError(Job *job, int *inout_status)
1176 {
1177           SwitchOutputTo(job->node);
1178 #ifdef USE_META
1179           if (useMeta) {
1180                     meta_job_error(job, job->node,
1181                         job->ignerr, WEXITSTATUS(*inout_status));
1182           }
1183 #endif
1184           if (!shouldDieQuietly(job->node, -1)) {
1185                     DebugFailedJob(job);
1186                     (void)printf("*** [%s] Error code %d%s\n",
1187                         job->node->name, WEXITSTATUS(*inout_status),
1188                         job->ignerr ? " (ignored)" : "");
1189           }
1190 
1191           if (job->ignerr)
1192                     *inout_status = 0;
1193           else {
1194                     if (deleteOnError)
1195                               JobDeleteTarget(job->node);
1196                     PrintOnError(job->node, "\n");
1197           }
1198 }
1199 
1200 static void
JobFinishDoneExited(Job * job,int * inout_status)1201 JobFinishDoneExited(Job *job, int *inout_status)
1202 {
1203           DEBUG2(JOB, "Process %d [%s] exited.\n", job->pid, job->node->name);
1204 
1205           if (WEXITSTATUS(*inout_status) != 0)
1206                     JobFinishDoneExitedError(job, inout_status);
1207           else if (DEBUG(JOB)) {
1208                     SwitchOutputTo(job->node);
1209                     (void)printf("*** [%s] Completed successfully\n",
1210                         job->node->name);
1211           }
1212 }
1213 
1214 static void
JobFinishDoneSignaled(Job * job,int status)1215 JobFinishDoneSignaled(Job *job, int status)
1216 {
1217           SwitchOutputTo(job->node);
1218           DebugFailedJob(job);
1219           (void)printf("*** [%s] Signal %d\n", job->node->name, WTERMSIG(status));
1220           if (deleteOnError)
1221                     JobDeleteTarget(job->node);
1222 }
1223 
1224 static void
JobFinishDone(Job * job,int * inout_status)1225 JobFinishDone(Job *job, int *inout_status)
1226 {
1227           if (WIFEXITED(*inout_status))
1228                     JobFinishDoneExited(job, inout_status);
1229           else
1230                     JobFinishDoneSignaled(job, *inout_status);
1231 
1232           (void)fflush(stdout);
1233 }
1234 
1235 /*
1236  * Do final processing for the given job including updating parent nodes and
1237  * starting new jobs as available/necessary.
1238  *
1239  * Deferred commands for the job are placed on the .END node.
1240  *
1241  * If there was a serious error (job_errors != 0; not an ignored one), no more
1242  * jobs will be started.
1243  *
1244  * Input:
1245  *        job                 job to finish
1246  *        status              sub-why job went away
1247  */
1248 static void
JobFinish(Job * job,int status)1249 JobFinish(Job *job, int status)
1250 {
1251           bool done, return_job_token;
1252 
1253           DEBUG3(JOB, "JobFinish: %d [%s], status %d\n",
1254               job->pid, job->node->name, status);
1255 
1256           if ((WIFEXITED(status) &&
1257                ((WEXITSTATUS(status) != 0 && !job->ignerr))) ||
1258               WIFSIGNALED(status)) {
1259                     /* Finished because of an error. */
1260 
1261                     JobClosePipes(job);
1262                     if (job->cmdFILE != NULL && job->cmdFILE != stdout) {
1263                               if (fclose(job->cmdFILE) != 0)
1264                                         Punt("Cannot write shell script for '%s': %s",
1265                                             job->node->name, strerror(errno));
1266                               job->cmdFILE = NULL;
1267                     }
1268                     done = true;
1269 
1270           } else if (WIFEXITED(status)) {
1271                     /*
1272                      * Deal with ignored errors in -B mode. We need to print a
1273                      * message telling of the ignored error as well as to run
1274                      * the next command.
1275                      */
1276                     done = WEXITSTATUS(status) != 0;
1277 
1278                     JobClosePipes(job);
1279 
1280           } else {
1281                     /* No need to close things down or anything. */
1282                     done = false;
1283           }
1284 
1285           if (done)
1286                     JobFinishDone(job, &status);
1287 
1288 #ifdef USE_META
1289           if (useMeta) {
1290                     int meta_status = meta_job_finish(job);
1291                     if (meta_status != 0 && status == 0)
1292                               status = meta_status;
1293           }
1294 #endif
1295 
1296           return_job_token = false;
1297 
1298           Trace_Log(JOBEND, job);
1299           if (!job->special) {
1300                     if (status != 0 ||
1301                         (aborting == ABORT_ERROR) || aborting == ABORT_INTERRUPT)
1302                               return_job_token = true;
1303           }
1304 
1305           if (aborting != ABORT_ERROR && aborting != ABORT_INTERRUPT &&
1306               status == 0) {
1307                     /*
1308                      * As long as we aren't aborting and the job didn't return a
1309                      * non-zero status that we shouldn't ignore, we call
1310                      * Make_Update to update the parents.
1311                      */
1312                     JobSaveCommands(job);
1313                     job->node->made = MADE;
1314                     if (!job->special)
1315                               return_job_token = true;
1316                     Make_Update(job->node);
1317                     job->status = JOB_ST_FREE;
1318           } else if (status != 0) {
1319                     job_errors++;
1320                     job->status = JOB_ST_FREE;
1321           }
1322 
1323           if (job_errors > 0 && !opts.keepgoing && aborting != ABORT_INTERRUPT) {
1324                     /* Prevent more jobs from getting started. */
1325                     aborting = ABORT_ERROR;
1326           }
1327 
1328           if (return_job_token)
1329                     TokenPool_Return();
1330 
1331           if (aborting == ABORT_ERROR && jobTokensRunning == 0) {
1332                     if (shouldDieQuietly(NULL, -1))
1333                               exit(2);
1334                     Fatal("%d error%s", job_errors, job_errors == 1 ? "" : "s");
1335           }
1336 }
1337 
1338 static void
TouchRegular(GNode * gn)1339 TouchRegular(GNode *gn)
1340 {
1341           const char *file = GNode_Path(gn);
1342           struct utimbuf times;
1343           int fd;
1344           char c;
1345 
1346           times.actime = now;
1347           times.modtime = now;
1348           if (utime(file, &times) >= 0)
1349                     return;
1350 
1351           fd = open(file, O_RDWR | O_CREAT, 0666);
1352           if (fd < 0) {
1353                     (void)fprintf(stderr, "*** couldn't touch %s: %s\n",
1354                         file, strerror(errno));
1355                     (void)fflush(stderr);
1356                     return;             /* XXX: What about propagating the error? */
1357           }
1358 
1359           /*
1360            * Last resort: update the file's time stamps in the traditional way.
1361            * XXX: This doesn't work for empty files, which are sometimes used
1362            * as marker files.
1363            */
1364           if (read(fd, &c, 1) == 1) {
1365                     (void)lseek(fd, 0, SEEK_SET);
1366                     while (write(fd, &c, 1) == -1 && errno == EAGAIN)
1367                               continue;
1368           }
1369           (void)close(fd);    /* XXX: What about propagating the error? */
1370 }
1371 
1372 /*
1373  * Touch the given target. Called by Job_Make when the -t flag was given.
1374  *
1375  * The modification date of the file is changed.
1376  * If the file did not exist, it is created.
1377  */
1378 void
Job_Touch(GNode * gn,bool echo)1379 Job_Touch(GNode *gn, bool echo)
1380 {
1381           if (gn->type &
1382               (OP_JOIN | OP_USE | OP_USEBEFORE | OP_EXEC | OP_OPTIONAL |
1383                OP_SPECIAL | OP_PHONY)) {
1384                     /*
1385                      * These are "virtual" targets and should not really be
1386                      * created.
1387                      */
1388                     return;
1389           }
1390 
1391           if (echo || !GNode_ShouldExecute(gn)) {
1392                     (void)fprintf(stdout, "touch %s\n", gn->name);
1393                     (void)fflush(stdout);
1394           }
1395 
1396           if (!GNode_ShouldExecute(gn))
1397                     return;
1398 
1399           if (gn->type & OP_ARCHV)
1400                     Arch_Touch(gn);
1401           else if (gn->type & OP_LIB)
1402                     Arch_TouchLib(gn);
1403           else
1404                     TouchRegular(gn);
1405 }
1406 
1407 /*
1408  * Make sure the given node has all the commands it needs.
1409  *
1410  * The node will have commands from the .DEFAULT rule added to it if it
1411  * needs them.
1412  *
1413  * Input:
1414  *        gn                  The target whose commands need verifying
1415  *        abortProc Function to abort with message
1416  *
1417  * Results:
1418  *        true if the commands are ok.
1419  */
1420 bool
Job_CheckCommands(GNode * gn,void (* abortProc)(const char *,...))1421 Job_CheckCommands(GNode *gn, void (*abortProc)(const char *, ...))
1422 {
1423           if (GNode_IsTarget(gn))
1424                     return true;
1425           if (!Lst_IsEmpty(&gn->commands))
1426                     return true;
1427           if ((gn->type & OP_LIB) && !Lst_IsEmpty(&gn->children))
1428                     return true;
1429 
1430           /*
1431            * No commands. Look for .DEFAULT rule from which we might infer
1432            * commands.
1433            */
1434           if (defaultNode != NULL && !Lst_IsEmpty(&defaultNode->commands) &&
1435               !(gn->type & OP_SPECIAL)) {
1436                     /*
1437                      * The traditional Make only looks for a .DEFAULT if the node
1438                      * was never the target of an operator, so that's what we do
1439                      * too.
1440                      *
1441                      * The .DEFAULT node acts like a transformation rule, in that
1442                      * gn also inherits any attributes or sources attached to
1443                      * .DEFAULT itself.
1444                      */
1445                     Make_HandleUse(defaultNode, gn);
1446                     Var_Set(gn, IMPSRC, GNode_VarTarget(gn));
1447                     return true;
1448           }
1449 
1450           Dir_UpdateMTime(gn, false);
1451           if (gn->mtime != 0 || (gn->type & OP_SPECIAL))
1452                     return true;
1453 
1454           /*
1455            * The node wasn't the target of an operator.  We have no .DEFAULT
1456            * rule to go on and the target doesn't already exist. There's
1457            * nothing more we can do for this branch. If the -k flag wasn't
1458            * given, we stop in our tracks, otherwise we just don't update
1459            * this node's parents so they never get examined.
1460            */
1461 
1462           if (gn->flags.fromDepend) {
1463                     if (!Job_RunTarget(".STALE", gn->fname))
1464                               fprintf(stdout,
1465                                   "%s: %s:%u: ignoring stale %s for %s\n",
1466                                   progname, gn->fname, gn->lineno, makeDependfile,
1467                                   gn->name);
1468                     return true;
1469           }
1470 
1471           if (gn->type & OP_OPTIONAL) {
1472                     (void)fprintf(stdout, "%s: don't know how to make %s (%s)\n",
1473                         progname, gn->name, "ignored");
1474                     (void)fflush(stdout);
1475                     return true;
1476           }
1477 
1478           if (opts.keepgoing) {
1479                     (void)fprintf(stdout, "%s: don't know how to make %s (%s)\n",
1480                         progname, gn->name, "continuing");
1481                     (void)fflush(stdout);
1482                     return false;
1483           }
1484 
1485           abortProc("don't know how to make %s. Stop", gn->name);
1486           return false;
1487 }
1488 
1489 /*
1490  * Execute the shell for the given job.
1491  *
1492  * See Job_CatchOutput for handling the output of the shell.
1493  */
1494 static void
JobExec(Job * job,char ** argv)1495 JobExec(Job *job, char **argv)
1496 {
1497           int cpid;           /* ID of new child */
1498           sigset_t mask;
1499 
1500           if (DEBUG(JOB)) {
1501                     int i;
1502 
1503                     debug_printf("Running %s\n", job->node->name);
1504                     debug_printf("\tCommand: ");
1505                     for (i = 0; argv[i] != NULL; i++) {
1506                               debug_printf("%s ", argv[i]);
1507                     }
1508                     debug_printf("\n");
1509           }
1510 
1511           /*
1512            * Some jobs produce no output, and it's disconcerting to have
1513            * no feedback of their running (since they produce no output, the
1514            * banner with their name in it never appears). This is an attempt to
1515            * provide that feedback, even if nothing follows it.
1516            */
1517           if (job->echo)
1518                     SwitchOutputTo(job->node);
1519 
1520           /* No interruptions until this job is in the jobs table. */
1521           JobsTable_Lock(&mask);
1522 
1523           /* Pre-emptively mark job running, pid still zero though */
1524           job->status = JOB_ST_RUNNING;
1525 
1526           Var_ReexportVars(job->node);
1527 
1528           cpid = FORK_FUNCTION();
1529           if (cpid == -1)
1530                     Punt("Cannot fork: %s", strerror(errno));
1531 
1532           if (cpid == 0) {
1533                     /* Child */
1534                     sigset_t tmask;
1535 
1536 #ifdef USE_META
1537                     if (useMeta)
1538                               meta_job_child(job);
1539 #endif
1540                     /*
1541                      * Reset all signal handlers; this is necessary because we
1542                      * also need to unblock signals before we exec(2).
1543                      */
1544                     JobSigReset();
1545 
1546                     sigemptyset(&tmask);
1547                     JobsTable_Unlock(&tmask);
1548 
1549                     /*
1550                      * Must duplicate the input stream down to the child's input
1551                      * and reset it to the beginning (again). Since the stream
1552                      * was marked close-on-exec, we must clear that bit in the
1553                      * new input.
1554                      */
1555                     if (dup2(fileno(job->cmdFILE), STDIN_FILENO) == -1)
1556                               execDie("dup2", "job->cmdFILE");
1557                     if (fcntl(STDIN_FILENO, F_SETFD, 0) == -1)
1558                               execDie("fcntl clear close-on-exec", "stdin");
1559                     if (lseek(STDIN_FILENO, 0, SEEK_SET) == -1)
1560                               execDie("lseek to 0", "stdin");
1561 
1562                     if (job->node->type & (OP_MAKE | OP_SUBMAKE)) {
1563                               /* Pass job token pipe to submakes. */
1564                               if (fcntl(tokenPoolJob.inPipe, F_SETFD, 0) == -1)
1565                                         execDie("clear close-on-exec",
1566                                             "tokenPoolJob.inPipe");
1567                               if (fcntl(tokenPoolJob.outPipe, F_SETFD, 0) == -1)
1568                                         execDie("clear close-on-exec",
1569                                             "tokenPoolJob.outPipe");
1570                     }
1571 
1572                     /*
1573                      * Set up the child's output to be routed through the pipe
1574                      * we've created for it.
1575                      */
1576                     if (dup2(job->outPipe, STDOUT_FILENO) == -1)
1577                               execDie("dup2", "job->outPipe");
1578 
1579                     /*
1580                      * The output channels are marked close on exec. This bit
1581                      * was duplicated by dup2 (on some systems), so we have
1582                      * to clear it before routing the shell's error output to
1583                      * the same place as its standard output.
1584                      */
1585                     if (fcntl(STDOUT_FILENO, F_SETFD, 0) == -1)
1586                               execDie("clear close-on-exec", "stdout");
1587                     if (dup2(STDOUT_FILENO, STDERR_FILENO) == -1)
1588                               execDie("dup2", "1, 2");
1589 
1590                     /*
1591                      * We want to switch the child into a different process
1592                      * family so we can kill it and all its descendants in
1593                      * one fell swoop, by killing its process family, but not
1594                      * commit suicide.
1595                      */
1596 #if defined(MAKE_NATIVE) || defined(HAVE_SETPGID)
1597 # if defined(SYSV)
1598                     /* XXX: dsl - I'm sure this should be setpgrp()... */
1599                     (void)setsid();
1600 # else
1601                     (void)setpgid(0, getpid());
1602 # endif
1603 #endif
1604 
1605                     (void)execv(shellPath, argv);
1606                     execDie("exec", shellPath);
1607           }
1608 
1609           /* Parent, continuing after the child exec */
1610           job->pid = cpid;
1611 
1612           Trace_Log(JOBSTART, job);
1613 
1614 #ifdef USE_META
1615           if (useMeta)
1616                     meta_job_parent(job, cpid);
1617 #endif
1618 
1619           /*
1620            * Set the current position in the buffer to the beginning
1621            * and mark another stream to watch in the outputs mask
1622            */
1623           job->curPos = 0;
1624 
1625           watchfd(job);
1626 
1627           if (job->cmdFILE != NULL && job->cmdFILE != stdout) {
1628                     if (fclose(job->cmdFILE) != 0)
1629                               Punt("Cannot write shell script for '%s': %s",
1630                                   job->node->name, strerror(errno));
1631                     job->cmdFILE = NULL;
1632           }
1633 
1634           /* Now that the job is actually running, add it to the table. */
1635           if (DEBUG(JOB)) {
1636                     debug_printf("JobExec(%s): pid %d added to jobs table\n",
1637                         job->node->name, job->pid);
1638                     DumpJobs("job started");
1639           }
1640           JobsTable_Unlock(&mask);
1641 }
1642 
1643 /* Create the argv needed to execute the shell for a given job. */
1644 static void
JobMakeArgv(Job * job,char ** argv)1645 JobMakeArgv(Job *job, char **argv)
1646 {
1647           int argc;
1648           static char args[10];         /* For merged arguments */
1649 
1650           argv[0] = UNCONST(shellName);
1651           argc = 1;
1652 
1653           if ((shell->errFlag != NULL && shell->errFlag[0] != '-') ||
1654               (shell->echoFlag != NULL && shell->echoFlag[0] != '-')) {
1655                     /*
1656                      * At least one of the flags doesn't have a minus before it,
1657                      * so merge them together. Have to do this because the Bourne
1658                      * shell thinks its second argument is a file to source.
1659                      * Grrrr. Note the ten-character limitation on the combined
1660                      * arguments.
1661                      *
1662                      * TODO: Research until when the above comments were
1663                      * practically relevant.
1664                      */
1665                     (void)snprintf(args, sizeof args, "-%s%s",
1666                         (job->ignerr ? "" :
1667                               (shell->errFlag != NULL ? shell->errFlag : "")),
1668                         (!job->echo ? "" :
1669                               (shell->echoFlag != NULL ? shell->echoFlag : "")));
1670 
1671                     if (args[1] != '\0') {
1672                               argv[argc] = args;
1673                               argc++;
1674                     }
1675           } else {
1676                     if (!job->ignerr && shell->errFlag != NULL) {
1677                               argv[argc] = UNCONST(shell->errFlag);
1678                               argc++;
1679                     }
1680                     if (job->echo && shell->echoFlag != NULL) {
1681                               argv[argc] = UNCONST(shell->echoFlag);
1682                               argc++;
1683                     }
1684           }
1685           argv[argc] = NULL;
1686 }
1687 
1688 static void
JobWriteShellCommands(Job * job,GNode * gn,bool * out_run)1689 JobWriteShellCommands(Job *job, GNode *gn, bool *out_run)
1690 {
1691           /*
1692            * tfile is the name of a file into which all shell commands
1693            * are put. It is removed before the child shell is executed,
1694            * unless DEBUG(SCRIPT) is set.
1695            */
1696           char tfile[MAXPATHLEN];
1697           int tfd;            /* File descriptor to the temp file */
1698 
1699           tfd = Job_TempFile(NULL, tfile, sizeof tfile);
1700 
1701           job->cmdFILE = fdopen(tfd, "w+");
1702           if (job->cmdFILE == NULL)
1703                     Punt("Could not fdopen %s", tfile);
1704 
1705           (void)fcntl(fileno(job->cmdFILE), F_SETFD, FD_CLOEXEC);
1706 
1707 #ifdef USE_META
1708           if (useMeta) {
1709                     meta_job_start(job, gn);
1710                     if (gn->type & OP_SILENT)     /* might have changed */
1711                               job->echo = false;
1712           }
1713 #endif
1714 
1715           *out_run = JobWriteCommands(job);
1716 }
1717 
1718 void
Job_Make(GNode * gn)1719 Job_Make(GNode *gn)
1720 {
1721           Job *job;           /* new job descriptor */
1722           char *argv[10];               /* Argument vector to shell */
1723           bool cmdsOK;                  /* true if the nodes commands were all right */
1724           bool run;
1725 
1726           for (job = job_table; job < job_table_end; job++) {
1727                     if (job->status == JOB_ST_FREE)
1728                               break;
1729           }
1730           if (job >= job_table_end)
1731                     Punt("Job_Make no job slots vacant");
1732 
1733           memset(job, 0, sizeof *job);
1734           job->node = gn;
1735           job->tailCmds = NULL;
1736           job->status = JOB_ST_SET_UP;
1737 
1738           job->special = (gn->type & OP_SPECIAL) != OP_NONE;
1739           job->ignerr = opts.ignoreErrors || gn->type & OP_IGNORE;
1740           job->echo = !(opts.silent || gn->type & OP_SILENT);
1741 
1742           /*
1743            * Check the commands now so any attributes from .DEFAULT have a
1744            * chance to migrate to the node.
1745            */
1746           cmdsOK = Job_CheckCommands(gn, Error);
1747 
1748           job->inPollfd = NULL;
1749 
1750           if (Lst_IsEmpty(&gn->commands)) {
1751                     job->cmdFILE = stdout;
1752                     run = false;
1753 
1754                     /*
1755                      * We're serious here, but if the commands were bogus, we're
1756                      * also dead...
1757                      */
1758                     if (!cmdsOK) {
1759                               PrintOnError(gn, "\n");       /* provide some clue */
1760                               DieHorribly();
1761                     }
1762           } else if (((gn->type & OP_MAKE) && !opts.noRecursiveExecute) ||
1763               (!opts.noExecute && !opts.touch)) {
1764                     /*
1765                      * The above condition looks very similar to
1766                      * GNode_ShouldExecute but is subtly different.  It prevents
1767                      * that .MAKE targets are touched since these are usually
1768                      * virtual targets.
1769                      */
1770 
1771                     int parseErrorsBefore;
1772 
1773                     /*
1774                      * We're serious here, but if the commands were bogus, we're
1775                      * also dead...
1776                      */
1777                     if (!cmdsOK) {
1778                               PrintOnError(gn, "\n");       /* provide some clue */
1779                               DieHorribly();
1780                     }
1781 
1782                     parseErrorsBefore = parseErrors;
1783                     JobWriteShellCommands(job, gn, &run);
1784                     if (parseErrors != parseErrorsBefore)
1785                               run = false;
1786                     (void)fflush(job->cmdFILE);
1787           } else if (!GNode_ShouldExecute(gn)) {
1788                     /*
1789                      * Just write all the commands to stdout in one fell swoop.
1790                      * This still sets up job->tailCmds correctly.
1791                      */
1792                     SwitchOutputTo(gn);
1793                     job->cmdFILE = stdout;
1794                     if (cmdsOK)
1795                               JobWriteCommands(job);
1796                     run = false;
1797                     (void)fflush(job->cmdFILE);
1798           } else {
1799                     Job_Touch(gn, job->echo);
1800                     run = false;
1801           }
1802 
1803           /* If we're not supposed to execute a shell, don't. */
1804           if (!run) {
1805                     if (!job->special)
1806                               TokenPool_Return();
1807                     /* Unlink and close the command file if we opened one */
1808                     if (job->cmdFILE != NULL && job->cmdFILE != stdout) {
1809                               (void)fclose(job->cmdFILE);
1810                               job->cmdFILE = NULL;
1811                     }
1812 
1813                     /*
1814                      * We only want to work our way up the graph if we aren't
1815                      * here because the commands for the job were no good.
1816                      */
1817                     if (cmdsOK && aborting == ABORT_NONE) {
1818                               JobSaveCommands(job);
1819                               job->node->made = MADE;
1820                               Make_Update(job->node);
1821                     }
1822                     job->status = JOB_ST_FREE;
1823                     return;
1824           }
1825 
1826           /*
1827            * Set up the control arguments to the shell. This is based on the
1828            * flags set earlier for this job.
1829            */
1830           JobMakeArgv(job, argv);
1831 
1832           /* Create the pipe by which we'll get the shell's output. */
1833           JobCreatePipe(job, 3);
1834 
1835           JobExec(job, argv);
1836 }
1837 
1838 /*
1839  * If the shell has an output filter (which only csh and ksh have by default),
1840  * print the output of the child process, skipping the noPrint text of the
1841  * shell.
1842  *
1843  * Return the part of the output that the calling function needs to output by
1844  * itself.
1845  */
1846 static char *
PrintFilteredOutput(char * p,const char * endp)1847 PrintFilteredOutput(char *p, const char *endp)    /* XXX: p should be const */
1848 {
1849           char *ep;           /* XXX: should be const */
1850 
1851           if (shell->noPrint == NULL || shell->noPrint[0] == '\0')
1852                     return p;
1853 
1854           /*
1855            * XXX: What happens if shell->noPrint occurs on the boundary of
1856            * the buffer?  To work correctly in all cases, this should rather
1857            * be a proper stream filter instead of doing string matching on
1858            * selected chunks of the output.
1859            */
1860           while ((ep = strstr(p, shell->noPrint)) != NULL) {
1861                     if (ep != p) {
1862                               *ep = '\0';         /* XXX: avoid writing to the buffer */
1863                               /*
1864                                * The only way there wouldn't be a newline after
1865                                * this line is if it were the last in the buffer.
1866                                * however, since the noPrint output comes after it,
1867                                * there must be a newline, so we don't print one.
1868                                */
1869                               /* XXX: What about null bytes in the output? */
1870                               (void)fprintf(stdout, "%s", p);
1871                               (void)fflush(stdout);
1872                     }
1873                     p = ep + shell->noPrintLen;
1874                     if (p == endp)
1875                               break;
1876                     p++;                /* skip over the (XXX: assumed) newline */
1877                     pp_skip_whitespace(&p);
1878           }
1879           return p;
1880 }
1881 
1882 /*
1883  * This function is called whenever there is something to read on the pipe.
1884  * We collect more output from the given job and store it in the job's
1885  * outBuf. If this makes up a line, we print it tagged by the job's
1886  * identifier, as necessary.
1887  *
1888  * In the output of the shell, the 'noPrint' lines are removed. If the
1889  * command is not alone on the line (the character after it is not \0 or
1890  * \n), we do print whatever follows it.
1891  *
1892  * Input:
1893  *        job                 the job whose output needs printing
1894  *        finish              true if this is the last time we'll be called
1895  *                            for this job
1896  */
1897 static void
CollectOutput(Job * job,bool finish)1898 CollectOutput(Job *job, bool finish)
1899 {
1900           bool gotNL;                   /* true if got a newline */
1901           bool fbuf;                    /* true if our buffer filled up */
1902           size_t nr;                    /* number of bytes read */
1903           size_t i;           /* auxiliary index into outBuf */
1904           size_t max;                   /* limit for i (end of current data) */
1905           ssize_t nRead;                /* (Temporary) number of bytes read */
1906 
1907           /* Read as many bytes as will fit in the buffer. */
1908 again:
1909           gotNL = false;
1910           fbuf = false;
1911 
1912           nRead = read(job->inPipe, &job->outBuf[job->curPos],
1913               JOB_BUFSIZE - job->curPos);
1914           if (nRead < 0) {
1915                     if (errno == EAGAIN)
1916                               return;
1917                     if (DEBUG(JOB))
1918                               perror("CollectOutput(piperead)");
1919                     nr = 0;
1920           } else
1921                     nr = (size_t)nRead;
1922 
1923           if (nr == 0)
1924                     finish = false;     /* stop looping */
1925 
1926           /*
1927            * If we hit the end-of-file (the job is dead), we must flush its
1928            * remaining output, so pretend we read a newline if there's any
1929            * output remaining in the buffer.
1930            */
1931           if (nr == 0 && job->curPos != 0) {
1932                     job->outBuf[job->curPos] = '\n';
1933                     nr = 1;
1934           }
1935 
1936           max = job->curPos + nr;
1937           for (i = job->curPos; i < max; i++)
1938                     if (job->outBuf[i] == '\0')
1939                               job->outBuf[i] = ' ';
1940 
1941           /* Look for the last newline in the bytes we just got. */
1942           for (i = job->curPos + nr - 1;
1943                i >= job->curPos && i != (size_t)-1; i--) {
1944                     if (job->outBuf[i] == '\n') {
1945                               gotNL = true;
1946                               break;
1947                     }
1948           }
1949 
1950           if (!gotNL) {
1951                     job->curPos += nr;
1952                     if (job->curPos == JOB_BUFSIZE) {
1953                               /*
1954                                * If we've run out of buffer space, we have no choice
1955                                * but to print the stuff. sigh.
1956                                */
1957                               fbuf = true;
1958                               i = job->curPos;
1959                     }
1960           }
1961           if (gotNL || fbuf) {
1962                     /*
1963                      * Need to send the output to the screen. Null terminate it
1964                      * first, overwriting the newline character if there was one.
1965                      * So long as the line isn't one we should filter (according
1966                      * to the shell description), we print the line, preceded
1967                      * by a target banner if this target isn't the same as the
1968                      * one for which we last printed something.
1969                      * The rest of the data in the buffer are then shifted down
1970                      * to the start of the buffer and curPos is set accordingly.
1971                      */
1972                     job->outBuf[i] = '\0';
1973                     if (i >= job->curPos) {
1974                               char *p;
1975 
1976                               /*
1977                                * FIXME: SwitchOutputTo should be here, according to
1978                                * the comment above.  But since PrintOutput does not
1979                                * do anything in the default shell, this bug has gone
1980                                * unnoticed until now.
1981                                */
1982                               p = PrintFilteredOutput(job->outBuf, &job->outBuf[i]);
1983 
1984                               /*
1985                                * There's still more in the output buffer. This time,
1986                                * though, we know there's no newline at the end, so
1987                                * we add one of our own free will.
1988                                */
1989                               if (*p != '\0') {
1990                                         if (!opts.silent)
1991                                                   SwitchOutputTo(job->node);
1992 #ifdef USE_META
1993                                         if (useMeta) {
1994                                                   meta_job_output(job, p,
1995                                                       gotNL ? "\n" : "");
1996                                         }
1997 #endif
1998                                         (void)fprintf(stdout, "%s%s", p,
1999                                             gotNL ? "\n" : "");
2000                                         (void)fflush(stdout);
2001                               }
2002                     }
2003                     /*
2004                      * max is the last offset still in the buffer. Move any
2005                      * remaining characters to the start of the buffer and
2006                      * update the end marker curPos.
2007                      */
2008                     if (i < max) {
2009                               (void)memmove(job->outBuf, &job->outBuf[i + 1],
2010                                   max - (i + 1));
2011                               job->curPos = max - (i + 1);
2012                     } else {
2013                               assert(i == max);
2014                               job->curPos = 0;
2015                     }
2016           }
2017           if (finish) {
2018                     /*
2019                      * If the finish flag is true, we must loop until we hit
2020                      * end-of-file on the pipe. This is guaranteed to happen
2021                      * eventually since the other end of the pipe is now closed
2022                      * (we closed it explicitly and the child has exited). When
2023                      * we do get an EOF, finish will be set false and we'll fall
2024                      * through and out.
2025                      */
2026                     goto again;
2027           }
2028 }
2029 
2030 static void
JobRun(GNode * targ)2031 JobRun(GNode *targ)
2032 {
2033           /* Don't let these special jobs overlap with other unrelated jobs. */
2034           Compat_Make(targ, targ);
2035           if (GNode_IsError(targ)) {
2036                     PrintOnError(targ, "\n\nStop.\n");
2037                     exit(1);
2038           }
2039 }
2040 
2041 void
Job_CatchChildren(void)2042 Job_CatchChildren(void)
2043 {
2044           int pid;
2045           int status;
2046 
2047           if (jobTokensRunning == 0)
2048                     return;
2049           if (caught_sigchld == 0)
2050                     return;
2051           caught_sigchld = 0;
2052 
2053           while ((pid = waitpid((pid_t)-1, &status, WNOHANG | WUNTRACED)) > 0) {
2054                     DEBUG2(JOB, "Process %d exited/stopped status %x.\n",
2055                         pid, status);
2056                     JobReapChild(pid, status, true);
2057           }
2058 }
2059 
2060 /*
2061  * It is possible that wait[pid]() was called from elsewhere,
2062  * this lets us reap jobs regardless.
2063  */
2064 void
JobReapChild(pid_t pid,int status,bool isJobs)2065 JobReapChild(pid_t pid, int status, bool isJobs)
2066 {
2067           Job *job;
2068 
2069           if (jobTokensRunning == 0)
2070                     return;
2071 
2072           job = JobFindPid(pid, JOB_ST_RUNNING, isJobs);
2073           if (job == NULL) {
2074                     if (isJobs && !lurking_children)
2075                               Error("Child (%d) status %x not in table?",
2076                                   pid, status);
2077                     return;
2078           }
2079 
2080           if (WIFSTOPPED(status)) {
2081                     DEBUG2(JOB, "Process %d (%s) stopped.\n",
2082                         job->pid, job->node->name);
2083                     if (!make_suspended) {
2084                               switch (WSTOPSIG(status)) {
2085                               case SIGTSTP:
2086                                         (void)printf("*** [%s] Suspended\n",
2087                                             job->node->name);
2088                                         break;
2089                               case SIGSTOP:
2090                                         (void)printf("*** [%s] Stopped\n",
2091                                             job->node->name);
2092                                         break;
2093                               default:
2094                                         (void)printf("*** [%s] Stopped -- signal %d\n",
2095                                             job->node->name, WSTOPSIG(status));
2096                               }
2097                               job->suspended = true;
2098                     }
2099                     (void)fflush(stdout);
2100                     return;
2101           }
2102 
2103           job->status = JOB_ST_FINISHED;
2104           job->exit_status = status;
2105           if (WIFEXITED(status))
2106                     job->node->exit_status = WEXITSTATUS(status);
2107 
2108           JobFinish(job, status);
2109 }
2110 
2111 void
Job_CatchOutput(void)2112 Job_CatchOutput(void)
2113 {
2114           int nready;
2115           Job *job;
2116           unsigned i;
2117 
2118           (void)fflush(stdout);
2119 
2120           do {
2121                     /* Maybe skip the job token pipe. */
2122                     nfds_t skip = wantToken ? 0 : 1;
2123                     nready = poll(fds + skip, fdsLen - skip, POLL_MSEC);
2124           } while (nready < 0 && errno == EINTR);
2125 
2126           if (nready < 0)
2127                     Punt("poll: %s", strerror(errno));
2128 
2129           if (nready > 0 && childExitJob.inPollfd->revents & POLLIN) {
2130                     char token;
2131                     ssize_t count = read(childExitJob.inPipe, &token, 1);
2132                     if (count == 1) {
2133                               if (token == DO_JOB_RESUME[0])
2134                                         /*
2135                                          * Complete relay requested from our SIGCONT
2136                                          * handler.
2137                                          */
2138                                         JobRestartJobs();
2139                     } else if (count == 0)
2140                               Punt("unexpected eof on token pipe");
2141                     else
2142                               Punt("token pipe read: %s", strerror(errno));
2143                     nready--;
2144           }
2145 
2146           Job_CatchChildren();
2147           if (nready == 0)
2148                     return;
2149 
2150           for (i = npseudojobs * nfds_per_job(); i < fdsLen; i++) {
2151                     if (fds[i].revents == 0)
2152                               continue;
2153                     job = jobByFdIndex[i];
2154                     if (job->status == JOB_ST_RUNNING)
2155                               CollectOutput(job, false);
2156 #if defined(USE_FILEMON) && !defined(USE_FILEMON_DEV)
2157                     /*
2158                      * With meta mode, we may have activity on the job's filemon
2159                      * descriptor too, which at the moment is any pollfd other
2160                      * than job->inPollfd.
2161                      */
2162                     if (useMeta && job->inPollfd != &fds[i]) {
2163                               if (meta_job_event(job) <= 0)
2164                                         fds[i].events = 0;  /* never mind */
2165                     }
2166 #endif
2167                     if (--nready == 0)
2168                               return;
2169           }
2170 }
2171 
2172 static void
InitShellNameAndPath(void)2173 InitShellNameAndPath(void)
2174 {
2175           shellName = shell->name;
2176 
2177 #ifdef DEFSHELL_CUSTOM
2178           if (shellName[0] == '/') {
2179                     shellPath = bmake_strdup(shellName);
2180                     shellName = str_basename(shellPath);
2181                     return;
2182           }
2183 #endif
2184 
2185           shellPath = str_concat3(_PATH_DEFSHELLDIR, "/", shellName);
2186 }
2187 
2188 void
Shell_Init(void)2189 Shell_Init(void)
2190 {
2191           if (shellPath == NULL)
2192                     InitShellNameAndPath();
2193 
2194           Var_SetWithFlags(SCOPE_CMDLINE, ".SHELL", shellPath,
2195                                VAR_SET_INTERNAL|VAR_SET_READONLY);
2196           if (shell->errFlag == NULL)
2197                     shell->errFlag = "";
2198           if (shell->echoFlag == NULL)
2199                     shell->echoFlag = "";
2200           if (shell->hasErrCtl && shell->errFlag[0] != '\0') {
2201                     if (shellErrFlag != NULL &&
2202                         strcmp(shell->errFlag, &shellErrFlag[1]) != 0) {
2203                               free(shellErrFlag);
2204                               shellErrFlag = NULL;
2205                     }
2206                     if (shellErrFlag == NULL)
2207                               shellErrFlag = str_concat2("-", shell->errFlag);
2208           } else if (shellErrFlag != NULL) {
2209                     free(shellErrFlag);
2210                     shellErrFlag = NULL;
2211           }
2212 }
2213 
2214 /* Return the shell string literal that results in a newline character. */
2215 const char *
Shell_GetNewline(void)2216 Shell_GetNewline(void)
2217 {
2218           return shell->newline;
2219 }
2220 
2221 void
Job_SetPrefix(void)2222 Job_SetPrefix(void)
2223 {
2224           if (targPrefix != NULL)
2225                     free(targPrefix);
2226           else if (!Var_Exists(SCOPE_GLOBAL, ".MAKE.JOB.PREFIX"))
2227                     Global_Set(".MAKE.JOB.PREFIX", "---");
2228 
2229           targPrefix = Var_Subst("${.MAKE.JOB.PREFIX}",
2230               SCOPE_GLOBAL, VARE_EVAL);
2231           /* TODO: handle errors */
2232 }
2233 
2234 static void
AddSig(int sig,SignalProc handler)2235 AddSig(int sig, SignalProc handler)
2236 {
2237           if (bmake_signal(sig, SIG_IGN) != SIG_IGN) {
2238                     sigaddset(&caught_signals, sig);
2239                     (void)bmake_signal(sig, handler);
2240           }
2241 }
2242 
2243 void
Job_Init(void)2244 Job_Init(void)
2245 {
2246           Job_SetPrefix();
2247 
2248           job_table = bmake_malloc((size_t)opts.maxJobs * sizeof *job_table);
2249           memset(job_table, 0, (size_t)opts.maxJobs * sizeof *job_table);
2250           job_table_end = job_table + opts.maxJobs;
2251           wantToken = false;
2252           caught_sigchld = 0;
2253 
2254           aborting = ABORT_NONE;
2255           job_errors = 0;
2256 
2257           /*
2258            * There is a non-zero chance that we already have children,
2259            * e.g. after 'make -f- <<EOF'.
2260            * Since their termination causes a 'Child (pid) not in table'
2261            * message, Collect the status of any that are already dead, and
2262            * suppress the error message if there are any undead ones.
2263            */
2264           for (;;) {
2265                     int rval, status;
2266                     rval = waitpid((pid_t)-1, &status, WNOHANG);
2267                     if (rval > 0)
2268                               continue;
2269                     if (rval == 0)
2270                               lurking_children = true;
2271                     break;
2272           }
2273 
2274           Shell_Init();
2275 
2276           JobCreatePipe(&childExitJob, 3);
2277 
2278           {
2279                     size_t nfds = (npseudojobs + (size_t)opts.maxJobs) *
2280                                     nfds_per_job();
2281                     fds = bmake_malloc(sizeof *fds * nfds);
2282                     jobByFdIndex = bmake_malloc(sizeof *jobByFdIndex * nfds);
2283           }
2284 
2285           /* These are permanent entries and take slots 0 and 1 */
2286           watchfd(&tokenPoolJob);
2287           watchfd(&childExitJob);
2288 
2289           sigemptyset(&caught_signals);
2290           (void)bmake_signal(SIGCHLD, JobChildSig);
2291           sigaddset(&caught_signals, SIGCHLD);
2292 
2293           /* Handle the signals specified by POSIX. */
2294           AddSig(SIGINT, JobPassSig_int);
2295           AddSig(SIGHUP, JobPassSig_term);
2296           AddSig(SIGTERM, JobPassSig_term);
2297           AddSig(SIGQUIT, JobPassSig_term);
2298 
2299           /*
2300            * These signals need to be passed to the jobs, as each job has its
2301            * own process group and thus the terminal driver doesn't forward the
2302            * signals itself.
2303            */
2304           AddSig(SIGTSTP, JobPassSig_suspend);
2305           AddSig(SIGTTOU, JobPassSig_suspend);
2306           AddSig(SIGTTIN, JobPassSig_suspend);
2307           AddSig(SIGWINCH, JobCondPassSig);
2308           AddSig(SIGCONT, JobContinueSig);
2309 
2310           (void)Job_RunTarget(".BEGIN", NULL);
2311           /* Create the .END node, see Targ_GetEndNode in Compat_MakeAll. */
2312           (void)Targ_GetEndNode();
2313 }
2314 
2315 static void
DelSig(int sig)2316 DelSig(int sig)
2317 {
2318           if (sigismember(&caught_signals, sig) != 0)
2319                     (void)bmake_signal(sig, SIG_DFL);
2320 }
2321 
2322 static void
JobSigReset(void)2323 JobSigReset(void)
2324 {
2325           DelSig(SIGINT);
2326           DelSig(SIGHUP);
2327           DelSig(SIGQUIT);
2328           DelSig(SIGTERM);
2329           DelSig(SIGTSTP);
2330           DelSig(SIGTTOU);
2331           DelSig(SIGTTIN);
2332           DelSig(SIGWINCH);
2333           DelSig(SIGCONT);
2334           (void)bmake_signal(SIGCHLD, SIG_DFL);
2335 }
2336 
2337 static Shell *
FindShellByName(const char * name)2338 FindShellByName(const char *name)
2339 {
2340           Shell *sh = shells;
2341           const Shell *shellsEnd = sh + sizeof shells / sizeof shells[0];
2342 
2343           for (sh = shells; sh < shellsEnd; sh++) {
2344                     if (strcmp(name, sh->name) == 0)
2345                               return sh;
2346           }
2347           return NULL;
2348 }
2349 
2350 /*
2351  * Parse a shell specification and set up 'shell', shellPath and
2352  * shellName appropriately.
2353  *
2354  * Input:
2355  *        line                The shell spec
2356  *
2357  * Results:
2358  *        Returns false if the specification was incorrect.
2359  *        If successful, 'shell' is usable, shellPath is the full path of the
2360  *        shell described by 'shell', and shellName is the final component of
2361  *        shellPath.
2362  *
2363  * Notes:
2364  *        A shell specification has the form ".SHELL: keyword=value...". Double
2365  *        quotes can be used to enclose blanks in words. A backslash escapes
2366  *        anything (most notably a double-quote and a space) and
2367  *        provides the usual escape sequences from C. There should be no
2368  *        unnecessary spaces in the word. The keywords are:
2369  *            name  Name of shell.
2370  *            path  Location of shell.
2371  *            quiet Command to turn off echoing.
2372  *            echo  Command to turn echoing on
2373  *            filter          The output from the shell command that turns off
2374  *                            echoing, to be filtered from the final output.
2375  *            echoFlag        Flag to turn echoing on at the start.
2376  *            errFlag         Flag to turn error checking on at the start.
2377  *            hasErrCtl       True if the shell has error checking control.
2378  *            newline         String literal to represent a newline character.
2379  *            check If hasErrCtl is true: The command to turn on error
2380  *                            checking. If hasErrCtl is false: The template for a
2381  *                            shell command that echoes a command for which error
2382  *                            checking is off.
2383  *            ignore          If hasErrCtl is true: The command to turn off error
2384  *                            checking. If hasErrCtl is false: The template for a
2385  *                            shell command that executes a command so as to ignore
2386  *                            any errors it returns.
2387  */
2388 bool
Job_ParseShell(char * line)2389 Job_ParseShell(char *line)
2390 {
2391           Words wordsList;
2392           char **words;
2393           char **argv;
2394           size_t argc;
2395           char *path;
2396           Shell newShell;
2397           bool fullSpec = false;
2398           Shell *sh;
2399 
2400           /* XXX: don't use line as an iterator variable */
2401           pp_skip_whitespace(&line);
2402 
2403           free(shell_freeIt);
2404 
2405           memset(&newShell, 0, sizeof newShell);
2406 
2407           wordsList = Str_Words(line, true);
2408           words = wordsList.words;
2409           argc = wordsList.len;
2410           path = wordsList.freeIt;
2411           if (words == NULL) {
2412                     Error("Unterminated quoted string [%s]", line);
2413                     return false;
2414           }
2415           shell_freeIt = path;
2416 
2417           for (path = NULL, argv = words; argc != 0; argc--, argv++) {
2418                     char *arg = *argv;
2419                     if (strncmp(arg, "path=", 5) == 0) {
2420                               path = arg + 5;
2421                     } else if (strncmp(arg, "name=", 5) == 0) {
2422                               newShell.name = arg + 5;
2423                     } else {
2424                               if (strncmp(arg, "quiet=", 6) == 0) {
2425                                         newShell.echoOff = arg + 6;
2426                               } else if (strncmp(arg, "echo=", 5) == 0) {
2427                                         newShell.echoOn = arg + 5;
2428                               } else if (strncmp(arg, "filter=", 7) == 0) {
2429                                         newShell.noPrint = arg + 7;
2430                                         newShell.noPrintLen = strlen(newShell.noPrint);
2431                               } else if (strncmp(arg, "echoFlag=", 9) == 0) {
2432                                         newShell.echoFlag = arg + 9;
2433                               } else if (strncmp(arg, "errFlag=", 8) == 0) {
2434                                         newShell.errFlag = arg + 8;
2435                               } else if (strncmp(arg, "hasErrCtl=", 10) == 0) {
2436                                         char c = arg[10];
2437                                         newShell.hasErrCtl = c == 'Y' || c == 'y' ||
2438                                                                  c == 'T' || c == 't';
2439                               } else if (strncmp(arg, "newline=", 8) == 0) {
2440                                         newShell.newline = arg + 8;
2441                               } else if (strncmp(arg, "check=", 6) == 0) {
2442                                         /*
2443                                          * Before 2020-12-10, these two variables had
2444                                          * been a single variable.
2445                                          */
2446                                         newShell.errOn = arg + 6;
2447                                         newShell.echoTmpl = arg + 6;
2448                               } else if (strncmp(arg, "ignore=", 7) == 0) {
2449                                         /*
2450                                          * Before 2020-12-10, these two variables had
2451                                          * been a single variable.
2452                                          */
2453                                         newShell.errOff = arg + 7;
2454                                         newShell.runIgnTmpl = arg + 7;
2455                               } else if (strncmp(arg, "errout=", 7) == 0) {
2456                                         newShell.runChkTmpl = arg + 7;
2457                               } else if (strncmp(arg, "comment=", 8) == 0) {
2458                                         newShell.commentChar = arg[8];
2459                               } else {
2460                                         Parse_Error(PARSE_FATAL,
2461                                             "Unknown keyword \"%s\"", arg);
2462                                         free(words);
2463                                         return false;
2464                               }
2465                               fullSpec = true;
2466                     }
2467           }
2468 
2469           if (path == NULL) {
2470                     if (newShell.name == NULL) {
2471                               Parse_Error(PARSE_FATAL,
2472                                   "Neither path nor name specified");
2473                               free(words);
2474                               return false;
2475                     } else {
2476                               if ((sh = FindShellByName(newShell.name)) == NULL) {
2477                                         Parse_Error(PARSE_WARNING,
2478                                             "%s: No matching shell", newShell.name);
2479                                         free(words);
2480                                         return false;
2481                               }
2482                               shell = sh;
2483                               shellName = newShell.name;
2484                               if (shellPath != NULL) {
2485                                         free(shellPath);
2486                                         shellPath = NULL;
2487                                         Shell_Init();
2488                               }
2489                     }
2490           } else {
2491                     free(shellPath);
2492                     shellPath = bmake_strdup(path);
2493                     shellName = newShell.name != NULL ? newShell.name
2494                         : str_basename(path);
2495                     if (!fullSpec) {
2496                               if ((sh = FindShellByName(shellName)) == NULL) {
2497                                         Parse_Error(PARSE_WARNING,
2498                                             "%s: No matching shell", shellName);
2499                                         free(words);
2500                                         return false;
2501                               }
2502                               shell = sh;
2503                     } else {
2504                               shell = bmake_malloc(sizeof *shell);
2505                               *shell = newShell;
2506                     }
2507                     /* This will take care of shellErrFlag. */
2508                     Shell_Init();
2509           }
2510 
2511           if (shell->echoOn != NULL && shell->echoOff != NULL)
2512                     shell->hasEchoCtl = true;
2513 
2514           if (!shell->hasErrCtl) {
2515                     if (shell->echoTmpl == NULL)
2516                               shell->echoTmpl = "";
2517                     if (shell->runIgnTmpl == NULL)
2518                               shell->runIgnTmpl = "%s\n";
2519           }
2520 
2521           /*
2522            * Do not free up the words themselves, since they may be in use
2523            * by the shell specification.
2524            */
2525           free(words);
2526           return true;
2527 }
2528 
2529 /*
2530  * After receiving an interrupt signal, terminate all child processes and if
2531  * necessary make the .INTERRUPT target.
2532  */
2533 static void
JobInterrupt(bool runINTERRUPT,int signo)2534 JobInterrupt(bool runINTERRUPT, int signo)
2535 {
2536           Job *job;
2537           GNode *interrupt;
2538           sigset_t mask;
2539 
2540           aborting = ABORT_INTERRUPT;
2541 
2542           JobsTable_Lock(&mask);
2543 
2544           for (job = job_table; job < job_table_end; job++) {
2545                     if (job->status == JOB_ST_RUNNING && job->pid != 0) {
2546                               DEBUG2(JOB,
2547                                   "JobInterrupt passing signal %d to child %d.\n",
2548                                   signo, job->pid);
2549                               KILLPG(job->pid, signo);
2550                     }
2551           }
2552 
2553           for (job = job_table; job < job_table_end; job++) {
2554                     if (job->status == JOB_ST_RUNNING && job->pid != 0) {
2555                               int status;
2556                               (void)waitpid(job->pid, &status, 0);
2557                               JobDeleteTarget(job->node);
2558                     }
2559           }
2560 
2561           JobsTable_Unlock(&mask);
2562 
2563           if (runINTERRUPT && !opts.touch) {
2564                     interrupt = Targ_FindNode(".INTERRUPT");
2565                     if (interrupt != NULL) {
2566                               opts.ignoreErrors = false;
2567                               JobRun(interrupt);
2568                     }
2569           }
2570           Trace_Log(MAKEINTR, NULL);
2571           exit(signo);                  /* XXX: why signo? */
2572 }
2573 
2574 /* Make the .END target, returning the number of job-related errors. */
2575 int
Job_Finish(void)2576 Job_Finish(void)
2577 {
2578           GNode *endNode = Targ_GetEndNode();
2579           if (!Lst_IsEmpty(&endNode->commands) ||
2580               !Lst_IsEmpty(&endNode->children)) {
2581                     if (job_errors != 0)
2582                               Error("Errors reported so .END ignored");
2583                     else
2584                               JobRun(endNode);
2585           }
2586           return job_errors;
2587 }
2588 
2589 #ifdef CLEANUP
2590 void
Job_End(void)2591 Job_End(void)
2592 {
2593           free(shell_freeIt);
2594 }
2595 #endif
2596 
2597 /* Waits for all running jobs to finish. */
2598 void
Job_Wait(void)2599 Job_Wait(void)
2600 {
2601           aborting = ABORT_WAIT;        /* Prevent other jobs from starting. */
2602           while (jobTokensRunning != 0)
2603                     Job_CatchOutput();
2604           aborting = ABORT_NONE;
2605 }
2606 
2607 /*
2608  * Abort all currently running jobs without handling output or anything.
2609  * This function is to be called only in the event of a major error.
2610  * Most definitely NOT to be called from JobInterrupt.
2611  */
2612 void
Job_AbortAll(void)2613 Job_AbortAll(void)
2614 {
2615           Job *job;
2616           int status;
2617 
2618           aborting = ABORT_ERROR;
2619 
2620           if (jobTokensRunning != 0) {
2621                     for (job = job_table; job < job_table_end; job++) {
2622                               if (job->status != JOB_ST_RUNNING)
2623                                         continue;
2624                               KILLPG(job->pid, SIGINT);
2625                               KILLPG(job->pid, SIGKILL);
2626                     }
2627           }
2628 
2629           while (waitpid((pid_t)-1, &status, WNOHANG) > 0)
2630                     continue;
2631 }
2632 
2633 /*
2634  * Tries to restart stopped jobs if there are slots available.
2635  * Called in response to a SIGCONT.
2636  */
2637 static void
JobRestartJobs(void)2638 JobRestartJobs(void)
2639 {
2640           Job *job;
2641 
2642           for (job = job_table; job < job_table_end; job++) {
2643                     if (job->status == JOB_ST_RUNNING &&
2644                         (make_suspended || job->suspended)) {
2645                               DEBUG1(JOB, "Restarting stopped job pid %d.\n",
2646                                   job->pid);
2647                               if (job->suspended) {
2648                                         (void)printf("*** [%s] Continued\n",
2649                                             job->node->name);
2650                                         (void)fflush(stdout);
2651                               }
2652                               job->suspended = false;
2653                               if (KILLPG(job->pid, SIGCONT) != 0)
2654                                         DEBUG1(JOB, "Failed to send SIGCONT to %d\n",
2655                                             job->pid);
2656                     }
2657                     if (job->status == JOB_ST_FINISHED) {
2658                               /*
2659                                * Job exit deferred after calling waitpid() in a
2660                                * signal handler
2661                                */
2662                               JobFinish(job, job->exit_status);
2663                     }
2664           }
2665           make_suspended = false;
2666 }
2667 
2668 static void
watchfd(Job * job)2669 watchfd(Job *job)
2670 {
2671           if (job->inPollfd != NULL)
2672                     Punt("Watching watched job");
2673 
2674           fds[fdsLen].fd = job->inPipe;
2675           fds[fdsLen].events = POLLIN;
2676           jobByFdIndex[fdsLen] = job;
2677           job->inPollfd = &fds[fdsLen];
2678           fdsLen++;
2679 #if defined(USE_FILEMON) && !defined(USE_FILEMON_DEV)
2680           if (useMeta) {
2681                     fds[fdsLen].fd = meta_job_fd(job);
2682                     fds[fdsLen].events = fds[fdsLen].fd == -1 ? 0 : POLLIN;
2683                     jobByFdIndex[fdsLen] = job;
2684                     fdsLen++;
2685           }
2686 #endif
2687 }
2688 
2689 static void
clearfd(Job * job)2690 clearfd(Job *job)
2691 {
2692           size_t i;
2693           if (job->inPollfd == NULL)
2694                     Punt("Unwatching unwatched job");
2695           i = (size_t)(job->inPollfd - fds);
2696           fdsLen--;
2697 #if defined(USE_FILEMON) && !defined(USE_FILEMON_DEV)
2698           if (useMeta) {
2699                     assert(nfds_per_job() == 2);
2700                     if (i % 2 != 0)
2701                               Punt("odd-numbered fd with meta");
2702                     fdsLen--;
2703           }
2704 #endif
2705           /* Move last job in table into hole made by dead job. */
2706           if (fdsLen != i) {
2707                     fds[i] = fds[fdsLen];
2708                     jobByFdIndex[i] = jobByFdIndex[fdsLen];
2709                     jobByFdIndex[i]->inPollfd = &fds[i];
2710 #if defined(USE_FILEMON) && !defined(USE_FILEMON_DEV)
2711                     if (useMeta) {
2712                               fds[i + 1] = fds[fdsLen + 1];
2713                               jobByFdIndex[i + 1] = jobByFdIndex[fdsLen + 1];
2714                     }
2715 #endif
2716           }
2717           job->inPollfd = NULL;
2718 }
2719 
2720 int
Job_TempFile(const char * pattern,char * tfile,size_t tfile_sz)2721 Job_TempFile(const char *pattern, char *tfile, size_t tfile_sz)
2722 {
2723           int fd;
2724           sigset_t mask;
2725 
2726           JobsTable_Lock(&mask);
2727           fd = mkTempFile(pattern, tfile, tfile_sz);
2728           if (tfile != NULL && !DEBUG(SCRIPT))
2729                     unlink(tfile);
2730           JobsTable_Unlock(&mask);
2731 
2732           return fd;
2733 }
2734 
2735 static void
TokenPool_Write(char tok)2736 TokenPool_Write(char tok)
2737 {
2738           if (write(tokenPoolJob.outPipe, &tok, 1) != 1)
2739                     Punt("Cannot write \"%c\" to the token pool: %s",
2740                         tok, strerror(errno));
2741 }
2742 
2743 /*
2744  * Put a token (back) into the job token pool.
2745  * This allows a make process to start a build job.
2746  */
2747 static void
TokenPool_Add(void)2748 TokenPool_Add(void)
2749 {
2750           char tok = JOB_TOKENS[aborting], tok1;
2751 
2752           /* If we are depositing an error token, flush everything else. */
2753           while (tok != '+' && read(tokenPoolJob.inPipe, &tok1, 1) == 1)
2754                     continue;
2755 
2756           DEBUG3(JOB, "TokenPool_Add: pid %d, aborting %s, token %c\n",
2757               getpid(), aborting_name[aborting], tok);
2758           TokenPool_Write(tok);
2759 }
2760 
2761 static void
TokenPool_InitClient(int jp_0,int jp_1)2762 TokenPool_InitClient(int jp_0, int jp_1)
2763 {
2764           tokenPoolJob.inPipe = jp_0;
2765           tokenPoolJob.outPipe = jp_1;
2766           (void)fcntl(jp_0, F_SETFD, FD_CLOEXEC);
2767           (void)fcntl(jp_1, F_SETFD, FD_CLOEXEC);
2768 }
2769 
2770 /* Prepare the job token pipe in the root make process. */
2771 static void
TokenPool_InitServer(int max_tokens)2772 TokenPool_InitServer(int max_tokens)
2773 {
2774           int i;
2775           char jobarg[64];
2776 
2777           JobCreatePipe(&tokenPoolJob, 15);
2778 
2779           snprintf(jobarg, sizeof jobarg, "%d,%d",
2780               tokenPoolJob.inPipe, tokenPoolJob.outPipe);
2781 
2782           Global_Append(MAKEFLAGS, "-J");
2783           Global_Append(MAKEFLAGS, jobarg);
2784 
2785           /*
2786            * Preload the job pipe with one token per job, save the one
2787            * "extra" token for the primary job.
2788            */
2789           SetNonblocking(tokenPoolJob.outPipe);
2790           for (i = 1; i < max_tokens; i++)
2791                     TokenPool_Add();
2792 }
2793 
2794 void
TokenPool_Init(int max_tokens,int jp_0,int jp_1)2795 TokenPool_Init(int max_tokens, int jp_0, int jp_1)
2796 {
2797           if (jp_0 >= 0 && jp_1 >= 0)
2798                     TokenPool_InitClient(jp_0, jp_1);
2799           else
2800                     TokenPool_InitServer(max_tokens);
2801 }
2802 
2803 /* Return a taken token to the pool. */
2804 void
TokenPool_Return(void)2805 TokenPool_Return(void)
2806 {
2807           jobTokensRunning--;
2808           if (jobTokensRunning < 0)
2809                     Punt("token botch");
2810           if (jobTokensRunning != 0 || JOB_TOKENS[aborting] != '+')
2811                     TokenPool_Add();
2812 }
2813 
2814 /*
2815  * Attempt to take a token from the pool.
2816  *
2817  * If the pool is empty, set wantToken so that we wake up when a token is
2818  * released.
2819  *
2820  * Returns true if a token was taken, and false if the pool is currently
2821  * empty.
2822  */
2823 bool
TokenPool_Take(void)2824 TokenPool_Take(void)
2825 {
2826           char tok, tok1;
2827           ssize_t count;
2828 
2829           wantToken = false;
2830           DEBUG3(JOB, "TokenPool_Take: pid %d, aborting %s, running %d\n",
2831               getpid(), aborting_name[aborting], jobTokensRunning);
2832 
2833           if (aborting != ABORT_NONE || jobTokensRunning >= opts.maxJobs)
2834                     return false;
2835 
2836           count = read(tokenPoolJob.inPipe, &tok, 1);
2837           if (count == 0)
2838                     Fatal("eof on job pipe");
2839           if (count < 0 && jobTokensRunning != 0) {
2840                     if (errno != EAGAIN)
2841                               Fatal("job pipe read: %s", strerror(errno));
2842                     DEBUG1(JOB, "TokenPool_Take: pid %d blocked for token\n",
2843                         getpid());
2844                     wantToken = true;
2845                     return false;
2846           }
2847 
2848           if (count == 1 && tok != '+') {
2849                     /* make being aborted - remove any other job tokens */
2850                     DEBUG2(JOB, "TokenPool_Take: pid %d aborted by token %c\n",
2851                         getpid(), tok);
2852                     while (read(tokenPoolJob.inPipe, &tok1, 1) == 1)
2853                               continue;
2854                     /* And put the stopper back */
2855                     TokenPool_Write(tok);
2856                     if (shouldDieQuietly(NULL, 1)) {
2857                               Job_Wait();
2858                               exit(6);
2859                     }
2860                     Fatal("A failure has been detected "
2861                           "in another branch of the parallel make");
2862           }
2863 
2864           if (count == 1 && jobTokensRunning == 0)
2865                     /* We didn't want the token really */
2866                     TokenPool_Write(tok);
2867 
2868           jobTokensRunning++;
2869           DEBUG1(JOB, "TokenPool_Take: pid %d took a token\n", getpid());
2870           return true;
2871 }
2872 
2873 /* Make the named target if found, exit if the target fails. */
2874 bool
Job_RunTarget(const char * target,const char * fname)2875 Job_RunTarget(const char *target, const char *fname)
2876 {
2877           GNode *gn = Targ_FindNode(target);
2878           if (gn == NULL)
2879                     return false;
2880 
2881           if (fname != NULL)
2882                     Var_Set(gn, ALLSRC, fname);
2883 
2884           JobRun(gn);
2885           return true;
2886 }
2887 
2888 #ifdef USE_SELECT
2889 int
emul_poll(struct pollfd * fd,int nfd,int timeout)2890 emul_poll(struct pollfd *fd, int nfd, int timeout)
2891 {
2892           fd_set rfds, wfds;
2893           int i, maxfd, nselect, npoll;
2894           struct timeval tv, *tvp;
2895           long usecs;
2896 
2897           FD_ZERO(&rfds);
2898           FD_ZERO(&wfds);
2899 
2900           maxfd = -1;
2901           for (i = 0; i < nfd; i++) {
2902                     fd[i].revents = 0;
2903 
2904                     if (fd[i].events & POLLIN)
2905                               FD_SET(fd[i].fd, &rfds);
2906 
2907                     if (fd[i].events & POLLOUT)
2908                               FD_SET(fd[i].fd, &wfds);
2909 
2910                     if (fd[i].fd > maxfd)
2911                               maxfd = fd[i].fd;
2912           }
2913 
2914           if (maxfd >= FD_SETSIZE) {
2915                     Punt("Ran out of fd_set slots; "
2916                          "recompile with a larger FD_SETSIZE.");
2917           }
2918 
2919           if (timeout < 0) {
2920                     tvp = NULL;
2921           } else {
2922                     usecs = timeout * 1000;
2923                     tv.tv_sec = usecs / 1000000;
2924                     tv.tv_usec = usecs % 1000000;
2925                     tvp = &tv;
2926           }
2927 
2928           nselect = select(maxfd + 1, &rfds, &wfds, NULL, tvp);
2929 
2930           if (nselect <= 0)
2931                     return nselect;
2932 
2933           npoll = 0;
2934           for (i = 0; i < nfd; i++) {
2935                     if (FD_ISSET(fd[i].fd, &rfds))
2936                               fd[i].revents |= POLLIN;
2937 
2938                     if (FD_ISSET(fd[i].fd, &wfds))
2939                               fd[i].revents |= POLLOUT;
2940 
2941                     if (fd[i].revents)
2942                               npoll++;
2943           }
2944 
2945           return npoll;
2946 }
2947 #endif                                  /* USE_SELECT */
2948