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