diff options
Diffstat (limited to 'usr.bin/make/job.c')
-rw-r--r-- | usr.bin/make/job.c | 1513 |
1 files changed, 975 insertions, 538 deletions
diff --git a/usr.bin/make/job.c b/usr.bin/make/job.c index ed5f2fc..1f4d4ee 100644 --- a/usr.bin/make/job.c +++ b/usr.bin/make/job.c @@ -97,13 +97,13 @@ static char sccsid[] = "@(#)job.c 8.2 (Berkeley) 3/19/94"; */ #include <sys/types.h> -#include <sys/signal.h> #include <sys/stat.h> #include <sys/file.h> #include <sys/time.h> #include <sys/wait.h> #include <fcntl.h> #include <errno.h> +#include <utime.h> #include <stdio.h> #include <string.h> #include <signal.h> @@ -112,6 +112,12 @@ static char sccsid[] = "@(#)job.c 8.2 (Berkeley) 3/19/94"; #include "dir.h" #include "job.h" #include "pathnames.h" +#ifdef REMOTE +#include "rmt.h" +# define STATIC +#else +# define STATIC static +#endif extern int errno; @@ -124,6 +130,11 @@ static int aborting = 0; /* why is the make aborting? */ #define ABORT_INTERRUPT 2 /* Because it was interrupted */ #define ABORT_WAIT 3 /* Waiting for jobs to finish */ +/* + * XXX: Avoid SunOS bug... FILENO() is fp->_file, and file + * is a char! So when we go above 127 we turn negative! + */ +#define FILENO(a) ((unsigned) fileno(a)) /* * post-make command processing. The node postCommands is really just the @@ -136,7 +147,6 @@ static int numCommands; /* The number of commands actually printed * for a target. Should this number be * 0, no shell will be executed. */ - /* * Return values from JobStart. */ @@ -176,17 +186,20 @@ static Shell shells[] = { { "sh", TRUE, "set -", "set -v", "set -", 5, + TRUE, "set -e", "set +e", +#ifdef OLDBOURNESHELL FALSE, "echo \"%s\"\n", "sh -c '%s || exit 0'\n", +#endif "v", "e", }, /* * UNKNOWN. */ { - (char *)0, - FALSE, (char *)0, (char *)0, (char *)0, 0, - FALSE, (char *)0, (char *)0, - (char *)0, (char *)0, + (char *) 0, + FALSE, (char *) 0, (char *) 0, (char *) 0, 0, + FALSE, (char *) 0, (char *) 0, + (char *) 0, (char *) 0, } }; static Shell *commandShell = &shells[DEFSHELL];/* this is the shell to @@ -194,17 +207,17 @@ static Shell *commandShell = &shells[DEFSHELL];/* this is the shell to * commands in the Makefile. * It is set by the * Job_ParseShell function */ -static char *shellPath = (char *) NULL, /* full pathname of +static char *shellPath = NULL, /* full pathname of * executable image */ *shellName; /* last component of shell */ static int maxJobs; /* The most children we can run at once */ static int maxLocal; /* The most local ones we can have */ -int nJobs; /* The number of children currently running */ -int nLocal; /* The number of local children */ -Lst jobs; /* The structures that describe them */ -Boolean jobFull; /* Flag to tell when the job table is full. It +STATIC int nJobs; /* The number of children currently running */ +STATIC int nLocal; /* The number of local children */ +STATIC Lst jobs; /* The structures that describe them */ +STATIC Boolean jobFull; /* Flag to tell when the job table is full. It * is set TRUE when (1) the total number of * running jobs equals the maximum allowed or * (2) a job can only be run locally, but @@ -214,12 +227,21 @@ static fd_set outputs; /* Set of descriptors of pipes connected to * the output channels of children */ #endif -GNode *lastNode; /* The node for which output was most recently +STATIC GNode *lastNode; /* The node for which output was most recently * produced. */ -char *targFmt; /* Format string to use to head output from a +STATIC char *targFmt; /* Format string to use to head output from a * job when it's not the most-recent job heard * from */ -#define TARG_FMT "--- %s ---\n" /* Default format */ + +#ifdef REMOTE +# define TARG_FMT "--- %s at %s ---\n" /* Default format */ +# define MESSAGE(fp, gn) \ + (void) fprintf(fp, targFmt, gn->name, gn->rem.hname); +#else +# define TARG_FMT "--- %s ---\n" /* Default format */ +# define MESSAGE(fp, gn) \ + (void) fprintf(fp, targFmt, gn->name); +#endif /* * When JobStart attempts to run a job remotely but can't, and isn't allowed @@ -227,34 +249,64 @@ char *targFmt; /* Format string to use to head output from a * been migrated home, the job is placed on the stoppedJobs queue to be run * when the next job finishes. */ -Lst stoppedJobs; /* Lst of Job structures describing +STATIC Lst stoppedJobs; /* Lst of Job structures describing * jobs that were stopped due to concurrency * limits or migration home */ #if defined(USE_PGRP) && defined(SYSV) -#define KILL(pid,sig) killpg (-(pid),(sig)) +# define KILL(pid, sig) killpg(-(pid), (sig)) #else # if defined(USE_PGRP) -#define KILL(pid,sig) killpg ((pid),(sig)) +# define KILL(pid, sig) killpg((pid), (sig)) # else -#define KILL(pid,sig) kill ((pid),(sig)) +# define KILL(pid, sig) kill((pid), (sig)) # endif #endif +/* + * Grmpf... There is no way to set bits of the wait structure + * anymore with the stupid W*() macros. I liked the union wait + * stuff much more. So, we devise our own macros... This is + * really ugly, use dramamine sparingly. You have been warned. + */ +#define W_SETMASKED(st, val, fun) \ + { \ + int sh = (int) ~0; \ + int mask = fun(sh); \ + \ + for (sh = 0; ((mask >> sh) & 1) == 0; sh++) \ + continue; \ + *(st) = (*(st) & ~mask) | ((val) << sh); \ + } + +#define W_SETTERMSIG(st, val) W_SETMASKED(st, val, WTERMSIG) +#define W_SETEXITSTATUS(st, val) W_SETMASKED(st, val, WEXITSTATUS) + + static int JobCondPassSig __P((ClientData, ClientData)); static void JobPassSig __P((int)); static int JobCmpPid __P((ClientData, ClientData)); static int JobPrintCommand __P((ClientData, ClientData)); static int JobSaveCommand __P((ClientData, ClientData)); -static void JobFinish __P((Job *, union wait)); +static void JobClose __P((Job *)); +#ifdef REMOTE +static int JobCmpRmtID __P((Job *, int)); +# ifdef RMT_WILL_WATCH +static void JobLocalInput __P((int, Job *)); +# endif +#else +static void JobFinish __P((Job *, int *)); static void JobExec __P((Job *, char **)); +#endif static void JobMakeArgv __P((Job *, char **)); static void JobRestart __P((Job *)); static int JobStart __P((GNode *, int, Job *)); +static char *JobOutput __P((Job *, char *, char *, int)); static void JobDoOutput __P((Job *, Boolean)); static Shell *JobMatchShell __P((char *)); -static void JobInterrupt __P((int)); +static void JobInterrupt __P((int, int)); +static void JobRestartJobs __P((void)); /*- *----------------------------------------------------------------------- @@ -279,7 +331,7 @@ JobCondPassSig(jobp, signop) int signo = *(int *) signop; #ifdef RMT_WANTS_SIGNALS if (job->flags & JOB_REMOTE) { - (void)Rmt_Signal(job, signo); + (void) Rmt_Signal(job, signo); } else { KILL(job->pid, signo); } @@ -288,9 +340,15 @@ JobCondPassSig(jobp, signop) * Assume that sending the signal to job->pid will signal any remote * job as well. */ + if (DEBUG(JOB)) { + (void) fprintf(stdout, + "JobCondPassSig passing signal %d to child %d.\n", + signo, job->pid); + (void) fflush(stdout); + } KILL(job->pid, signo); #endif - return(0); + return 0; } /*- @@ -311,9 +369,14 @@ static void JobPassSig(signo) int signo; /* The signal number we've received */ { - int mask; + sigset_t nmask, omask; + struct sigaction act; - Lst_ForEach(jobs, JobCondPassSig, (ClientData)(long)signo); + if (DEBUG(JOB)) { + (void) fprintf(stdout, "JobPassSig(%d) called.\n", signo); + (void) fflush(stdout); + } + Lst_ForEach(jobs, JobCondPassSig, (ClientData) &signo); /* * Deal with proper cleanup based on the signal received. We only run @@ -321,9 +384,9 @@ JobPassSig(signo) * three termination signals are more of a "get out *now*" command. */ if (signo == SIGINT) { - JobInterrupt(TRUE); + JobInterrupt(TRUE, signo); } else if ((signo == SIGHUP) || (signo == SIGTERM) || (signo == SIGQUIT)) { - JobInterrupt(FALSE); + JobInterrupt(FALSE, signo); } /* @@ -339,18 +402,31 @@ JobPassSig(signo) * This ensures that all our jobs get continued when we wake up before * we take any other signal. */ - mask = sigblock(0); - (void) sigsetmask(~0 & ~(1 << (signo-1))); - signal(signo, SIG_DFL); + sigemptyset(&nmask); + sigaddset(&nmask, signo); + sigprocmask(SIG_SETMASK, &nmask, &omask); + act.sa_handler = SIG_DFL; + sigemptyset(&act.sa_mask); + act.sa_flags = 0; + sigaction(signo, &act, NULL); - kill(getpid(), signo); + if (DEBUG(JOB)) { + (void) fprintf(stdout, + "JobPassSig passing signal to self, mask = %x.\n", + ~0 & ~(1 << (signo-1))); + (void) fflush(stdout); + } + (void) signal(signo, SIG_DFL); + + (void) KILL(getpid(), signo); signo = SIGCONT; Lst_ForEach(jobs, JobCondPassSig, (ClientData) &signo); - sigsetmask(mask); - signal(signo, JobPassSig); - + (void) sigprocmask(SIG_SETMASK, &omask, NULL); + sigprocmask(SIG_SETMASK, &omask, NULL); + act.sa_handler = JobPassSig; + sigaction(signo, &act, NULL); } /*- @@ -368,12 +444,35 @@ JobPassSig(signo) *----------------------------------------------------------------------- */ static int -JobCmpPid (job, pid) +JobCmpPid(job, pid) ClientData job; /* job to examine */ ClientData pid; /* process id desired */ { - return ( *(int *) pid - ((Job *) job)->pid); + return *(int *) pid - ((Job *) job)->pid; +} + +#ifdef REMOTE +/*- + *----------------------------------------------------------------------- + * JobCmpRmtID -- + * Compare the rmtID of the job with the given rmtID and return 0 if they + * are equal. + * + * Results: + * 0 if the rmtID's match + * + * Side Effects: + * None. + *----------------------------------------------------------------------- + */ +static int +JobCmpRmtID(job, rmtID) + ClientData job; /* job to examine */ + ClientData rmtID; /* remote id desired */ +{ + return(*(int *) rmtID - *(int *) job->rmtID); } +#endif /*- *----------------------------------------------------------------------- @@ -403,7 +502,7 @@ JobCmpPid (job, pid) *----------------------------------------------------------------------- */ static int -JobPrintCommand (cmdp, jobp) +JobPrintCommand(cmdp, jobp) ClientData cmdp; /* command string to print */ ClientData jobp; /* job for which to print it */ { @@ -422,19 +521,24 @@ JobPrintCommand (cmdp, jobp) char *cmd = (char *) cmdp; Job *job = (Job *) jobp; - noSpecials = (noExecute && ! (job->node->type & OP_MAKE)); + noSpecials = (noExecute && !(job->node->type & OP_MAKE)); - if (strcmp (cmd, "...") == 0) { + if (strcmp(cmd, "...") == 0) { job->node->type |= OP_SAVE_CMDS; if ((job->flags & JOB_IGNDOTS) == 0) { - job->tailCmds = Lst_Succ (Lst_Member (job->node->commands, - (ClientData)cmd)); - return (1); + job->tailCmds = Lst_Succ(Lst_Member(job->node->commands, + (ClientData)cmd)); + return 1; } - return (0); + return 0; } -#define DBPRINTF(fmt, arg) if (DEBUG(JOB)) printf (fmt, arg); fprintf (job->cmdFILE, fmt, arg) +#define DBPRINTF(fmt, arg) if (DEBUG(JOB)) { \ + (void) fprintf(stdout, fmt, arg); \ + (void) fflush(stdout); \ + } \ + (void) fprintf(job->cmdFILE, fmt, arg); \ + (void) fflush(job->cmdFILE); numCommands += 1; @@ -442,9 +546,9 @@ JobPrintCommand (cmdp, jobp) * For debugging, we replace each command with the result of expanding * the variables in the command. */ - cmdNode = Lst_Member (job->node->commands, (ClientData)cmd); - cmdStart = cmd = Var_Subst (NULL, cmd, job->node, FALSE); - Lst_Replace (cmdNode, (ClientData)cmdStart); + cmdNode = Lst_Member(job->node->commands, (ClientData)cmd); + cmdStart = cmd = Var_Subst(NULL, cmd, job->node, FALSE); + Lst_Replace(cmdNode, (ClientData)cmdStart); cmdTemplate = "%s\n"; @@ -464,16 +568,16 @@ JobPrintCommand (cmdp, jobp) cmd++; if (shutUp) { - if (! (job->flags & JOB_SILENT) && !noSpecials && + if (!(job->flags & JOB_SILENT) && !noSpecials && commandShell->hasEchoCtl) { - DBPRINTF ("%s\n", commandShell->echoOff); + DBPRINTF("%s\n", commandShell->echoOff); } else { shutUp = FALSE; } } if (errOff) { - if ( ! (job->flags & JOB_IGNERR) && !noSpecials) { + if ( !(job->flags & JOB_IGNERR) && !noSpecials) { if (commandShell->hasErrCtl) { /* * we don't want the error-control commands showing @@ -483,16 +587,16 @@ JobPrintCommand (cmdp, jobp) * string too, but why make it any more complex than * it already is? */ - if (! (job->flags & JOB_SILENT) && !shutUp && + if (!(job->flags & JOB_SILENT) && !shutUp && commandShell->hasEchoCtl) { - DBPRINTF ("%s\n", commandShell->echoOff); - DBPRINTF ("%s\n", commandShell->ignErr); - DBPRINTF ("%s\n", commandShell->echoOn); + DBPRINTF("%s\n", commandShell->echoOff); + DBPRINTF("%s\n", commandShell->ignErr); + DBPRINTF("%s\n", commandShell->echoOn); } else { - DBPRINTF ("%s\n", commandShell->ignErr); + DBPRINTF("%s\n", commandShell->ignErr); } } else if (commandShell->ignErr && - (*commandShell->ignErr != '\0')) + (*commandShell->ignErr != '\0')) { /* * The shell has no error control, so we need to be @@ -503,10 +607,10 @@ JobPrintCommand (cmdp, jobp) * to ignore errors. Set cmdTemplate to use the weirdness * instead of the simple "%s\n" template. */ - if (! (job->flags & JOB_SILENT) && !shutUp && + if (!(job->flags & JOB_SILENT) && !shutUp && commandShell->hasEchoCtl) { - DBPRINTF ("%s\n", commandShell->echoOff); - DBPRINTF (commandShell->errCheck, cmd); + DBPRINTF("%s\n", commandShell->echoOff); + DBPRINTF(commandShell->errCheck, cmd); shutUp = TRUE; } cmdTemplate = commandShell->ignErr; @@ -524,7 +628,7 @@ JobPrintCommand (cmdp, jobp) } } - DBPRINTF (cmdTemplate, cmd); + DBPRINTF(cmdTemplate, cmd); if (errOff) { /* @@ -533,15 +637,15 @@ JobPrintCommand (cmdp, jobp) * for the whole command... */ if (!shutUp && !(job->flags & JOB_SILENT) && commandShell->hasEchoCtl){ - DBPRINTF ("%s\n", commandShell->echoOff); + DBPRINTF("%s\n", commandShell->echoOff); shutUp = TRUE; } - DBPRINTF ("%s\n", commandShell->errCheck); + DBPRINTF("%s\n", commandShell->errCheck); } if (shutUp) { - DBPRINTF ("%s\n", commandShell->echoOn); + DBPRINTF("%s\n", commandShell->echoOn); } - return (0); + return 0; } /*- @@ -559,13 +663,48 @@ JobPrintCommand (cmdp, jobp) *----------------------------------------------------------------------- */ static int -JobSaveCommand (cmd, gn) +JobSaveCommand(cmd, gn) ClientData cmd; ClientData gn; { - cmd = (ClientData) Var_Subst (NULL, (char *) cmd, (GNode *) gn, FALSE); - (void)Lst_AtEnd (postCommands->commands, cmd); - return (0); + cmd = (ClientData) Var_Subst(NULL, (char *) cmd, (GNode *) gn, FALSE); + (void) Lst_AtEnd(postCommands->commands, cmd); + return(0); +} + + +/*- + *----------------------------------------------------------------------- + * JobClose -- + * Called to close both input and output pipes when a job is finished. + * + * Results: + * Nada + * + * Side Effects: + * The file descriptors associated with the job are closed. + * + *----------------------------------------------------------------------- + */ +static void +JobClose(job) + Job *job; +{ + if (usePipes) { +#ifdef RMT_WILL_WATCH + Rmt_Ignore(job->inPipe); +#else + FD_CLR(job->inPipe, &outputs); +#endif + if (job->outPipe != job->inPipe) { + (void) close(job->outPipe); + } + JobDoOutput(job, TRUE); + (void) close(job->inPipe); + } else { + (void) close(job->outFd); + JobDoOutput(job, TRUE); + } } /*- @@ -593,15 +732,15 @@ JobSaveCommand (cmd, gn) */ /*ARGSUSED*/ static void -JobFinish (job, status) - Job *job; /* job to finish */ - union wait status; /* sub-why job went away */ +JobFinish(job, status) + Job *job; /* job to finish */ + int *status; /* sub-why job went away */ { - Boolean done; + Boolean done; - if ((WIFEXITED(status) && - (((status.w_retcode != 0) && !(job->flags & JOB_IGNERR)))) || - (WIFSIGNALED(status) && (status.w_termsig != SIGCONT))) + if ((WIFEXITED(*status) && + (((WEXITSTATUS(*status) != 0) && !(job->flags & JOB_IGNERR)))) || + (WIFSIGNALED(*status) && (WTERMSIG(*status) != SIGCONT))) { /* * If it exited non-zero and either we're doing things our @@ -611,36 +750,38 @@ JobFinish (job, status) * cases, finish out the job's output before printing the exit * status... */ - if (usePipes) { -#ifdef RMT_WILL_WATCH - Rmt_Ignore(job->inPipe); -#else - FD_CLR(job->inPipe, &outputs); -#endif /* RMT_WILL_WATCH */ - if (job->outPipe != job->inPipe) { - (void)close (job->outPipe); - } - JobDoOutput (job, TRUE); - (void)close (job->inPipe); - } else { - (void)close (job->outFd); - JobDoOutput (job, TRUE); - } - +#ifdef REMOTE + KILL(job->pid, SIGCONT); +#endif + JobClose(job); if (job->cmdFILE != NULL && job->cmdFILE != stdout) { - fclose(job->cmdFILE); + (void) fclose(job->cmdFILE); } done = TRUE; - } else if (WIFEXITED(status) && status.w_retcode != 0) { +#ifdef REMOTE + if (job->flags & JOB_REMOTE) + Rmt_Done(job->rmtID, job->node); +#endif + } else if (WIFEXITED(*status)) { /* * Deal with ignored errors in -B mode. We need to print a message * telling of the ignored error as well as setting status.w_status * to 0 so the next command gets run. To do this, we set done to be - * TRUE if in -B mode and the job exited non-zero. Note we don't + * TRUE if in -B mode and the job exited non-zero. + */ + done = WEXITSTATUS(*status) != 0; + /* + * Old comment said: "Note we don't * want to close down any of the streams until we know we're at the - * end. + * end." + * But we do. Otherwise when are we going to print the rest of the + * stuff? */ - done = TRUE; + JobClose(job); +#ifdef REMOTE + if (job->flags & JOB_REMOTE) + Rmt_Done(job->rmtID, job->node); +#endif /* REMOTE */ } else { /* * No need to close things down or anything. @@ -649,55 +790,69 @@ JobFinish (job, status) } if (done || - WIFSTOPPED(status) || - (WIFSIGNALED(status) && (status.w_termsig == SIGCONT)) || + WIFSTOPPED(*status) || + (WIFSIGNALED(*status) && (WTERMSIG(*status) == SIGCONT)) || DEBUG(JOB)) { FILE *out; - if (!usePipes && (job->flags & JOB_IGNERR)) { + if (compatMake && !usePipes && (job->flags & JOB_IGNERR)) { /* * If output is going to a file and this job is ignoring * errors, arrange to have the exit status sent to the * output file as well. */ - out = fdopen (job->outFd, "w"); + out = fdopen(job->outFd, "w"); } else { out = stdout; } - if (WIFEXITED(status)) { - if (status.w_retcode != 0) { + if (WIFEXITED(*status)) { + if (DEBUG(JOB)) { + (void) fprintf(stdout, "Process %d exited.\n", job->pid); + (void) fflush(stdout); + } + if (WEXITSTATUS(*status) != 0) { if (usePipes && job->node != lastNode) { - fprintf (out, targFmt, job->node->name); + MESSAGE(out, job->node); lastNode = job->node; } - fprintf (out, "*** Error code %d%s\n", status.w_retcode, - (job->flags & JOB_IGNERR) ? " (ignored)" : ""); + (void) fprintf(out, "*** Error code %d%s\n", + WEXITSTATUS(*status), + (job->flags & JOB_IGNERR) ? "(ignored)" : ""); if (job->flags & JOB_IGNERR) { - status.w_status = 0; + *status = 0; } } else if (DEBUG(JOB)) { if (usePipes && job->node != lastNode) { - fprintf (out, targFmt, job->node->name); + MESSAGE(out, job->node); lastNode = job->node; } - fprintf (out, "*** Completed successfully\n"); + (void) fprintf(out, "*** Completed successfully\n"); + } + } else if (WIFSTOPPED(*status)) { + if (DEBUG(JOB)) { + (void) fprintf(stdout, "Process %d stopped.\n", job->pid); + (void) fflush(stdout); } - } else if (WIFSTOPPED(status)) { if (usePipes && job->node != lastNode) { - fprintf (out, targFmt, job->node->name); + MESSAGE(out, job->node); lastNode = job->node; } - if (! (job->flags & JOB_REMIGRATE)) { - fprintf (out, "*** Stopped -- signal %d\n", status.w_stopsig); + if (!(job->flags & JOB_REMIGRATE)) { + (void) fprintf(out, "*** Stopped -- signal %d\n", + WSTOPSIG(*status)); } job->flags |= JOB_RESUME; (void)Lst_AtEnd(stoppedJobs, (ClientData)job); - fflush(out); +#ifdef REMOTE + if (job->flags & JOB_REMIGRATE) + JobRestart(job); +#endif + (void) fflush(out); return; - } else if (status.w_termsig == SIGCONT) { + } else if (WTERMSIG(*status) == SIGCONT) { /* * If the beastie has continued, shift the Job from the stopped * list to the running one (or re-stop it if concurrency is @@ -705,37 +860,58 @@ JobFinish (job, status) */ if (job->flags & (JOB_RESUME|JOB_REMIGRATE|JOB_RESTART)) { if (usePipes && job->node != lastNode) { - fprintf (out, targFmt, job->node->name); + MESSAGE(out, job->node); lastNode = job->node; } - fprintf (out, "*** Continued\n"); + (void) fprintf(out, "*** Continued\n"); } - if (! (job->flags & JOB_CONTINUING)) { - JobRestart(job); - } else { - Lst_AtEnd(jobs, (ClientData)job); - nJobs += 1; - if (! (job->flags & JOB_REMOTE)) { - nLocal += 1; - } - if (nJobs == maxJobs) { - jobFull = TRUE; - if (DEBUG(JOB)) { - printf("Job queue is full.\n"); - } + if (!(job->flags & JOB_CONTINUING)) { + if (DEBUG(JOB)) { + (void) fprintf(stdout, + "Warning: process %d was not continuing.\n", + job->pid); + (void) fflush(stdout); } +#ifdef notdef + /* + * We don't really want to restart a job from scratch just + * because it continued, especially not without killing the + * continuing process! That's why this is ifdef'ed out. + * FD - 9/17/90 + */ + JobRestart(job); +#endif } - fflush(out); - return; + job->flags &= ~JOB_CONTINUING; + Lst_AtEnd(jobs, (ClientData)job); + nJobs += 1; + if (!(job->flags & JOB_REMOTE)) { + if (DEBUG(JOB)) { + (void) fprintf(stdout, + "Process %d is continuing locally.\n", + job->pid); + (void) fflush(stdout); + } + nLocal += 1; + } + if (nJobs == maxJobs) { + jobFull = TRUE; + if (DEBUG(JOB)) { + (void) fprintf(stdout, "Job queue is full.\n"); + (void) fflush(stdout); + } + } + (void) fflush(out); + return; } else { if (usePipes && job->node != lastNode) { - fprintf (out, targFmt, job->node->name); + MESSAGE(out, job->node); lastNode = job->node; } - fprintf (out, "*** Signal %d\n", status.w_termsig); + (void) fprintf(out, "*** Signal %d\n", WTERMSIG(*status)); } - fflush (out); + (void) fflush(out); } /* @@ -743,30 +919,26 @@ JobFinish (job, status) * try and restart the job on the next command. If JobStart says it's * ok, it's ok. If there's an error, this puppy is done. */ - if ((status.w_status == 0) && - !Lst_IsAtEnd (job->node->commands)) - { - switch (JobStart (job->node, - job->flags & JOB_IGNDOTS, - job)) - { - case JOB_RUNNING: - done = FALSE; - break; - case JOB_ERROR: - done = TRUE; - status.w_retcode = 1; - break; - case JOB_FINISHED: - /* - * If we got back a JOB_FINISHED code, JobStart has already - * called Make_Update and freed the job descriptor. We set - * done to false here to avoid fake cycles and double frees. - * JobStart needs to do the update so we can proceed up the - * graph when given the -n flag.. - */ - done = FALSE; - break; + if (compatMake && (WIFEXITED(*status) && + !Lst_IsAtEnd(job->node->commands))) { + switch (JobStart(job->node, job->flags & JOB_IGNDOTS, job)) { + case JOB_RUNNING: + done = FALSE; + break; + case JOB_ERROR: + done = TRUE; + W_SETEXITSTATUS(status, 1); + break; + case JOB_FINISHED: + /* + * If we got back a JOB_FINISHED code, JobStart has already + * called Make_Update and freed the job descriptor. We set + * done to false here to avoid fake cycles and double frees. + * JobStart needs to do the update so we can proceed up the + * graph when given the -n flag.. + */ + done = FALSE; + break; } } else { done = TRUE; @@ -776,7 +948,7 @@ JobFinish (job, status) if (done && (aborting != ABORT_ERROR) && (aborting != ABORT_INTERRUPT) && - (status.w_status == 0)) + (*status == 0)) { /* * As long as we aren't aborting and the job didn't return a non-zero @@ -785,21 +957,19 @@ JobFinish (job, status) * on the .END target. */ if (job->tailCmds != NILLNODE) { - Lst_ForEachFrom (job->node->commands, job->tailCmds, + Lst_ForEachFrom(job->node->commands, job->tailCmds, JobSaveCommand, - (ClientData)job->node); + (ClientData)job->node); } job->node->made = MADE; - Make_Update (job->node); + Make_Update(job->node); free((Address)job); - } else if (status.w_status) { + } else if (*status != 0) { errors += 1; free((Address)job); } - while (!errors && !jobFull && !Lst_IsEmpty(stoppedJobs)) { - JobRestart((Job *)Lst_DeQueue(stoppedJobs)); - } + JobRestartJobs(); /* * Set aborting if any error. @@ -817,8 +987,8 @@ JobFinish (job, status) /* * If we are aborting and the job table is now empty, we finish. */ - (void) unlink (tfile); - Finish (errors); + (void) eunlink(tfile); + Finish(errors); } } @@ -837,12 +1007,12 @@ JobFinish (job, status) *----------------------------------------------------------------------- */ void -Job_Touch (gn, silent) +Job_Touch(gn, silent) GNode *gn; /* the node of the file to touch */ Boolean silent; /* TRUE if should not print messages */ { int streamID; /* ID of stream opened to do the touch */ - struct timeval times[2]; /* Times for utimes() call */ + struct utimbuf times; /* Times for utime() call */ if (gn->type & (OP_JOIN|OP_USE|OP_EXEC|OP_OPTIONAL)) { /* @@ -853,7 +1023,8 @@ Job_Touch (gn, silent) } if (!silent) { - printf ("touch %s\n", gn->name); + (void) fprintf(stdout, "touch %s\n", gn->name); + (void) fflush(stdout); } if (noExecute) { @@ -861,16 +1032,15 @@ Job_Touch (gn, silent) } if (gn->type & OP_ARCHV) { - Arch_Touch (gn); + Arch_Touch(gn); } else if (gn->type & OP_LIB) { - Arch_TouchLib (gn); + Arch_TouchLib(gn); } else { char *file = gn->path ? gn->path : gn->name; - times[0].tv_sec = times[1].tv_sec = now; - times[0].tv_usec = times[1].tv_usec = 0; - if (utimes(file, times) < 0){ - streamID = open (file, O_RDWR | O_CREAT, 0666); + times.actime = times.modtime = now; + if (utime(file, ×) < 0){ + streamID = open(file, O_RDWR | O_CREAT, 0666); if (streamID >= 0) { char c; @@ -880,13 +1050,16 @@ Job_Touch (gn, silent) * modification time, then close the file. */ if (read(streamID, &c, 1) == 1) { - lseek(streamID, 0L, L_SET); - write(streamID, &c, 1); + (void) lseek(streamID, 0L, L_SET); + (void) write(streamID, &c, 1); } - (void)close (streamID); - } else - printf("*** couldn't touch %s: %s", file, strerror(errno)); + (void) close(streamID); + } else { + (void) fprintf(stdout, "*** couldn't touch %s: %s", + file, strerror(errno)); + (void) fflush(stdout); + } } } } @@ -905,13 +1078,13 @@ Job_Touch (gn, silent) *----------------------------------------------------------------------- */ Boolean -Job_CheckCommands (gn, abortProc) +Job_CheckCommands(gn, abortProc) GNode *gn; /* The target whose commands need * verifying */ - void (*abortProc) __P((char *, ...)); + void (*abortProc) __P((char *, ...)); /* Function to abort with message */ { - if (OP_NOP(gn->type) && Lst_IsEmpty (gn->commands) && + if (OP_NOP(gn->type) && Lst_IsEmpty(gn->commands) && (gn->type & OP_LIB) == 0) { /* * No commands. Look for .DEFAULT rule from which we might infer @@ -929,10 +1102,10 @@ Job_CheckCommands (gn, abortProc) * .DEFAULT itself. */ Make_HandleUse(DEFAULT, gn); - Var_Set (IMPSRC, Var_Value (TARGET, gn, &p1), gn); + Var_Set(IMPSRC, Var_Value(TARGET, gn, &p1), gn); if (p1) free(p1); - } else if (Dir_MTime (gn) == 0) { + } else if (Dir_MTime(gn) == 0) { /* * The node wasn't the target of an operator we have no .DEFAULT * rule to go on and the target doesn't already exist. There's @@ -940,21 +1113,22 @@ Job_CheckCommands (gn, abortProc) * given, we stop in our tracks, otherwise we just don't update * this node's parents so they never get examined. */ + static const char msg[] = "make: don't know how to make"; + if (gn->type & OP_OPTIONAL) { - printf ("make: don't know how to make %s (ignored)\n", - gn->name); + (void) fprintf(stdout, "%s %s(ignored)\n", msg, gn->name); + (void) fflush(stdout); } else if (keepgoing) { - printf ("make: don't know how to make %s (continuing)\n", - gn->name); - return (FALSE); + (void) fprintf(stdout, "%s %s(continuing)\n", msg, gn->name); + (void) fflush(stdout); + return FALSE; } else { - (*abortProc) ("make: don't know how to make %s. Stop", - gn->name); - return(FALSE); + (*abortProc)("%s %s. Stop", msg, gn->name); + return FALSE; } } } - return (TRUE); + return TRUE; } #ifdef RMT_WILL_WATCH /*- @@ -1005,13 +1179,14 @@ JobExec(job, argv) if (DEBUG(JOB)) { int i; - printf("Running %s %sly\n", job->node->name, - job->flags&JOB_REMOTE?"remote":"local"); - printf("\tCommand: "); - for (i = 0; argv[i] != (char *)NULL; i++) { - printf("%s ", argv[i]); + (void) fprintf(stdout, "Running %s %sly\n", job->node->name, + job->flags&JOB_REMOTE?"remote":"local"); + (void) fprintf(stdout, "\tCommand: "); + for (i = 0; argv[i] != NULL; i++) { + (void) fprintf(stdout, "%s ", argv[i]); } - printf("\n"); + (void) fprintf(stdout, "\n"); + (void) fflush(stdout); } /* @@ -1021,9 +1196,8 @@ JobExec(job, argv) * provide that feedback, even if nothing follows it. */ if ((lastNode != job->node) && (job->flags & JOB_FIRST) && - !(job->flags & JOB_SILENT)) - { - printf(targFmt, job->node->name); + !(job->flags & JOB_SILENT)) { + MESSAGE(stdout, job->node); lastNode = job->node; } @@ -1033,8 +1207,8 @@ JobExec(job, argv) } #endif /* RMT_NO_EXEC */ - if ((cpid = vfork()) == -1) { - Punt ("Cannot fork"); + if ((cpid = vfork()) == -1) { + Punt("Cannot fork"); } else if (cpid == 0) { /* @@ -1042,23 +1216,26 @@ JobExec(job, argv) * reset it to the beginning (again). Since the stream was marked * close-on-exec, we must clear that bit in the new input. */ - (void) dup2(fileno(job->cmdFILE), 0); - fcntl(0, F_SETFD, 0); - lseek(0, 0, L_SET); + if (dup2(FILENO(job->cmdFILE), 0) == -1) + Punt("Cannot dup2: %s", strerror(errno)); + (void) fcntl(0, F_SETFD, 0); + (void) lseek(0, 0, L_SET); if (usePipes) { /* * Set up the child's output to be routed through the pipe * we've created for it. */ - (void) dup2 (job->outPipe, 1); + if (dup2(job->outPipe, 1) == -1) + Punt("Cannot dup2: %s", strerror(errno)); } else { /* * We're capturing output in a file, so we duplicate the * descriptor to the temporary file into the standard * output. */ - (void) dup2 (job->outFd, 1); + if (dup2(job->outFd, 1) == -1) + Punt("Cannot dup2: %s", strerror(errno)); } /* * The output channels are marked close on exec. This bit was @@ -1066,8 +1243,9 @@ JobExec(job, argv) * it before routing the shell's error output to the same place as * its standard output. */ - fcntl(1, F_SETFD, 0); - (void) dup2 (1, 2); + (void) fcntl(1, F_SETFD, 0); + if (dup2(1, 2) == -1) + Punt("Cannot dup2: %s", strerror(errno)); #ifdef USE_PGRP /* @@ -1075,15 +1253,27 @@ JobExec(job, argv) * we can kill it and all its descendants in one fell swoop, * by killing its process family, but not commit suicide. */ +# if defined(SYSV) + (void) setsid(); +# else + (void) setpgid(0, getpid()); +# endif +#endif /* USE_PGRP */ - (void) setpgrp(0, getpid()); -#endif USE_PGRP - - (void) execv (shellPath, argv); - (void) write (2, "Could not execute shell\n", - sizeof ("Could not execute shell")); - _exit (1); +#ifdef REMOTE + if (job->flags & JOB_REMOTE) { + Rmt_Exec(shellPath, argv, FALSE); + } else +#endif /* REMOTE */ + (void) execv(shellPath, argv); + + (void) write(2, "Could not execute shell\n", + sizeof("Could not execute shell")); + _exit(1); } else { +#ifdef REMOTE + long omask = sigblock(sigmask(SIGCHLD)); +#endif job->pid = cpid; if (usePipes && (job->flags & JOB_FIRST) ) { @@ -1102,17 +1292,24 @@ JobExec(job, argv) } if (job->flags & JOB_REMOTE) { +#ifndef REMOTE job->rmtID = 0; +#else + job->rmtID = Rmt_LastID(job->pid); +#endif /* REMOTE */ } else { nLocal += 1; /* - * XXX: Used to not happen if CUSTOMS. Why? + * XXX: Used to not happen if REMOTE. Why? */ - if (job->cmdFILE != stdout) { - fclose(job->cmdFILE); + if (job->cmdFILE != NULL && job->cmdFILE != stdout) { + (void) fclose(job->cmdFILE); job->cmdFILE = NULL; } } +#ifdef REMOTE + (void) sigsetmask(omask); +#endif } #ifdef RMT_NO_EXEC @@ -1122,7 +1319,7 @@ jobExecFinish: * Now the job is actually running, add it to the table. */ nJobs += 1; - (void)Lst_AtEnd (jobs, (ClientData)job); + (void) Lst_AtEnd(jobs, (ClientData)job); if (nJobs == maxJobs) { jobFull = TRUE; } @@ -1180,7 +1377,7 @@ JobMakeArgv(job, argv) argc++; } } - argv[argc] = (char *)NULL; + argv[argc] = NULL; } /*- @@ -1200,44 +1397,91 @@ static void JobRestart(job) Job *job; /* Job to restart */ { +#ifdef REMOTE + int host; +#endif + if (job->flags & JOB_REMIGRATE) { - if (DEBUG(JOB)) { - printf("Remigrating %x\n", job->pid); + if ( +#ifdef REMOTE + verboseRemigrates || +#endif + DEBUG(JOB)) { + (void) fprintf(stdout, "*** remigrating %x(%s)\n", + job->pid, job->node->name); + (void) fflush(stdout); } - if (nLocal != maxLocal) { + +#ifdef REMOTE + if (!Rmt_ReExport(job->pid, job->node, &host)) { + if (verboseRemigrates || DEBUG(JOB)) { + (void) fprintf(stdout, "*** couldn't migrate...\n"); + (void) fflush(stdout); + } +#endif + if (nLocal != maxLocal) { /* * Job cannot be remigrated, but there's room on the local * machine, so resume the job and note that another * local job has started. */ - if (DEBUG(JOB)) { - printf("resuming on local machine\n"); - } + if ( +#ifdef REMOTE + verboseRemigrates || +#endif + DEBUG(JOB)) { + (void) fprintf(stdout, "*** resuming on local machine\n"); + (void) fflush(stdout); + } KILL(job->pid, SIGCONT); nLocal +=1; +#ifdef REMOTE + job->flags &= ~(JOB_REMIGRATE|JOB_RESUME|JOB_REMOTE); + job->flags |= JOB_CONTINUING; +#else job->flags &= ~(JOB_REMIGRATE|JOB_RESUME); +#endif } else { /* * Job cannot be restarted. Mark the table as full and * place the job back on the list of stopped jobs. */ - if (DEBUG(JOB)) { - printf("holding\n"); - } + if ( +#ifdef REMOTE + verboseRemigrates || +#endif + DEBUG(JOB)) { + (void) fprintf(stdout, "*** holding\n"); + (void) fflush(stdout); + } (void)Lst_AtFront(stoppedJobs, (ClientData)job); jobFull = TRUE; if (DEBUG(JOB)) { - printf("Job queue is full.\n"); + (void) fprintf(stdout, "Job queue is full.\n"); + (void) fflush(stdout); } return; + } +#ifdef REMOTE + } else { + /* + * Clear out the remigrate and resume flags. Set the continuing + * flag so we know later on that the process isn't exiting just + * because of a signal. + */ + job->flags &= ~(JOB_REMIGRATE|JOB_RESUME); + job->flags |= JOB_CONTINUING; + job->rmtID = host; } +#endif (void)Lst_AtEnd(jobs, (ClientData)job); nJobs += 1; if (nJobs == maxJobs) { jobFull = TRUE; if (DEBUG(JOB)) { - printf("Job queue is full.\n"); + (void) fprintf(stdout, "Job queue is full.\n"); + (void) fflush(stdout); } } } else if (job->flags & JOB_RESTART) { @@ -1254,31 +1498,58 @@ JobRestart(job) JobMakeArgv(job, argv); if (DEBUG(JOB)) { - printf("Restarting %s...", job->node->name); + (void) fprintf(stdout, "Restarting %s...", job->node->name); + (void) fflush(stdout); } - if (((nLocal >= maxLocal) && ! (job->flags & JOB_SPECIAL))) { +#ifdef REMOTE + if ((job->node->type&OP_NOEXPORT) || + (nLocal < maxLocal && runLocalFirst) +# ifdef RMT_NO_EXEC + || !Rmt_Export(shellPath, argv, job) +# else + || !Rmt_Begin(shellPath, argv, job->node) +# endif +#endif + { + if (((nLocal >= maxLocal) && !(job->flags & JOB_SPECIAL))) { /* * Can't be exported and not allowed to run locally -- put it * back on the hold queue and mark the table full */ if (DEBUG(JOB)) { - printf("holding\n"); + (void) fprintf(stdout, "holding\n"); + (void) fflush(stdout); } (void)Lst_AtFront(stoppedJobs, (ClientData)job); jobFull = TRUE; if (DEBUG(JOB)) { - printf("Job queue is full.\n"); + (void) fprintf(stdout, "Job queue is full.\n"); + (void) fflush(stdout); } return; - } else { + } else { /* * Job may be run locally. */ if (DEBUG(JOB)) { - printf("running locally\n"); + (void) fprintf(stdout, "running locally\n"); + (void) fflush(stdout); } job->flags &= ~JOB_REMOTE; + } + } +#ifdef REMOTE + else { + /* + * Can be exported. Hooray! + */ + if (DEBUG(JOB)) { + (void) fprintf(stdout, "exporting\n"); + (void) fflush(stdout); + } + job->flags |= JOB_REMOTE; } +#endif JobExec(job, argv); } else { /* @@ -1286,13 +1557,20 @@ JobRestart(job) * we don't know... */ if (DEBUG(JOB)) { - printf("Resuming %s...", job->node->name); + (void) fprintf(stdout, "Resuming %s...", job->node->name); + (void) fflush(stdout); } if (((job->flags & JOB_REMOTE) || - (nLocal < maxLocal) || - (((job->flags & JOB_SPECIAL)) && - (maxLocal == 0))) && - (nJobs != maxJobs)) + (nLocal < maxLocal) || +#ifdef REMOTE + (((job->flags & JOB_SPECIAL) && + (job->node->type & OP_NOEXPORT)) && + (maxLocal == 0))) && +#else + ((job->flags & JOB_SPECIAL) && + (maxLocal == 0))) && +#endif + (nJobs != maxJobs)) { /* * If the job is remote, it's ok to resume it as long as the @@ -1303,7 +1581,7 @@ JobRestart(job) */ Boolean error; extern int errno; - union wait status; + int status; #ifdef RMT_WANTS_SIGNALS if (job->flags & JOB_REMOTE) { @@ -1318,19 +1596,20 @@ JobRestart(job) * actually put the thing in the job table. */ job->flags |= JOB_CONTINUING; - status.w_termsig = SIGCONT; - JobFinish(job, status); + W_SETTERMSIG(&status, SIGCONT); + JobFinish(job, &status); job->flags &= ~(JOB_RESUME|JOB_CONTINUING); if (DEBUG(JOB)) { - printf("done\n"); + (void) fprintf(stdout, "done\n"); + (void) fflush(stdout); } } else { Error("couldn't resume %s: %s", job->node->name, strerror(errno)); - status.w_status = 0; - status.w_retcode = 1; - JobFinish(job, status); + status = 0; + W_SETEXITSTATUS(&status, 1); + JobFinish(job, &status); } } else { /* @@ -1338,12 +1617,14 @@ JobRestart(job) * place the job back on the list of stopped jobs. */ if (DEBUG(JOB)) { - printf("table full\n"); + (void) fprintf(stdout, "table full\n"); + (void) fflush(stdout); } - (void)Lst_AtFront(stoppedJobs, (ClientData)job); + (void) Lst_AtFront(stoppedJobs, (ClientData)job); jobFull = TRUE; if (DEBUG(JOB)) { - printf("Job queue is full.\n"); + (void) fprintf(stdout, "Job queue is full.\n"); + (void) fflush(stdout); } } } @@ -1366,7 +1647,7 @@ JobRestart(job) *----------------------------------------------------------------------- */ static int -JobStart (gn, flags, previous) +JobStart(gn, flags, previous) GNode *gn; /* target to create */ int flags; /* flags for the job to override normal ones. * e.g. JOB_SPECIAL or JOB_IGNDOTS */ @@ -1380,12 +1661,12 @@ JobStart (gn, flags, previous) Boolean local; /* Set true if the job was run locally */ Boolean noExec; /* Set true if we decide not to run the job */ - if (previous != (Job *)NULL) { - previous->flags &= ~ (JOB_FIRST|JOB_IGNERR|JOB_SILENT|JOB_REMOTE); + if (previous != NULL) { + previous->flags &= ~(JOB_FIRST|JOB_IGNERR|JOB_SILENT|JOB_REMOTE); job = previous; } else { - job = (Job *) emalloc (sizeof (Job)); - if (job == (Job *)NULL) { + job = (Job *) emalloc(sizeof(Job)); + if (job == NULL) { Punt("JobStart out of memory"); } flags |= JOB_FIRST; @@ -1400,10 +1681,10 @@ JobStart (gn, flags, previous) * are also added to the field. */ job->flags = 0; - if (Targ_Ignore (gn)) { + if (Targ_Ignore(gn)) { job->flags |= JOB_IGNERR; } - if (Targ_Silent (gn)) { + if (Targ_Silent(gn)) { job->flags |= JOB_SILENT; } job->flags |= flags; @@ -1412,7 +1693,7 @@ JobStart (gn, flags, previous) * Check the commands now so any attributes from .DEFAULT have a chance * to migrate to the node */ - if (job->flags & JOB_FIRST) { + if (!compatMake && job->flags & JOB_FIRST) { cmdsOK = Job_CheckCommands(gn, Error); } else { cmdsOK = TRUE; @@ -1433,11 +1714,11 @@ JobStart (gn, flags, previous) DieHorribly(); } - job->cmdFILE = fopen (tfile, "w+"); - if (job->cmdFILE == (FILE *) NULL) { - Punt ("Could not open %s", tfile); + job->cmdFILE = fopen(tfile, "w+"); + if (job->cmdFILE == NULL) { + Punt("Could not open %s", tfile); } - fcntl(fileno(job->cmdFILE), F_SETFD, 1); + (void) fcntl(FILENO(job->cmdFILE), F_SETFD, 1); /* * Send the commands to the command file, flush all its buffers then * rewind and remove the thing. @@ -1460,13 +1741,14 @@ JobStart (gn, flags, previous) if ((job->flags&JOB_FIRST) && (Lst_Open(gn->commands) != SUCCESS)){ cmdsOK = FALSE; } else { - LstNode ln = Lst_Next (gn->commands); + LstNode ln = Lst_Next(gn->commands); if ((ln == NILLNODE) || - JobPrintCommand ((char *)Lst_Datum (ln), job)) + JobPrintCommand((ClientData) Lst_Datum(ln), + (ClientData) job)) { noExec = TRUE; - Lst_Close (gn->commands); + Lst_Close(gn->commands); } if (noExec && !(job->flags & JOB_FIRST)) { /* @@ -1480,21 +1762,7 @@ JobStart (gn, flags, previous) * Job_CatchChildren b/c it wasn't clear if there were * more commands to execute or not... */ - if (usePipes) { -#ifdef RMT_WILL_WATCH - Rmt_Ignore(job->inPipe); -#else - FD_CLR(job->inPipe, &outputs); -#endif - if (job->outPipe != job->inPipe) { - (void)close (job->outPipe); - } - JobDoOutput (job, TRUE); - (void)close (job->inPipe); - } else { - (void)close (job->outFd); - JobDoOutput (job, TRUE); - } + JobClose(job); } } } else { @@ -1502,7 +1770,7 @@ JobStart (gn, flags, previous) * We can do all the commands at once. hooray for sanity */ numCommands = 0; - Lst_ForEach (gn->commands, JobPrintCommand, (ClientData)job); + Lst_ForEach(gn->commands, JobPrintCommand, (ClientData)job); /* * If we didn't print out any commands to the shell script, @@ -1518,7 +1786,7 @@ JobStart (gn, flags, previous) * in one fell swoop. This will still set up job->tailCmds correctly. */ if (lastNode != gn) { - printf (targFmt, gn->name); + MESSAGE(stdout, gn); lastNode = gn; } job->cmdFILE = stdout; @@ -1542,7 +1810,7 @@ JobStart (gn, flags, previous) * up the graph. */ job->cmdFILE = stdout; - Job_Touch (gn, job->flags&JOB_SILENT); + Job_Touch(gn, job->flags&JOB_SILENT); noExec = TRUE; } @@ -1554,10 +1822,11 @@ JobStart (gn, flags, previous) * Unlink and close the command file if we opened one */ if (job->cmdFILE != stdout) { - (void) unlink (tfile); - fclose(job->cmdFILE); + (void) eunlink(tfile); + if (job->cmdFILE != NULL) + (void) fclose(job->cmdFILE); } else { - fflush (stdout); + (void) fflush(stdout); } /* @@ -1569,7 +1838,7 @@ JobStart (gn, flags, previous) if (job->tailCmds != NILLNODE) { Lst_ForEachFrom(job->node->commands, job->tailCmds, JobSaveCommand, - (ClientData)job->node); + (ClientData)job->node); } Make_Update(job->node); } @@ -1580,8 +1849,8 @@ JobStart (gn, flags, previous) return(JOB_ERROR); } } else { - fflush (job->cmdFILE); - (void) unlink (tfile); + (void) fflush(job->cmdFILE); + (void) eunlink(tfile); } /* @@ -1596,29 +1865,47 @@ JobStart (gn, flags, previous) * starting a job and then set up its temporary-file name. This is just * tfile with two extra digits tacked on -- jobno. */ - if (job->flags & JOB_FIRST) { + if (!compatMake || (job->flags & JOB_FIRST)) { if (usePipes) { int fd[2]; - (void) pipe(fd); + if (pipe(fd) == -1) + Punt("Cannot create pipe: %s", strerror(errno)); job->inPipe = fd[0]; job->outPipe = fd[1]; - (void)fcntl (job->inPipe, F_SETFD, 1); - (void)fcntl (job->outPipe, F_SETFD, 1); + (void) fcntl(job->inPipe, F_SETFD, 1); + (void) fcntl(job->outPipe, F_SETFD, 1); } else { - printf ("Remaking `%s'\n", gn->name); - fflush (stdout); - sprintf (job->outFile, "%s%02d", tfile, jobno); + (void) fprintf(stdout, "Remaking `%s'\n", gn->name); + (void) fflush(stdout); + sprintf(job->outFile, "%s%02d", tfile, jobno); jobno = (jobno + 1) % 100; job->outFd = open(job->outFile,O_WRONLY|O_CREAT|O_APPEND,0600); - (void)fcntl (job->outFd, F_SETFD, 1); + (void) fcntl(job->outFd, F_SETFD, 1); } } - local = TRUE; +#ifdef REMOTE + if (!(gn->type & OP_NOEXPORT) && !(runLocalFirst && nLocal < maxLocal)) { +#ifdef RMT_NO_EXEC + local = !Rmt_Export(shellPath, argv, job); +#else + local = !Rmt_Begin(shellPath, argv, job->node); +#endif /* RMT_NO_EXEC */ + if (!local) { + job->flags |= JOB_REMOTE; + } + } else +#endif + local = TRUE; if (local && (((nLocal >= maxLocal) && - !(job->flags & JOB_SPECIAL) && - (maxLocal != 0)))) + !(job->flags & JOB_SPECIAL) && +#ifdef REMOTE + (!(gn->type & OP_NOEXPORT) || (maxLocal != 0)) +#else + (maxLocal != 0) +#endif + ))) { /* * The job can only be run locally, but we've hit the limit of @@ -1626,15 +1913,17 @@ JobStart (gn, flags, previous) * finishes. Note that the special jobs (.BEGIN, .INTERRUPT and .END) * may be run locally even when the local limit has been reached * (e.g. when maxLocal == 0), though they will be exported if at - * all possible. + * all possible. In addition, any target marked with .NOEXPORT will + * be run locally if maxLocal is 0. */ jobFull = TRUE; if (DEBUG(JOB)) { - printf("Can only run job locally.\n"); + (void) fprintf(stdout, "Can only run job locally.\n"); + (void) fflush(stdout); } job->flags |= JOB_RESTART; - (void)Lst_AtEnd(stoppedJobs, (ClientData)job); + (void) Lst_AtEnd(stoppedJobs, (ClientData)job); } else { if ((nLocal >= maxLocal) && local) { /* @@ -1643,7 +1932,8 @@ JobStart (gn, flags, previous) */ jobFull = TRUE; if (DEBUG(JOB)) { - printf("Local job queue is full.\n"); + (void) fprintf(stdout, "Local job queue is full.\n"); + (void) fflush(stdout); } } JobExec(job, argv); @@ -1651,6 +1941,52 @@ JobStart (gn, flags, previous) return(JOB_RUNNING); } +static char * +JobOutput(job, cp, endp, msg) + register Job *job; + register char *cp, *endp; + int msg; +{ + register char *ecp; + + if (commandShell->noPrint) { + ecp = Str_FindSubstring(cp, commandShell->noPrint); + while (ecp != NULL) { + if (cp != ecp) { + *ecp = '\0'; + if (msg && job->node != lastNode) { + MESSAGE(stdout, job->node); + lastNode = job->node; + } + /* + * The only way there wouldn't be a newline after + * this line is if it were the last in the buffer. + * however, since the non-printable comes after it, + * there must be a newline, so we don't print one. + */ + (void) fprintf(stdout, "%s", cp); + (void) fflush(stdout); + } + cp = ecp + commandShell->noPLen; + if (cp != endp) { + /* + * Still more to print, look again after skipping + * the whitespace following the non-printable + * command.... + */ + cp++; + while (*cp == ' ' || *cp == '\t' || *cp == '\n') { + cp++; + } + ecp = Str_FindSubstring(cp, commandShell->noPrint); + } else { + return cp; + } + } + } + return cp; +} + /*- *----------------------------------------------------------------------- * JobDoOutput -- @@ -1678,13 +2014,14 @@ JobStart (gn, flags, previous) * curPos may be shifted as may the contents of outBuf. *----------------------------------------------------------------------- */ -static void -JobDoOutput (job, finish) +STATIC void +JobDoOutput(job, finish) register Job *job; /* the job whose output needs printing */ Boolean finish; /* TRUE if this is the last time we'll be * called for this job */ { Boolean gotNL = FALSE; /* true if got a newline */ + Boolean fbuf; /* true if our buffer filled up */ register int nr; /* number of bytes read */ register int i; /* auxiliary index into outBuf */ register int max; /* limit for i (end of current data) */ @@ -1699,8 +2036,10 @@ JobDoOutput (job, finish) * Read as many bytes as will fit in the buffer. */ end_loop: + gotNL = FALSE; + fbuf = FALSE; - nRead = read (job->inPipe, &job->outBuf[job->curPos], + nRead = read(job->inPipe, &job->outBuf[job->curPos], JOB_BUFSIZE - job->curPos); if (nRead < 0) { if (DEBUG(JOB)) { @@ -1750,11 +2089,11 @@ end_loop: * If we've run out of buffer space, we have no choice * but to print the stuff. sigh. */ - gotNL = TRUE; + fbuf = TRUE; i = job->curPos; } } - if (gotNL) { + if (gotNL || fbuf) { /* * Need to send the output to the screen. Null terminate it * first, overwriting the newline character if there was one. @@ -1767,45 +2106,9 @@ end_loop: */ job->outBuf[i] = '\0'; if (i >= job->curPos) { - register char *cp, *ecp; - - cp = job->outBuf; - if (commandShell->noPrint) { - ecp = Str_FindSubstring(job->outBuf, - commandShell->noPrint); - while (ecp != (char *)NULL) { - if (cp != ecp) { - *ecp = '\0'; - if (job->node != lastNode) { - printf (targFmt, job->node->name); - lastNode = job->node; - } - /* - * The only way there wouldn't be a newline after - * this line is if it were the last in the buffer. - * however, since the non-printable comes after it, - * there must be a newline, so we don't print one. - */ - printf ("%s", cp); - } - cp = ecp + commandShell->noPLen; - if (cp != &job->outBuf[i]) { - /* - * Still more to print, look again after skipping - * the whitespace following the non-printable - * command.... - */ - cp++; - while (*cp == ' ' || *cp == '\t' || *cp == '\n') { - cp++; - } - ecp = Str_FindSubstring (cp, - commandShell->noPrint); - } else { - break; - } - } - } + char *cp; + + cp = JobOutput(job, job->outBuf, &job->outBuf[i], FALSE); /* * There's still more in that thar buffer. This time, though, @@ -1814,17 +2117,16 @@ end_loop: */ if (*cp != '\0') { if (job->node != lastNode) { - printf (targFmt, job->node->name); + MESSAGE(stdout, job->node); lastNode = job->node; } - printf ("%s\n", cp); + (void) fprintf(stdout, "%s%s", cp, gotNL ? "\n" : ""); + (void) fflush(stdout); } - - fflush (stdout); } if (i < max - 1) { /* shift the remaining characters down */ - memcpy ( job->outBuf, &job->outBuf[i + 1], max - (i + 1)); + (void) memcpy(job->outBuf, &job->outBuf[i + 1], max - (i + 1)); job->curPos = max - (i + 1); } else { @@ -1838,10 +2140,11 @@ end_loop: if (finish) { /* * If the finish flag is true, we must loop until we hit - * end-of-file on the pipe. This is guaranteed to happen eventually - * since the other end of the pipe is now closed (we closed it - * explicitly and the child has exited). When we do get an EOF, - * finish will be set FALSE and we'll fall through and out. + * end-of-file on the pipe. This is guaranteed to happen + * eventually since the other end of the pipe is now closed + * (we closed it explicitly and the child has exited). When + * we do get an EOF, finish will be set FALSE and we'll fall + * through and out. */ goto end_loop; } @@ -1856,62 +2159,36 @@ end_loop: * Change to read in blocks and do FindSubString type things as for * pipes? That would allow for "@echo -n..." */ - oFILE = fopen (job->outFile, "r"); - if (oFILE != (FILE *) NULL) { - printf ("Results of making %s:\n", job->node->name); - while (fgets (inLine, sizeof(inLine), oFILE) != NULL) { - register char *cp, *ecp, *endp; + oFILE = fopen(job->outFile, "r"); + if (oFILE != NULL) { + (void) fprintf(stdout, "Results of making %s:\n", job->node->name); + (void) fflush(stdout); + while (fgets(inLine, sizeof(inLine), oFILE) != NULL) { + register char *cp, *endp, *oendp; cp = inLine; - endp = inLine + strlen(inLine); + oendp = endp = inLine + strlen(inLine); if (endp[-1] == '\n') { *--endp = '\0'; } - if (commandShell->noPrint) { - ecp = Str_FindSubstring(cp, commandShell->noPrint); - while (ecp != (char *)NULL) { - if (cp != ecp) { - *ecp = '\0'; - /* - * The only way there wouldn't be a newline after - * this line is if it were the last in the buffer. - * however, since the non-printable comes after it, - * there must be a newline, so we don't print one. - */ - printf ("%s", cp); - } - cp = ecp + commandShell->noPLen; - if (cp != endp) { - /* - * Still more to print, look again after skipping - * the whitespace following the non-printable - * command.... - */ - cp++; - while (*cp == ' ' || *cp == '\t' || *cp == '\n') { - cp++; - } - ecp = Str_FindSubstring(cp, commandShell->noPrint); - } else { - break; - } - } - } + cp = JobOutput(job, inLine, endp, FALSE); /* * There's still more in that thar buffer. This time, though, * we know there's no newline at the end, so we add one of * our own free will. */ - if (*cp != '\0') { - printf ("%s\n", cp); + (void) fprintf(stdout, "%s", cp); + (void) fflush(stdout); + if (endp != oendp) { + (void) fprintf(stdout, "\n"); + (void) fflush(stdout); } } - fclose (oFILE); - (void) unlink (job->outFile); + (void) fclose(oFILE); + (void) eunlink(job->outFile); } } - fflush(stdout); } /*- @@ -1934,13 +2211,13 @@ end_loop: *----------------------------------------------------------------------- */ void -Job_CatchChildren (block) +Job_CatchChildren(block) Boolean block; /* TRUE if should block on the wait. */ { int pid; /* pid of dead child */ register Job *job; /* job descriptor for dead child */ LstNode jnode; /* list element for finding job */ - union wait status; /* Exit/termination status */ + int status; /* Exit/termination status */ /* * Don't even bother if we know there's no one around. @@ -1949,40 +2226,54 @@ Job_CatchChildren (block) return; } - while ((pid = wait3((int *)&status, (block?0:WNOHANG)|WUNTRACED, - (struct rusage *)0)) > 0) + while ((pid = waitpid((pid_t) -1, &status, + (block?0:WNOHANG)|WUNTRACED)) > 0) { - if (DEBUG(JOB)) - printf("Process %d exited or stopped.\n", pid); + if (DEBUG(JOB)) { + (void) fprintf(stdout, "Process %d exited or stopped.\n", pid); + (void) fflush(stdout); + } - jnode = Lst_Find (jobs, (ClientData)&pid, JobCmpPid); + jnode = Lst_Find(jobs, (ClientData)&pid, JobCmpPid); if (jnode == NILLNODE) { - if (WIFSIGNALED(status) && (status.w_termsig == SIGCONT)) { + if (WIFSIGNALED(status) && (WTERMSIG(status) == SIGCONT)) { jnode = Lst_Find(stoppedJobs, (ClientData) &pid, JobCmpPid); if (jnode == NILLNODE) { Error("Resumed child (%d) not in table", pid); continue; } job = (Job *)Lst_Datum(jnode); - (void)Lst_Remove(stoppedJobs, jnode); + (void) Lst_Remove(stoppedJobs, jnode); } else { - Error ("Child (%d) not in table?", pid); + Error("Child (%d) not in table?", pid); continue; } } else { - job = (Job *) Lst_Datum (jnode); - (void)Lst_Remove (jobs, jnode); + job = (Job *) Lst_Datum(jnode); + (void) Lst_Remove(jobs, jnode); nJobs -= 1; if (jobFull && DEBUG(JOB)) { - printf("Job queue is no longer full.\n"); + (void) fprintf(stdout, "Job queue is no longer full.\n"); + (void) fflush(stdout); } jobFull = FALSE; +#ifdef REMOTE + if (!(job->flags & JOB_REMOTE)) { + if (DEBUG(JOB)) { + (void) fprintf(stdout, + "Job queue has one fewer local process.\n"); + (void) fflush(stdout); + } + nLocal -= 1; + } +#else nLocal -= 1; +#endif } - JobFinish (job, status); + JobFinish(job, &status); } } @@ -2003,7 +2294,7 @@ Job_CatchChildren (block) * ----------------------------------------------------------------------- */ void -Job_CatchOutput () +Job_CatchOutput() { int nfds; struct timeval timeout; @@ -2014,7 +2305,7 @@ Job_CatchOutput () int pnJobs; /* Previous nJobs */ #endif - fflush(stdout); + (void) fflush(stdout); #ifdef RMT_WILL_WATCH pnJobs = nJobs; @@ -2043,21 +2334,21 @@ Job_CatchOutput () timeout.tv_sec = SEL_SEC; timeout.tv_usec = SEL_USEC; - if ((nfds = select (FD_SETSIZE, &readfds, (fd_set *) 0, (fd_set *) 0, &timeout)) < 0) - { + if ((nfds = select(FD_SETSIZE, &readfds, (fd_set *) 0, + (fd_set *) 0, &timeout)) <= 0) return; - } else { - if (Lst_Open (jobs) == FAILURE) { - Punt ("Cannot open job table"); + else { + if (Lst_Open(jobs) == FAILURE) { + Punt("Cannot open job table"); } - while (nfds && (ln = Lst_Next (jobs)) != NILLNODE) { - job = (Job *) Lst_Datum (ln); + while (nfds && (ln = Lst_Next(jobs)) != NILLNODE) { + job = (Job *) Lst_Datum(ln); if (FD_ISSET(job->inPipe, &readfds)) { - JobDoOutput (job, FALSE); + JobDoOutput(job, FALSE); nfds -= 1; } } - Lst_Close (jobs); + Lst_Close(jobs); } } #endif /* RMT_WILL_WATCH */ @@ -2078,10 +2369,10 @@ Job_CatchOutput () *----------------------------------------------------------------------- */ void -Job_Make (gn) +Job_Make(gn) GNode *gn; { - (void)JobStart (gn, 0, (Job *)NULL); + (void) JobStart(gn, 0, NULL); } /*- @@ -2097,7 +2388,7 @@ Job_Make (gn) *----------------------------------------------------------------------- */ void -Job_Init (maxproc, maxlocal) +Job_Init(maxproc, maxlocal) int maxproc; /* the greatest number of jobs which may be * running at one time */ int maxlocal; /* the greatest number of local jobs which may @@ -2105,9 +2396,9 @@ Job_Init (maxproc, maxlocal) { GNode *begin; /* node for commands to do at the very start */ - sprintf (tfile, "/tmp/make%05d", getpid()); + (void) sprintf(tfile, "/tmp/make%05d", getpid()); - jobs = Lst_Init (FALSE); + jobs = Lst_Init(FALSE); stoppedJobs = Lst_Init(FALSE); maxJobs = maxproc; maxLocal = maxlocal; @@ -2120,7 +2411,11 @@ Job_Init (maxproc, maxlocal) lastNode = NILGNODE; - if (maxJobs == 1) { + if (maxJobs == 1 +#ifdef REMOTE + || noMessages +#endif + ) { /* * If only one job can run at a time, there's no need for a banner, * no is there? @@ -2130,7 +2425,7 @@ Job_Init (maxproc, maxlocal) targFmt = TARG_FMT; } - if (shellPath == (char *) NULL) { + if (shellPath == NULL) { /* * The user didn't specify a shell to use, so we are using the * default one... Both the absolute path and the last component @@ -2139,13 +2434,13 @@ Job_Init (maxproc, maxlocal) * All default shells are located in _PATH_DEFSHELLDIR. */ shellName = commandShell->name; - shellPath = str_concat (_PATH_DEFSHELLDIR, shellName, STR_ADDSLASH); + shellPath = str_concat(_PATH_DEFSHELLDIR, shellName, STR_ADDSLASH); } - if (commandShell->exit == (char *)NULL) { + if (commandShell->exit == NULL) { commandShell->exit = ""; } - if (commandShell->echo == (char *)NULL) { + if (commandShell->echo == NULL) { commandShell->echo = ""; } @@ -2153,17 +2448,17 @@ Job_Init (maxproc, maxlocal) * Catch the four signals that POSIX specifies if they aren't ignored. * JobPassSig will take care of calling JobInterrupt if appropriate. */ - if (signal (SIGINT, SIG_IGN) != SIG_IGN) { - signal (SIGINT, JobPassSig); + if (signal(SIGINT, SIG_IGN) != SIG_IGN) { + (void) signal(SIGINT, JobPassSig); } - if (signal (SIGHUP, SIG_IGN) != SIG_IGN) { - signal (SIGHUP, JobPassSig); + if (signal(SIGHUP, SIG_IGN) != SIG_IGN) { + (void) signal(SIGHUP, JobPassSig); } - if (signal (SIGQUIT, SIG_IGN) != SIG_IGN) { - signal (SIGQUIT, JobPassSig); + if (signal(SIGQUIT, SIG_IGN) != SIG_IGN) { + (void) signal(SIGQUIT, JobPassSig); } - if (signal (SIGTERM, SIG_IGN) != SIG_IGN) { - signal (SIGTERM, JobPassSig); + if (signal(SIGTERM, SIG_IGN) != SIG_IGN) { + (void) signal(SIGTERM, JobPassSig); } /* * There are additional signals that need to be caught and passed if @@ -2172,32 +2467,32 @@ Job_Init (maxproc, maxlocal) * signals from the terminal driver as we own the terminal) */ #if defined(RMT_WANTS_SIGNALS) || defined(USE_PGRP) - if (signal (SIGTSTP, SIG_IGN) != SIG_IGN) { - signal (SIGTSTP, JobPassSig); + if (signal(SIGTSTP, SIG_IGN) != SIG_IGN) { + (void) signal(SIGTSTP, JobPassSig); } - if (signal (SIGTTOU, SIG_IGN) != SIG_IGN) { - signal (SIGTTOU, JobPassSig); + if (signal(SIGTTOU, SIG_IGN) != SIG_IGN) { + (void) signal(SIGTTOU, JobPassSig); } - if (signal (SIGTTIN, SIG_IGN) != SIG_IGN) { - signal (SIGTTIN, JobPassSig); + if (signal(SIGTTIN, SIG_IGN) != SIG_IGN) { + (void) signal(SIGTTIN, JobPassSig); } - if (signal (SIGWINCH, SIG_IGN) != SIG_IGN) { - signal (SIGWINCH, JobPassSig); + if (signal(SIGWINCH, SIG_IGN) != SIG_IGN) { + (void) signal(SIGWINCH, JobPassSig); } #endif - begin = Targ_FindNode (".BEGIN", TARG_NOCREATE); + begin = Targ_FindNode(".BEGIN", TARG_NOCREATE); if (begin != NILGNODE) { - JobStart (begin, JOB_SPECIAL, (Job *)0); + JobStart(begin, JOB_SPECIAL, (Job *)0); while (nJobs) { Job_CatchOutput(); #ifndef RMT_WILL_WATCH - Job_CatchChildren (!usePipes); + Job_CatchChildren(!usePipes); #endif /* RMT_WILL_WATCH */ } } - postCommands = Targ_FindNode (".END", TARG_CREATE); + postCommands = Targ_FindNode(".END", TARG_CREATE); } /*- @@ -2215,9 +2510,9 @@ Job_Init (maxproc, maxlocal) *----------------------------------------------------------------------- */ Boolean -Job_Full () +Job_Full() { - return (aborting || jobFull); + return(aborting || jobFull); } /*- @@ -2237,7 +2532,7 @@ Job_Full () * ----------------------------------------------------------------------- */ Boolean -Job_Empty () +Job_Empty() { if (nJobs == 0) { if (!Lst_IsEmpty(stoppedJobs) && !aborting) { @@ -2246,9 +2541,7 @@ Job_Empty () * it...Try and restart the stopped jobs. */ jobFull = FALSE; - while (!jobFull && !Lst_IsEmpty(stoppedJobs)) { - JobRestart((Job *)Lst_DeQueue(stoppedJobs)); - } + JobRestartJobs(); return(FALSE); } else { return(TRUE); @@ -2272,7 +2565,7 @@ Job_Empty () *----------------------------------------------------------------------- */ static Shell * -JobMatchShell (name) +JobMatchShell(name) char *name; /* Final component of shell path */ { register Shell *sh; /* Pointer into shells table */ @@ -2281,24 +2574,23 @@ JobMatchShell (name) *cp2; char *eoname; - eoname = name + strlen (name); + eoname = name + strlen(name); - match = (Shell *) NULL; + match = NULL; for (sh = shells; sh->name != NULL; sh++) { - for (cp1 = eoname - strlen (sh->name), cp2 = sh->name; + for (cp1 = eoname - strlen(sh->name), cp2 = sh->name; *cp1 != '\0' && *cp1 == *cp2; cp1++, cp2++) { continue; } if (*cp1 != *cp2) { continue; - } else if (match == (Shell *) NULL || - strlen (match->name) < strlen (sh->name)) { - match = sh; + } else if (match == NULL || strlen(match->name) < strlen(sh->name)) { + match = sh; } } - return (match == (Shell *) NULL ? sh : match); + return(match == NULL ? sh : match); } /*- @@ -2345,7 +2637,7 @@ JobMatchShell (name) *----------------------------------------------------------------------- */ ReturnStatus -Job_ParseShell (line) +Job_ParseShell(line) char *line; /* The shell spec */ { char **words; @@ -2356,64 +2648,64 @@ Job_ParseShell (line) Shell newShell; Boolean fullSpec = FALSE; - while (isspace (*line)) { + while (isspace(*line)) { line++; } - words = brk_string (line, &wordCount, TRUE); + words = brk_string(line, &wordCount, TRUE); - memset ((Address)&newShell, 0, sizeof(newShell)); + memset((Address)&newShell, 0, sizeof(newShell)); /* * Parse the specification by keyword */ - for (path = (char *)NULL, argc = wordCount - 1, argv = words + 1; + for (path = NULL, argc = wordCount - 1, argv = words + 1; argc != 0; argc--, argv++) { - if (strncmp (*argv, "path=", 5) == 0) { + if (strncmp(*argv, "path=", 5) == 0) { path = &argv[0][5]; - } else if (strncmp (*argv, "name=", 5) == 0) { + } else if (strncmp(*argv, "name=", 5) == 0) { newShell.name = &argv[0][5]; } else { - if (strncmp (*argv, "quiet=", 6) == 0) { + if (strncmp(*argv, "quiet=", 6) == 0) { newShell.echoOff = &argv[0][6]; - } else if (strncmp (*argv, "echo=", 5) == 0) { + } else if (strncmp(*argv, "echo=", 5) == 0) { newShell.echoOn = &argv[0][5]; - } else if (strncmp (*argv, "filter=", 7) == 0) { + } else if (strncmp(*argv, "filter=", 7) == 0) { newShell.noPrint = &argv[0][7]; newShell.noPLen = strlen(newShell.noPrint); - } else if (strncmp (*argv, "echoFlag=", 9) == 0) { + } else if (strncmp(*argv, "echoFlag=", 9) == 0) { newShell.echo = &argv[0][9]; - } else if (strncmp (*argv, "errFlag=", 8) == 0) { + } else if (strncmp(*argv, "errFlag=", 8) == 0) { newShell.exit = &argv[0][8]; - } else if (strncmp (*argv, "hasErrCtl=", 10) == 0) { + } else if (strncmp(*argv, "hasErrCtl=", 10) == 0) { char c = argv[0][10]; newShell.hasErrCtl = !((c != 'Y') && (c != 'y') && - (c != 'T') && (c != 't')); - } else if (strncmp (*argv, "check=", 6) == 0) { + (c != 'T') && (c != 't')); + } else if (strncmp(*argv, "check=", 6) == 0) { newShell.errCheck = &argv[0][6]; - } else if (strncmp (*argv, "ignore=", 7) == 0) { + } else if (strncmp(*argv, "ignore=", 7) == 0) { newShell.ignErr = &argv[0][7]; } else { - Parse_Error (PARSE_FATAL, "Unknown keyword \"%s\"", + Parse_Error(PARSE_FATAL, "Unknown keyword \"%s\"", *argv); - return (FAILURE); + return(FAILURE); } fullSpec = TRUE; } } - if (path == (char *)NULL) { + if (path == NULL) { /* * If no path was given, the user wants one of the pre-defined shells, * yes? So we find the one s/he wants with the help of JobMatchShell * and set things up the right way. shellPath will be set up by * Job_Init. */ - if (newShell.name == (char *)NULL) { - Parse_Error (PARSE_FATAL, "Neither path nor name specified"); - return (FAILURE); + if (newShell.name == NULL) { + Parse_Error(PARSE_FATAL, "Neither path nor name specified"); + return(FAILURE); } else { - commandShell = JobMatchShell (newShell.name); + commandShell = JobMatchShell(newShell.name); shellName = newShell.name; } } else { @@ -2425,19 +2717,19 @@ Job_ParseShell (line) * path the user gave for the shell. */ shellPath = path; - path = strrchr (path, '/'); - if (path == (char *)NULL) { + path = strrchr(path, '/'); + if (path == NULL) { path = shellPath; } else { path += 1; } - if (newShell.name != (char *)NULL) { + if (newShell.name != NULL) { shellName = newShell.name; } else { shellName = path; } if (!fullSpec) { - commandShell = JobMatchShell (shellName); + commandShell = JobMatchShell(shellName); } else { commandShell = (Shell *) emalloc(sizeof(Shell)); *commandShell = newShell; @@ -2449,10 +2741,10 @@ Job_ParseShell (line) } if (!commandShell->hasErrCtl) { - if (commandShell->errCheck == (char *)NULL) { + if (commandShell->errCheck == NULL) { commandShell->errCheck = ""; } - if (commandShell->ignErr == (char *)NULL) { + if (commandShell->ignErr == NULL) { commandShell->ignErr = "%s\n"; } } @@ -2461,7 +2753,7 @@ Job_ParseShell (line) * Do not free up the words themselves, since they might be in use by the * shell specification... */ - free (words); + free(words); return SUCCESS; } @@ -2479,9 +2771,10 @@ Job_ParseShell (line) *----------------------------------------------------------------------- */ static void -JobInterrupt (runINTERRUPT) +JobInterrupt(runINTERRUPT, signo) int runINTERRUPT; /* Non-zero if commands for the .INTERRUPT * target should be executed */ + int signo; /* signal received */ { LstNode ln; /* element in job table */ Job *job; /* job descriptor in that element */ @@ -2489,18 +2782,16 @@ JobInterrupt (runINTERRUPT) aborting = ABORT_INTERRUPT; - (void)Lst_Open (jobs); - while ((ln = Lst_Next (jobs)) != NILLNODE) { - job = (Job *) Lst_Datum (ln); + (void) Lst_Open(jobs); + while ((ln = Lst_Next(jobs)) != NILLNODE) { + job = (Job *) Lst_Datum(ln); - if (!Targ_Precious (job->node)) { - char *file = (job->node->path == (char *)NULL ? + if (!Targ_Precious(job->node)) { + char *file = (job->node->path == NULL ? job->node->name : job->node->path); - struct stat st; - if (!noExecute && lstat(file, &st) != -1 && !S_ISDIR(st.st_mode) && - unlink(file) != -1) { - Error ("*** %s removed", file); + if (!noExecute && eunlink(file) != -1) { + Error("*** %s removed", file); } } #ifdef RMT_WANTS_SIGNALS @@ -2508,44 +2799,110 @@ JobInterrupt (runINTERRUPT) /* * If job is remote, let the Rmt module do the killing. */ - if (!Rmt_Signal(job, SIGINT)) { + if (!Rmt_Signal(job, signo)) { /* * If couldn't kill the thing, finish it out now with an * error code, since no exit report will come in likely. */ - union wait status; + int status; status.w_status = 0; status.w_retcode = 1; - JobFinish(job, status); + JobFinish(job, &status); } } else if (job->pid) { - KILL(job->pid, SIGINT); + KILL(job->pid, signo); } #else if (job->pid) { + if (DEBUG(JOB)) { + (void) fprintf(stdout, + "JobInterrupt passing signal to child %d.\n", + job->pid); + (void) fflush(stdout); + } + KILL(job->pid, signo); + } +#endif /* RMT_WANTS_SIGNALS */ + } + +#ifdef REMOTE + (void)Lst_Open(stoppedJobs); + while ((ln = Lst_Next(stoppedJobs)) != NILLNODE) { + job = (Job *) Lst_Datum(ln); + + if (job->flags & JOB_RESTART) { + if (DEBUG(JOB)) { + (void) fprintf(stdout, "%s%s", + "JobInterrupt skipping job on stopped queue", + "-- it was waiting to be restarted.\n"); + (void) fflush(stdout); + } + continue; + } + if (!Targ_Precious(job->node)) { + char *file = (job->node->path == NULL ? + job->node->name : + job->node->path); + if (eunlink(file) == 0) { + Error("*** %s removed", file); + } + } + /* + * Resume the thing so it will take the signal. + */ + if (DEBUG(JOB)) { + (void) fprintf(stdout, + "JobInterrupt passing CONT to stopped child %d.\n", + job->pid); + (void) fflush(stdout); + } + KILL(job->pid, SIGCONT); +#ifdef RMT_WANTS_SIGNALS + if (job->flags & JOB_REMOTE) { + /* + * If job is remote, let the Rmt module do the killing. + */ + if (!Rmt_Signal(job, SIGINT)) { + /* + * If couldn't kill the thing, finish it out now with an + * error code, since no exit report will come in likely. + */ + int status; + status.w_status = 0; + status.w_retcode = 1; + JobFinish(job, &status); + } + } else if (job->pid) { + if (DEBUG(JOB)) { + (void) fprintf(stdout, + "JobInterrupt passing interrupt to stopped child %d.\n", + job->pid); + (void) fflush(stdout); + } KILL(job->pid, SIGINT); } #endif /* RMT_WANTS_SIGNALS */ } - Lst_Close (jobs); +#endif + Lst_Close(stoppedJobs); if (runINTERRUPT && !touchFlag) { - interrupt = Targ_FindNode (".INTERRUPT", TARG_NOCREATE); + interrupt = Targ_FindNode(".INTERRUPT", TARG_NOCREATE); if (interrupt != NILGNODE) { ignoreErrors = FALSE; - JobStart (interrupt, JOB_IGNDOTS, (Job *)0); + JobStart(interrupt, JOB_IGNDOTS, (Job *)0); while (nJobs) { Job_CatchOutput(); #ifndef RMT_WILL_WATCH - Job_CatchChildren (!usePipes); + Job_CatchChildren(!usePipes); #endif /* RMT_WILL_WATCH */ } } } - (void) unlink (tfile); - exit (0); + (void) eunlink(tfile); + exit(signo); } /* @@ -2563,24 +2920,23 @@ JobInterrupt (runINTERRUPT) *----------------------------------------------------------------------- */ int -Job_End () +Job_End() { - if (postCommands != NILGNODE && !Lst_IsEmpty (postCommands->commands)) { + if (postCommands != NILGNODE && !Lst_IsEmpty(postCommands->commands)) { if (errors) { - Error ("Errors reported so .END ignored"); + Error("Errors reported so .END ignored"); } else { - JobStart (postCommands, JOB_SPECIAL | JOB_IGNDOTS, - (Job *)0); + JobStart(postCommands, JOB_SPECIAL | JOB_IGNDOTS, NULL); while (nJobs) { Job_CatchOutput(); #ifndef RMT_WILL_WATCH - Job_CatchChildren (!usePipes); + Job_CatchChildren(!usePipes); #endif /* RMT_WILL_WATCH */ } } } - (void) unlink (tfile); + (void) eunlink(tfile); return(errors); } @@ -2626,9 +2982,9 @@ Job_Wait() *----------------------------------------------------------------------- */ void -Job_AbortAll () +Job_AbortAll() { - LstNode ln; /* element in job table */ + LstNode ln; /* element in job table */ Job *job; /* the job descriptor in that element */ int foo; @@ -2636,9 +2992,9 @@ Job_AbortAll () if (nJobs) { - (void)Lst_Open (jobs); - while ((ln = Lst_Next (jobs)) != NILLNODE) { - job = (Job *) Lst_Datum (ln); + (void) Lst_Open(jobs); + while ((ln = Lst_Next(jobs)) != NILLNODE) { + job = (Job *) Lst_Datum(ln); /* * kill the child process with increasingly drastic signals to make @@ -2662,7 +3018,88 @@ Job_AbortAll () /* * Catch as many children as want to report in at first, then give up */ - while (wait3(&foo, WNOHANG, (struct rusage *)0) > 0) + while (waitpid((pid_t) -1, &foo, WNOHANG) > 0) continue; - (void) unlink (tfile); + (void) eunlink(tfile); +} + +#ifdef REMOTE +/*- + *----------------------------------------------------------------------- + * JobFlagForMigration -- + * Handle the eviction of a child. Called from RmtStatusChange. + * Flags the child as remigratable and then suspends it. + * + * Results: + * none. + * + * Side Effects: + * The job descriptor is flagged for remigration. + * + *----------------------------------------------------------------------- + */ +void +JobFlagForMigration(hostID) + int hostID; /* ID of host we used, for matching children. */ +{ + register Job *job; /* job descriptor for dead child */ + LstNode jnode; /* list element for finding job */ + + if (DEBUG(JOB)) { + (void) fprintf(stdout, "JobFlagForMigration(%d) called.\n", hostID); + (void) fflush(stdout); + } + jnode = Lst_Find(jobs, (ClientData)hostID, JobCmpRmtID); + + if (jnode == NILLNODE) { + jnode = Lst_Find(stoppedJobs, (ClientData)hostID, JobCmpRmtID); + if (jnode == NILLNODE) { + if (DEBUG(JOB)) { + Error("Evicting host(%d) not in table", hostID); + } + return; + } + } + job = (Job *) Lst_Datum(jnode); + + if (DEBUG(JOB)) { + (void) fprintf(stdout, + "JobFlagForMigration(%d) found job '%s'.\n", hostID, + job->node->name); + (void) fflush(stdout); + } + + KILL(job->pid, SIGSTOP); + + job->flags |= JOB_REMIGRATE; +} + +#endif + +/*- + *----------------------------------------------------------------------- + * JobRestartJobs -- + * Tries to restart stopped jobs if there are slots available. + * Note that this tries to restart them regardless of pending errors. + * It's not good to leave stopped jobs lying around! + * + * Results: + * None. + * + * Side Effects: + * Resumes(and possibly migrates) jobs. + * + *----------------------------------------------------------------------- + */ +static void +JobRestartJobs() +{ + while (!jobFull && !Lst_IsEmpty(stoppedJobs)) { + if (DEBUG(JOB)) { + (void) fprintf(stdout, + "Job queue is not full. Restarting a stopped job.\n"); + (void) fflush(stdout); + } + JobRestart((Job *)Lst_DeQueue(stoppedJobs)); + } } |