Annotation of src/usr.bin/make/job.c, Revision 1.1.1.1
1.1 deraadt 1: /* $NetBSD: job.c,v 1.11 1995/09/27 18:44:40 jtc Exp $ */
2:
3: /*
4: * Copyright (c) 1988, 1989, 1990 The Regents of the University of California.
5: * Copyright (c) 1988, 1989 by Adam de Boor
6: * Copyright (c) 1989 by Berkeley Softworks
7: * All rights reserved.
8: *
9: * This code is derived from software contributed to Berkeley by
10: * Adam de Boor.
11: *
12: * Redistribution and use in source and binary forms, with or without
13: * modification, are permitted provided that the following conditions
14: * are met:
15: * 1. Redistributions of source code must retain the above copyright
16: * notice, this list of conditions and the following disclaimer.
17: * 2. Redistributions in binary form must reproduce the above copyright
18: * notice, this list of conditions and the following disclaimer in the
19: * documentation and/or other materials provided with the distribution.
20: * 3. All advertising materials mentioning features or use of this software
21: * must display the following acknowledgement:
22: * This product includes software developed by the University of
23: * California, Berkeley and its contributors.
24: * 4. Neither the name of the University nor the names of its contributors
25: * may be used to endorse or promote products derived from this software
26: * without specific prior written permission.
27: *
28: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
29: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
30: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
31: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
32: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
33: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
34: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
35: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
36: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
37: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
38: * SUCH DAMAGE.
39: */
40:
41: #ifndef lint
42: #if 0
43: static char sccsid[] = "@(#)job.c 5.15 (Berkeley) 3/1/91";
44: #else
45: static char rcsid[] = "$NetBSD: job.c,v 1.11 1995/09/27 18:44:40 jtc Exp $";
46: #endif
47: #endif /* not lint */
48:
49: /*-
50: * job.c --
51: * handle the creation etc. of our child processes.
52: *
53: * Interface:
54: * Job_Make Start the creation of the given target.
55: *
56: * Job_CatchChildren Check for and handle the termination of any
57: * children. This must be called reasonably
58: * frequently to keep the whole make going at
59: * a decent clip, since job table entries aren't
60: * removed until their process is caught this way.
61: * Its single argument is TRUE if the function
62: * should block waiting for a child to terminate.
63: *
64: * Job_CatchOutput Print any output our children have produced.
65: * Should also be called fairly frequently to
66: * keep the user informed of what's going on.
67: * If no output is waiting, it will block for
68: * a time given by the SEL_* constants, below,
69: * or until output is ready.
70: *
71: * Job_Init Called to intialize this module. in addition,
72: * any commands attached to the .BEGIN target
73: * are executed before this function returns.
74: * Hence, the makefile must have been parsed
75: * before this function is called.
76: *
77: * Job_Full Return TRUE if the job table is filled.
78: *
79: * Job_Empty Return TRUE if the job table is completely
80: * empty.
81: *
82: * Job_ParseShell Given the line following a .SHELL target, parse
83: * the line as a shell specification. Returns
84: * FAILURE if the spec was incorrect.
85: *
86: * Job_End Perform any final processing which needs doing.
87: * This includes the execution of any commands
88: * which have been/were attached to the .END
89: * target. It should only be called when the
90: * job table is empty.
91: *
92: * Job_AbortAll Abort all currently running jobs. It doesn't
93: * handle output or do anything for the jobs,
94: * just kills them. It should only be called in
95: * an emergency, as it were.
96: *
97: * Job_CheckCommands Verify that the commands for a target are
98: * ok. Provide them if necessary and possible.
99: *
100: * Job_Touch Update a target without really updating it.
101: *
102: * Job_Wait Wait for all currently-running jobs to finish.
103: */
104:
105: #include <sys/types.h>
106: #include <sys/stat.h>
107: #include <sys/file.h>
108: #include <sys/time.h>
109: #include <sys/wait.h>
110: #include <fcntl.h>
111: #include <errno.h>
112: #include <signal.h>
113: #include <stdio.h>
114: #include <string.h>
115: #include <signal.h>
116: #include "make.h"
117: #include "hash.h"
118: #include "dir.h"
119: #include "job.h"
120: #include "pathnames.h"
121:
122: extern int errno;
123:
124: /*
125: * error handling variables
126: */
127: static int errors = 0; /* number of errors reported */
128: static int aborting = 0; /* why is the make aborting? */
129: #define ABORT_ERROR 1 /* Because of an error */
130: #define ABORT_INTERRUPT 2 /* Because it was interrupted */
131: #define ABORT_WAIT 3 /* Waiting for jobs to finish */
132:
133:
134: /*
135: * post-make command processing. The node postCommands is really just the
136: * .END target but we keep it around to avoid having to search for it
137: * all the time.
138: */
139: static GNode *postCommands; /* node containing commands to execute when
140: * everything else is done */
141: static int numCommands; /* The number of commands actually printed
142: * for a target. Should this number be
143: * 0, no shell will be executed. */
144:
145:
146: /*
147: * Return values from JobStart.
148: */
149: #define JOB_RUNNING 0 /* Job is running */
150: #define JOB_ERROR 1 /* Error in starting the job */
151: #define JOB_FINISHED 2 /* The job is already finished */
152: #define JOB_STOPPED 3 /* The job is stopped */
153:
154: /*
155: * tfile is the name of a file into which all shell commands are put. It is
156: * used over by removing it before the child shell is executed. The XXXXX in
157: * the string are replaced by the pid of the make process in a 5-character
158: * field with leading zeroes.
159: */
160: static char tfile[] = TMPPAT;
161:
162:
163: /*
164: * Descriptions for various shells.
165: */
166: static Shell shells[] = {
167: /*
168: * CSH description. The csh can do echo control by playing
169: * with the setting of the 'echo' shell variable. Sadly,
170: * however, it is unable to do error control nicely.
171: */
172: {
173: "csh",
174: TRUE, "unset verbose", "set verbose", "unset verbose", 10,
175: FALSE, "echo \"%s\"\n", "csh -c \"%s || exit 0\"",
176: "v", "e",
177: },
178: /*
179: * SH description. Echo control is also possible and, under
180: * sun UNIX anyway, one can even control error checking.
181: */
182: {
183: "sh",
184: TRUE, "set -", "set -v", "set -", 5,
185: FALSE, "echo \"%s\"\n", "sh -c '%s || exit 0'\n",
186: "v", "e",
187: },
188: /*
189: * UNKNOWN.
190: */
191: {
192: (char *)0,
193: FALSE, (char *)0, (char *)0, (char *)0, 0,
194: FALSE, (char *)0, (char *)0,
195: (char *)0, (char *)0,
196: }
197: };
198: static Shell *commandShell = &shells[DEFSHELL];/* this is the shell to
199: * which we pass all
200: * commands in the Makefile.
201: * It is set by the
202: * Job_ParseShell function */
203: static char *shellPath = (char *) NULL, /* full pathname of
204: * executable image */
205: *shellName; /* last component of shell */
206:
207:
208: static int maxJobs; /* The most children we can run at once */
209: static int maxLocal; /* The most local ones we can have */
210: int nJobs; /* The number of children currently running */
211: int nLocal; /* The number of local children */
212: Lst jobs; /* The structures that describe them */
213: Boolean jobFull; /* Flag to tell when the job table is full. It
214: * is set TRUE when (1) the total number of
215: * running jobs equals the maximum allowed or
216: * (2) a job can only be run locally, but
217: * nLocal equals maxLocal */
218: #ifndef RMT_WILL_WATCH
219: static fd_set outputs; /* Set of descriptors of pipes connected to
220: * the output channels of children */
221: #endif
222:
223: GNode *lastNode; /* The node for which output was most recently
224: * produced. */
225: char *targFmt; /* Format string to use to head output from a
226: * job when it's not the most-recent job heard
227: * from */
228: #define TARG_FMT "--- %s ---\n" /* Default format */
229:
230: /*
231: * When JobStart attempts to run a job remotely but can't, and isn't allowed
232: * to run the job locally, or when Job_CatchChildren detects a job that has
233: * been migrated home, the job is placed on the stoppedJobs queue to be run
234: * when the next job finishes.
235: */
236: Lst stoppedJobs; /* Lst of Job structures describing
237: * jobs that were stopped due to concurrency
238: * limits or migration home */
239:
240:
241: #if defined(USE_PGRP) && defined(SYSV)
242: #define KILL(pid,sig) killpg (-(pid),(sig))
243: #else
244: # if defined(USE_PGRP)
245: #define KILL(pid,sig) killpg ((pid),(sig))
246: # else
247: #define KILL(pid,sig) kill ((pid),(sig))
248: # endif
249: #endif
250:
251: static int JobCondPassSig __P((ClientData, ClientData));
252: static void JobPassSig __P((int));
253: static int JobCmpPid __P((ClientData, ClientData));
254: static int JobPrintCommand __P((ClientData, ClientData));
255: static int JobSaveCommand __P((ClientData, ClientData));
256: static void JobFinish __P((Job *, union wait));
257: static void JobExec __P((Job *, char **));
258: static void JobMakeArgv __P((Job *, char **));
259: static void JobRestart __P((Job *));
260: static int JobStart __P((GNode *, int, Job *));
261: static void JobDoOutput __P((Job *, Boolean));
262: static Shell *JobMatchShell __P((char *));
263: static void JobInterrupt __P((int));
264:
265: /*-
266: *-----------------------------------------------------------------------
267: * JobCondPassSig --
268: * Pass a signal to a job if the job is remote or if USE_PGRP
269: * is defined.
270: *
271: * Results:
272: * === 0
273: *
274: * Side Effects:
275: * None, except the job may bite it.
276: *
277: *-----------------------------------------------------------------------
278: */
279: static int
280: JobCondPassSig(jobp, signop)
281: ClientData jobp; /* Job to biff */
282: ClientData signop; /* Signal to send it */
283: {
284: Job *job = (Job *) jobp;
285: int signo = *(int *) signop;
286: #ifdef RMT_WANTS_SIGNALS
287: if (job->flags & JOB_REMOTE) {
288: (void)Rmt_Signal(job, signo);
289: } else {
290: KILL(job->pid, signo);
291: }
292: #else
293: /*
294: * Assume that sending the signal to job->pid will signal any remote
295: * job as well.
296: */
297: KILL(job->pid, signo);
298: #endif
299: return(0);
300: }
301:
302: /*-
303: *-----------------------------------------------------------------------
304: * JobPassSig --
305: * Pass a signal on to all remote jobs and to all local jobs if
306: * USE_PGRP is defined, then die ourselves.
307: *
308: * Results:
309: * None.
310: *
311: * Side Effects:
312: * We die by the same signal.
313: *
314: *-----------------------------------------------------------------------
315: */
316: static void
317: JobPassSig(signo)
318: int signo; /* The signal number we've received */
319: {
320: int mask;
321:
322: Lst_ForEach(jobs, JobCondPassSig, (ClientData)(long)signo);
323:
324: /*
325: * Deal with proper cleanup based on the signal received. We only run
326: * the .INTERRUPT target if the signal was in fact an interrupt. The other
327: * three termination signals are more of a "get out *now*" command.
328: */
329: if (signo == SIGINT) {
330: JobInterrupt(TRUE);
331: } else if ((signo == SIGHUP) || (signo == SIGTERM) || (signo == SIGQUIT)) {
332: JobInterrupt(FALSE);
333: }
334:
335: /*
336: * Leave gracefully if SIGQUIT, rather than core dumping.
337: */
338: if (signo == SIGQUIT) {
339: Finish(0);
340: }
341:
342: /*
343: * Send ourselves the signal now we've given the message to everyone else.
344: * Note we block everything else possible while we're getting the signal.
345: * This ensures that all our jobs get continued when we wake up before
346: * we take any other signal.
347: */
348: mask = sigblock(0);
349: (void) sigsetmask(~0 & ~(1 << (signo-1)));
350: signal(signo, SIG_DFL);
351:
352: kill(getpid(), signo);
353:
354: signo = SIGCONT;
355: Lst_ForEach(jobs, JobCondPassSig, (ClientData) &signo);
356:
357: sigsetmask(mask);
358: signal(signo, JobPassSig);
359:
360: }
361:
362: /*-
363: *-----------------------------------------------------------------------
364: * JobCmpPid --
365: * Compare the pid of the job with the given pid and return 0 if they
366: * are equal. This function is called from Job_CatchChildren via
367: * Lst_Find to find the job descriptor of the finished job.
368: *
369: * Results:
370: * 0 if the pid's match
371: *
372: * Side Effects:
373: * None
374: *-----------------------------------------------------------------------
375: */
376: static int
377: JobCmpPid (job, pid)
378: ClientData job; /* job to examine */
379: ClientData pid; /* process id desired */
380: {
381: return ( *(int *) pid - ((Job *) job)->pid);
382: }
383:
384: /*-
385: *-----------------------------------------------------------------------
386: * JobPrintCommand --
387: * Put out another command for the given job. If the command starts
388: * with an @ or a - we process it specially. In the former case,
389: * so long as the -s and -n flags weren't given to make, we stick
390: * a shell-specific echoOff command in the script. In the latter,
391: * we ignore errors for the entire job, unless the shell has error
392: * control.
393: * If the command is just "..." we take all future commands for this
394: * job to be commands to be executed once the entire graph has been
395: * made and return non-zero to signal that the end of the commands
396: * was reached. These commands are later attached to the postCommands
397: * node and executed by Job_End when all things are done.
398: * This function is called from JobStart via Lst_ForEach.
399: *
400: * Results:
401: * Always 0, unless the command was "..."
402: *
403: * Side Effects:
404: * If the command begins with a '-' and the shell has no error control,
405: * the JOB_IGNERR flag is set in the job descriptor.
406: * If the command is "..." and we're not ignoring such things,
407: * tailCmds is set to the successor node of the cmd.
408: * numCommands is incremented if the command is actually printed.
409: *-----------------------------------------------------------------------
410: */
411: static int
412: JobPrintCommand (cmdp, jobp)
413: ClientData cmdp; /* command string to print */
414: ClientData jobp; /* job for which to print it */
415: {
416: Boolean noSpecials; /* true if we shouldn't worry about
417: * inserting special commands into
418: * the input stream. */
419: Boolean shutUp = FALSE; /* true if we put a no echo command
420: * into the command file */
421: Boolean errOff = FALSE; /* true if we turned error checking
422: * off before printing the command
423: * and need to turn it back on */
424: char *cmdTemplate; /* Template to use when printing the
425: * command */
426: char *cmdStart; /* Start of expanded command */
427: LstNode cmdNode; /* Node for replacing the command */
428: char *cmd = (char *) cmdp;
429: Job *job = (Job *) jobp;
430:
431: noSpecials = (noExecute && ! (job->node->type & OP_MAKE));
432:
433: if (strcmp (cmd, "...") == 0) {
434: job->node->type |= OP_SAVE_CMDS;
435: if ((job->flags & JOB_IGNDOTS) == 0) {
436: job->tailCmds = Lst_Succ (Lst_Member (job->node->commands,
437: (ClientData)cmd));
438: return (1);
439: }
440: return (0);
441: }
442:
443: #define DBPRINTF(fmt, arg) if (DEBUG(JOB)) printf (fmt, arg); fprintf (job->cmdFILE, fmt, arg)
444:
445: numCommands += 1;
446:
447: /*
448: * For debugging, we replace each command with the result of expanding
449: * the variables in the command.
450: */
451: cmdNode = Lst_Member (job->node->commands, (ClientData)cmd);
452: cmdStart = cmd = Var_Subst (NULL, cmd, job->node, FALSE);
453: Lst_Replace (cmdNode, (ClientData)cmdStart);
454:
455: cmdTemplate = "%s\n";
456:
457: /*
458: * Check for leading @' and -'s to control echoing and error checking.
459: */
460: while (*cmd == '@' || *cmd == '-') {
461: if (*cmd == '@') {
462: shutUp = TRUE;
463: } else {
464: errOff = TRUE;
465: }
466: cmd++;
467: }
468:
469: while (isspace((unsigned char) *cmd))
470: cmd++;
471:
472: if (shutUp) {
473: if (! (job->flags & JOB_SILENT) && !noSpecials &&
474: commandShell->hasEchoCtl) {
475: DBPRINTF ("%s\n", commandShell->echoOff);
476: } else {
477: shutUp = FALSE;
478: }
479: }
480:
481: if (errOff) {
482: if ( ! (job->flags & JOB_IGNERR) && !noSpecials) {
483: if (commandShell->hasErrCtl) {
484: /*
485: * we don't want the error-control commands showing
486: * up either, so we turn off echoing while executing
487: * them. We could put another field in the shell
488: * structure to tell JobDoOutput to look for this
489: * string too, but why make it any more complex than
490: * it already is?
491: */
492: if (! (job->flags & JOB_SILENT) && !shutUp &&
493: commandShell->hasEchoCtl) {
494: DBPRINTF ("%s\n", commandShell->echoOff);
495: DBPRINTF ("%s\n", commandShell->ignErr);
496: DBPRINTF ("%s\n", commandShell->echoOn);
497: } else {
498: DBPRINTF ("%s\n", commandShell->ignErr);
499: }
500: } else if (commandShell->ignErr &&
501: (*commandShell->ignErr != '\0'))
502: {
503: /*
504: * The shell has no error control, so we need to be
505: * weird to get it to ignore any errors from the command.
506: * If echoing is turned on, we turn it off and use the
507: * errCheck template to echo the command. Leave echoing
508: * off so the user doesn't see the weirdness we go through
509: * to ignore errors. Set cmdTemplate to use the weirdness
510: * instead of the simple "%s\n" template.
511: */
512: if (! (job->flags & JOB_SILENT) && !shutUp &&
513: commandShell->hasEchoCtl) {
514: DBPRINTF ("%s\n", commandShell->echoOff);
515: DBPRINTF (commandShell->errCheck, cmd);
516: shutUp = TRUE;
517: }
518: cmdTemplate = commandShell->ignErr;
519: /*
520: * The error ignoration (hee hee) is already taken care
521: * of by the ignErr template, so pretend error checking
522: * is still on.
523: */
524: errOff = FALSE;
525: } else {
526: errOff = FALSE;
527: }
528: } else {
529: errOff = FALSE;
530: }
531: }
532:
533: DBPRINTF (cmdTemplate, cmd);
534:
535: if (errOff) {
536: /*
537: * If echoing is already off, there's no point in issuing the
538: * echoOff command. Otherwise we issue it and pretend it was on
539: * for the whole command...
540: */
541: if (!shutUp && !(job->flags & JOB_SILENT) && commandShell->hasEchoCtl){
542: DBPRINTF ("%s\n", commandShell->echoOff);
543: shutUp = TRUE;
544: }
545: DBPRINTF ("%s\n", commandShell->errCheck);
546: }
547: if (shutUp) {
548: DBPRINTF ("%s\n", commandShell->echoOn);
549: }
550: return (0);
551: }
552:
553: /*-
554: *-----------------------------------------------------------------------
555: * JobSaveCommand --
556: * Save a command to be executed when everything else is done.
557: * Callback function for JobFinish...
558: *
559: * Results:
560: * Always returns 0
561: *
562: * Side Effects:
563: * The command is tacked onto the end of postCommands's commands list.
564: *
565: *-----------------------------------------------------------------------
566: */
567: static int
568: JobSaveCommand (cmd, gn)
569: ClientData cmd;
570: ClientData gn;
571: {
572: cmd = (ClientData) Var_Subst (NULL, (char *) cmd, (GNode *) gn, FALSE);
573: (void)Lst_AtEnd (postCommands->commands, cmd);
574: return (0);
575: }
576:
577: /*-
578: *-----------------------------------------------------------------------
579: * JobFinish --
580: * Do final processing for the given job including updating
581: * parents and starting new jobs as available/necessary. Note
582: * that we pay no attention to the JOB_IGNERR flag here.
583: * This is because when we're called because of a noexecute flag
584: * or something, jstat.w_status is 0 and when called from
585: * Job_CatchChildren, the status is zeroed if it s/b ignored.
586: *
587: * Results:
588: * None
589: *
590: * Side Effects:
591: * Some nodes may be put on the toBeMade queue.
592: * Final commands for the job are placed on postCommands.
593: *
594: * If we got an error and are aborting (aborting == ABORT_ERROR) and
595: * the job list is now empty, we are done for the day.
596: * If we recognized an error (errors !=0), we set the aborting flag
597: * to ABORT_ERROR so no more jobs will be started.
598: *-----------------------------------------------------------------------
599: */
600: /*ARGSUSED*/
601: static void
602: JobFinish (job, status)
603: Job *job; /* job to finish */
604: union wait status; /* sub-why job went away */
605: {
606: Boolean done;
607:
608: if ((WIFEXITED(status) &&
609: (((status.w_retcode != 0) && !(job->flags & JOB_IGNERR)))) ||
610: (WIFSIGNALED(status) && (status.w_termsig != SIGCONT)))
611: {
612: /*
613: * If it exited non-zero and either we're doing things our
614: * way or we're not ignoring errors, the job is finished.
615: * Similarly, if the shell died because of a signal
616: * the job is also finished. In these
617: * cases, finish out the job's output before printing the exit
618: * status...
619: */
620: if (usePipes) {
621: #ifdef RMT_WILL_WATCH
622: Rmt_Ignore(job->inPipe);
623: #else
624: FD_CLR(job->inPipe, &outputs);
625: #endif /* RMT_WILL_WATCH */
626: if (job->outPipe != job->inPipe) {
627: (void)close (job->outPipe);
628: }
629: JobDoOutput (job, TRUE);
630: (void)close (job->inPipe);
631: } else {
632: (void)close (job->outFd);
633: JobDoOutput (job, TRUE);
634: }
635:
636: if (job->cmdFILE != NULL && job->cmdFILE != stdout) {
637: fclose(job->cmdFILE);
638: }
639: done = TRUE;
640: } else if (WIFEXITED(status) && status.w_retcode != 0) {
641: /*
642: * Deal with ignored errors in -B mode. We need to print a message
643: * telling of the ignored error as well as setting status.w_status
644: * to 0 so the next command gets run. To do this, we set done to be
645: * TRUE if in -B mode and the job exited non-zero. Note we don't
646: * want to close down any of the streams until we know we're at the
647: * end.
648: */
649: done = TRUE;
650: } else {
651: /*
652: * No need to close things down or anything.
653: */
654: done = FALSE;
655: }
656:
657: if (done ||
658: WIFSTOPPED(status) ||
659: (WIFSIGNALED(status) && (status.w_termsig == SIGCONT)) ||
660: DEBUG(JOB))
661: {
662: FILE *out;
663:
664: if (!usePipes && (job->flags & JOB_IGNERR)) {
665: /*
666: * If output is going to a file and this job is ignoring
667: * errors, arrange to have the exit status sent to the
668: * output file as well.
669: */
670: out = fdopen (job->outFd, "w");
671: } else {
672: out = stdout;
673: }
674:
675: if (WIFEXITED(status)) {
676: if (status.w_retcode != 0) {
677: if (usePipes && job->node != lastNode) {
678: fprintf (out, targFmt, job->node->name);
679: lastNode = job->node;
680: }
681: fprintf (out, "*** Error code %d%s\n", status.w_retcode,
682: (job->flags & JOB_IGNERR) ? " (ignored)" : "");
683:
684: if (job->flags & JOB_IGNERR) {
685: status.w_status = 0;
686: }
687: } else if (DEBUG(JOB)) {
688: if (usePipes && job->node != lastNode) {
689: fprintf (out, targFmt, job->node->name);
690: lastNode = job->node;
691: }
692: fprintf (out, "*** Completed successfully\n");
693: }
694: } else if (WIFSTOPPED(status)) {
695: if (usePipes && job->node != lastNode) {
696: fprintf (out, targFmt, job->node->name);
697: lastNode = job->node;
698: }
699: if (! (job->flags & JOB_REMIGRATE)) {
700: fprintf (out, "*** Stopped -- signal %d\n", status.w_stopsig);
701: }
702: job->flags |= JOB_RESUME;
703: (void)Lst_AtEnd(stoppedJobs, (ClientData)job);
704: fflush(out);
705: return;
706: } else if (status.w_termsig == SIGCONT) {
707: /*
708: * If the beastie has continued, shift the Job from the stopped
709: * list to the running one (or re-stop it if concurrency is
710: * exceeded) and go and get another child.
711: */
712: if (job->flags & (JOB_RESUME|JOB_REMIGRATE|JOB_RESTART)) {
713: if (usePipes && job->node != lastNode) {
714: fprintf (out, targFmt, job->node->name);
715: lastNode = job->node;
716: }
717: fprintf (out, "*** Continued\n");
718: }
719: if (! (job->flags & JOB_CONTINUING)) {
720: JobRestart(job);
721: } else {
722: Lst_AtEnd(jobs, (ClientData)job);
723: nJobs += 1;
724: if (! (job->flags & JOB_REMOTE)) {
725: nLocal += 1;
726: }
727: if (nJobs == maxJobs) {
728: jobFull = TRUE;
729: if (DEBUG(JOB)) {
730: printf("Job queue is full.\n");
731: }
732: }
733: }
734: fflush(out);
735: return;
736: } else {
737: if (usePipes && job->node != lastNode) {
738: fprintf (out, targFmt, job->node->name);
739: lastNode = job->node;
740: }
741: fprintf (out, "*** Signal %d\n", status.w_termsig);
742: }
743:
744: fflush (out);
745: }
746:
747: /*
748: * Now handle the -B-mode stuff. If the beast still isn't finished,
749: * try and restart the job on the next command. If JobStart says it's
750: * ok, it's ok. If there's an error, this puppy is done.
751: */
752: if ((status.w_status == 0) &&
753: !Lst_IsAtEnd (job->node->commands))
754: {
755: switch (JobStart (job->node,
756: job->flags & JOB_IGNDOTS,
757: job))
758: {
759: case JOB_RUNNING:
760: done = FALSE;
761: break;
762: case JOB_ERROR:
763: done = TRUE;
764: status.w_retcode = 1;
765: break;
766: case JOB_FINISHED:
767: /*
768: * If we got back a JOB_FINISHED code, JobStart has already
769: * called Make_Update and freed the job descriptor. We set
770: * done to false here to avoid fake cycles and double frees.
771: * JobStart needs to do the update so we can proceed up the
772: * graph when given the -n flag..
773: */
774: done = FALSE;
775: break;
776: }
777: } else {
778: done = TRUE;
779: }
780:
781:
782: if (done &&
783: (aborting != ABORT_ERROR) &&
784: (aborting != ABORT_INTERRUPT) &&
785: (status.w_status == 0))
786: {
787: /*
788: * As long as we aren't aborting and the job didn't return a non-zero
789: * status that we shouldn't ignore, we call Make_Update to update
790: * the parents. In addition, any saved commands for the node are placed
791: * on the .END target.
792: */
793: if (job->tailCmds != NILLNODE) {
794: Lst_ForEachFrom (job->node->commands, job->tailCmds,
795: JobSaveCommand,
796: (ClientData)job->node);
797: }
798: job->node->made = MADE;
799: Make_Update (job->node);
800: free((Address)job);
801: } else if (status.w_status) {
802: errors += 1;
803: free((Address)job);
804: }
805:
806: while (!errors && !jobFull && !Lst_IsEmpty(stoppedJobs)) {
807: JobRestart((Job *)Lst_DeQueue(stoppedJobs));
808: }
809:
810: /*
811: * Set aborting if any error.
812: */
813: if (errors && !keepgoing && (aborting != ABORT_INTERRUPT)) {
814: /*
815: * If we found any errors in this batch of children and the -k flag
816: * wasn't given, we set the aborting flag so no more jobs get
817: * started.
818: */
819: aborting = ABORT_ERROR;
820: }
821:
822: if ((aborting == ABORT_ERROR) && Job_Empty()) {
823: /*
824: * If we are aborting and the job table is now empty, we finish.
825: */
826: (void) unlink (tfile);
827: Finish (errors);
828: }
829: }
830:
831: /*-
832: *-----------------------------------------------------------------------
833: * Job_Touch --
834: * Touch the given target. Called by JobStart when the -t flag was
835: * given
836: *
837: * Results:
838: * None
839: *
840: * Side Effects:
841: * The data modification of the file is changed. In addition, if the
842: * file did not exist, it is created.
843: *-----------------------------------------------------------------------
844: */
845: void
846: Job_Touch (gn, silent)
847: GNode *gn; /* the node of the file to touch */
848: Boolean silent; /* TRUE if should not print messages */
849: {
850: int streamID; /* ID of stream opened to do the touch */
851: struct timeval times[2]; /* Times for utimes() call */
852:
853: if (gn->type & (OP_JOIN|OP_USE|OP_EXEC|OP_OPTIONAL)) {
854: /*
855: * .JOIN, .USE, .ZEROTIME and .OPTIONAL targets are "virtual" targets
856: * and, as such, shouldn't really be created.
857: */
858: return;
859: }
860:
861: if (!silent) {
862: printf ("touch %s\n", gn->name);
863: }
864:
865: if (noExecute) {
866: return;
867: }
868:
869: if (gn->type & OP_ARCHV) {
870: Arch_Touch (gn);
871: } else if (gn->type & OP_LIB) {
872: Arch_TouchLib (gn);
873: } else {
874: char *file = gn->path ? gn->path : gn->name;
875:
876: times[0].tv_sec = times[1].tv_sec = now;
877: times[0].tv_usec = times[1].tv_usec = 0;
878: if (utimes(file, times) < 0){
879: streamID = open (file, O_RDWR | O_CREAT, 0666);
880:
881: if (streamID >= 0) {
882: char c;
883:
884: /*
885: * Read and write a byte to the file to change the
886: * modification time, then close the file.
887: */
888: if (read(streamID, &c, 1) == 1) {
889: lseek(streamID, (off_t) 0, SEEK_SET);
890: write(streamID, &c, 1);
891: }
892:
893: (void)close (streamID);
894: } else
895: printf("*** couldn't touch %s: %s", file, strerror(errno));
896: }
897: }
898: }
899:
900: /*-
901: *-----------------------------------------------------------------------
902: * Job_CheckCommands --
903: * Make sure the given node has all the commands it needs.
904: *
905: * Results:
906: * TRUE if the commands list is/was ok.
907: *
908: * Side Effects:
909: * The node will have commands from the .DEFAULT rule added to it
910: * if it needs them.
911: *-----------------------------------------------------------------------
912: */
913: Boolean
914: Job_CheckCommands (gn, abortProc)
915: GNode *gn; /* The target whose commands need
916: * verifying */
917: void (*abortProc) __P((char *, ...));
918: /* Function to abort with message */
919: {
920: if (OP_NOP(gn->type) && Lst_IsEmpty (gn->commands) &&
921: (gn->type & OP_LIB) == 0) {
922: /*
923: * No commands. Look for .DEFAULT rule from which we might infer
924: * commands
925: */
926: if ((DEFAULT != NILGNODE) && !Lst_IsEmpty(DEFAULT->commands)) {
927: char *p1;
928: /*
929: * Make only looks for a .DEFAULT if the node was never the
930: * target of an operator, so that's what we do too. If
931: * a .DEFAULT was given, we substitute its commands for gn's
932: * commands and set the IMPSRC variable to be the target's name
933: * The DEFAULT node acts like a transformation rule, in that
934: * gn also inherits any attributes or sources attached to
935: * .DEFAULT itself.
936: */
937: Make_HandleUse(DEFAULT, gn);
938: Var_Set (IMPSRC, Var_Value (TARGET, gn, &p1), gn);
939: if (p1)
940: free(p1);
941: } else if (Dir_MTime (gn) == 0) {
942: /*
943: * The node wasn't the target of an operator we have no .DEFAULT
944: * rule to go on and the target doesn't already exist. There's
945: * nothing more we can do for this branch. If the -k flag wasn't
946: * given, we stop in our tracks, otherwise we just don't update
947: * this node's parents so they never get examined.
948: */
949: if (gn->type & OP_OPTIONAL) {
950: printf ("make: don't know how to make %s (ignored)\n",
951: gn->name);
952: } else if (keepgoing) {
953: printf ("make: don't know how to make %s (continuing)\n",
954: gn->name);
955: return (FALSE);
956: } else {
957: (*abortProc) ("make: don't know how to make %s. Stop",
958: gn->name);
959: return(FALSE);
960: }
961: }
962: }
963: return (TRUE);
964: }
965: #ifdef RMT_WILL_WATCH
966: /*-
967: *-----------------------------------------------------------------------
968: * JobLocalInput --
969: * Handle a pipe becoming readable. Callback function for Rmt_Watch
970: *
971: * Results:
972: * None
973: *
974: * Side Effects:
975: * JobDoOutput is called.
976: *
977: *-----------------------------------------------------------------------
978: */
979: /*ARGSUSED*/
980: static void
981: JobLocalInput(stream, job)
982: int stream; /* Stream that's ready (ignored) */
983: Job *job; /* Job to which the stream belongs */
984: {
985: JobDoOutput(job, FALSE);
986: }
987: #endif /* RMT_WILL_WATCH */
988:
989: /*-
990: *-----------------------------------------------------------------------
991: * JobExec --
992: * Execute the shell for the given job. Called from JobStart and
993: * JobRestart.
994: *
995: * Results:
996: * None.
997: *
998: * Side Effects:
999: * A shell is executed, outputs is altered and the Job structure added
1000: * to the job table.
1001: *
1002: *-----------------------------------------------------------------------
1003: */
1004: static void
1005: JobExec(job, argv)
1006: Job *job; /* Job to execute */
1007: char **argv;
1008: {
1009: int cpid; /* ID of new child */
1010:
1011: if (DEBUG(JOB)) {
1012: int i;
1013:
1014: printf("Running %s %sly\n", job->node->name,
1015: job->flags&JOB_REMOTE?"remote":"local");
1016: printf("\tCommand: ");
1017: for (i = 0; argv[i] != (char *)NULL; i++) {
1018: printf("%s ", argv[i]);
1019: }
1020: printf("\n");
1021: }
1022:
1023: /*
1024: * Some jobs produce no output and it's disconcerting to have
1025: * no feedback of their running (since they produce no output, the
1026: * banner with their name in it never appears). This is an attempt to
1027: * provide that feedback, even if nothing follows it.
1028: */
1029: if ((lastNode != job->node) && (job->flags & JOB_FIRST) &&
1030: !(job->flags & JOB_SILENT))
1031: {
1032: printf(targFmt, job->node->name);
1033: lastNode = job->node;
1034: }
1035:
1036: #ifdef RMT_NO_EXEC
1037: if (job->flags & JOB_REMOTE) {
1038: goto jobExecFinish;
1039: }
1040: #endif /* RMT_NO_EXEC */
1041:
1042: if ((cpid = vfork()) == -1) {
1043: Punt ("Cannot fork");
1044: } else if (cpid == 0) {
1045:
1046: /*
1047: * Must duplicate the input stream down to the child's input and
1048: * reset it to the beginning (again). Since the stream was marked
1049: * close-on-exec, we must clear that bit in the new input.
1050: */
1051: (void) dup2(fileno(job->cmdFILE), 0);
1052: fcntl(0, F_SETFD, 0);
1053: lseek(0, (off_t) 0, SEEK_SET);
1054:
1055: if (usePipes) {
1056: /*
1057: * Set up the child's output to be routed through the pipe
1058: * we've created for it.
1059: */
1060: (void) dup2 (job->outPipe, 1);
1061: } else {
1062: /*
1063: * We're capturing output in a file, so we duplicate the
1064: * descriptor to the temporary file into the standard
1065: * output.
1066: */
1067: (void) dup2 (job->outFd, 1);
1068: }
1069: /*
1070: * The output channels are marked close on exec. This bit was
1071: * duplicated by the dup2 (on some systems), so we have to clear
1072: * it before routing the shell's error output to the same place as
1073: * its standard output.
1074: */
1075: fcntl(1, F_SETFD, 0);
1076: (void) dup2 (1, 2);
1077:
1078: #ifdef USE_PGRP
1079: /*
1080: * We want to switch the child into a different process family so
1081: * we can kill it and all its descendants in one fell swoop,
1082: * by killing its process family, but not commit suicide.
1083: */
1084:
1085: (void) setpgrp(0, getpid());
1086: #endif USE_PGRP
1087:
1088: (void) execv (shellPath, argv);
1089: (void) write (2, "Could not execute shell\n",
1090: sizeof ("Could not execute shell"));
1091: _exit (1);
1092: } else {
1093: job->pid = cpid;
1094:
1095: if (usePipes && (job->flags & JOB_FIRST) ) {
1096: /*
1097: * The first time a job is run for a node, we set the current
1098: * position in the buffer to the beginning and mark another
1099: * stream to watch in the outputs mask
1100: */
1101: job->curPos = 0;
1102:
1103: #ifdef RMT_WILL_WATCH
1104: Rmt_Watch(job->inPipe, JobLocalInput, job);
1105: #else
1106: FD_SET(job->inPipe, &outputs);
1107: #endif /* RMT_WILL_WATCH */
1108: }
1109:
1110: if (job->flags & JOB_REMOTE) {
1111: job->rmtID = 0;
1112: } else {
1113: nLocal += 1;
1114: /*
1115: * XXX: Used to not happen if CUSTOMS. Why?
1116: */
1117: if (job->cmdFILE != stdout) {
1118: fclose(job->cmdFILE);
1119: job->cmdFILE = NULL;
1120: }
1121: }
1122: }
1123:
1124: #ifdef RMT_NO_EXEC
1125: jobExecFinish:
1126: #endif
1127: /*
1128: * Now the job is actually running, add it to the table.
1129: */
1130: nJobs += 1;
1131: (void)Lst_AtEnd (jobs, (ClientData)job);
1132: if (nJobs == maxJobs) {
1133: jobFull = TRUE;
1134: }
1135: }
1136:
1137: /*-
1138: *-----------------------------------------------------------------------
1139: * JobMakeArgv --
1140: * Create the argv needed to execute the shell for a given job.
1141: *
1142: *
1143: * Results:
1144: *
1145: * Side Effects:
1146: *
1147: *-----------------------------------------------------------------------
1148: */
1149: static void
1150: JobMakeArgv(job, argv)
1151: Job *job;
1152: char **argv;
1153: {
1154: int argc;
1155: static char args[10]; /* For merged arguments */
1156:
1157: argv[0] = shellName;
1158: argc = 1;
1159:
1160: if ((commandShell->exit && (*commandShell->exit != '-')) ||
1161: (commandShell->echo && (*commandShell->echo != '-')))
1162: {
1163: /*
1164: * At least one of the flags doesn't have a minus before it, so
1165: * merge them together. Have to do this because the *(&(@*#*&#$#
1166: * Bourne shell thinks its second argument is a file to source.
1167: * Grrrr. Note the ten-character limitation on the combined arguments.
1168: */
1169: (void)sprintf(args, "-%s%s",
1170: ((job->flags & JOB_IGNERR) ? "" :
1171: (commandShell->exit ? commandShell->exit : "")),
1172: ((job->flags & JOB_SILENT) ? "" :
1173: (commandShell->echo ? commandShell->echo : "")));
1174:
1175: if (args[1]) {
1176: argv[argc] = args;
1177: argc++;
1178: }
1179: } else {
1180: if (!(job->flags & JOB_IGNERR) && commandShell->exit) {
1181: argv[argc] = commandShell->exit;
1182: argc++;
1183: }
1184: if (!(job->flags & JOB_SILENT) && commandShell->echo) {
1185: argv[argc] = commandShell->echo;
1186: argc++;
1187: }
1188: }
1189: argv[argc] = (char *)NULL;
1190: }
1191:
1192: /*-
1193: *-----------------------------------------------------------------------
1194: * JobRestart --
1195: * Restart a job that stopped for some reason.
1196: *
1197: * Results:
1198: * None.
1199: *
1200: * Side Effects:
1201: * jobFull will be set if the job couldn't be run.
1202: *
1203: *-----------------------------------------------------------------------
1204: */
1205: static void
1206: JobRestart(job)
1207: Job *job; /* Job to restart */
1208: {
1209: if (job->flags & JOB_REMIGRATE) {
1210: if (DEBUG(JOB)) {
1211: printf("Remigrating %x\n", job->pid);
1212: }
1213: if (nLocal != maxLocal) {
1214: /*
1215: * Job cannot be remigrated, but there's room on the local
1216: * machine, so resume the job and note that another
1217: * local job has started.
1218: */
1219: if (DEBUG(JOB)) {
1220: printf("resuming on local machine\n");
1221: }
1222: KILL(job->pid, SIGCONT);
1223: nLocal +=1;
1224: job->flags &= ~(JOB_REMIGRATE|JOB_RESUME);
1225: } else {
1226: /*
1227: * Job cannot be restarted. Mark the table as full and
1228: * place the job back on the list of stopped jobs.
1229: */
1230: if (DEBUG(JOB)) {
1231: printf("holding\n");
1232: }
1233: (void)Lst_AtFront(stoppedJobs, (ClientData)job);
1234: jobFull = TRUE;
1235: if (DEBUG(JOB)) {
1236: printf("Job queue is full.\n");
1237: }
1238: return;
1239: }
1240:
1241: (void)Lst_AtEnd(jobs, (ClientData)job);
1242: nJobs += 1;
1243: if (nJobs == maxJobs) {
1244: jobFull = TRUE;
1245: if (DEBUG(JOB)) {
1246: printf("Job queue is full.\n");
1247: }
1248: }
1249: } else if (job->flags & JOB_RESTART) {
1250: /*
1251: * Set up the control arguments to the shell. This is based on the
1252: * flags set earlier for this job. If the JOB_IGNERR flag is clear,
1253: * the 'exit' flag of the commandShell is used to cause it to exit
1254: * upon receiving an error. If the JOB_SILENT flag is clear, the
1255: * 'echo' flag of the commandShell is used to get it to start echoing
1256: * as soon as it starts processing commands.
1257: */
1258: char *argv[4];
1259:
1260: JobMakeArgv(job, argv);
1261:
1262: if (DEBUG(JOB)) {
1263: printf("Restarting %s...", job->node->name);
1264: }
1265: if (((nLocal >= maxLocal) && ! (job->flags & JOB_SPECIAL))) {
1266: /*
1267: * Can't be exported and not allowed to run locally -- put it
1268: * back on the hold queue and mark the table full
1269: */
1270: if (DEBUG(JOB)) {
1271: printf("holding\n");
1272: }
1273: (void)Lst_AtFront(stoppedJobs, (ClientData)job);
1274: jobFull = TRUE;
1275: if (DEBUG(JOB)) {
1276: printf("Job queue is full.\n");
1277: }
1278: return;
1279: } else {
1280: /*
1281: * Job may be run locally.
1282: */
1283: if (DEBUG(JOB)) {
1284: printf("running locally\n");
1285: }
1286: job->flags &= ~JOB_REMOTE;
1287: }
1288: JobExec(job, argv);
1289: } else {
1290: /*
1291: * The job has stopped and needs to be restarted. Why it stopped,
1292: * we don't know...
1293: */
1294: if (DEBUG(JOB)) {
1295: printf("Resuming %s...", job->node->name);
1296: }
1297: if (((job->flags & JOB_REMOTE) ||
1298: (nLocal < maxLocal) ||
1299: (((job->flags & JOB_SPECIAL)) &&
1300: (maxLocal == 0))) &&
1301: (nJobs != maxJobs))
1302: {
1303: /*
1304: * If the job is remote, it's ok to resume it as long as the
1305: * maximum concurrency won't be exceeded. If it's local and
1306: * we haven't reached the local concurrency limit already (or the
1307: * job must be run locally and maxLocal is 0), it's also ok to
1308: * resume it.
1309: */
1310: Boolean error;
1311: extern int errno;
1312: union wait status;
1313:
1314: #ifdef RMT_WANTS_SIGNALS
1315: if (job->flags & JOB_REMOTE) {
1316: error = !Rmt_Signal(job, SIGCONT);
1317: } else
1318: #endif /* RMT_WANTS_SIGNALS */
1319: error = (KILL(job->pid, SIGCONT) != 0);
1320:
1321: if (!error) {
1322: /*
1323: * Make sure the user knows we've continued the beast and
1324: * actually put the thing in the job table.
1325: */
1326: job->flags |= JOB_CONTINUING;
1327: status.w_termsig = SIGCONT;
1328: JobFinish(job, status);
1329:
1330: job->flags &= ~(JOB_RESUME|JOB_CONTINUING);
1331: if (DEBUG(JOB)) {
1332: printf("done\n");
1333: }
1334: } else {
1335: Error("couldn't resume %s: %s",
1336: job->node->name, strerror(errno));
1337: status.w_status = 0;
1338: status.w_retcode = 1;
1339: JobFinish(job, status);
1340: }
1341: } else {
1342: /*
1343: * Job cannot be restarted. Mark the table as full and
1344: * place the job back on the list of stopped jobs.
1345: */
1346: if (DEBUG(JOB)) {
1347: printf("table full\n");
1348: }
1349: (void)Lst_AtFront(stoppedJobs, (ClientData)job);
1350: jobFull = TRUE;
1351: if (DEBUG(JOB)) {
1352: printf("Job queue is full.\n");
1353: }
1354: }
1355: }
1356: }
1357:
1358: /*-
1359: *-----------------------------------------------------------------------
1360: * JobStart --
1361: * Start a target-creation process going for the target described
1362: * by the graph node gn.
1363: *
1364: * Results:
1365: * JOB_ERROR if there was an error in the commands, JOB_FINISHED
1366: * if there isn't actually anything left to do for the job and
1367: * JOB_RUNNING if the job has been started.
1368: *
1369: * Side Effects:
1370: * A new Job node is created and added to the list of running
1371: * jobs. PMake is forked and a child shell created.
1372: *-----------------------------------------------------------------------
1373: */
1374: static int
1375: JobStart (gn, flags, previous)
1376: GNode *gn; /* target to create */
1377: int flags; /* flags for the job to override normal ones.
1378: * e.g. JOB_SPECIAL or JOB_IGNDOTS */
1379: Job *previous; /* The previous Job structure for this node,
1380: * if any. */
1381: {
1382: register Job *job; /* new job descriptor */
1383: char *argv[4]; /* Argument vector to shell */
1384: static int jobno = 0; /* job number of catching output in a file */
1385: Boolean cmdsOK; /* true if the nodes commands were all right */
1386: Boolean local; /* Set true if the job was run locally */
1387: Boolean noExec; /* Set true if we decide not to run the job */
1388:
1389: if (previous != (Job *)NULL) {
1390: previous->flags &= ~ (JOB_FIRST|JOB_IGNERR|JOB_SILENT|JOB_REMOTE);
1391: job = previous;
1392: } else {
1393: job = (Job *) emalloc (sizeof (Job));
1394: if (job == (Job *)NULL) {
1395: Punt("JobStart out of memory");
1396: }
1397: flags |= JOB_FIRST;
1398: }
1399:
1400: job->node = gn;
1401: job->tailCmds = NILLNODE;
1402:
1403: /*
1404: * Set the initial value of the flags for this job based on the global
1405: * ones and the node's attributes... Any flags supplied by the caller
1406: * are also added to the field.
1407: */
1408: job->flags = 0;
1409: if (Targ_Ignore (gn)) {
1410: job->flags |= JOB_IGNERR;
1411: }
1412: if (Targ_Silent (gn)) {
1413: job->flags |= JOB_SILENT;
1414: }
1415: job->flags |= flags;
1416:
1417: /*
1418: * Check the commands now so any attributes from .DEFAULT have a chance
1419: * to migrate to the node
1420: */
1421: if (job->flags & JOB_FIRST) {
1422: cmdsOK = Job_CheckCommands(gn, Error);
1423: } else {
1424: cmdsOK = TRUE;
1425: }
1426:
1427: /*
1428: * If the -n flag wasn't given, we open up OUR (not the child's)
1429: * temporary file to stuff commands in it. The thing is rd/wr so we don't
1430: * need to reopen it to feed it to the shell. If the -n flag *was* given,
1431: * we just set the file to be stdout. Cute, huh?
1432: */
1433: if ((gn->type & OP_MAKE) || (!noExecute && !touchFlag)) {
1434: /*
1435: * We're serious here, but if the commands were bogus, we're
1436: * also dead...
1437: */
1438: if (!cmdsOK) {
1439: DieHorribly();
1440: }
1441:
1442: job->cmdFILE = fopen (tfile, "w+");
1443: if (job->cmdFILE == (FILE *) NULL) {
1444: Punt ("Could not open %s", tfile);
1445: }
1446: fcntl(fileno(job->cmdFILE), F_SETFD, 1);
1447: /*
1448: * Send the commands to the command file, flush all its buffers then
1449: * rewind and remove the thing.
1450: */
1451: noExec = FALSE;
1452:
1453: /*
1454: * used to be backwards; replace when start doing multiple commands
1455: * per shell.
1456: */
1457: if (compatMake) {
1458: /*
1459: * Be compatible: If this is the first time for this node,
1460: * verify its commands are ok and open the commands list for
1461: * sequential access by later invocations of JobStart.
1462: * Once that is done, we take the next command off the list
1463: * and print it to the command file. If the command was an
1464: * ellipsis, note that there's nothing more to execute.
1465: */
1466: if ((job->flags&JOB_FIRST) && (Lst_Open(gn->commands) != SUCCESS)){
1467: cmdsOK = FALSE;
1468: } else {
1469: LstNode ln = Lst_Next (gn->commands);
1470:
1471: if ((ln == NILLNODE) ||
1472: JobPrintCommand ((char *)Lst_Datum (ln), job))
1473: {
1474: noExec = TRUE;
1475: Lst_Close (gn->commands);
1476: }
1477: if (noExec && !(job->flags & JOB_FIRST)) {
1478: /*
1479: * If we're not going to execute anything, the job
1480: * is done and we need to close down the various
1481: * file descriptors we've opened for output, then
1482: * call JobDoOutput to catch the final characters or
1483: * send the file to the screen... Note that the i/o streams
1484: * are only open if this isn't the first job.
1485: * Note also that this could not be done in
1486: * Job_CatchChildren b/c it wasn't clear if there were
1487: * more commands to execute or not...
1488: */
1489: if (usePipes) {
1490: #ifdef RMT_WILL_WATCH
1491: Rmt_Ignore(job->inPipe);
1492: #else
1493: FD_CLR(job->inPipe, &outputs);
1494: #endif
1495: if (job->outPipe != job->inPipe) {
1496: (void)close (job->outPipe);
1497: }
1498: JobDoOutput (job, TRUE);
1499: (void)close (job->inPipe);
1500: } else {
1501: (void)close (job->outFd);
1502: JobDoOutput (job, TRUE);
1503: }
1504: }
1505: }
1506: } else {
1507: /*
1508: * We can do all the commands at once. hooray for sanity
1509: */
1510: numCommands = 0;
1511: Lst_ForEach (gn->commands, JobPrintCommand, (ClientData)job);
1512:
1513: /*
1514: * If we didn't print out any commands to the shell script,
1515: * there's not much point in executing the shell, is there?
1516: */
1517: if (numCommands == 0) {
1518: noExec = TRUE;
1519: }
1520: }
1521: } else if (noExecute) {
1522: /*
1523: * Not executing anything -- just print all the commands to stdout
1524: * in one fell swoop. This will still set up job->tailCmds correctly.
1525: */
1526: if (lastNode != gn) {
1527: printf (targFmt, gn->name);
1528: lastNode = gn;
1529: }
1530: job->cmdFILE = stdout;
1531: /*
1532: * Only print the commands if they're ok, but don't die if they're
1533: * not -- just let the user know they're bad and keep going. It
1534: * doesn't do any harm in this case and may do some good.
1535: */
1536: if (cmdsOK) {
1537: Lst_ForEach(gn->commands, JobPrintCommand, (ClientData)job);
1538: }
1539: /*
1540: * Don't execute the shell, thank you.
1541: */
1542: noExec = TRUE;
1543: } else {
1544: /*
1545: * Just touch the target and note that no shell should be executed.
1546: * Set cmdFILE to stdout to make life easier. Check the commands, too,
1547: * but don't die if they're no good -- it does no harm to keep working
1548: * up the graph.
1549: */
1550: job->cmdFILE = stdout;
1551: Job_Touch (gn, job->flags&JOB_SILENT);
1552: noExec = TRUE;
1553: }
1554:
1555: /*
1556: * If we're not supposed to execute a shell, don't.
1557: */
1558: if (noExec) {
1559: /*
1560: * Unlink and close the command file if we opened one
1561: */
1562: if (job->cmdFILE != stdout) {
1563: (void) unlink (tfile);
1564: fclose(job->cmdFILE);
1565: } else {
1566: fflush (stdout);
1567: }
1568:
1569: /*
1570: * We only want to work our way up the graph if we aren't here because
1571: * the commands for the job were no good.
1572: */
1573: if (cmdsOK) {
1574: if (aborting == 0) {
1575: if (job->tailCmds != NILLNODE) {
1576: Lst_ForEachFrom(job->node->commands, job->tailCmds,
1577: JobSaveCommand,
1578: (ClientData)job->node);
1579: }
1580: Make_Update(job->node);
1581: }
1582: free((Address)job);
1583: return(JOB_FINISHED);
1584: } else {
1585: free((Address)job);
1586: return(JOB_ERROR);
1587: }
1588: } else {
1589: fflush (job->cmdFILE);
1590: (void) unlink (tfile);
1591: }
1592:
1593: /*
1594: * Set up the control arguments to the shell. This is based on the flags
1595: * set earlier for this job.
1596: */
1597: JobMakeArgv(job, argv);
1598:
1599: /*
1600: * If we're using pipes to catch output, create the pipe by which we'll
1601: * get the shell's output. If we're using files, print out that we're
1602: * starting a job and then set up its temporary-file name. This is just
1603: * tfile with two extra digits tacked on -- jobno.
1604: */
1605: if (job->flags & JOB_FIRST) {
1606: if (usePipes) {
1607: int fd[2];
1608: (void) pipe(fd);
1609: job->inPipe = fd[0];
1610: job->outPipe = fd[1];
1611: (void)fcntl (job->inPipe, F_SETFD, 1);
1612: (void)fcntl (job->outPipe, F_SETFD, 1);
1613: } else {
1614: printf ("Remaking `%s'\n", gn->name);
1615: fflush (stdout);
1616: sprintf (job->outFile, "%s%02d", tfile, jobno);
1617: jobno = (jobno + 1) % 100;
1618: job->outFd = open(job->outFile,O_WRONLY|O_CREAT|O_APPEND,0600);
1619: (void)fcntl (job->outFd, F_SETFD, 1);
1620: }
1621: }
1622:
1623: local = TRUE;
1624:
1625: if (local && (((nLocal >= maxLocal) &&
1626: !(job->flags & JOB_SPECIAL) &&
1627: (maxLocal != 0))))
1628: {
1629: /*
1630: * The job can only be run locally, but we've hit the limit of
1631: * local concurrency, so put the job on hold until some other job
1632: * finishes. Note that the special jobs (.BEGIN, .INTERRUPT and .END)
1633: * may be run locally even when the local limit has been reached
1634: * (e.g. when maxLocal == 0), though they will be exported if at
1635: * all possible.
1636: */
1637: jobFull = TRUE;
1638:
1639: if (DEBUG(JOB)) {
1640: printf("Can only run job locally.\n");
1641: }
1642: job->flags |= JOB_RESTART;
1643: (void)Lst_AtEnd(stoppedJobs, (ClientData)job);
1644: } else {
1645: if ((nLocal >= maxLocal) && local) {
1646: /*
1647: * If we're running this job locally as a special case (see above),
1648: * at least say the table is full.
1649: */
1650: jobFull = TRUE;
1651: if (DEBUG(JOB)) {
1652: printf("Local job queue is full.\n");
1653: }
1654: }
1655: JobExec(job, argv);
1656: }
1657: return(JOB_RUNNING);
1658: }
1659:
1660: /*-
1661: *-----------------------------------------------------------------------
1662: * JobDoOutput --
1663: * This function is called at different times depending on
1664: * whether the user has specified that output is to be collected
1665: * via pipes or temporary files. In the former case, we are called
1666: * whenever there is something to read on the pipe. We collect more
1667: * output from the given job and store it in the job's outBuf. If
1668: * this makes up a line, we print it tagged by the job's identifier,
1669: * as necessary.
1670: * If output has been collected in a temporary file, we open the
1671: * file and read it line by line, transfering it to our own
1672: * output channel until the file is empty. At which point we
1673: * remove the temporary file.
1674: * In both cases, however, we keep our figurative eye out for the
1675: * 'noPrint' line for the shell from which the output came. If
1676: * we recognize a line, we don't print it. If the command is not
1677: * alone on the line (the character after it is not \0 or \n), we
1678: * do print whatever follows it.
1679: *
1680: * Results:
1681: * None
1682: *
1683: * Side Effects:
1684: * curPos may be shifted as may the contents of outBuf.
1685: *-----------------------------------------------------------------------
1686: */
1687: static void
1688: JobDoOutput (job, finish)
1689: register Job *job; /* the job whose output needs printing */
1690: Boolean finish; /* TRUE if this is the last time we'll be
1691: * called for this job */
1692: {
1693: Boolean gotNL = FALSE; /* true if got a newline */
1694: register int nr; /* number of bytes read */
1695: register int i; /* auxiliary index into outBuf */
1696: register int max; /* limit for i (end of current data) */
1697: int nRead; /* (Temporary) number of bytes read */
1698:
1699: FILE *oFILE; /* Stream pointer to shell's output file */
1700: char inLine[132];
1701:
1702:
1703: if (usePipes) {
1704: /*
1705: * Read as many bytes as will fit in the buffer.
1706: */
1707: end_loop:
1708:
1709: nRead = read (job->inPipe, &job->outBuf[job->curPos],
1710: JOB_BUFSIZE - job->curPos);
1711: if (nRead < 0) {
1712: if (DEBUG(JOB)) {
1713: perror("JobDoOutput(piperead)");
1714: }
1715: nr = 0;
1716: } else {
1717: nr = nRead;
1718: }
1719:
1720: /*
1721: * If we hit the end-of-file (the job is dead), we must flush its
1722: * remaining output, so pretend we read a newline if there's any
1723: * output remaining in the buffer.
1724: * Also clear the 'finish' flag so we stop looping.
1725: */
1726: if ((nr == 0) && (job->curPos != 0)) {
1727: job->outBuf[job->curPos] = '\n';
1728: nr = 1;
1729: finish = FALSE;
1730: } else if (nr == 0) {
1731: finish = FALSE;
1732: }
1733:
1734: /*
1735: * Look for the last newline in the bytes we just got. If there is
1736: * one, break out of the loop with 'i' as its index and gotNL set
1737: * TRUE.
1738: */
1739: max = job->curPos + nr;
1740: for (i = job->curPos + nr - 1; i >= job->curPos; i--) {
1741: if (job->outBuf[i] == '\n') {
1742: gotNL = TRUE;
1743: break;
1744: } else if (job->outBuf[i] == '\0') {
1745: /*
1746: * Why?
1747: */
1748: job->outBuf[i] = ' ';
1749: }
1750: }
1751:
1752: if (!gotNL) {
1753: job->curPos += nr;
1754: if (job->curPos == JOB_BUFSIZE) {
1755: /*
1756: * If we've run out of buffer space, we have no choice
1757: * but to print the stuff. sigh.
1758: */
1759: gotNL = TRUE;
1760: i = job->curPos;
1761: }
1762: }
1763: if (gotNL) {
1764: /*
1765: * Need to send the output to the screen. Null terminate it
1766: * first, overwriting the newline character if there was one.
1767: * So long as the line isn't one we should filter (according
1768: * to the shell description), we print the line, preceeded
1769: * by a target banner if this target isn't the same as the
1770: * one for which we last printed something.
1771: * The rest of the data in the buffer are then shifted down
1772: * to the start of the buffer and curPos is set accordingly.
1773: */
1774: job->outBuf[i] = '\0';
1775: if (i >= job->curPos) {
1776: register char *cp, *ecp;
1777:
1778: cp = job->outBuf;
1779: if (commandShell->noPrint) {
1780: ecp = Str_FindSubstring(job->outBuf,
1781: commandShell->noPrint);
1782: while (ecp != (char *)NULL) {
1783: if (cp != ecp) {
1784: *ecp = '\0';
1785: if (job->node != lastNode) {
1786: printf (targFmt, job->node->name);
1787: lastNode = job->node;
1788: }
1789: /*
1790: * The only way there wouldn't be a newline after
1791: * this line is if it were the last in the buffer.
1792: * however, since the non-printable comes after it,
1793: * there must be a newline, so we don't print one.
1794: */
1795: printf ("%s", cp);
1796: }
1797: cp = ecp + commandShell->noPLen;
1798: if (cp != &job->outBuf[i]) {
1799: /*
1800: * Still more to print, look again after skipping
1801: * the whitespace following the non-printable
1802: * command....
1803: */
1804: cp++;
1805: while (*cp == ' ' || *cp == '\t' || *cp == '\n') {
1806: cp++;
1807: }
1808: ecp = Str_FindSubstring (cp,
1809: commandShell->noPrint);
1810: } else {
1811: break;
1812: }
1813: }
1814: }
1815:
1816: /*
1817: * There's still more in that thar buffer. This time, though,
1818: * we know there's no newline at the end, so we add one of
1819: * our own free will.
1820: */
1821: if (*cp != '\0') {
1822: if (job->node != lastNode) {
1823: printf (targFmt, job->node->name);
1824: lastNode = job->node;
1825: }
1826: printf ("%s\n", cp);
1827: }
1828:
1829: fflush (stdout);
1830: }
1831: if (i < max - 1) {
1832: /* shift the remaining characters down */
1833: memcpy ( job->outBuf, &job->outBuf[i + 1], max - (i + 1));
1834: job->curPos = max - (i + 1);
1835:
1836: } else {
1837: /*
1838: * We have written everything out, so we just start over
1839: * from the start of the buffer. No copying. No nothing.
1840: */
1841: job->curPos = 0;
1842: }
1843: }
1844: if (finish) {
1845: /*
1846: * If the finish flag is true, we must loop until we hit
1847: * end-of-file on the pipe. This is guaranteed to happen eventually
1848: * since the other end of the pipe is now closed (we closed it
1849: * explicitly and the child has exited). When we do get an EOF,
1850: * finish will be set FALSE and we'll fall through and out.
1851: */
1852: goto end_loop;
1853: }
1854: } else {
1855: /*
1856: * We've been called to retrieve the output of the job from the
1857: * temporary file where it's been squirreled away. This consists of
1858: * opening the file, reading the output line by line, being sure not
1859: * to print the noPrint line for the shell we used, then close and
1860: * remove the temporary file. Very simple.
1861: *
1862: * Change to read in blocks and do FindSubString type things as for
1863: * pipes? That would allow for "@echo -n..."
1864: */
1865: oFILE = fopen (job->outFile, "r");
1866: if (oFILE != (FILE *) NULL) {
1867: printf ("Results of making %s:\n", job->node->name);
1868: while (fgets (inLine, sizeof(inLine), oFILE) != NULL) {
1869: register char *cp, *ecp, *endp;
1870:
1871: cp = inLine;
1872: endp = inLine + strlen(inLine);
1873: if (endp[-1] == '\n') {
1874: *--endp = '\0';
1875: }
1876: if (commandShell->noPrint) {
1877: ecp = Str_FindSubstring(cp, commandShell->noPrint);
1878: while (ecp != (char *)NULL) {
1879: if (cp != ecp) {
1880: *ecp = '\0';
1881: /*
1882: * The only way there wouldn't be a newline after
1883: * this line is if it were the last in the buffer.
1884: * however, since the non-printable comes after it,
1885: * there must be a newline, so we don't print one.
1886: */
1887: printf ("%s", cp);
1888: }
1889: cp = ecp + commandShell->noPLen;
1890: if (cp != endp) {
1891: /*
1892: * Still more to print, look again after skipping
1893: * the whitespace following the non-printable
1894: * command....
1895: */
1896: cp++;
1897: while (*cp == ' ' || *cp == '\t' || *cp == '\n') {
1898: cp++;
1899: }
1900: ecp = Str_FindSubstring(cp, commandShell->noPrint);
1901: } else {
1902: break;
1903: }
1904: }
1905: }
1906:
1907: /*
1908: * There's still more in that thar buffer. This time, though,
1909: * we know there's no newline at the end, so we add one of
1910: * our own free will.
1911: */
1912: if (*cp != '\0') {
1913: printf ("%s\n", cp);
1914: }
1915: }
1916: fclose (oFILE);
1917: (void) unlink (job->outFile);
1918: }
1919: }
1920: fflush(stdout);
1921: }
1922:
1923: /*-
1924: *-----------------------------------------------------------------------
1925: * Job_CatchChildren --
1926: * Handle the exit of a child. Called from Make_Make.
1927: *
1928: * Results:
1929: * none.
1930: *
1931: * Side Effects:
1932: * The job descriptor is removed from the list of children.
1933: *
1934: * Notes:
1935: * We do waits, blocking or not, according to the wisdom of our
1936: * caller, until there are no more children to report. For each
1937: * job, call JobFinish to finish things off. This will take care of
1938: * putting jobs on the stoppedJobs queue.
1939: *
1940: *-----------------------------------------------------------------------
1941: */
1942: void
1943: Job_CatchChildren (block)
1944: Boolean block; /* TRUE if should block on the wait. */
1945: {
1946: int pid; /* pid of dead child */
1947: register Job *job; /* job descriptor for dead child */
1948: LstNode jnode; /* list element for finding job */
1949: union wait status; /* Exit/termination status */
1950:
1951: /*
1952: * Don't even bother if we know there's no one around.
1953: */
1954: if (nLocal == 0) {
1955: return;
1956: }
1957:
1958: while ((pid = wait3((int *)&status, (block?0:WNOHANG)|WUNTRACED,
1959: (struct rusage *)0)) > 0)
1960: {
1961: if (DEBUG(JOB))
1962: printf("Process %d exited or stopped.\n", pid);
1963:
1964:
1965: jnode = Lst_Find (jobs, (ClientData)&pid, JobCmpPid);
1966:
1967: if (jnode == NILLNODE) {
1968: if (WIFSIGNALED(status) && (status.w_termsig == SIGCONT)) {
1969: jnode = Lst_Find(stoppedJobs, (ClientData) &pid, JobCmpPid);
1970: if (jnode == NILLNODE) {
1971: Error("Resumed child (%d) not in table", pid);
1972: continue;
1973: }
1974: job = (Job *)Lst_Datum(jnode);
1975: (void)Lst_Remove(stoppedJobs, jnode);
1976: } else {
1977: Error ("Child (%d) not in table?", pid);
1978: continue;
1979: }
1980: } else {
1981: job = (Job *) Lst_Datum (jnode);
1982: (void)Lst_Remove (jobs, jnode);
1983: nJobs -= 1;
1984: if (jobFull && DEBUG(JOB)) {
1985: printf("Job queue is no longer full.\n");
1986: }
1987: jobFull = FALSE;
1988: nLocal -= 1;
1989: }
1990:
1991: JobFinish (job, status);
1992: }
1993: }
1994:
1995: /*-
1996: *-----------------------------------------------------------------------
1997: * Job_CatchOutput --
1998: * Catch the output from our children, if we're using
1999: * pipes do so. Otherwise just block time until we get a
2000: * signal (most likely a SIGCHLD) since there's no point in
2001: * just spinning when there's nothing to do and the reaping
2002: * of a child can wait for a while.
2003: *
2004: * Results:
2005: * None
2006: *
2007: * Side Effects:
2008: * Output is read from pipes if we're piping.
2009: * -----------------------------------------------------------------------
2010: */
2011: void
2012: Job_CatchOutput ()
2013: {
2014: int nfds;
2015: struct timeval timeout;
2016: fd_set readfds;
2017: register LstNode ln;
2018: register Job *job;
2019: #ifdef RMT_WILL_WATCH
2020: int pnJobs; /* Previous nJobs */
2021: #endif
2022:
2023: fflush(stdout);
2024: #ifdef RMT_WILL_WATCH
2025: pnJobs = nJobs;
2026:
2027: /*
2028: * It is possible for us to be called with nJobs equal to 0. This happens
2029: * if all the jobs finish and a job that is stopped cannot be run
2030: * locally (eg if maxLocal is 0) and cannot be exported. The job will
2031: * be placed back on the stoppedJobs queue, Job_Empty() will return false,
2032: * Make_Run will call us again when there's nothing for which to wait.
2033: * nJobs never changes, so we loop forever. Hence the check. It could
2034: * be argued that we should sleep for a bit so as not to swamp the
2035: * exportation system with requests. Perhaps we should.
2036: *
2037: * NOTE: IT IS THE RESPONSIBILITY OF Rmt_Wait TO CALL Job_CatchChildren
2038: * IN A TIMELY FASHION TO CATCH ANY LOCALLY RUNNING JOBS THAT EXIT.
2039: * It may use the variable nLocal to determine if it needs to call
2040: * Job_CatchChildren (if nLocal is 0, there's nothing for which to
2041: * wait...)
2042: */
2043: while (nJobs != 0 && pnJobs == nJobs) {
2044: Rmt_Wait();
2045: }
2046: #else
2047: if (usePipes) {
2048: readfds = outputs;
2049: timeout.tv_sec = SEL_SEC;
2050: timeout.tv_usec = SEL_USEC;
2051:
2052: if ((nfds = select (FD_SETSIZE, &readfds, (fd_set *) 0, (fd_set *) 0, &timeout)) < 0)
2053: {
2054: return;
2055: } else {
2056: if (Lst_Open (jobs) == FAILURE) {
2057: Punt ("Cannot open job table");
2058: }
2059: while (nfds && (ln = Lst_Next (jobs)) != NILLNODE) {
2060: job = (Job *) Lst_Datum (ln);
2061: if (FD_ISSET(job->inPipe, &readfds)) {
2062: JobDoOutput (job, FALSE);
2063: nfds -= 1;
2064: }
2065: }
2066: Lst_Close (jobs);
2067: }
2068: }
2069: #endif /* RMT_WILL_WATCH */
2070: }
2071:
2072: /*-
2073: *-----------------------------------------------------------------------
2074: * Job_Make --
2075: * Start the creation of a target. Basically a front-end for
2076: * JobStart used by the Make module.
2077: *
2078: * Results:
2079: * None.
2080: *
2081: * Side Effects:
2082: * Another job is started.
2083: *
2084: *-----------------------------------------------------------------------
2085: */
2086: void
2087: Job_Make (gn)
2088: GNode *gn;
2089: {
2090: (void)JobStart (gn, 0, (Job *)NULL);
2091: }
2092:
2093: /*-
2094: *-----------------------------------------------------------------------
2095: * Job_Init --
2096: * Initialize the process module
2097: *
2098: * Results:
2099: * none
2100: *
2101: * Side Effects:
2102: * lists and counters are initialized
2103: *-----------------------------------------------------------------------
2104: */
2105: void
2106: Job_Init (maxproc, maxlocal)
2107: int maxproc; /* the greatest number of jobs which may be
2108: * running at one time */
2109: int maxlocal; /* the greatest number of local jobs which may
2110: * be running at once. */
2111: {
2112: GNode *begin; /* node for commands to do at the very start */
2113:
2114: sprintf (tfile, "/tmp/make%05d", getpid());
2115:
2116: jobs = Lst_Init (FALSE);
2117: stoppedJobs = Lst_Init(FALSE);
2118: maxJobs = maxproc;
2119: maxLocal = maxlocal;
2120: nJobs = 0;
2121: nLocal = 0;
2122: jobFull = FALSE;
2123:
2124: aborting = 0;
2125: errors = 0;
2126:
2127: lastNode = NILGNODE;
2128:
2129: if (maxJobs == 1) {
2130: /*
2131: * If only one job can run at a time, there's no need for a banner,
2132: * no is there?
2133: */
2134: targFmt = "";
2135: } else {
2136: targFmt = TARG_FMT;
2137: }
2138:
2139: if (shellPath == (char *) NULL) {
2140: /*
2141: * The user didn't specify a shell to use, so we are using the
2142: * default one... Both the absolute path and the last component
2143: * must be set. The last component is taken from the 'name' field
2144: * of the default shell description pointed-to by commandShell.
2145: * All default shells are located in _PATH_DEFSHELLDIR.
2146: */
2147: shellName = commandShell->name;
2148: shellPath = str_concat (_PATH_DEFSHELLDIR, shellName, STR_ADDSLASH);
2149: }
2150:
2151: if (commandShell->exit == (char *)NULL) {
2152: commandShell->exit = "";
2153: }
2154: if (commandShell->echo == (char *)NULL) {
2155: commandShell->echo = "";
2156: }
2157:
2158: /*
2159: * Catch the four signals that POSIX specifies if they aren't ignored.
2160: * JobPassSig will take care of calling JobInterrupt if appropriate.
2161: */
2162: if (signal (SIGINT, SIG_IGN) != SIG_IGN) {
2163: signal (SIGINT, JobPassSig);
2164: }
2165: if (signal (SIGHUP, SIG_IGN) != SIG_IGN) {
2166: signal (SIGHUP, JobPassSig);
2167: }
2168: if (signal (SIGQUIT, SIG_IGN) != SIG_IGN) {
2169: signal (SIGQUIT, JobPassSig);
2170: }
2171: if (signal (SIGTERM, SIG_IGN) != SIG_IGN) {
2172: signal (SIGTERM, JobPassSig);
2173: }
2174: /*
2175: * There are additional signals that need to be caught and passed if
2176: * either the export system wants to be told directly of signals or if
2177: * we're giving each job its own process group (since then it won't get
2178: * signals from the terminal driver as we own the terminal)
2179: */
2180: #if defined(RMT_WANTS_SIGNALS) || defined(USE_PGRP)
2181: if (signal (SIGTSTP, SIG_IGN) != SIG_IGN) {
2182: signal (SIGTSTP, JobPassSig);
2183: }
2184: if (signal (SIGTTOU, SIG_IGN) != SIG_IGN) {
2185: signal (SIGTTOU, JobPassSig);
2186: }
2187: if (signal (SIGTTIN, SIG_IGN) != SIG_IGN) {
2188: signal (SIGTTIN, JobPassSig);
2189: }
2190: if (signal (SIGWINCH, SIG_IGN) != SIG_IGN) {
2191: signal (SIGWINCH, JobPassSig);
2192: }
2193: #endif
2194:
2195: begin = Targ_FindNode (".BEGIN", TARG_NOCREATE);
2196:
2197: if (begin != NILGNODE) {
2198: JobStart (begin, JOB_SPECIAL, (Job *)0);
2199: while (nJobs) {
2200: Job_CatchOutput();
2201: #ifndef RMT_WILL_WATCH
2202: Job_CatchChildren (!usePipes);
2203: #endif /* RMT_WILL_WATCH */
2204: }
2205: }
2206: postCommands = Targ_FindNode (".END", TARG_CREATE);
2207: }
2208:
2209: /*-
2210: *-----------------------------------------------------------------------
2211: * Job_Full --
2212: * See if the job table is full. It is considered full if it is OR
2213: * if we are in the process of aborting OR if we have
2214: * reached/exceeded our local quota. This prevents any more jobs
2215: * from starting up.
2216: *
2217: * Results:
2218: * TRUE if the job table is full, FALSE otherwise
2219: * Side Effects:
2220: * None.
2221: *-----------------------------------------------------------------------
2222: */
2223: Boolean
2224: Job_Full ()
2225: {
2226: return (aborting || jobFull);
2227: }
2228:
2229: /*-
2230: *-----------------------------------------------------------------------
2231: * Job_Empty --
2232: * See if the job table is empty. Because the local concurrency may
2233: * be set to 0, it is possible for the job table to become empty,
2234: * while the list of stoppedJobs remains non-empty. In such a case,
2235: * we want to restart as many jobs as we can.
2236: *
2237: * Results:
2238: * TRUE if it is. FALSE if it ain't.
2239: *
2240: * Side Effects:
2241: * None.
2242: *
2243: * -----------------------------------------------------------------------
2244: */
2245: Boolean
2246: Job_Empty ()
2247: {
2248: if (nJobs == 0) {
2249: if (!Lst_IsEmpty(stoppedJobs) && !aborting) {
2250: /*
2251: * The job table is obviously not full if it has no jobs in
2252: * it...Try and restart the stopped jobs.
2253: */
2254: jobFull = FALSE;
2255: while (!jobFull && !Lst_IsEmpty(stoppedJobs)) {
2256: JobRestart((Job *)Lst_DeQueue(stoppedJobs));
2257: }
2258: return(FALSE);
2259: } else {
2260: return(TRUE);
2261: }
2262: } else {
2263: return(FALSE);
2264: }
2265: }
2266:
2267: /*-
2268: *-----------------------------------------------------------------------
2269: * JobMatchShell --
2270: * Find a matching shell in 'shells' given its final component.
2271: *
2272: * Results:
2273: * A pointer to the Shell structure.
2274: *
2275: * Side Effects:
2276: * None.
2277: *
2278: *-----------------------------------------------------------------------
2279: */
2280: static Shell *
2281: JobMatchShell (name)
2282: char *name; /* Final component of shell path */
2283: {
2284: register Shell *sh; /* Pointer into shells table */
2285: Shell *match; /* Longest-matching shell */
2286: register char *cp1,
2287: *cp2;
2288: char *eoname;
2289:
2290: eoname = name + strlen (name);
2291:
2292: match = (Shell *) NULL;
2293:
2294: for (sh = shells; sh->name != NULL; sh++) {
2295: for (cp1 = eoname - strlen (sh->name), cp2 = sh->name;
2296: *cp1 != '\0' && *cp1 == *cp2;
2297: cp1++, cp2++) {
2298: continue;
2299: }
2300: if (*cp1 != *cp2) {
2301: continue;
2302: } else if (match == (Shell *) NULL ||
2303: strlen (match->name) < strlen (sh->name)) {
2304: match = sh;
2305: }
2306: }
2307: return (match == (Shell *) NULL ? sh : match);
2308: }
2309:
2310: /*-
2311: *-----------------------------------------------------------------------
2312: * Job_ParseShell --
2313: * Parse a shell specification and set up commandShell, shellPath
2314: * and shellName appropriately.
2315: *
2316: * Results:
2317: * FAILURE if the specification was incorrect.
2318: *
2319: * Side Effects:
2320: * commandShell points to a Shell structure (either predefined or
2321: * created from the shell spec), shellPath is the full path of the
2322: * shell described by commandShell, while shellName is just the
2323: * final component of shellPath.
2324: *
2325: * Notes:
2326: * A shell specification consists of a .SHELL target, with dependency
2327: * operator, followed by a series of blank-separated words. Double
2328: * quotes can be used to use blanks in words. A backslash escapes
2329: * anything (most notably a double-quote and a space) and
2330: * provides the functionality it does in C. Each word consists of
2331: * keyword and value separated by an equal sign. There should be no
2332: * unnecessary spaces in the word. The keywords are as follows:
2333: * name Name of shell.
2334: * path Location of shell. Overrides "name" if given
2335: * quiet Command to turn off echoing.
2336: * echo Command to turn echoing on
2337: * filter Result of turning off echoing that shouldn't be
2338: * printed.
2339: * echoFlag Flag to turn echoing on at the start
2340: * errFlag Flag to turn error checking on at the start
2341: * hasErrCtl True if shell has error checking control
2342: * check Command to turn on error checking if hasErrCtl
2343: * is TRUE or template of command to echo a command
2344: * for which error checking is off if hasErrCtl is
2345: * FALSE.
2346: * ignore Command to turn off error checking if hasErrCtl
2347: * is TRUE or template of command to execute a
2348: * command so as to ignore any errors it returns if
2349: * hasErrCtl is FALSE.
2350: *
2351: *-----------------------------------------------------------------------
2352: */
2353: ReturnStatus
2354: Job_ParseShell (line)
2355: char *line; /* The shell spec */
2356: {
2357: char **words;
2358: int wordCount;
2359: register char **argv;
2360: register int argc;
2361: char *path;
2362: Shell newShell;
2363: Boolean fullSpec = FALSE;
2364:
2365: while (isspace (*line)) {
2366: line++;
2367: }
2368: words = brk_string (line, &wordCount, TRUE);
2369:
2370: memset ((Address)&newShell, 0, sizeof(newShell));
2371:
2372: /*
2373: * Parse the specification by keyword
2374: */
2375: for (path = (char *)NULL, argc = wordCount - 1, argv = words + 1;
2376: argc != 0;
2377: argc--, argv++) {
2378: if (strncmp (*argv, "path=", 5) == 0) {
2379: path = &argv[0][5];
2380: } else if (strncmp (*argv, "name=", 5) == 0) {
2381: newShell.name = &argv[0][5];
2382: } else {
2383: if (strncmp (*argv, "quiet=", 6) == 0) {
2384: newShell.echoOff = &argv[0][6];
2385: } else if (strncmp (*argv, "echo=", 5) == 0) {
2386: newShell.echoOn = &argv[0][5];
2387: } else if (strncmp (*argv, "filter=", 7) == 0) {
2388: newShell.noPrint = &argv[0][7];
2389: newShell.noPLen = strlen(newShell.noPrint);
2390: } else if (strncmp (*argv, "echoFlag=", 9) == 0) {
2391: newShell.echo = &argv[0][9];
2392: } else if (strncmp (*argv, "errFlag=", 8) == 0) {
2393: newShell.exit = &argv[0][8];
2394: } else if (strncmp (*argv, "hasErrCtl=", 10) == 0) {
2395: char c = argv[0][10];
2396: newShell.hasErrCtl = !((c != 'Y') && (c != 'y') &&
2397: (c != 'T') && (c != 't'));
2398: } else if (strncmp (*argv, "check=", 6) == 0) {
2399: newShell.errCheck = &argv[0][6];
2400: } else if (strncmp (*argv, "ignore=", 7) == 0) {
2401: newShell.ignErr = &argv[0][7];
2402: } else {
2403: Parse_Error (PARSE_FATAL, "Unknown keyword \"%s\"",
2404: *argv);
2405: return (FAILURE);
2406: }
2407: fullSpec = TRUE;
2408: }
2409: }
2410:
2411: if (path == (char *)NULL) {
2412: /*
2413: * If no path was given, the user wants one of the pre-defined shells,
2414: * yes? So we find the one s/he wants with the help of JobMatchShell
2415: * and set things up the right way. shellPath will be set up by
2416: * Job_Init.
2417: */
2418: if (newShell.name == (char *)NULL) {
2419: Parse_Error (PARSE_FATAL, "Neither path nor name specified");
2420: return (FAILURE);
2421: } else {
2422: commandShell = JobMatchShell (newShell.name);
2423: shellName = newShell.name;
2424: }
2425: } else {
2426: /*
2427: * The user provided a path. If s/he gave nothing else (fullSpec is
2428: * FALSE), try and find a matching shell in the ones we know of.
2429: * Else we just take the specification at its word and copy it
2430: * to a new location. In either case, we need to record the
2431: * path the user gave for the shell.
2432: */
2433: shellPath = path;
2434: path = strrchr (path, '/');
2435: if (path == (char *)NULL) {
2436: path = shellPath;
2437: } else {
2438: path += 1;
2439: }
2440: if (newShell.name != (char *)NULL) {
2441: shellName = newShell.name;
2442: } else {
2443: shellName = path;
2444: }
2445: if (!fullSpec) {
2446: commandShell = JobMatchShell (shellName);
2447: } else {
2448: commandShell = (Shell *) emalloc(sizeof(Shell));
2449: *commandShell = newShell;
2450: }
2451: }
2452:
2453: if (commandShell->echoOn && commandShell->echoOff) {
2454: commandShell->hasEchoCtl = TRUE;
2455: }
2456:
2457: if (!commandShell->hasErrCtl) {
2458: if (commandShell->errCheck == (char *)NULL) {
2459: commandShell->errCheck = "";
2460: }
2461: if (commandShell->ignErr == (char *)NULL) {
2462: commandShell->ignErr = "%s\n";
2463: }
2464: }
2465:
2466: /*
2467: * Do not free up the words themselves, since they might be in use by the
2468: * shell specification...
2469: */
2470: free (words);
2471: return SUCCESS;
2472: }
2473:
2474: /*-
2475: *-----------------------------------------------------------------------
2476: * JobInterrupt --
2477: * Handle the receipt of an interrupt.
2478: *
2479: * Results:
2480: * None
2481: *
2482: * Side Effects:
2483: * All children are killed. Another job will be started if the
2484: * .INTERRUPT target was given.
2485: *-----------------------------------------------------------------------
2486: */
2487: static void
2488: JobInterrupt (runINTERRUPT)
2489: int runINTERRUPT; /* Non-zero if commands for the .INTERRUPT
2490: * target should be executed */
2491: {
2492: LstNode ln; /* element in job table */
2493: Job *job; /* job descriptor in that element */
2494: GNode *interrupt; /* the node describing the .INTERRUPT target */
2495:
2496: aborting = ABORT_INTERRUPT;
2497:
2498: (void)Lst_Open (jobs);
2499: while ((ln = Lst_Next (jobs)) != NILLNODE) {
2500: job = (Job *) Lst_Datum (ln);
2501:
2502: if (!Targ_Precious (job->node)) {
2503: char *file = (job->node->path == (char *)NULL ?
2504: job->node->name :
2505: job->node->path);
2506: struct stat st;
2507: if (!noExecute && lstat(file, &st) != -1 && !S_ISDIR(st.st_mode) &&
2508: unlink(file) != -1) {
2509: Error ("*** %s removed", file);
2510: }
2511: }
2512: #ifdef RMT_WANTS_SIGNALS
2513: if (job->flags & JOB_REMOTE) {
2514: /*
2515: * If job is remote, let the Rmt module do the killing.
2516: */
2517: if (!Rmt_Signal(job, SIGINT)) {
2518: /*
2519: * If couldn't kill the thing, finish it out now with an
2520: * error code, since no exit report will come in likely.
2521: */
2522: union wait status;
2523:
2524: status.w_status = 0;
2525: status.w_retcode = 1;
2526: JobFinish(job, status);
2527: }
2528: } else if (job->pid) {
2529: KILL(job->pid, SIGINT);
2530: }
2531: #else
2532: if (job->pid) {
2533: KILL(job->pid, SIGINT);
2534: }
2535: #endif /* RMT_WANTS_SIGNALS */
2536: }
2537: Lst_Close (jobs);
2538:
2539: if (runINTERRUPT && !touchFlag) {
2540: interrupt = Targ_FindNode (".INTERRUPT", TARG_NOCREATE);
2541: if (interrupt != NILGNODE) {
2542: ignoreErrors = FALSE;
2543:
2544: JobStart (interrupt, JOB_IGNDOTS, (Job *)0);
2545: while (nJobs) {
2546: Job_CatchOutput();
2547: #ifndef RMT_WILL_WATCH
2548: Job_CatchChildren (!usePipes);
2549: #endif /* RMT_WILL_WATCH */
2550: }
2551: }
2552: }
2553: (void) unlink (tfile);
2554: exit (0);
2555: }
2556:
2557: /*
2558: *-----------------------------------------------------------------------
2559: * Job_End --
2560: * Do final processing such as the running of the commands
2561: * attached to the .END target.
2562: *
2563: * Results:
2564: * Number of errors reported.
2565: *
2566: * Side Effects:
2567: * The process' temporary file (tfile) is removed if it still
2568: * existed.
2569: *-----------------------------------------------------------------------
2570: */
2571: int
2572: Job_End ()
2573: {
2574: if (postCommands != NILGNODE && !Lst_IsEmpty (postCommands->commands)) {
2575: if (errors) {
2576: Error ("Errors reported so .END ignored");
2577: } else {
2578: JobStart (postCommands, JOB_SPECIAL | JOB_IGNDOTS,
2579: (Job *)0);
2580:
2581: while (nJobs) {
2582: Job_CatchOutput();
2583: #ifndef RMT_WILL_WATCH
2584: Job_CatchChildren (!usePipes);
2585: #endif /* RMT_WILL_WATCH */
2586: }
2587: }
2588: }
2589: (void) unlink (tfile);
2590: return(errors);
2591: }
2592:
2593: /*-
2594: *-----------------------------------------------------------------------
2595: * Job_Wait --
2596: * Waits for all running jobs to finish and returns. Sets 'aborting'
2597: * to ABORT_WAIT to prevent other jobs from starting.
2598: *
2599: * Results:
2600: * None.
2601: *
2602: * Side Effects:
2603: * Currently running jobs finish.
2604: *
2605: *-----------------------------------------------------------------------
2606: */
2607: void
2608: Job_Wait()
2609: {
2610: aborting = ABORT_WAIT;
2611: while (nJobs != 0) {
2612: Job_CatchOutput();
2613: #ifndef RMT_WILL_WATCH
2614: Job_CatchChildren(!usePipes);
2615: #endif /* RMT_WILL_WATCH */
2616: }
2617: aborting = 0;
2618: }
2619:
2620: /*-
2621: *-----------------------------------------------------------------------
2622: * Job_AbortAll --
2623: * Abort all currently running jobs without handling output or anything.
2624: * This function is to be called only in the event of a major
2625: * error. Most definitely NOT to be called from JobInterrupt.
2626: *
2627: * Results:
2628: * None
2629: *
2630: * Side Effects:
2631: * All children are killed, not just the firstborn
2632: *-----------------------------------------------------------------------
2633: */
2634: void
2635: Job_AbortAll ()
2636: {
2637: LstNode ln; /* element in job table */
2638: Job *job; /* the job descriptor in that element */
2639: int foo;
2640:
2641: aborting = ABORT_ERROR;
2642:
2643: if (nJobs) {
2644:
2645: (void)Lst_Open (jobs);
2646: while ((ln = Lst_Next (jobs)) != NILLNODE) {
2647: job = (Job *) Lst_Datum (ln);
2648:
2649: /*
2650: * kill the child process with increasingly drastic signals to make
2651: * darn sure it's dead.
2652: */
2653: #ifdef RMT_WANTS_SIGNALS
2654: if (job->flags & JOB_REMOTE) {
2655: Rmt_Signal(job, SIGINT);
2656: Rmt_Signal(job, SIGKILL);
2657: } else {
2658: KILL(job->pid, SIGINT);
2659: KILL(job->pid, SIGKILL);
2660: }
2661: #else
2662: KILL(job->pid, SIGINT);
2663: KILL(job->pid, SIGKILL);
2664: #endif /* RMT_WANTS_SIGNALS */
2665: }
2666: }
2667:
2668: /*
2669: * Catch as many children as want to report in at first, then give up
2670: */
2671: while (wait3(&foo, WNOHANG, (struct rusage *)0) > 0)
2672: continue;
2673: (void) unlink (tfile);
2674: }