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