[BACK]Return to job.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / make

Annotation of src/usr.bin/make/job.c, Revision 1.121

1.121   ! espie       1: /*     $OpenBSD: job.c,v 1.120 2010/07/19 19:46:44 espie Exp $ */
1.6       millert     2: /*     $NetBSD: job.c,v 1.16 1996/11/06 17:59:08 christos Exp $        */
1.1       deraadt     3:
                      4: /*
                      5:  * Copyright (c) 1988, 1989, 1990 The Regents of the University of California.
                      6:  * Copyright (c) 1988, 1989 by Adam de Boor
                      7:  * Copyright (c) 1989 by Berkeley Softworks
                      8:  * All rights reserved.
                      9:  *
                     10:  * This code is derived from software contributed to Berkeley by
                     11:  * Adam de Boor.
                     12:  *
                     13:  * Redistribution and use in source and binary forms, with or without
                     14:  * modification, are permitted provided that the following conditions
                     15:  * are met:
                     16:  * 1. Redistributions of source code must retain the above copyright
                     17:  *    notice, this list of conditions and the following disclaimer.
                     18:  * 2. Redistributions in binary form must reproduce the above copyright
                     19:  *    notice, this list of conditions and the following disclaimer in the
                     20:  *    documentation and/or other materials provided with the distribution.
1.55      millert    21:  * 3. Neither the name of the University nor the names of its contributors
1.1       deraadt    22:  *    may be used to endorse or promote products derived from this software
                     23:  *    without specific prior written permission.
                     24:  *
                     25:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
                     26:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     27:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                     28:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
                     29:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     30:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
                     31:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     32:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     33:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     34:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     35:  * SUCH DAMAGE.
                     36:  */
                     37:
                     38: /*-
                     39:  * job.c --
                     40:  *     handle the creation etc. of our child processes.
                     41:  *
                     42:  * Interface:
1.40      espie      43:  *     Job_Make                Start the creation of the given target.
1.1       deraadt    44:  *
1.53      jmc        45:  *     Job_Init                Called to initialize this module. in addition,
1.40      espie      46:  *                             any commands attached to the .BEGIN target
                     47:  *                             are executed before this function returns.
                     48:  *                             Hence, the makefile must have been parsed
                     49:  *                             before this function is called.
                     50:  *
                     51:  *     Job_End                 Cleanup any memory used.
                     52:  *
1.117     espie      53:  *     can_start_job           Return true if we can start job
1.40      espie      54:  *
1.41      espie      55:  *     Job_Empty               Return true if the job table is completely
1.40      espie      56:  *                             empty.
                     57:  *
                     58:  *     Job_Finish              Perform any final processing which needs doing.
                     59:  *                             This includes the execution of any commands
                     60:  *                             which have been/were attached to the .END
                     61:  *                             target. It should only be called when the
                     62:  *                             job table is empty.
                     63:  *
1.117     espie      64:  *     Job_AbortAll            Abort all current jobs. It doesn't
1.40      espie      65:  *                             handle output or do anything for the jobs,
                     66:  *                             just kills them. It should only be called in
                     67:  *                             an emergency, as it were.
1.1       deraadt    68:  *
1.117     espie      69:  *     Job_Wait                Wait for all running jobs to finish.
1.1       deraadt    70:  */
                     71:
                     72: #include <sys/types.h>
                     73: #include <sys/wait.h>
1.41      espie      74: #include <ctype.h>
                     75: #include <errno.h>
1.1       deraadt    76: #include <fcntl.h>
1.41      espie      77: #include <signal.h>
1.69      espie      78: #include <stdarg.h>
1.1       deraadt    79: #include <stdio.h>
1.42      espie      80: #include <stdlib.h>
1.1       deraadt    81: #include <string.h>
1.41      espie      82: #include <unistd.h>
                     83: #include "config.h"
                     84: #include "defines.h"
1.1       deraadt    85: #include "job.h"
1.63      espie      86: #include "engine.h"
1.1       deraadt    87: #include "pathnames.h"
1.41      espie      88: #include "var.h"
                     89: #include "targ.h"
                     90: #include "error.h"
                     91: #include "lst.h"
                     92: #include "extern.h"
                     93: #include "gnode.h"
                     94: #include "memory.h"
                     95: #include "make.h"
                     96:
1.50      espie      97: /*
                     98:  * The SEL_ constants determine the maximum amount of time spent in select
                     99:  * before coming out to see if a child has finished. SEL_SEC is the number of
                    100:  * seconds and SEL_USEC is the number of micro-seconds
                    101:  */
                    102: #define SEL_SEC        0
                    103: #define SEL_USEC       500000
                    104:
                    105:
                    106: /*-
                    107:  * Job Table definitions.
                    108:  *
                    109:  * Each job has several things associated with it:
                    110:  *     1) The process id of the child shell
                    111:  *     2) The graph node describing the target being made by this job
1.93      espie     112:  *     3) An FILE* for writing out the commands. This is only
1.50      espie     113:  *        used before the job is actually started.
1.93      espie     114:  *     4) Things used for handling the shell's output.
1.76      espie     115:  *        the output is being caught via a pipe and
1.50      espie     116:  *        the descriptors of our pipe, an array in which output is line
                    117:  *        buffered and the current position in that buffer are all
1.78      espie     118:  *        maintained for each job.
1.93      espie     119:  *     5) A word of flags which determine how the module handles errors,
1.50      espie     120:  *        echoing, etc. for the job
                    121:  *
                    122:  * The job "table" is kept as a linked Lst in 'jobs', with the number of
                    123:  * active jobs maintained in the 'nJobs' variable. At no time will this
                    124:  * exceed the value of 'maxJobs', initialized by the Job_Init function.
                    125:  *
                    126:  * When a job is finished, the Make_Update function is called on each of the
                    127:  * parents of the node which was just remade. This takes care of the upward
                    128:  * traversal of the dependency graph.
                    129:  */
                    130: #define JOB_BUFSIZE    1024
1.101     espie     131: struct job_pipe {
                    132:        int fd;
                    133:        char buffer[JOB_BUFSIZE];
                    134:        size_t pos;
                    135: };
1.119     espie     136:
1.50      espie     137: typedef struct Job_ {
1.51      mpech     138:     pid_t      pid;        /* The child's process ID */
1.50      espie     139:     GNode      *node;      /* The target the child is making */
                    140:     short      flags;      /* Flags to control treatment of job */
1.117     espie     141:     LstNode    p;
1.111     espie     142: #define JOB_DIDOUTPUT  0x001
1.117     espie     143: #define JOB_IS_SPECIAL 0x004   /* Target is a special one. */
                    144: #define JOB_IS_EXPENSIVE 0x002
1.101     espie     145:     struct job_pipe in[2];
1.50      espie     146: } Job;
                    147:
1.117     espie     148: struct job_pid {
                    149:        pid_t pid;
                    150: };
1.78      espie     151:
1.40      espie     152: static int     aborting = 0;       /* why is the make aborting? */
                    153: #define ABORT_ERROR    1           /* Because of an error */
                    154: #define ABORT_INTERRUPT 2          /* Because it was interrupted */
                    155: #define ABORT_WAIT     3           /* Waiting for jobs to finish */
1.1       deraadt   156:
1.40      espie     157: static int     maxJobs;        /* The most children we can run at once */
1.117     espie     158: static int     nJobs;          /* The number of current children */
                    159: static bool    expensive_job;
1.95      espie     160: static LIST    runningJobs;    /* The structures that describe them */
1.48      espie     161: static GNode   *lastNode;      /* The node for which output was most recently
1.1       deraadt   162:                                 * produced. */
1.117     espie     163: static LIST    job_pids;       /* a simple list that doesn't move that much */
1.112     espie     164:
                    165: /* data structure linked to job handling through select */
                    166: static fd_set *output_mask = NULL;     /* File descriptors to look for */
1.119     espie     167:
1.112     espie     168: static fd_set *actual_mask = NULL;     /* actual select argument */
                    169: static int largest_fd = -1;
                    170: static size_t mask_size = 0;
                    171:
                    172: /* wait possibilities */
                    173: #define JOB_EXITED 0
                    174: #define JOB_SIGNALED 1
                    175: #define JOB_UNKNOWN 4
                    176:
1.101     espie     177: static LIST    errorsList;
                    178: static int     errors;
                    179: struct error_info {
1.112     espie     180:        int reason;
                    181:        int code;
1.111     espie     182:        GNode *n;
1.101     espie     183: };
                    184:
1.117     espie     185: /* for blocking/unblocking */
                    186: static sigset_t oset, set;
                    187: static void block_signals(void);
                    188: static void unblock_signals(void);
1.1       deraadt   189:
1.93      espie     190: static void handle_all_signals(void);
                    191: static void handle_signal(int);
1.40      espie     192: static int JobCmpPid(void *, void *);
1.117     espie     193: static void process_job_status(Job *, int);
1.101     espie     194: static void JobExec(Job *);
1.97      espie     195: static void JobStart(GNode *, int);
1.117     espie     196: static void JobInterrupt(bool, int);
1.84      espie     197: static void debug_printf(const char *, ...);
1.98      espie     198: static Job *prepare_job(GNode *, int);
1.105     espie     199: static void banner(Job *, FILE *);
1.117     espie     200: static bool Job_Full(void);
1.112     espie     201:
                    202: /***
                    203:  ***  Input/output from jobs
                    204:  ***/
                    205:
                    206: /* prepare_pipe(jp, &fd):
                    207:  *     set up pipe data structure (buffer and pos) corresponding to
                    208:  *     pointed fd, and prepare to watch for it.
                    209:  */
                    210: static void prepare_pipe(struct job_pipe *, int *);
                    211:
                    212: /* close_job_pipes(j):
                    213:  *     handle final output from job, and close pipes properly
                    214:  */
                    215: static void close_job_pipes(Job *);
                    216:
                    217:
                    218: static void handle_all_jobs_output(void);
                    219:
1.119     espie     220: /* handle_job_output(job, n, finish):
1.112     espie     221:  *     n = 0 or 1 (stdout/stderr), set finish to retrieve everything.
                    222:  */
                    223: static void handle_job_output(Job *, int, bool);
                    224:
1.101     espie     225: static void print_partial_buffer(struct job_pipe *, Job *, FILE *, size_t);
1.119     espie     226: static void print_partial_buffer_and_shift(struct job_pipe *, Job *, FILE *,
1.101     espie     227:     size_t);
                    228: static bool print_complete_lines(struct job_pipe *, Job *, FILE *, size_t);
1.112     espie     229:
                    230:
                    231: static void register_error(int, int, Job *);
1.111     espie     232: static void loop_handle_running_jobs(void);
                    233: static void Job_CatchChildren(void);
1.93      espie     234:
1.101     espie     235: static void
1.112     espie     236: register_error(int reason, int code, Job *job)
1.101     espie     237: {
                    238:        struct error_info *p;
1.1       deraadt   239:
1.101     espie     240:        errors++;
                    241:        p = emalloc(sizeof(struct error_info));
1.112     espie     242:        p->reason = reason;
                    243:        p->code = code;
1.111     espie     244:        p->n = job->node;
                    245:        Lst_AtEnd(&errorsList, p);
1.101     espie     246: }
1.93      espie     247:
1.101     espie     248: void
                    249: print_errors()
1.88      espie     250: {
1.101     espie     251:        LstNode ln;
                    252:        struct error_info *p;
1.111     espie     253:        const char *type;
1.88      espie     254:
1.101     espie     255:        for (ln = Lst_First(&errorsList); ln != NULL; ln = Lst_Adv(ln)) {
                    256:                p = (struct error_info *)Lst_Datum(ln);
1.112     espie     257:                switch(p->reason) {
                    258:                case JOB_EXITED:
1.111     espie     259:                        type = "Exit status";
1.112     espie     260:                        break;
                    261:                case JOB_SIGNALED:
1.111     espie     262:                        type = "Received signal";
1.112     espie     263:                        break;
                    264:                default:
                    265:                        type = "Should not happen";
                    266:                        break;
1.101     espie     267:                }
1.121   ! espie     268:        if (p->n->origin.lineno)
1.111     espie     269:                Error(" %s %d (%s, line %lu of %s)",
1.121   ! espie     270:                    type, p->code, p->n->name, p->n->origin.lineno, p->n->origin.fname);
1.119     espie     271:        else
1.112     espie     272:                Error(" %s %d (%s)", type, p->code, p->n->name);
1.101     espie     273:        }
1.88      espie     274: }
                    275:
1.57      espie     276: static void
1.105     espie     277: banner(Job *job, FILE *out)
1.57      espie     278: {
1.101     espie     279:        if (job->node != lastNode) {
1.119     espie     280:                if (DEBUG(JOBBANNER))
1.101     espie     281:                        (void)fprintf(out, "--- %s ---\n", job->node->name);
                    282:                lastNode = job->node;
1.57      espie     283:        }
                    284: }
                    285:
1.117     espie     286: volatile sig_atomic_t got_SIGTSTP, got_SIGTTOU, got_SIGTTIN, got_SIGWINCH,
                    287:     got_SIGCONT;
1.57      espie     288: static void
1.93      espie     289: handle_all_signals()
1.57      espie     290: {
1.117     espie     291:        while (got_signal) {
1.93      espie     292:                got_signal = 0;
                    293:
1.117     espie     294:                if (got_SIGINT) {
                    295:                        got_SIGINT=0;
                    296:                        handle_signal(SIGINT);
                    297:                }
                    298:                if (got_SIGHUP) {
                    299:                        got_SIGHUP=0;
                    300:                        handle_signal(SIGHUP);
                    301:                }
                    302:                if (got_SIGQUIT) {
                    303:                        got_SIGQUIT=0;
                    304:                        handle_signal(SIGQUIT);
                    305:                }
                    306:                if (got_SIGTERM) {
                    307:                        got_SIGTERM=0;
                    308:                        handle_signal(SIGTERM);
                    309:                }
                    310:                if (got_SIGTSTP) {
                    311:                        got_SIGTSTP=0;
                    312:                        signal(SIGTSTP, parallel_handler);
                    313:                }
                    314:                if (got_SIGTTOU) {
                    315:                        got_SIGTTOU=0;
                    316:                        signal(SIGTTOU, parallel_handler);
                    317:                }
                    318:                if (got_SIGTTIN) {
                    319:                        got_SIGTTIN=0;
                    320:                        signal(SIGTTIN, parallel_handler);
                    321:                }
                    322:                if (got_SIGWINCH) {
                    323:                        got_SIGWINCH=0;
                    324:                        signal(SIGWINCH, parallel_handler);
                    325:                }
                    326:                if (got_SIGCONT) {
                    327:                        got_SIGCONT = 0;
                    328:                        signal(SIGCONT, parallel_handler);
                    329:                }
1.57      espie     330:        }
                    331: }
                    332:
1.117     espie     333: /* this is safe from interrupts, actually */
                    334: void
                    335: parallel_handler(int signo)
1.1       deraadt   336: {
1.117     espie     337:        int save_errno = errno;
1.114     espie     338:        LstNode ln;
1.117     espie     339:        for (ln = Lst_First(&job_pids); ln != NULL; ln = Lst_Adv(ln)) {
                    340:                struct job_pid *p = Lst_Datum(ln);
                    341:                killpg(p->pid, signo);
                    342:        }
                    343:        errno = save_errno;
                    344:
                    345:        switch(signo) {
                    346:        case SIGINT:
                    347:                got_SIGINT++;
                    348:                got_signal = 1;
                    349:                return;
                    350:        case SIGHUP:
                    351:                got_SIGHUP++;
                    352:                got_signal = 1;
                    353:                return;
                    354:        case SIGQUIT:
                    355:                got_SIGQUIT++;
                    356:                got_signal = 1;
                    357:                return;
                    358:        case SIGTERM:
                    359:                got_SIGTERM++;
                    360:                got_signal = 1;
                    361:                return;
                    362:        case SIGTSTP:
                    363:                got_SIGTSTP++;
                    364:                got_signal = 1;
                    365:                break;
                    366:        case SIGTTOU:
                    367:                got_SIGTTOU++;
                    368:                got_signal = 1;
                    369:                break;
                    370:        case SIGTTIN:
                    371:                got_SIGTTIN++;
                    372:                got_signal = 1;
                    373:                break;
                    374:        case SIGWINCH:
                    375:                got_SIGWINCH++;
                    376:                got_signal = 1;
                    377:                break;
                    378:        case SIGCONT:
                    379:                got_SIGCONT++;
                    380:                got_signal = 1;
                    381:                break;
1.66      espie     382:        }
1.117     espie     383:        (void)killpg(getpid(), signo);
                    384:
                    385:        (void)signal(signo, SIG_DFL);
                    386:        errno = save_errno;
1.1       deraadt   387: }
                    388:
                    389: /*-
                    390:  *-----------------------------------------------------------------------
1.94      espie     391:  * handle_signal --
1.117     espie     392:  *     handle a signal for ourselves
1.1       deraadt   393:  *
                    394:  *-----------------------------------------------------------------------
                    395:  */
                    396: static void
1.117     espie     397: handle_signal(int signo)
1.1       deraadt   398: {
1.66      espie     399:        if (DEBUG(JOB)) {
1.93      espie     400:                (void)fprintf(stdout, "handle_signal(%d) called.\n", signo);
1.66      espie     401:                (void)fflush(stdout);
                    402:        }
                    403:
                    404:        /*
                    405:         * Deal with proper cleanup based on the signal received. We only run
                    406:         * the .INTERRUPT target if the signal was in fact an interrupt. The
                    407:         * other three termination signals are more of a "get out *now*"
                    408:         * command.
                    409:         */
1.117     espie     410:        if (signo == SIGINT)
1.66      espie     411:                JobInterrupt(true, signo);
1.117     espie     412:        else if (signo == SIGHUP || signo == SIGTERM || signo == SIGQUIT)
1.66      espie     413:                JobInterrupt(false, signo);
1.1       deraadt   414:
1.117     espie     415:        if (signo == SIGQUIT)
1.66      espie     416:                Finish(0);
1.1       deraadt   417: }
                    418:
                    419: /*-
                    420:  *-----------------------------------------------------------------------
                    421:  * JobCmpPid  --
                    422:  *     Compare the pid of the job with the given pid and return 0 if they
                    423:  *     are equal. This function is called from Job_CatchChildren via
                    424:  *     Lst_Find to find the job descriptor of the finished job.
                    425:  *
                    426:  * Results:
                    427:  *     0 if the pid's match
                    428:  *-----------------------------------------------------------------------
                    429:  */
                    430: static int
1.56      espie     431: JobCmpPid(void *job,   /* job to examine */
                    432:     void *pid)         /* process id desired */
1.1       deraadt   433: {
1.66      espie     434:        return *(pid_t *)pid - ((Job *)job)->pid;
1.1       deraadt   435: }
                    436:
1.69      espie     437: static void
1.84      espie     438: debug_printf(const char *fmt, ...)
                    439: {
                    440:        if (DEBUG(JOB)) {
                    441:                va_list va;
                    442:
                    443:                va_start(va, fmt);
                    444:                (void)vfprintf(stdout, fmt, va);
                    445:                fflush(stdout);
                    446:                va_end(va);
                    447:        }
                    448: }
1.119     espie     449:
1.2       deraadt   450: static void
1.112     espie     451: close_job_pipes(Job *job)
1.2       deraadt   452: {
1.101     espie     453:        int i;
                    454:
1.112     espie     455:        for (i = 1; i >= 0; i--) {
                    456:                FD_CLR(job->in[i].fd, output_mask);
1.101     espie     457:                handle_job_output(job, i, true);
                    458:                (void)close(job->in[i].fd);
1.66      espie     459:        }
1.1       deraadt   460: }
                    461:
                    462: /*-
                    463:  *-----------------------------------------------------------------------
1.117     espie     464:  * process_job_status  --
                    465:  *     Do processing for the given job including updating
1.119     espie     466:  *     parents and starting new jobs as available/necessary.
1.1       deraadt   467:  *
                    468:  * Side Effects:
                    469:  *     Some nodes may be put on the toBeMade queue.
1.78      espie     470:  *     Final commands for the job are placed on end_node.
1.1       deraadt   471:  *
1.6       millert   472:  *     If we got an error and are aborting (aborting == ABORT_ERROR) and
1.1       deraadt   473:  *     the job list is now empty, we are done for the day.
1.101     espie     474:  *     If we recognized an error we set the aborting flag
1.1       deraadt   475:  *     to ABORT_ERROR so no more jobs will be started.
                    476:  *-----------------------------------------------------------------------
                    477:  */
                    478: /*ARGSUSED*/
1.112     espie     479:
1.1       deraadt   480: static void
1.117     espie     481: process_job_status(Job *job, int status)
1.2       deraadt   482: {
1.112     espie     483:        int reason, code;
1.117     espie     484:        bool     done;
                    485:
1.119     espie     486:        debug_printf("Process %ld (%s) exited with status %d.\n",
1.117     espie     487:            (long)job->pid, job->node->name, status);
1.112     espie     488:        /* parse status */
                    489:        if (WIFEXITED(status)) {
                    490:                reason = JOB_EXITED;
                    491:                code = WEXITSTATUS(status);
                    492:        } else if (WIFSIGNALED(status)) {
                    493:                reason = JOB_SIGNALED;
                    494:                code = WTERMSIG(status);
                    495:        } else {
                    496:                /* can't happen, set things to be bad. */
                    497:                reason = UNKNOWN;
                    498:                code = status;
                    499:        }
1.2       deraadt   500:
1.112     espie     501:        if ((reason == JOB_EXITED &&
                    502:             code != 0 && !(job->node->type & OP_IGNORE)) ||
1.117     espie     503:            reason == JOB_SIGNALED) {
1.66      espie     504:                /*
                    505:                 * If it exited non-zero and either we're doing things our
                    506:                 * way or we're not ignoring errors, the job is finished.
                    507:                 * Similarly, if the shell died because of a signal
                    508:                 * the job is also finished. In these
                    509:                 * cases, finish out the job's output before printing the exit
                    510:                 * status...
                    511:                 */
1.112     espie     512:                close_job_pipes(job);
1.66      espie     513:                done = true;
1.112     espie     514:        } else if (reason == JOB_EXITED) {
1.66      espie     515:                /*
1.117     espie     516:                 * Deal with ignored errors. We need to print a message telling
                    517:                 * of the ignored error as well as setting status.w_status to 0
                    518:                 * so the next command gets run. To do this, we set done to be
                    519:                 * true and the job exited non-zero.
1.66      espie     520:                 */
1.112     espie     521:                done = code != 0;
                    522:                close_job_pipes(job);
1.66      espie     523:        } else {
                    524:                /*
                    525:                 * No need to close things down or anything.
                    526:                 */
                    527:                done = false;
1.1       deraadt   528:        }
1.6       millert   529:
1.112     espie     530:        if (done || DEBUG(JOB)) {
                    531:                if (reason == JOB_EXITED) {
1.119     espie     532:                        debug_printf("Process %ld (%s) exited.\n",
1.117     espie     533:                            (long)job->pid, job->node->name);
1.112     espie     534:                        if (code != 0) {
1.105     espie     535:                                banner(job, stdout);
1.111     espie     536:                                (void)fprintf(stdout, "*** Error code %d %s\n",
1.112     espie     537:                                    code,
1.119     espie     538:                                    (job->node->type & OP_IGNORE) ?
1.106     espie     539:                                    "(ignored)" : "");
1.66      espie     540:
1.106     espie     541:                                if (job->node->type & OP_IGNORE) {
1.112     espie     542:                                        reason = JOB_EXITED;
                    543:                                        code = 0;
1.66      espie     544:                                }
                    545:                        } else if (DEBUG(JOB)) {
1.101     espie     546:                                (void)fprintf(stdout,
1.119     espie     547:                                    "*** %ld (%s) Completed successfully\n",
1.117     espie     548:                                    (long)job->pid, job->node->name);
1.66      espie     549:                        }
                    550:                } else {
1.105     espie     551:                        banner(job, stdout);
1.112     espie     552:                        (void)fprintf(stdout, "*** Signal %d\n", code);
1.40      espie     553:                }
1.66      espie     554:
1.101     espie     555:                (void)fflush(stdout);
1.1       deraadt   556:        }
                    557:
1.85      espie     558:        done = true;
1.1       deraadt   559:
1.66      espie     560:        if (done &&
                    561:            aborting != ABORT_ERROR &&
                    562:            aborting != ABORT_INTERRUPT &&
1.112     espie     563:            reason == JOB_EXITED && code == 0) {
1.66      espie     564:                /* As long as we aren't aborting and the job didn't return a
                    565:                 * non-zero status that we shouldn't ignore, we call
1.101     espie     566:                 * Make_Update to update the parents. */
1.108     espie     567:                job->node->built_status = MADE;
1.66      espie     568:                Make_Update(job->node);
1.112     espie     569:        } else if (!(reason == JOB_EXITED && code == 0)) {
                    570:                register_error(reason, code, job);
1.66      espie     571:        }
1.117     espie     572:        free(job);
1.1       deraadt   573:
1.119     espie     574:        if (errors && !keepgoing &&
1.117     espie     575:            aborting != ABORT_INTERRUPT)
1.66      espie     576:                aborting = ABORT_ERROR;
1.6       millert   577:
1.117     espie     578:        if (aborting == ABORT_ERROR && Job_Empty())
1.66      espie     579:                Finish(errors);
1.1       deraadt   580: }
                    581:
1.119     espie     582: static void
1.101     espie     583: prepare_pipe(struct job_pipe *p, int *fd)
                    584: {
                    585:        p->pos = 0;
                    586:        (void)fcntl(fd[0], F_SETFD, FD_CLOEXEC);
1.119     espie     587:        p->fd = fd[0];
1.101     espie     588:        close(fd[1]);
                    589:
1.112     espie     590:        if (output_mask == NULL || p->fd > largest_fd) {
1.101     espie     591:                int fdn, ofdn;
                    592:
                    593:                fdn = howmany(p->fd+1, NFDBITS);
1.112     espie     594:                ofdn = howmany(largest_fd+1, NFDBITS);
1.101     espie     595:
                    596:                if (fdn != ofdn) {
1.119     espie     597:                        output_mask = emult_realloc(output_mask, fdn,
1.112     espie     598:                            sizeof(fd_mask));
1.119     espie     599:                        memset(((char *)output_mask) + ofdn * sizeof(fd_mask),
1.113     espie     600:                            0, (fdn-ofdn) * sizeof(fd_mask));
1.119     espie     601:                        actual_mask = emult_realloc(actual_mask, fdn,
1.112     espie     602:                            sizeof(fd_mask));
                    603:                        mask_size = fdn * sizeof(fd_mask);
1.101     espie     604:                }
1.112     espie     605:                largest_fd = p->fd;
1.101     espie     606:        }
                    607:        fcntl(p->fd, F_SETFL, O_NONBLOCK);
1.112     espie     608:        FD_SET(p->fd, output_mask);
1.101     espie     609: }
                    610:
1.1       deraadt   611: /*-
                    612:  *-----------------------------------------------------------------------
                    613:  * JobExec --
1.119     espie     614:  *     Execute the shell for the given job. Called from JobStart
1.1       deraadt   615:  *
                    616:  * Side Effects:
                    617:  *     A shell is executed, outputs is altered and the Job structure added
                    618:  *     to the job table.
                    619:  *-----------------------------------------------------------------------
                    620:  */
                    621: static void
1.101     espie     622: JobExec(Job *job)
1.1       deraadt   623: {
1.66      espie     624:        pid_t cpid;     /* ID of new child */
1.117     espie     625:        struct job_pid *p;
1.101     espie     626:        int fds[4];
                    627:        int *fdout = fds;
                    628:        int *fderr = fds+2;
                    629:        int i;
1.6       millert   630:
1.105     espie     631:        banner(job, stdout);
1.101     espie     632:
1.117     espie     633:        setup_engine(1);
1.101     espie     634:
1.119     espie     635:        /* Create the pipe by which we'll get the shell's output.
1.101     espie     636:         */
                    637:        if (pipe(fdout) == -1)
                    638:                Punt("Cannot create pipe: %s", strerror(errno));
1.1       deraadt   639:
1.101     espie     640:        if (pipe(fderr) == -1)
                    641:                Punt("Cannot create pipe: %s", strerror(errno));
1.94      espie     642:
1.117     espie     643:        block_signals();
1.66      espie     644:        if ((cpid = fork()) == -1) {
                    645:                Punt("Cannot fork");
1.117     espie     646:                unblock_signals();
1.66      espie     647:        } else if (cpid == 0) {
1.104     espie     648:                supervise_jobs = false;
1.101     espie     649:                /* standard pipe code to route stdout and stderr */
                    650:                close(fdout[0]);
                    651:                if (dup2(fdout[1], 1) == -1)
                    652:                        Punt("Cannot dup2(outPipe): %s", strerror(errno));
                    653:                if (fdout[1] != 1)
                    654:                        close(fdout[1]);
                    655:                close(fderr[0]);
                    656:                if (dup2(fderr[1], 2) == -1)
                    657:                        Punt("Cannot dup2(errPipe): %s", strerror(errno));
                    658:                if (fderr[1] != 2)
                    659:                        close(fderr[1]);
1.1       deraadt   660:
1.66      espie     661:                /*
                    662:                 * We want to switch the child into a different process family
                    663:                 * so we can kill it and all its descendants in one fell swoop,
                    664:                 * by killing its process family, but not commit suicide.
                    665:                 */
                    666:                (void)setpgid(0, getpid());
1.1       deraadt   667:
1.109     espie     668:                if (random_delay)
1.110     espie     669:                        if (!(nJobs == 1 && no_jobs_left()))
                    670:                                usleep(random() % random_delay);
1.109     espie     671:
1.117     espie     672:                setup_all_signals(SigHandler, SIG_DFL);
                    673:                unblock_signals();
1.116     espie     674:                /* this exits directly */
                    675:                run_gnode_parallel(job->node);
                    676:                /*NOTREACHED*/
1.66      espie     677:        } else {
1.104     espie     678:                supervise_jobs = true;
1.66      espie     679:                job->pid = cpid;
                    680:
1.101     espie     681:                /* we set the current position in the buffers to the beginning
1.87      espie     682:                 * and mark another stream to watch in the outputs mask
                    683:                 */
1.101     espie     684:                for (i = 0; i < 2; i++)
                    685:                        prepare_pipe(&job->in[i], fds+2*i);
1.1       deraadt   686:        }
1.48      espie     687:        /*
1.66      espie     688:         * Now the job is actually running, add it to the table.
1.48      espie     689:         */
1.67      espie     690:        nJobs++;
1.95      espie     691:        Lst_AtEnd(&runningJobs, job);
1.117     espie     692:        if (job->flags & JOB_IS_EXPENSIVE)
                    693:                expensive_job = true;
                    694:        p = emalloc(sizeof(struct job_pid));
                    695:        p->pid = cpid;
                    696:        Lst_AtEnd(&job_pids, p);
                    697:        job->p = Lst_Last(&job_pids);
1.1       deraadt   698:
1.117     espie     699:        unblock_signals();
1.96      espie     700:        if (DEBUG(JOB)) {
1.117     espie     701:                LstNode ln;
                    702:
                    703:                (void)fprintf(stdout, "Running %ld (%s)\n", (long)cpid,
1.96      espie     704:                    job->node->name);
1.119     espie     705:                for (ln = Lst_First(&job->node->commands); ln != NULL ;
1.117     espie     706:                    ln = Lst_Adv(ln))
                    707:                        fprintf(stdout, "\t%s\n", (char *)Lst_Datum(ln));
1.96      espie     708:                (void)fflush(stdout);
                    709:        }
1.117     espie     710:
1.96      espie     711: }
                    712:
1.117     espie     713: static bool
                    714: expensive_command(const char *s)
1.1       deraadt   715: {
1.117     espie     716:        const char *p;
                    717:        bool include = false;
                    718:        bool expensive = false;
1.66      espie     719:
1.117     espie     720:        /* okay, comments are cheap, always */
                    721:        if (*s == '#')
                    722:                return false;
1.66      espie     723:
1.117     espie     724:        for (p = s; *p != '\0'; p++) {
                    725:                if (*p == ' ' || *p == '\t') {
                    726:                        include = false;
                    727:                        if (p[1] == '-' && p[2] == 'I')
                    728:                                include = true;
                    729:                }
                    730:                if (include)
                    731:                        continue;
                    732:                /* KMP variant, avoid looking twice at the same
                    733:                 * letter.
                    734:                 */
                    735:                if (*p != 'm')
                    736:                        continue;
                    737:                if (p[1] != 'a')
                    738:                        continue;
                    739:                p++;
                    740:                if (p[1] != 'k')
                    741:                        continue;
                    742:                p++;
                    743:                if (p[1] != 'e')
                    744:                        continue;
                    745:                p++;
                    746:                expensive = true;
                    747:                while (p[1] != '\0' && p[1] != ' ' && p[1] != '\t') {
                    748:                        if (p[1] == '.') {
                    749:                                expensive = false;
                    750:                                break;
1.66      espie     751:                        }
1.117     espie     752:                        p++;
1.1       deraadt   753:                }
1.117     espie     754:                if (expensive)
                    755:                        return true;
1.1       deraadt   756:        }
1.117     espie     757:        return false;
                    758: }
                    759:
                    760: static bool
                    761: expensive_commands(Lst l)
                    762: {
                    763:        LstNode ln;
                    764:        for (ln = Lst_First(l); ln != NULL; ln = Lst_Adv(ln))
                    765:                if (expensive_command(Lst_Datum(ln)))
                    766:                        return true;
                    767:        return false;
1.1       deraadt   768: }
                    769:
1.98      espie     770: static Job *
                    771: prepare_job(GNode *gn, int flags)
1.78      espie     772: {
                    773:        bool cmdsOK;            /* true if the nodes commands were all right */
                    774:        bool noExec;            /* Set true if we decide not to run the job */
1.66      espie     775:
1.1       deraadt   776:        /*
1.66      espie     777:         * Check the commands now so any attributes from .DEFAULT have a chance
                    778:         * to migrate to the node
1.1       deraadt   779:         */
1.114     espie     780:        cmdsOK = Job_CheckCommands(gn);
1.112     espie     781:        expand_commands(gn);
1.1       deraadt   782:
1.66      espie     783:        if ((gn->type & OP_MAKE) || (!noExecute && !touchFlag)) {
                    784:                /*
                    785:                 * We're serious here, but if the commands were bogus, we're
                    786:                 * also dead...
                    787:                 */
1.114     espie     788:                if (!cmdsOK)
                    789:                        job_failure(gn, Punt);
1.6       millert   790:
1.101     espie     791:                if (Lst_IsEmpty(&gn->commands))
                    792:                        noExec = true;
                    793:                else
                    794:                        noExec = false;
1.66      espie     795:
1.101     espie     796:        } else if (noExecute) {
                    797:                if (!cmdsOK || Lst_IsEmpty(&gn->commands))
1.85      espie     798:                        noExec = true;
1.101     espie     799:                else
                    800:                        noExec = false;
1.66      espie     801:        } else {
                    802:                /*
                    803:                 * Just touch the target and note that no shell should be
1.101     espie     804:                 * executed.  Check
1.66      espie     805:                 * the commands, too, but don't die if they're no good -- it
                    806:                 * does no harm to keep working up the graph.
1.30      espie     807:                 */
1.106     espie     808:                Job_Touch(gn);
1.41      espie     809:                noExec = true;
1.1       deraadt   810:        }
1.66      espie     811:
1.1       deraadt   812:        /*
1.66      espie     813:         * If we're not supposed to execute a shell, don't.
1.1       deraadt   814:         */
1.66      espie     815:        if (noExec) {
                    816:                /*
                    817:                 * We only want to work our way up the graph if we aren't here
                    818:                 * because the commands for the job were no good.
                    819:                 */
1.115     espie     820:                if (cmdsOK && !aborting) {
                    821:                        gn->built_status = MADE;
                    822:                        Make_Update(gn);
1.66      espie     823:                }
1.99      espie     824:                return NULL;
1.1       deraadt   825:        } else {
1.115     espie     826:                Job *job;               /* new job descriptor */
                    827:                job = emalloc(sizeof(Job));
                    828:                if (job == NULL)
                    829:                        Punt("JobStart out of memory");
                    830:
                    831:                job->node = gn;
                    832:
                    833:                /*
                    834:                 * Set the initial value of the flags for this job based on the
                    835:                 * global ones and the node's attributes... Any flags supplied
                    836:                 * by the caller are also added to the field.
                    837:                 */
                    838:                job->flags = flags;
1.117     espie     839:                if (expensive_commands(&gn->expanded)) {
                    840:                        job->flags |= JOB_IS_EXPENSIVE;
                    841:                }
1.115     espie     842:
1.98      espie     843:                return job;
1.1       deraadt   844:        }
1.98      espie     845: }
1.1       deraadt   846:
1.98      espie     847: /*-
                    848:  *-----------------------------------------------------------------------
                    849:  * JobStart  --
                    850:  *     Start a target-creation process going for the target described
                    851:  *     by the graph node gn.
                    852:  *
                    853:  * Side Effects:
                    854:  *     A new Job node is created and added to the list of running
1.114     espie     855:  *     jobs. Make is forked and a child shell created.
1.98      espie     856:  *-----------------------------------------------------------------------
                    857:  */
                    858: static void
                    859: JobStart(GNode *gn,            /* target to create */
                    860:     int flags)                 /* flags for the job to override normal ones.
1.117     espie     861:                                 * e.g. JOB_IS_SPECIAL */
1.98      espie     862: {
                    863:        Job *job;
                    864:        job = prepare_job(gn, flags);
                    865:        if (!job)
                    866:                return;
1.117     espie     867:        JobExec(job);
1.1       deraadt   868: }
                    869:
1.101     espie     870: /* Helper functions for JobDoOutput */
                    871:
                    872:
1.105     espie     873: /* output debugging banner and print characters from 0 to endpos */
1.101     espie     874: static void
                    875: print_partial_buffer(struct job_pipe *p, Job *job, FILE *out, size_t endPos)
1.2       deraadt   876: {
1.101     espie     877:        size_t i;
1.2       deraadt   878:
1.105     espie     879:        banner(job, out);
1.111     espie     880:        job->flags |= JOB_DIDOUTPUT;
1.101     espie     881:        for (i = 0; i < endPos; i++)
                    882:                putc(p->buffer[i], out);
                    883: }
                    884:
                    885: /* print partial buffer and shift remaining contents */
                    886: static void
                    887: print_partial_buffer_and_shift(struct job_pipe *p, Job *job, FILE *out,
                    888:     size_t endPos)
                    889: {
                    890:        size_t i;
                    891:
                    892:        print_partial_buffer(p, job, out, endPos);
                    893:
                    894:        for (i = endPos; i < p->pos; i++)
                    895:                p->buffer[i-endPos] = p->buffer[i];
                    896:        p->pos -= endPos;
                    897: }
                    898:
                    899: /* print complete lines, looking back to the limit position
                    900:  * (stuff before limit was already scanned).
                    901:  * returns true if something was printed.
                    902:  */
                    903: static bool
                    904: print_complete_lines(struct job_pipe *p, Job *job, FILE *out, size_t limit)
                    905: {
                    906:        size_t i;
                    907:
                    908:        for (i = p->pos; i > limit; i--) {
                    909:                if (p->buffer[i-1] == '\n') {
                    910:                        print_partial_buffer_and_shift(p, job, out, i);
                    911:                        return true;
1.2       deraadt   912:                }
                    913:        }
1.101     espie     914:        return false;
1.2       deraadt   915: }
1.111     espie     916:
1.1       deraadt   917: /*-
                    918:  *-----------------------------------------------------------------------
1.101     espie     919:  * handle_pipe --
1.89      espie     920:  *     This functions is called whenever there is something to read on the
                    921:  *     pipe. We collect more output from the given job and store it in the
1.101     espie     922:  *     job's outBuf. If this makes up lines, we print it tagged by the job's
1.89      espie     923:  *     identifier, as necessary.
1.1       deraadt   924:  *
                    925:  * Side Effects:
                    926:  *     curPos may be shifted as may the contents of outBuf.
                    927:  *-----------------------------------------------------------------------
                    928:  */
1.48      espie     929: static void
1.119     espie     930: handle_pipe(struct job_pipe *p,
1.101     espie     931:        Job *job, FILE *out, bool finish)
1.66      espie     932: {
                    933:        int nr;                 /* number of bytes read */
1.101     espie     934:        int oldpos;             /* optimization */
1.1       deraadt   935:
1.101     espie     936:        /* want to get everything ? -> we block */
                    937:        if (finish)
                    938:                fcntl(p->fd, F_SETFL, 0);
                    939:
                    940:        do {
                    941:                nr = read(p->fd, &p->buffer[p->pos],
                    942:                    JOB_BUFSIZE - p->pos);
                    943:                if (nr == -1) {
                    944:                        if (errno == EAGAIN)
                    945:                                break;
                    946:                        if (DEBUG(JOB)) {
                    947:                                perror("JobDoOutput(piperead)");
                    948:                        }
1.66      espie     949:                }
1.101     espie     950:                oldpos = p->pos;
                    951:                p->pos += nr;
                    952:                if (!print_complete_lines(p, job, out, oldpos))
                    953:                        if (p->pos == JOB_BUFSIZE) {
                    954:                                print_partial_buffer(p, job, out, p->pos);
                    955:                                p->pos = 0;
                    956:                        }
                    957:        } while (nr != 0);
1.1       deraadt   958:
1.101     espie     959:        /* at end of file, we print whatever is left */
                    960:        if (nr == 0) {
                    961:                print_partial_buffer(p, job, out, p->pos);
                    962:                if (p->pos > 0 && p->buffer[p->pos - 1] != '\n')
                    963:                        putchar('\n');
                    964:                p->pos = 0;
1.76      espie     965:        }
1.101     espie     966: }
1.6       millert   967:
1.101     espie     968: static void
                    969: handle_job_output(Job *job, int i, bool finish)
                    970: {
                    971:        handle_pipe(&job->in[i], job, i == 0 ? stdout : stderr, finish);
1.1       deraadt   972: }
                    973:
1.117     espie     974: static void
                    975: remove_job(LstNode ln, int status)
                    976: {
                    977:        Job *job;
                    978:
                    979:        job = (Job *)Lst_Datum(ln);
                    980:        Lst_Remove(&runningJobs, ln);
                    981:        block_signals();
                    982:        free(Lst_Datum(job->p));
                    983:        Lst_Remove(&job_pids, job->p);
                    984:        unblock_signals();
                    985:        nJobs--;
                    986:        if (job->flags & JOB_IS_EXPENSIVE)
                    987:                expensive_job = false;
                    988:        process_job_status(job, status);
                    989: }
                    990:
1.1       deraadt   991: /*-
                    992:  *-----------------------------------------------------------------------
                    993:  * Job_CatchChildren --
1.111     espie     994:  *     Handle the exit of a child. Called by handle_running_jobs
1.1       deraadt   995:  *
                    996:  * Side Effects:
                    997:  *     The job descriptor is removed from the list of children.
                    998:  *
                    999:  * Notes:
                   1000:  *     We do waits, blocking or not, according to the wisdom of our
                   1001:  *     caller, until there are no more children to report. For each
1.119     espie    1002:  *     job, call process_job_status to finish things off.
1.1       deraadt  1003:  *-----------------------------------------------------------------------
                   1004:  */
                   1005: void
1.76      espie    1006: Job_CatchChildren()
1.1       deraadt  1007: {
1.78      espie    1008:        pid_t pid;      /* pid of dead child */
                   1009:        LstNode jnode;  /* list element for finding job */
                   1010:        int status;     /* Exit/termination status */
1.1       deraadt  1011:
1.66      espie    1012:        /*
                   1013:         * Don't even bother if we know there's no one around.
                   1014:         */
1.112     espie    1015:        if (nJobs == 0)
1.66      espie    1016:                return;
1.6       millert  1017:
1.117     espie    1018:        while ((pid = waitpid(WAIT_ANY, &status, WNOHANG)) > 0) {
1.93      espie    1019:                handle_all_signals();
1.1       deraadt  1020:
1.95      espie    1021:                jnode = Lst_Find(&runningJobs, JobCmpPid, &pid);
1.1       deraadt  1022:
1.18      espie    1023:                if (jnode == NULL) {
1.117     espie    1024:                        Error("Child (%ld) not in table?", (long)pid);
1.66      espie    1025:                } else {
1.117     espie    1026:                        remove_job(jnode, status);
1.1       deraadt  1027:                }
                   1028:        }
                   1029: }
                   1030:
                   1031: void
1.112     espie    1032: handle_all_jobs_output(void)
1.1       deraadt  1033: {
1.66      espie    1034:        int nfds;
                   1035:        struct timeval timeout;
1.111     espie    1036:        LstNode ln, ln2;
1.66      espie    1037:        Job *job;
1.101     espie    1038:        int i;
1.111     espie    1039:        int status;
1.66      espie    1040:
1.112     espie    1041:        /* no jobs */
                   1042:        if (Lst_IsEmpty(&runningJobs))
                   1043:                return;
1.91      espie    1044:
1.77      espie    1045:        (void)fflush(stdout);
1.76      espie    1046:
1.112     espie    1047:        memcpy(actual_mask, output_mask, mask_size);
1.76      espie    1048:        timeout.tv_sec = SEL_SEC;
                   1049:        timeout.tv_usec = SEL_USEC;
1.66      espie    1050:
1.112     espie    1051:        nfds = select(largest_fd+1, actual_mask, NULL, NULL, &timeout);
1.93      espie    1052:        handle_all_signals();
1.118     espie    1053:        for (ln = Lst_First(&runningJobs); nfds && ln != NULL; ln = ln2) {
1.111     espie    1054:                ln2 = Lst_Adv(ln);
                   1055:                job = (Job *)Lst_Datum(ln);
                   1056:                job->flags &= ~JOB_DIDOUTPUT;
                   1057:                for (i = 1; i >= 0; i--) {
1.112     espie    1058:                        if (FD_ISSET(job->in[i].fd, actual_mask)) {
1.111     espie    1059:                                nfds--;
                   1060:                                handle_job_output(job, i, false);
                   1061:                        }
                   1062:                }
                   1063:                if (job->flags & JOB_DIDOUTPUT) {
1.117     espie    1064:                        if (waitpid(job->pid, &status, WNOHANG) == job->pid) {
                   1065:                                remove_job(ln, status);
1.111     espie    1066:                        } else {
                   1067:                                Lst_Requeue(&runningJobs, ln);
1.66      espie    1068:                        }
1.1       deraadt  1069:                }
                   1070:        }
                   1071: }
                   1072:
1.111     espie    1073: void
                   1074: handle_running_jobs()
                   1075: {
1.112     espie    1076:        handle_all_jobs_output();
1.111     espie    1077:        Job_CatchChildren();
                   1078: }
                   1079:
                   1080: static void
                   1081: loop_handle_running_jobs()
                   1082: {
                   1083:        while (nJobs)
                   1084:                handle_running_jobs();
                   1085: }
1.1       deraadt  1086: /*-
                   1087:  *-----------------------------------------------------------------------
                   1088:  * Job_Make --
                   1089:  *     Start the creation of a target. Basically a front-end for
                   1090:  *     JobStart used by the Make module.
                   1091:  *
                   1092:  * Side Effects:
                   1093:  *     Another job is started.
                   1094:  *-----------------------------------------------------------------------
                   1095:  */
                   1096: void
1.56      espie    1097: Job_Make(GNode *gn)
1.1       deraadt  1098: {
1.86      espie    1099:        (void)JobStart(gn, 0);
1.1       deraadt  1100: }
                   1101:
1.117     espie    1102:
                   1103: static void
                   1104: block_signals()
                   1105: {
                   1106:        sigprocmask(SIG_BLOCK, &set, &oset);
                   1107: }
                   1108:
                   1109: static void
                   1110: unblock_signals()
                   1111: {
                   1112:        sigprocmask(SIG_SETMASK, &oset, NULL);
                   1113: }
                   1114:
1.1       deraadt  1115: /*-
                   1116:  *-----------------------------------------------------------------------
                   1117:  * Job_Init --
                   1118:  *     Initialize the process module
                   1119:  *
                   1120:  * Side Effects:
                   1121:  *     lists and counters are initialized
                   1122:  *-----------------------------------------------------------------------
                   1123:  */
                   1124: void
1.83      espie    1125: Job_Init(int maxproc)
1.1       deraadt  1126: {
1.95      espie    1127:        Static_Lst_Init(&runningJobs);
1.101     espie    1128:        Static_Lst_Init(&errorsList);
1.117     espie    1129:        maxJobs = maxproc;
                   1130:        nJobs = 0;
1.101     espie    1131:        errors = 0;
1.117     espie    1132:        sigemptyset(&set);
                   1133:        sigaddset(&set, SIGINT);
                   1134:        sigaddset(&set, SIGHUP);
                   1135:        sigaddset(&set, SIGQUIT);
                   1136:        sigaddset(&set, SIGTERM);
                   1137:        sigaddset(&set, SIGTSTP);
                   1138:        sigaddset(&set, SIGTTOU);
                   1139:        sigaddset(&set, SIGTTIN);
1.66      espie    1140:
1.117     espie    1141:        aborting = 0;
1.40      espie    1142:
1.117     espie    1143:        lastNode = NULL;
1.1       deraadt  1144:
1.78      espie    1145:        if ((begin_node->type & OP_DUMMY) == 0) {
1.117     espie    1146:                JobStart(begin_node, JOB_IS_SPECIAL);
1.111     espie    1147:                loop_handle_running_jobs();
1.1       deraadt  1148:        }
                   1149: }
                   1150:
1.117     espie    1151: static bool
                   1152: Job_Full()
                   1153: {
                   1154:        return aborting || (nJobs >= maxJobs);
                   1155: }
1.1       deraadt  1156: /*-
                   1157:  *-----------------------------------------------------------------------
                   1158:  * Job_Full --
1.117     espie    1159:  *     See if the job table is full. It is considered full
1.1       deraadt  1160:  *     if we are in the process of aborting OR if we have
1.119     espie    1161:  *     reached/exceeded our quota.
1.1       deraadt  1162:  *
                   1163:  * Results:
1.41      espie    1164:  *     true if the job table is full, false otherwise
1.1       deraadt  1165:  *-----------------------------------------------------------------------
                   1166:  */
1.41      espie    1167: bool
1.117     espie    1168: can_start_job(void)
1.1       deraadt  1169: {
1.117     espie    1170:        if (Job_Full() || expensive_job)
                   1171:                return false;
1.119     espie    1172:        else
1.117     espie    1173:                return true;
1.1       deraadt  1174: }
                   1175:
                   1176: /*-
                   1177:  *-----------------------------------------------------------------------
                   1178:  * Job_Empty --
1.119     espie    1179:  *     See if the job table is empty.
1.1       deraadt  1180:  *
                   1181:  * Results:
1.41      espie    1182:  *     true if it is. false if it ain't.
1.1       deraadt  1183:  * -----------------------------------------------------------------------
                   1184:  */
1.41      espie    1185: bool
1.56      espie    1186: Job_Empty(void)
1.1       deraadt  1187: {
1.117     espie    1188:        if (nJobs == 0)
                   1189:                return true;
                   1190:        else
1.66      espie    1191:                return false;
1.1       deraadt  1192: }
                   1193:
                   1194: /*-
                   1195:  *-----------------------------------------------------------------------
                   1196:  * JobInterrupt --
                   1197:  *     Handle the receipt of an interrupt.
                   1198:  *
                   1199:  * Side Effects:
                   1200:  *     All children are killed. Another job will be started if the
                   1201:  *     .INTERRUPT target was given.
                   1202:  *-----------------------------------------------------------------------
                   1203:  */
                   1204: static void
1.117     espie    1205: JobInterrupt(bool runINTERRUPT,        /* true if commands for the .INTERRUPT
1.1       deraadt  1206:                                 * target should be executed */
1.66      espie    1207:     int signo)                 /* signal received */
1.1       deraadt  1208: {
1.66      espie    1209:        LstNode ln;             /* element in job table */
1.78      espie    1210:        Job *job;               /* job descriptor in that element */
1.66      espie    1211:
                   1212:        aborting = ABORT_INTERRUPT;
                   1213:
1.95      espie    1214:        for (ln = Lst_First(&runningJobs); ln != NULL; ln = Lst_Adv(ln)) {
1.66      espie    1215:                job = (Job *)Lst_Datum(ln);
                   1216:
                   1217:                if (!Targ_Precious(job->node)) {
                   1218:                        const char *file = job->node->path == NULL ?
                   1219:                            job->node->name : job->node->path;
                   1220:                        if (!noExecute && eunlink(file) != -1) {
                   1221:                                Error("*** %s removed", file);
                   1222:                        }
                   1223:                }
                   1224:                if (job->pid) {
1.84      espie    1225:                        debug_printf("JobInterrupt passing signal to "
                   1226:                            "child %ld.\n", (long)job->pid);
1.117     espie    1227:                        killpg(job->pid, signo);
1.66      espie    1228:                }
1.2       deraadt  1229:        }
1.1       deraadt  1230:
1.66      espie    1231:        if (runINTERRUPT && !touchFlag) {
1.78      espie    1232:                if ((interrupt_node->type & OP_DUMMY) == 0) {
1.66      espie    1233:                        ignoreErrors = false;
                   1234:
1.101     espie    1235:                        JobStart(interrupt_node, 0);
1.111     espie    1236:                        loop_handle_running_jobs();
1.66      espie    1237:                }
1.1       deraadt  1238:        }
1.66      espie    1239:        exit(signo);
1.1       deraadt  1240: }
                   1241:
                   1242: /*
                   1243:  *-----------------------------------------------------------------------
1.12      espie    1244:  * Job_Finish --
1.1       deraadt  1245:  *     Do final processing such as the running of the commands
1.6       millert  1246:  *     attached to the .END target.
1.1       deraadt  1247:  *
                   1248:  * Results:
                   1249:  *     Number of errors reported.
1.40      espie    1250:  *
1.1       deraadt  1251:  *-----------------------------------------------------------------------
                   1252:  */
                   1253: int
1.56      espie    1254: Job_Finish(void)
1.1       deraadt  1255: {
1.116     espie    1256:        if ((end_node->type & OP_DUMMY) == 0) {
1.66      espie    1257:                if (errors) {
                   1258:                        Error("Errors reported so .END ignored");
                   1259:                } else {
1.117     espie    1260:                        JobStart(end_node, JOB_IS_SPECIAL);
1.111     espie    1261:                        loop_handle_running_jobs();
1.66      espie    1262:                }
1.1       deraadt  1263:        }
1.66      espie    1264:        return errors;
1.1       deraadt  1265: }
                   1266:
1.41      espie    1267: #ifdef CLEANUP
1.12      espie    1268: void
1.56      espie    1269: Job_End(void)
1.12      espie    1270: {
1.41      espie    1271: }
1.13      espie    1272: #endif
1.40      espie    1273:
1.1       deraadt  1274: /*-
                   1275:  *-----------------------------------------------------------------------
                   1276:  * Job_Wait --
                   1277:  *     Waits for all running jobs to finish and returns. Sets 'aborting'
                   1278:  *     to ABORT_WAIT to prevent other jobs from starting.
                   1279:  *
                   1280:  * Side Effects:
                   1281:  *     Currently running jobs finish.
                   1282:  *
                   1283:  *-----------------------------------------------------------------------
                   1284:  */
                   1285: void
1.56      espie    1286: Job_Wait(void)
1.1       deraadt  1287: {
1.66      espie    1288:        aborting = ABORT_WAIT;
1.111     espie    1289:        loop_handle_running_jobs();
1.66      espie    1290:        aborting = 0;
1.1       deraadt  1291: }
                   1292:
                   1293: /*-
                   1294:  *-----------------------------------------------------------------------
                   1295:  * Job_AbortAll --
                   1296:  *     Abort all currently running jobs without handling output or anything.
                   1297:  *     This function is to be called only in the event of a major
                   1298:  *     error. Most definitely NOT to be called from JobInterrupt.
                   1299:  *
                   1300:  * Side Effects:
                   1301:  *     All children are killed, not just the firstborn
                   1302:  *-----------------------------------------------------------------------
                   1303:  */
                   1304: void
1.56      espie    1305: Job_AbortAll(void)
1.1       deraadt  1306: {
1.66      espie    1307:        LstNode ln;     /* element in job table */
                   1308:        Job *job;       /* the job descriptor in that element */
                   1309:        int foo;
1.6       millert  1310:
1.66      espie    1311:        aborting = ABORT_ERROR;
1.6       millert  1312:
1.66      espie    1313:        if (nJobs) {
1.119     espie    1314:                for (ln = Lst_First(&runningJobs); ln != NULL;
1.95      espie    1315:                    ln = Lst_Adv(ln)) {
1.66      espie    1316:                        job = (Job *)Lst_Datum(ln);
                   1317:
                   1318:                        /*
                   1319:                         * kill the child process with increasingly drastic
                   1320:                         * signals to make darn sure it's dead.
                   1321:                         */
1.117     espie    1322:                        killpg(job->pid, SIGINT);
                   1323:                        killpg(job->pid, SIGKILL);
1.66      espie    1324:                }
1.1       deraadt  1325:        }
1.6       millert  1326:
1.66      espie    1327:        /*
                   1328:         * Catch as many children as want to report in at first, then give up
                   1329:         */
1.117     espie    1330:        while (waitpid(WAIT_ANY, &foo, WNOHANG) > 0)
1.66      espie    1331:                continue;
1.2       deraadt  1332: }
1.40      espie    1333: