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: