[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.122

1.122   ! espie       1: /*     $OpenBSD: job.c,v 1.121 2012/03/22 13:47:12 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.122   ! espie     839:
        !           840:                if (gn->type & OP_CHEAP)
        !           841:                        return job;
        !           842:                if ((gn->type & OP_EXPENSIVE) ||
        !           843:                    expensive_commands(&gn->expanded))
1.117     espie     844:                        job->flags |= JOB_IS_EXPENSIVE;
1.115     espie     845:
1.98      espie     846:                return job;
1.1       deraadt   847:        }
1.98      espie     848: }
1.1       deraadt   849:
1.98      espie     850: /*-
                    851:  *-----------------------------------------------------------------------
                    852:  * JobStart  --
                    853:  *     Start a target-creation process going for the target described
                    854:  *     by the graph node gn.
                    855:  *
                    856:  * Side Effects:
                    857:  *     A new Job node is created and added to the list of running
1.114     espie     858:  *     jobs. Make is forked and a child shell created.
1.98      espie     859:  *-----------------------------------------------------------------------
                    860:  */
                    861: static void
                    862: JobStart(GNode *gn,            /* target to create */
                    863:     int flags)                 /* flags for the job to override normal ones.
1.117     espie     864:                                 * e.g. JOB_IS_SPECIAL */
1.98      espie     865: {
                    866:        Job *job;
                    867:        job = prepare_job(gn, flags);
                    868:        if (!job)
                    869:                return;
1.117     espie     870:        JobExec(job);
1.1       deraadt   871: }
                    872:
1.101     espie     873: /* Helper functions for JobDoOutput */
                    874:
                    875:
1.105     espie     876: /* output debugging banner and print characters from 0 to endpos */
1.101     espie     877: static void
                    878: print_partial_buffer(struct job_pipe *p, Job *job, FILE *out, size_t endPos)
1.2       deraadt   879: {
1.101     espie     880:        size_t i;
1.2       deraadt   881:
1.105     espie     882:        banner(job, out);
1.111     espie     883:        job->flags |= JOB_DIDOUTPUT;
1.101     espie     884:        for (i = 0; i < endPos; i++)
                    885:                putc(p->buffer[i], out);
                    886: }
                    887:
                    888: /* print partial buffer and shift remaining contents */
                    889: static void
                    890: print_partial_buffer_and_shift(struct job_pipe *p, Job *job, FILE *out,
                    891:     size_t endPos)
                    892: {
                    893:        size_t i;
                    894:
                    895:        print_partial_buffer(p, job, out, endPos);
                    896:
                    897:        for (i = endPos; i < p->pos; i++)
                    898:                p->buffer[i-endPos] = p->buffer[i];
                    899:        p->pos -= endPos;
                    900: }
                    901:
                    902: /* print complete lines, looking back to the limit position
                    903:  * (stuff before limit was already scanned).
                    904:  * returns true if something was printed.
                    905:  */
                    906: static bool
                    907: print_complete_lines(struct job_pipe *p, Job *job, FILE *out, size_t limit)
                    908: {
                    909:        size_t i;
                    910:
                    911:        for (i = p->pos; i > limit; i--) {
                    912:                if (p->buffer[i-1] == '\n') {
                    913:                        print_partial_buffer_and_shift(p, job, out, i);
                    914:                        return true;
1.2       deraadt   915:                }
                    916:        }
1.101     espie     917:        return false;
1.2       deraadt   918: }
1.111     espie     919:
1.1       deraadt   920: /*-
                    921:  *-----------------------------------------------------------------------
1.101     espie     922:  * handle_pipe --
1.89      espie     923:  *     This functions is called whenever there is something to read on the
                    924:  *     pipe. We collect more output from the given job and store it in the
1.101     espie     925:  *     job's outBuf. If this makes up lines, we print it tagged by the job's
1.89      espie     926:  *     identifier, as necessary.
1.1       deraadt   927:  *
                    928:  * Side Effects:
                    929:  *     curPos may be shifted as may the contents of outBuf.
                    930:  *-----------------------------------------------------------------------
                    931:  */
1.48      espie     932: static void
1.119     espie     933: handle_pipe(struct job_pipe *p,
1.101     espie     934:        Job *job, FILE *out, bool finish)
1.66      espie     935: {
                    936:        int nr;                 /* number of bytes read */
1.101     espie     937:        int oldpos;             /* optimization */
1.1       deraadt   938:
1.101     espie     939:        /* want to get everything ? -> we block */
                    940:        if (finish)
                    941:                fcntl(p->fd, F_SETFL, 0);
                    942:
                    943:        do {
                    944:                nr = read(p->fd, &p->buffer[p->pos],
                    945:                    JOB_BUFSIZE - p->pos);
                    946:                if (nr == -1) {
                    947:                        if (errno == EAGAIN)
                    948:                                break;
                    949:                        if (DEBUG(JOB)) {
                    950:                                perror("JobDoOutput(piperead)");
                    951:                        }
1.66      espie     952:                }
1.101     espie     953:                oldpos = p->pos;
                    954:                p->pos += nr;
                    955:                if (!print_complete_lines(p, job, out, oldpos))
                    956:                        if (p->pos == JOB_BUFSIZE) {
                    957:                                print_partial_buffer(p, job, out, p->pos);
                    958:                                p->pos = 0;
                    959:                        }
                    960:        } while (nr != 0);
1.1       deraadt   961:
1.101     espie     962:        /* at end of file, we print whatever is left */
                    963:        if (nr == 0) {
                    964:                print_partial_buffer(p, job, out, p->pos);
                    965:                if (p->pos > 0 && p->buffer[p->pos - 1] != '\n')
                    966:                        putchar('\n');
                    967:                p->pos = 0;
1.76      espie     968:        }
1.101     espie     969: }
1.6       millert   970:
1.101     espie     971: static void
                    972: handle_job_output(Job *job, int i, bool finish)
                    973: {
                    974:        handle_pipe(&job->in[i], job, i == 0 ? stdout : stderr, finish);
1.1       deraadt   975: }
                    976:
1.117     espie     977: static void
                    978: remove_job(LstNode ln, int status)
                    979: {
                    980:        Job *job;
                    981:
                    982:        job = (Job *)Lst_Datum(ln);
                    983:        Lst_Remove(&runningJobs, ln);
                    984:        block_signals();
                    985:        free(Lst_Datum(job->p));
                    986:        Lst_Remove(&job_pids, job->p);
                    987:        unblock_signals();
                    988:        nJobs--;
                    989:        if (job->flags & JOB_IS_EXPENSIVE)
                    990:                expensive_job = false;
                    991:        process_job_status(job, status);
                    992: }
                    993:
1.1       deraadt   994: /*-
                    995:  *-----------------------------------------------------------------------
                    996:  * Job_CatchChildren --
1.111     espie     997:  *     Handle the exit of a child. Called by handle_running_jobs
1.1       deraadt   998:  *
                    999:  * Side Effects:
                   1000:  *     The job descriptor is removed from the list of children.
                   1001:  *
                   1002:  * Notes:
                   1003:  *     We do waits, blocking or not, according to the wisdom of our
                   1004:  *     caller, until there are no more children to report. For each
1.119     espie    1005:  *     job, call process_job_status to finish things off.
1.1       deraadt  1006:  *-----------------------------------------------------------------------
                   1007:  */
                   1008: void
1.76      espie    1009: Job_CatchChildren()
1.1       deraadt  1010: {
1.78      espie    1011:        pid_t pid;      /* pid of dead child */
                   1012:        LstNode jnode;  /* list element for finding job */
                   1013:        int status;     /* Exit/termination status */
1.1       deraadt  1014:
1.66      espie    1015:        /*
                   1016:         * Don't even bother if we know there's no one around.
                   1017:         */
1.112     espie    1018:        if (nJobs == 0)
1.66      espie    1019:                return;
1.6       millert  1020:
1.117     espie    1021:        while ((pid = waitpid(WAIT_ANY, &status, WNOHANG)) > 0) {
1.93      espie    1022:                handle_all_signals();
1.1       deraadt  1023:
1.95      espie    1024:                jnode = Lst_Find(&runningJobs, JobCmpPid, &pid);
1.1       deraadt  1025:
1.18      espie    1026:                if (jnode == NULL) {
1.117     espie    1027:                        Error("Child (%ld) not in table?", (long)pid);
1.66      espie    1028:                } else {
1.117     espie    1029:                        remove_job(jnode, status);
1.1       deraadt  1030:                }
                   1031:        }
                   1032: }
                   1033:
                   1034: void
1.112     espie    1035: handle_all_jobs_output(void)
1.1       deraadt  1036: {
1.66      espie    1037:        int nfds;
                   1038:        struct timeval timeout;
1.111     espie    1039:        LstNode ln, ln2;
1.66      espie    1040:        Job *job;
1.101     espie    1041:        int i;
1.111     espie    1042:        int status;
1.66      espie    1043:
1.112     espie    1044:        /* no jobs */
                   1045:        if (Lst_IsEmpty(&runningJobs))
                   1046:                return;
1.91      espie    1047:
1.77      espie    1048:        (void)fflush(stdout);
1.76      espie    1049:
1.112     espie    1050:        memcpy(actual_mask, output_mask, mask_size);
1.76      espie    1051:        timeout.tv_sec = SEL_SEC;
                   1052:        timeout.tv_usec = SEL_USEC;
1.66      espie    1053:
1.112     espie    1054:        nfds = select(largest_fd+1, actual_mask, NULL, NULL, &timeout);
1.93      espie    1055:        handle_all_signals();
1.118     espie    1056:        for (ln = Lst_First(&runningJobs); nfds && ln != NULL; ln = ln2) {
1.111     espie    1057:                ln2 = Lst_Adv(ln);
                   1058:                job = (Job *)Lst_Datum(ln);
                   1059:                job->flags &= ~JOB_DIDOUTPUT;
                   1060:                for (i = 1; i >= 0; i--) {
1.112     espie    1061:                        if (FD_ISSET(job->in[i].fd, actual_mask)) {
1.111     espie    1062:                                nfds--;
                   1063:                                handle_job_output(job, i, false);
                   1064:                        }
                   1065:                }
                   1066:                if (job->flags & JOB_DIDOUTPUT) {
1.117     espie    1067:                        if (waitpid(job->pid, &status, WNOHANG) == job->pid) {
                   1068:                                remove_job(ln, status);
1.111     espie    1069:                        } else {
                   1070:                                Lst_Requeue(&runningJobs, ln);
1.66      espie    1071:                        }
1.1       deraadt  1072:                }
                   1073:        }
                   1074: }
                   1075:
1.111     espie    1076: void
                   1077: handle_running_jobs()
                   1078: {
1.112     espie    1079:        handle_all_jobs_output();
1.111     espie    1080:        Job_CatchChildren();
                   1081: }
                   1082:
                   1083: static void
                   1084: loop_handle_running_jobs()
                   1085: {
                   1086:        while (nJobs)
                   1087:                handle_running_jobs();
                   1088: }
1.1       deraadt  1089: /*-
                   1090:  *-----------------------------------------------------------------------
                   1091:  * Job_Make --
                   1092:  *     Start the creation of a target. Basically a front-end for
                   1093:  *     JobStart used by the Make module.
                   1094:  *
                   1095:  * Side Effects:
                   1096:  *     Another job is started.
                   1097:  *-----------------------------------------------------------------------
                   1098:  */
                   1099: void
1.56      espie    1100: Job_Make(GNode *gn)
1.1       deraadt  1101: {
1.86      espie    1102:        (void)JobStart(gn, 0);
1.1       deraadt  1103: }
                   1104:
1.117     espie    1105:
                   1106: static void
                   1107: block_signals()
                   1108: {
                   1109:        sigprocmask(SIG_BLOCK, &set, &oset);
                   1110: }
                   1111:
                   1112: static void
                   1113: unblock_signals()
                   1114: {
                   1115:        sigprocmask(SIG_SETMASK, &oset, NULL);
                   1116: }
                   1117:
1.1       deraadt  1118: /*-
                   1119:  *-----------------------------------------------------------------------
                   1120:  * Job_Init --
                   1121:  *     Initialize the process module
                   1122:  *
                   1123:  * Side Effects:
                   1124:  *     lists and counters are initialized
                   1125:  *-----------------------------------------------------------------------
                   1126:  */
                   1127: void
1.83      espie    1128: Job_Init(int maxproc)
1.1       deraadt  1129: {
1.95      espie    1130:        Static_Lst_Init(&runningJobs);
1.101     espie    1131:        Static_Lst_Init(&errorsList);
1.117     espie    1132:        maxJobs = maxproc;
                   1133:        nJobs = 0;
1.101     espie    1134:        errors = 0;
1.117     espie    1135:        sigemptyset(&set);
                   1136:        sigaddset(&set, SIGINT);
                   1137:        sigaddset(&set, SIGHUP);
                   1138:        sigaddset(&set, SIGQUIT);
                   1139:        sigaddset(&set, SIGTERM);
                   1140:        sigaddset(&set, SIGTSTP);
                   1141:        sigaddset(&set, SIGTTOU);
                   1142:        sigaddset(&set, SIGTTIN);
1.66      espie    1143:
1.117     espie    1144:        aborting = 0;
1.40      espie    1145:
1.117     espie    1146:        lastNode = NULL;
1.1       deraadt  1147:
1.78      espie    1148:        if ((begin_node->type & OP_DUMMY) == 0) {
1.117     espie    1149:                JobStart(begin_node, JOB_IS_SPECIAL);
1.111     espie    1150:                loop_handle_running_jobs();
1.1       deraadt  1151:        }
                   1152: }
                   1153:
1.117     espie    1154: static bool
                   1155: Job_Full()
                   1156: {
                   1157:        return aborting || (nJobs >= maxJobs);
                   1158: }
1.1       deraadt  1159: /*-
                   1160:  *-----------------------------------------------------------------------
                   1161:  * Job_Full --
1.117     espie    1162:  *     See if the job table is full. It is considered full
1.1       deraadt  1163:  *     if we are in the process of aborting OR if we have
1.119     espie    1164:  *     reached/exceeded our quota.
1.1       deraadt  1165:  *
                   1166:  * Results:
1.41      espie    1167:  *     true if the job table is full, false otherwise
1.1       deraadt  1168:  *-----------------------------------------------------------------------
                   1169:  */
1.41      espie    1170: bool
1.117     espie    1171: can_start_job(void)
1.1       deraadt  1172: {
1.117     espie    1173:        if (Job_Full() || expensive_job)
                   1174:                return false;
1.119     espie    1175:        else
1.117     espie    1176:                return true;
1.1       deraadt  1177: }
                   1178:
                   1179: /*-
                   1180:  *-----------------------------------------------------------------------
                   1181:  * Job_Empty --
1.119     espie    1182:  *     See if the job table is empty.
1.1       deraadt  1183:  *
                   1184:  * Results:
1.41      espie    1185:  *     true if it is. false if it ain't.
1.1       deraadt  1186:  * -----------------------------------------------------------------------
                   1187:  */
1.41      espie    1188: bool
1.56      espie    1189: Job_Empty(void)
1.1       deraadt  1190: {
1.117     espie    1191:        if (nJobs == 0)
                   1192:                return true;
                   1193:        else
1.66      espie    1194:                return false;
1.1       deraadt  1195: }
                   1196:
                   1197: /*-
                   1198:  *-----------------------------------------------------------------------
                   1199:  * JobInterrupt --
                   1200:  *     Handle the receipt of an interrupt.
                   1201:  *
                   1202:  * Side Effects:
                   1203:  *     All children are killed. Another job will be started if the
                   1204:  *     .INTERRUPT target was given.
                   1205:  *-----------------------------------------------------------------------
                   1206:  */
                   1207: static void
1.117     espie    1208: JobInterrupt(bool runINTERRUPT,        /* true if commands for the .INTERRUPT
1.1       deraadt  1209:                                 * target should be executed */
1.66      espie    1210:     int signo)                 /* signal received */
1.1       deraadt  1211: {
1.66      espie    1212:        LstNode ln;             /* element in job table */
1.78      espie    1213:        Job *job;               /* job descriptor in that element */
1.66      espie    1214:
                   1215:        aborting = ABORT_INTERRUPT;
                   1216:
1.95      espie    1217:        for (ln = Lst_First(&runningJobs); ln != NULL; ln = Lst_Adv(ln)) {
1.66      espie    1218:                job = (Job *)Lst_Datum(ln);
                   1219:
                   1220:                if (!Targ_Precious(job->node)) {
                   1221:                        const char *file = job->node->path == NULL ?
                   1222:                            job->node->name : job->node->path;
                   1223:                        if (!noExecute && eunlink(file) != -1) {
                   1224:                                Error("*** %s removed", file);
                   1225:                        }
                   1226:                }
                   1227:                if (job->pid) {
1.84      espie    1228:                        debug_printf("JobInterrupt passing signal to "
                   1229:                            "child %ld.\n", (long)job->pid);
1.117     espie    1230:                        killpg(job->pid, signo);
1.66      espie    1231:                }
1.2       deraadt  1232:        }
1.1       deraadt  1233:
1.66      espie    1234:        if (runINTERRUPT && !touchFlag) {
1.78      espie    1235:                if ((interrupt_node->type & OP_DUMMY) == 0) {
1.66      espie    1236:                        ignoreErrors = false;
                   1237:
1.101     espie    1238:                        JobStart(interrupt_node, 0);
1.111     espie    1239:                        loop_handle_running_jobs();
1.66      espie    1240:                }
1.1       deraadt  1241:        }
1.66      espie    1242:        exit(signo);
1.1       deraadt  1243: }
                   1244:
                   1245: /*
                   1246:  *-----------------------------------------------------------------------
1.12      espie    1247:  * Job_Finish --
1.1       deraadt  1248:  *     Do final processing such as the running of the commands
1.6       millert  1249:  *     attached to the .END target.
1.1       deraadt  1250:  *
                   1251:  * Results:
                   1252:  *     Number of errors reported.
1.40      espie    1253:  *
1.1       deraadt  1254:  *-----------------------------------------------------------------------
                   1255:  */
                   1256: int
1.56      espie    1257: Job_Finish(void)
1.1       deraadt  1258: {
1.116     espie    1259:        if ((end_node->type & OP_DUMMY) == 0) {
1.66      espie    1260:                if (errors) {
                   1261:                        Error("Errors reported so .END ignored");
                   1262:                } else {
1.117     espie    1263:                        JobStart(end_node, JOB_IS_SPECIAL);
1.111     espie    1264:                        loop_handle_running_jobs();
1.66      espie    1265:                }
1.1       deraadt  1266:        }
1.66      espie    1267:        return errors;
1.1       deraadt  1268: }
                   1269:
1.41      espie    1270: #ifdef CLEANUP
1.12      espie    1271: void
1.56      espie    1272: Job_End(void)
1.12      espie    1273: {
1.41      espie    1274: }
1.13      espie    1275: #endif
1.40      espie    1276:
1.1       deraadt  1277: /*-
                   1278:  *-----------------------------------------------------------------------
                   1279:  * Job_Wait --
                   1280:  *     Waits for all running jobs to finish and returns. Sets 'aborting'
                   1281:  *     to ABORT_WAIT to prevent other jobs from starting.
                   1282:  *
                   1283:  * Side Effects:
                   1284:  *     Currently running jobs finish.
                   1285:  *
                   1286:  *-----------------------------------------------------------------------
                   1287:  */
                   1288: void
1.56      espie    1289: Job_Wait(void)
1.1       deraadt  1290: {
1.66      espie    1291:        aborting = ABORT_WAIT;
1.111     espie    1292:        loop_handle_running_jobs();
1.66      espie    1293:        aborting = 0;
1.1       deraadt  1294: }
                   1295:
                   1296: /*-
                   1297:  *-----------------------------------------------------------------------
                   1298:  * Job_AbortAll --
                   1299:  *     Abort all currently running jobs without handling output or anything.
                   1300:  *     This function is to be called only in the event of a major
                   1301:  *     error. Most definitely NOT to be called from JobInterrupt.
                   1302:  *
                   1303:  * Side Effects:
                   1304:  *     All children are killed, not just the firstborn
                   1305:  *-----------------------------------------------------------------------
                   1306:  */
                   1307: void
1.56      espie    1308: Job_AbortAll(void)
1.1       deraadt  1309: {
1.66      espie    1310:        LstNode ln;     /* element in job table */
                   1311:        Job *job;       /* the job descriptor in that element */
                   1312:        int foo;
1.6       millert  1313:
1.66      espie    1314:        aborting = ABORT_ERROR;
1.6       millert  1315:
1.66      espie    1316:        if (nJobs) {
1.119     espie    1317:                for (ln = Lst_First(&runningJobs); ln != NULL;
1.95      espie    1318:                    ln = Lst_Adv(ln)) {
1.66      espie    1319:                        job = (Job *)Lst_Datum(ln);
                   1320:
                   1321:                        /*
                   1322:                         * kill the child process with increasingly drastic
                   1323:                         * signals to make darn sure it's dead.
                   1324:                         */
1.117     espie    1325:                        killpg(job->pid, SIGINT);
                   1326:                        killpg(job->pid, SIGKILL);
1.66      espie    1327:                }
1.1       deraadt  1328:        }
1.6       millert  1329:
1.66      espie    1330:        /*
                   1331:         * Catch as many children as want to report in at first, then give up
                   1332:         */
1.117     espie    1333:        while (waitpid(WAIT_ANY, &foo, WNOHANG) > 0)
1.66      espie    1334:                continue;
1.2       deraadt  1335: }
1.40      espie    1336: