version 1.40, 2001/05/03 13:41:06 |
version 1.41, 2001/05/23 12:34:44 |
|
|
* frequently to keep the whole make going at |
* frequently to keep the whole make going at |
* a decent clip, since job table entries aren't |
* a decent clip, since job table entries aren't |
* removed until their process is caught this way. |
* removed until their process is caught this way. |
* Its single argument is TRUE if the function |
* Its single argument is true if the function |
* should block waiting for a child to terminate. |
* should block waiting for a child to terminate. |
* |
* |
* Job_CatchOutput Print any output our children have produced. |
* Job_CatchOutput Print any output our children have produced. |
|
|
* |
* |
* Job_End Cleanup any memory used. |
* Job_End Cleanup any memory used. |
* |
* |
* Job_Full Return TRUE if the job table is filled. |
* Job_Full Return true if the job table is filled. |
* |
* |
* Job_Empty Return TRUE if the job table is completely |
* Job_Empty Return true if the job table is completely |
* empty. |
* empty. |
* |
* |
* Job_ParseShell Given the line following a .SHELL target, parse |
* Job_ParseShell Given the line following a .SHELL target, parse |
* the line as a shell specification. Returns |
* the line as a shell specification. Returns |
* FAILURE if the spec was incorrect. |
* false if the spec was incorrect. |
* |
* |
* Job_Finish Perform any final processing which needs doing. |
* Job_Finish Perform any final processing which needs doing. |
* This includes the execution of any commands |
* This includes the execution of any commands |
|
|
*/ |
*/ |
|
|
#include <sys/types.h> |
#include <sys/types.h> |
#include <sys/stat.h> |
|
#include <sys/file.h> |
|
#include <sys/time.h> |
|
#include <sys/wait.h> |
#include <sys/wait.h> |
#include <fcntl.h> |
#include <ctype.h> |
#include <errno.h> |
#include <errno.h> |
#include <utime.h> |
#include <fcntl.h> |
|
#include <signal.h> |
#include <stddef.h> |
#include <stddef.h> |
#include <stdio.h> |
#include <stdio.h> |
#include <string.h> |
#include <string.h> |
#include <signal.h> |
#include <unistd.h> |
#include "make.h" |
#include "config.h" |
#include "ohash.h" |
#include "defines.h" |
#include "dir.h" |
#include "dir.h" |
#include "job.h" |
#include "job.h" |
#include "pathnames.h" |
#include "pathnames.h" |
|
#include "arch.h" |
|
#include "var.h" |
|
#include "targ.h" |
|
#include "error.h" |
|
#include "str.h" |
|
#include "lst.h" |
|
#include "extern.h" |
|
#include "gnode.h" |
|
#include "memory.h" |
|
#include "make.h" |
|
#include "timestamp.h" |
|
#include "main.h" |
|
|
#ifdef REMOTE |
#ifdef REMOTE |
#include "rmt.h" |
#include "rmt.h" |
# define STATIC |
# define STATIC |
|
|
# define STATIC static |
# define STATIC static |
#endif |
#endif |
|
|
#ifndef lint |
|
#if 0 |
|
static char sccsid[] = "@(#)job.c 8.2 (Berkeley) 3/19/94"; |
|
#else |
|
UNUSED |
|
static char rcsid[] = "$OpenBSD$"; |
|
#endif |
|
#endif /* not lint */ |
|
|
|
|
|
/* |
/* |
* error handling variables |
* error handling variables |
*/ |
*/ |
|
|
*/ |
*/ |
{ |
{ |
"csh", |
"csh", |
TRUE, "unset verbose", "set verbose", "unset verbose", 10, |
true, "unset verbose", "set verbose", "unset verbose", 10, |
FALSE, "echo \"%s\"\n", "csh -c \"%s || exit 0\"", |
false, "echo \"%s\"\n", "csh -c \"%s || exit 0\"", |
"v", "e", |
"v", "e", |
}, |
}, |
/* |
/* |
|
|
*/ |
*/ |
{ |
{ |
"sh", |
"sh", |
TRUE, "set -", "set -v", "set -", 5, |
true, "set -", "set -v", "set -", 5, |
TRUE, "set -e", "set +e", |
true, "set -e", "set +e", |
#ifdef OLDBOURNESHELL |
#ifdef OLDBOURNESHELL |
FALSE, "echo \"%s\"\n", "sh -c '%s || exit 0'\n", |
false, "echo \"%s\"\n", "sh -c '%s || exit 0'\n", |
#endif |
#endif |
"v", "e", |
"v", "e", |
}, |
}, |
|
|
*/ |
*/ |
{ |
{ |
(char *)0, |
(char *)0, |
FALSE, (char *)0, (char *)0, (char *)0, 0, |
false, (char *)0, (char *)0, (char *)0, 0, |
FALSE, (char *)0, (char *)0, |
false, (char *)0, (char *)0, |
(char *)0, (char *)0, |
(char *)0, (char *)0, |
} |
} |
}; |
}; |
|
|
|
|
static int maxJobs; /* The most children we can run at once */ |
static int maxJobs; /* The most children we can run at once */ |
static int maxLocal; /* The most local ones we can have */ |
static int maxLocal; /* The most local ones we can have */ |
STATIC int nJobs; /* The number of children currently running */ |
STATIC int nJobs = 0; /* The number of children currently running */ |
STATIC int nLocal; /* The number of local children */ |
STATIC int nLocal; /* The number of local children */ |
STATIC LIST jobs; /* The structures that describe them */ |
STATIC LIST jobs; /* The structures that describe them */ |
STATIC Boolean jobFull; /* Flag to tell when the job table is full. It |
STATIC bool jobFull; /* Flag to tell when the job table is full. It |
* is set TRUE when (1) the total number of |
* is set true when (1) the total number of |
* running jobs equals the maximum allowed or |
* running jobs equals the maximum allowed or |
* (2) a job can only be run locally, but |
* (2) a job can only be run locally, but |
* nLocal equals maxLocal */ |
* nLocal equals maxLocal */ |
|
|
static void JobRestart(Job *); |
static void JobRestart(Job *); |
static int JobStart(GNode *, int, Job *); |
static int JobStart(GNode *, int, Job *); |
static char *JobOutput(Job *, char *, char *, int); |
static char *JobOutput(Job *, char *, char *, int); |
static void JobDoOutput(Job *, Boolean); |
static void JobDoOutput(Job *, bool); |
static Shell *JobMatchShell(char *); |
static Shell *JobMatchShell(char *); |
static void JobInterrupt(int, int); |
static void JobInterrupt(int, int); |
static void JobRestartJobs(void); |
static void JobRestartJobs(void); |
|
|
* three termination signals are more of a "get out *now*" command. |
* three termination signals are more of a "get out *now*" command. |
*/ |
*/ |
if (signo == SIGINT) { |
if (signo == SIGINT) { |
JobInterrupt(TRUE, signo); |
JobInterrupt(true, signo); |
} else if (signo == SIGHUP || signo == SIGTERM || signo == SIGQUIT) { |
} else if (signo == SIGHUP || signo == SIGTERM || signo == SIGQUIT) { |
JobInterrupt(FALSE, signo); |
JobInterrupt(false, signo); |
} |
} |
|
|
/* |
/* |
|
|
void *cmdp; /* command string to print */ |
void *cmdp; /* command string to print */ |
void *jobp; /* job for which to print it */ |
void *jobp; /* job for which to print it */ |
{ |
{ |
Boolean noSpecials; /* true if we shouldn't worry about |
bool noSpecials; /* true if we shouldn't worry about |
* inserting special commands into |
* inserting special commands into |
* the input stream. */ |
* the input stream. */ |
Boolean shutUp = FALSE; /* true if we put a no echo command |
bool shutUp = false; /* true if we put a no echo command |
* into the command file */ |
* into the command file */ |
Boolean errOff = FALSE; /* true if we turned error checking |
bool errOff = false; /* true if we turned error checking |
* off before printing the command |
* off before printing the command |
* and need to turn it back on */ |
* and need to turn it back on */ |
char *cmdTemplate; /* Template to use when printing the |
char *cmdTemplate; /* Template to use when printing the |
|
|
/* For debugging, we replace each command with the result of expanding |
/* For debugging, we replace each command with the result of expanding |
* the variables in the command. */ |
* the variables in the command. */ |
cmdNode = Lst_Member(&job->node->commands, cmd); |
cmdNode = Lst_Member(&job->node->commands, cmd); |
cmdStart = cmd = Var_Subst(cmd, &job->node->context, FALSE); |
cmdStart = cmd = Var_Subst(cmd, &job->node->context, false); |
Lst_Replace(cmdNode, cmdStart); |
Lst_Replace(cmdNode, cmdStart); |
|
|
cmdTemplate = "%s\n"; |
cmdTemplate = "%s\n"; |
|
|
*/ |
*/ |
for (;; cmd++) { |
for (;; cmd++) { |
if (*cmd == '@') |
if (*cmd == '@') |
shutUp = DEBUG(LOUD) ? FALSE : TRUE; |
shutUp = DEBUG(LOUD) ? false : true; |
else if (*cmd == '-') |
else if (*cmd == '-') |
errOff = TRUE; |
errOff = true; |
else if (*cmd != '+') |
else if (*cmd != '+') |
break; |
break; |
} |
} |
|
|
commandShell->hasEchoCtl) { |
commandShell->hasEchoCtl) { |
DBPRINTF("%s\n", commandShell->echoOff); |
DBPRINTF("%s\n", commandShell->echoOff); |
} else { |
} else { |
shutUp = FALSE; |
shutUp = false; |
} |
} |
} |
} |
|
|
|
|
commandShell->hasEchoCtl) { |
commandShell->hasEchoCtl) { |
DBPRINTF("%s\n", commandShell->echoOff); |
DBPRINTF("%s\n", commandShell->echoOff); |
DBPRINTF(commandShell->errCheck, cmd); |
DBPRINTF(commandShell->errCheck, cmd); |
shutUp = TRUE; |
shutUp = true; |
} |
} |
cmdTemplate = commandShell->ignErr; |
cmdTemplate = commandShell->ignErr; |
/* |
/* |
|
|
* of by the ignErr template, so pretend error checking |
* of by the ignErr template, so pretend error checking |
* is still on. |
* is still on. |
*/ |
*/ |
errOff = FALSE; |
errOff = false; |
} else { |
} else { |
errOff = FALSE; |
errOff = false; |
} |
} |
} else { |
} else { |
errOff = FALSE; |
errOff = false; |
} |
} |
} |
} |
|
|
|
|
*/ |
*/ |
if (!shutUp && !(job->flags & JOB_SILENT) && commandShell->hasEchoCtl){ |
if (!shutUp && !(job->flags & JOB_SILENT) && commandShell->hasEchoCtl){ |
DBPRINTF("%s\n", commandShell->echoOff); |
DBPRINTF("%s\n", commandShell->echoOff); |
shutUp = TRUE; |
shutUp = true; |
} |
} |
DBPRINTF("%s\n", commandShell->errCheck); |
DBPRINTF("%s\n", commandShell->errCheck); |
} |
} |
|
|
GNode *g = (GNode *)gn; |
GNode *g = (GNode *)gn; |
char *result; |
char *result; |
|
|
result = Var_Subst((char *)cmd, &g->context, FALSE); |
result = Var_Subst((char *)cmd, &g->context, false); |
Lst_AtEnd(&postCommands->commands, result); |
Lst_AtEnd(&postCommands->commands, result); |
} |
} |
|
|
|
|
if (job->outPipe != job->inPipe) { |
if (job->outPipe != job->inPipe) { |
(void)close(job->outPipe); |
(void)close(job->outPipe); |
} |
} |
JobDoOutput(job, TRUE); |
JobDoOutput(job, true); |
(void)close(job->inPipe); |
(void)close(job->inPipe); |
} else { |
} else { |
(void)close(job->outFd); |
(void)close(job->outFd); |
JobDoOutput(job, TRUE); |
JobDoOutput(job, true); |
} |
} |
} |
} |
|
|
|
|
Job *job; /* job to finish */ |
Job *job; /* job to finish */ |
int *status; /* sub-why job went away */ |
int *status; /* sub-why job went away */ |
{ |
{ |
Boolean done; |
bool done; |
|
|
if ((WIFEXITED(*status) && |
if ((WIFEXITED(*status) && |
WEXITSTATUS(*status) != 0 && !(job->flags & JOB_IGNERR)) || |
WEXITSTATUS(*status) != 0 && !(job->flags & JOB_IGNERR)) || |
|
|
if (job->cmdFILE != NULL && job->cmdFILE != stdout) { |
if (job->cmdFILE != NULL && job->cmdFILE != stdout) { |
(void)fclose(job->cmdFILE); |
(void)fclose(job->cmdFILE); |
} |
} |
done = TRUE; |
done = true; |
#ifdef REMOTE |
#ifdef REMOTE |
if (job->flags & JOB_REMOTE) |
if (job->flags & JOB_REMOTE) |
Rmt_Done(job->rmtID, job->node); |
Rmt_Done(job->rmtID, job->node); |
|
|
* Deal with ignored errors in -B mode. We need to print a message |
* 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 |
* 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 |
* 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. |
* true if in -B mode and the job exited non-zero. |
*/ |
*/ |
done = WEXITSTATUS(*status) != 0; |
done = WEXITSTATUS(*status) != 0; |
/* |
/* |
|
|
/* |
/* |
* No need to close things down or anything. |
* No need to close things down or anything. |
*/ |
*/ |
done = FALSE; |
done = false; |
} |
} |
|
|
if (done || |
if (done || |
|
|
nLocal += 1; |
nLocal += 1; |
} |
} |
if (nJobs == maxJobs) { |
if (nJobs == maxJobs) { |
jobFull = TRUE; |
jobFull = true; |
if (DEBUG(JOB)) { |
if (DEBUG(JOB)) { |
(void)fprintf(stdout, "Job queue is full.\n"); |
(void)fprintf(stdout, "Job queue is full.\n"); |
(void)fflush(stdout); |
(void)fflush(stdout); |
|
|
if (compatMake && WIFEXITED(*status) && job->node->current != NULL) { |
if (compatMake && WIFEXITED(*status) && job->node->current != NULL) { |
switch (JobStart(job->node, job->flags & JOB_IGNDOTS, job)) { |
switch (JobStart(job->node, job->flags & JOB_IGNDOTS, job)) { |
case JOB_RUNNING: |
case JOB_RUNNING: |
done = FALSE; |
done = false; |
break; |
break; |
case JOB_ERROR: |
case JOB_ERROR: |
done = TRUE; |
done = true; |
W_SETEXITSTATUS(status, 1); |
W_SETEXITSTATUS(status, 1); |
break; |
break; |
case JOB_FINISHED: |
case JOB_FINISHED: |
|
|
* JobStart needs to do the update so we can proceed up the |
* JobStart needs to do the update so we can proceed up the |
* graph when given the -n flag.. |
* graph when given the -n flag.. |
*/ |
*/ |
done = FALSE; |
done = false; |
break; |
break; |
} |
} |
} else |
} else |
done = TRUE; |
done = true; |
|
|
if (done && |
if (done && |
aborting != ABORT_ERROR && |
aborting != ABORT_ERROR && |
|
|
void |
void |
Job_Touch(gn, silent) |
Job_Touch(gn, silent) |
GNode *gn; /* the node of the file to touch */ |
GNode *gn; /* the node of the file to touch */ |
Boolean silent; /* TRUE if should not print messages */ |
bool silent; /* true if should not print messages */ |
{ |
{ |
int streamID; /* ID of stream opened to do the touch */ |
int streamID; /* ID of stream opened to do the touch */ |
|
|
|
|
* Make sure the given node has all the commands it needs. |
* Make sure the given node has all the commands it needs. |
* |
* |
* Results: |
* Results: |
* TRUE if the commands list is/was ok. |
* true if the commands list is/was ok. |
* |
* |
* Side Effects: |
* Side Effects: |
* The node will have commands from the .DEFAULT rule added to it |
* The node will have commands from the .DEFAULT rule added to it |
* if it needs them. |
* if it needs them. |
*----------------------------------------------------------------------- |
*----------------------------------------------------------------------- |
*/ |
*/ |
Boolean |
bool |
Job_CheckCommands(gn, abortProc) |
Job_CheckCommands(gn, abortProc) |
GNode *gn; /* The target whose commands need |
GNode *gn; /* The target whose commands need |
* verifying */ |
* verifying */ |
|
|
} else if (keepgoing) { |
} else if (keepgoing) { |
(void)fprintf(stdout, "%s %s(continuing)\n", msg, gn->name); |
(void)fprintf(stdout, "%s %s(continuing)\n", msg, gn->name); |
(void)fflush(stdout); |
(void)fflush(stdout); |
return FALSE; |
return false; |
} else { |
} else { |
(*abortProc)("%s %s. Stop in %s.", msg, gn->name, |
(*abortProc)("%s %s. Stop in %s.", msg, gn->name, |
Var_Value(".CURDIR")); |
Var_Value(".CURDIR")); |
return FALSE; |
return false; |
} |
} |
} |
} |
} |
} |
return TRUE; |
return true; |
} |
} |
#ifdef RMT_WILL_WATCH |
#ifdef RMT_WILL_WATCH |
/*- |
/*- |
|
|
int stream; /* Stream that's ready (ignored) */ |
int stream; /* Stream that's ready (ignored) */ |
Job *job; /* Job to which the stream belongs */ |
Job *job; /* Job to which the stream belongs */ |
{ |
{ |
JobDoOutput(job, FALSE); |
JobDoOutput(job, false); |
} |
} |
#endif /* RMT_WILL_WATCH */ |
#endif /* RMT_WILL_WATCH */ |
|
|
|
|
|
|
#ifdef REMOTE |
#ifdef REMOTE |
if (job->flags & JOB_REMOTE) { |
if (job->flags & JOB_REMOTE) { |
Rmt_Exec(shellPath, argv, FALSE); |
Rmt_Exec(shellPath, argv, false); |
} else |
} else |
#endif /* REMOTE */ |
#endif /* REMOTE */ |
(void)execv(shellPath, argv); |
(void)execv(shellPath, argv); |
|
|
nJobs += 1; |
nJobs += 1; |
Lst_AtEnd(&jobs, job); |
Lst_AtEnd(&jobs, job); |
if (nJobs == maxJobs) { |
if (nJobs == maxJobs) { |
jobFull = TRUE; |
jobFull = true; |
} |
} |
} |
} |
|
|
|
|
(void)fflush(stdout); |
(void)fflush(stdout); |
} |
} |
Lst_AtFront(&stoppedJobs, job); |
Lst_AtFront(&stoppedJobs, job); |
jobFull = TRUE; |
jobFull = true; |
if (DEBUG(JOB)) { |
if (DEBUG(JOB)) { |
(void)fprintf(stdout, "Job queue is full.\n"); |
(void)fprintf(stdout, "Job queue is full.\n"); |
(void)fflush(stdout); |
(void)fflush(stdout); |
|
|
Lst_AtEnd(&jobs, job); |
Lst_AtEnd(&jobs, job); |
nJobs += 1; |
nJobs += 1; |
if (nJobs == maxJobs) { |
if (nJobs == maxJobs) { |
jobFull = TRUE; |
jobFull = true; |
if (DEBUG(JOB)) { |
if (DEBUG(JOB)) { |
(void)fprintf(stdout, "Job queue is full.\n"); |
(void)fprintf(stdout, "Job queue is full.\n"); |
(void)fflush(stdout); |
(void)fflush(stdout); |
|
|
(void)fflush(stdout); |
(void)fflush(stdout); |
} |
} |
Lst_AtFront(&stoppedJobs, job); |
Lst_AtFront(&stoppedJobs, job); |
jobFull = TRUE; |
jobFull = true; |
if (DEBUG(JOB)) { |
if (DEBUG(JOB)) { |
(void)fprintf(stdout, "Job queue is full.\n"); |
(void)fprintf(stdout, "Job queue is full.\n"); |
(void)fflush(stdout); |
(void)fflush(stdout); |
|
|
* job must be run locally and maxLocal is 0), it's also ok to |
* job must be run locally and maxLocal is 0), it's also ok to |
* resume it. |
* resume it. |
*/ |
*/ |
Boolean error; |
bool error; |
int status; |
int status; |
|
|
#ifdef RMT_WANTS_SIGNALS |
#ifdef RMT_WANTS_SIGNALS |
|
|
(void)fflush(stdout); |
(void)fflush(stdout); |
} |
} |
Lst_AtFront(&stoppedJobs, job); |
Lst_AtFront(&stoppedJobs, job); |
jobFull = TRUE; |
jobFull = true; |
if (DEBUG(JOB)) { |
if (DEBUG(JOB)) { |
(void)fprintf(stdout, "Job queue is full.\n"); |
(void)fprintf(stdout, "Job queue is full.\n"); |
(void)fflush(stdout); |
(void)fflush(stdout); |
|
|
{ |
{ |
Job *job; /* new job descriptor */ |
Job *job; /* new job descriptor */ |
char *argv[4]; /* Argument vector to shell */ |
char *argv[4]; /* Argument vector to shell */ |
Boolean cmdsOK; /* true if the nodes commands were all right */ |
bool cmdsOK; /* true if the nodes commands were all right */ |
Boolean local; /* Set true if the job was run locally */ |
bool local; /* Set true if the job was run locally */ |
Boolean noExec; /* Set true if we decide not to run the job */ |
bool noExec; /* Set true if we decide not to run the job */ |
|
|
if (previous != NULL) { |
if (previous != NULL) { |
previous->flags &= ~(JOB_FIRST|JOB_IGNERR|JOB_SILENT|JOB_REMOTE); |
previous->flags &= ~(JOB_FIRST|JOB_IGNERR|JOB_SILENT|JOB_REMOTE); |
|
|
if (!compatMake && job->flags & JOB_FIRST) { |
if (!compatMake && job->flags & JOB_FIRST) { |
cmdsOK = Job_CheckCommands(gn, Error); |
cmdsOK = Job_CheckCommands(gn, Error); |
} else { |
} else { |
cmdsOK = TRUE; |
cmdsOK = true; |
} |
} |
|
|
/* |
/* |
|
|
* Send the commands to the command file, flush all its buffers then |
* Send the commands to the command file, flush all its buffers then |
* rewind and remove the thing. |
* rewind and remove the thing. |
*/ |
*/ |
noExec = FALSE; |
noExec = false; |
|
|
/* |
/* |
* used to be backwards; replace when start doing multiple commands |
* used to be backwards; replace when start doing multiple commands |
|
|
|
|
if (gn->current == NULL || |
if (gn->current == NULL || |
!JobPrintCommand(Lst_Datum(gn->current), job)) { |
!JobPrintCommand(Lst_Datum(gn->current), job)) { |
noExec = TRUE; |
noExec = true; |
gn->current = NULL; |
gn->current = NULL; |
} |
} |
if (noExec && !(job->flags & JOB_FIRST)) { |
if (noExec && !(job->flags & JOB_FIRST)) { |
|
|
* there's not much point in executing the shell, is there? |
* there's not much point in executing the shell, is there? |
*/ |
*/ |
if (numCommands == 0) { |
if (numCommands == 0) { |
noExec = TRUE; |
noExec = true; |
} |
} |
} |
} |
} else if (noExecute) { |
} else if (noExecute) { |
|
|
/* |
/* |
* Don't execute the shell, thank you. |
* Don't execute the shell, thank you. |
*/ |
*/ |
noExec = TRUE; |
noExec = true; |
} else { |
} else { |
/* |
/* |
* Just touch the target and note that no shell should be executed. |
* Just touch the target and note that no shell should be executed. |
|
|
*/ |
*/ |
job->cmdFILE = stdout; |
job->cmdFILE = stdout; |
Job_Touch(gn, job->flags&JOB_SILENT); |
Job_Touch(gn, job->flags&JOB_SILENT); |
noExec = TRUE; |
noExec = true; |
} |
} |
|
|
/* |
/* |
|
|
} |
} |
} else |
} else |
#endif |
#endif |
local = TRUE; |
local = true; |
|
|
if (local && nLocal >= maxLocal && |
if (local && nLocal >= maxLocal && |
!(job->flags & JOB_SPECIAL) && |
!(job->flags & JOB_SPECIAL) && |
|
|
* all possible. In addition, any target marked with .NOEXPORT will |
* all possible. In addition, any target marked with .NOEXPORT will |
* be run locally if maxLocal is 0. |
* be run locally if maxLocal is 0. |
*/ |
*/ |
jobFull = TRUE; |
jobFull = true; |
|
|
if (DEBUG(JOB)) { |
if (DEBUG(JOB)) { |
(void)fprintf(stdout, "Can only run job locally.\n"); |
(void)fprintf(stdout, "Can only run job locally.\n"); |
|
|
* If we're running this job locally as a special case (see above), |
* If we're running this job locally as a special case (see above), |
* at least say the table is full. |
* at least say the table is full. |
*/ |
*/ |
jobFull = TRUE; |
jobFull = true; |
if (DEBUG(JOB)) { |
if (DEBUG(JOB)) { |
(void)fprintf(stdout, "Local job queue is full.\n"); |
(void)fprintf(stdout, "Local job queue is full.\n"); |
(void)fflush(stdout); |
(void)fflush(stdout); |
|
|
STATIC void |
STATIC void |
JobDoOutput(job, finish) |
JobDoOutput(job, finish) |
Job *job; /* the job whose output needs printing */ |
Job *job; /* the job whose output needs printing */ |
Boolean finish; /* TRUE if this is the last time we'll be |
bool finish; /* true if this is the last time we'll be |
* called for this job */ |
* called for this job */ |
{ |
{ |
Boolean gotNL = FALSE; /* true if got a newline */ |
bool gotNL = false; /* true if got a newline */ |
Boolean fbuf; /* true if our buffer filled up */ |
bool fbuf; /* true if our buffer filled up */ |
int nr; /* number of bytes read */ |
int nr; /* number of bytes read */ |
int i; /* auxiliary index into outBuf */ |
int i; /* auxiliary index into outBuf */ |
int max; /* limit for i (end of current data) */ |
int max; /* limit for i (end of current data) */ |
|
|
* Read as many bytes as will fit in the buffer. |
* Read as many bytes as will fit in the buffer. |
*/ |
*/ |
end_loop: |
end_loop: |
gotNL = FALSE; |
gotNL = false; |
fbuf = FALSE; |
fbuf = false; |
|
|
nRead = read(job->inPipe, &job->outBuf[job->curPos], |
nRead = read(job->inPipe, &job->outBuf[job->curPos], |
JOB_BUFSIZE - job->curPos); |
JOB_BUFSIZE - job->curPos); |
|
|
if (nr == 0 && job->curPos != 0) { |
if (nr == 0 && job->curPos != 0) { |
job->outBuf[job->curPos] = '\n'; |
job->outBuf[job->curPos] = '\n'; |
nr = 1; |
nr = 1; |
finish = FALSE; |
finish = false; |
} else if (nr == 0) { |
} else if (nr == 0) { |
finish = FALSE; |
finish = false; |
} |
} |
|
|
/* |
/* |
* Look for the last newline in the bytes we just got. If there is |
* Look for the last newline in the bytes we just got. If there is |
* one, break out of the loop with 'i' as its index and gotNL set |
* one, break out of the loop with 'i' as its index and gotNL set |
* TRUE. |
* true. |
*/ |
*/ |
max = job->curPos + nr; |
max = job->curPos + nr; |
for (i = job->curPos + nr - 1; i >= job->curPos; i--) { |
for (i = job->curPos + nr - 1; i >= job->curPos; i--) { |
if (job->outBuf[i] == '\n') { |
if (job->outBuf[i] == '\n') { |
gotNL = TRUE; |
gotNL = true; |
break; |
break; |
} else if (job->outBuf[i] == '\0') { |
} else if (job->outBuf[i] == '\0') { |
/* |
/* |
|
|
* If we've run out of buffer space, we have no choice |
* If we've run out of buffer space, we have no choice |
* but to print the stuff. sigh. |
* but to print the stuff. sigh. |
*/ |
*/ |
fbuf = TRUE; |
fbuf = true; |
i = job->curPos; |
i = job->curPos; |
} |
} |
} |
} |
|
|
if (i >= job->curPos) { |
if (i >= job->curPos) { |
char *cp; |
char *cp; |
|
|
cp = JobOutput(job, job->outBuf, &job->outBuf[i], FALSE); |
cp = JobOutput(job, job->outBuf, &job->outBuf[i], false); |
|
|
/* |
/* |
* There's still more in that thar buffer. This time, though, |
* There's still more in that thar buffer. This time, though, |
|
|
* end-of-file on the pipe. This is guaranteed to happen |
* end-of-file on the pipe. This is guaranteed to happen |
* eventually since the other end of the pipe is now closed |
* eventually since the other end of the pipe is now closed |
* (we closed it explicitly and the child has exited). When |
* (we closed it explicitly and the child has exited). When |
* we do get an EOF, finish will be set FALSE and we'll fall |
* we do get an EOF, finish will be set false and we'll fall |
* through and out. |
* through and out. |
*/ |
*/ |
goto end_loop; |
goto end_loop; |
|
|
if (endp[-1] == '\n') { |
if (endp[-1] == '\n') { |
*--endp = '\0'; |
*--endp = '\0'; |
} |
} |
cp = JobOutput(job, inLine, endp, FALSE); |
cp = JobOutput(job, inLine, endp, false); |
|
|
/* |
/* |
* There's still more in that thar buffer. This time, though, |
* There's still more in that thar buffer. This time, though, |
|
|
*/ |
*/ |
void |
void |
Job_CatchChildren(block) |
Job_CatchChildren(block) |
Boolean block; /* TRUE if should block on the wait. */ |
bool block; /* true if should block on the wait. */ |
{ |
{ |
int pid; /* pid of dead child */ |
int pid; /* pid of dead child */ |
Job *job; /* job descriptor for dead child */ |
Job *job; /* job descriptor for dead child */ |
|
|
(void)fprintf(stdout, "Job queue is no longer full.\n"); |
(void)fprintf(stdout, "Job queue is no longer full.\n"); |
(void)fflush(stdout); |
(void)fflush(stdout); |
} |
} |
jobFull = FALSE; |
jobFull = false; |
#ifdef REMOTE |
#ifdef REMOTE |
if (!(job->flags & JOB_REMOTE)) { |
if (!(job->flags & JOB_REMOTE)) { |
if (DEBUG(JOB)) { |
if (DEBUG(JOB)) { |
|
|
for (ln = Lst_First(&jobs); nfds && ln != NULL; ln = Lst_Adv(ln)) { |
for (ln = Lst_First(&jobs); nfds && ln != NULL; ln = Lst_Adv(ln)) { |
job = (Job *)Lst_Datum(ln); |
job = (Job *)Lst_Datum(ln); |
if (FD_ISSET(job->inPipe, readfdsp)) { |
if (FD_ISSET(job->inPipe, readfdsp)) { |
JobDoOutput(job, FALSE); |
JobDoOutput(job, false); |
nfds -= 1; |
nfds -= 1; |
} |
} |
} |
} |
|
|
maxLocal = maxlocal; |
maxLocal = maxlocal; |
nJobs = 0; |
nJobs = 0; |
nLocal = 0; |
nLocal = 0; |
jobFull = FALSE; |
jobFull = false; |
|
|
aborting = 0; |
aborting = 0; |
errors = 0; |
errors = 0; |
|
|
* All default shells are located in _PATH_DEFSHELLDIR. |
* All default shells are located in _PATH_DEFSHELLDIR. |
*/ |
*/ |
shellName = commandShell->name; |
shellName = commandShell->name; |
shellPath = str_concat(_PATH_DEFSHELLDIR, shellName, '/'); |
shellPath = Str_concat(_PATH_DEFSHELLDIR, shellName, '/'); |
} |
} |
|
|
if (commandShell->exit == NULL) { |
if (commandShell->exit == NULL) { |
|
|
} |
} |
#endif |
#endif |
|
|
begin = Targ_FindNode(".BEGIN", NULL, TARG_NOCREATE); |
begin = Targ_FindNode(".BEGIN", TARG_NOCREATE); |
|
|
if (begin != NULL) { |
if (begin != NULL) { |
JobStart(begin, JOB_SPECIAL, (Job *)0); |
JobStart(begin, JOB_SPECIAL, (Job *)0); |
|
|
#endif /* RMT_WILL_WATCH */ |
#endif /* RMT_WILL_WATCH */ |
} |
} |
} |
} |
postCommands = Targ_FindNode(".END", NULL, TARG_CREATE); |
postCommands = Targ_FindNode(".END", TARG_CREATE); |
} |
} |
|
|
/*- |
/*- |
|
|
* from starting up. |
* from starting up. |
* |
* |
* Results: |
* Results: |
* TRUE if the job table is full, FALSE otherwise |
* true if the job table is full, false otherwise |
*----------------------------------------------------------------------- |
*----------------------------------------------------------------------- |
*/ |
*/ |
Boolean |
bool |
Job_Full() |
Job_Full() |
{ |
{ |
return aborting || jobFull; |
return aborting || jobFull; |
|
|
* we want to restart as many jobs as we can. |
* we want to restart as many jobs as we can. |
* |
* |
* Results: |
* Results: |
* TRUE if it is. FALSE if it ain't. |
* true if it is. false if it ain't. |
* ----------------------------------------------------------------------- |
* ----------------------------------------------------------------------- |
*/ |
*/ |
Boolean |
bool |
Job_Empty() |
Job_Empty() |
{ |
{ |
if (nJobs == 0) { |
if (nJobs == 0) { |
|
|
* The job table is obviously not full if it has no jobs in |
* The job table is obviously not full if it has no jobs in |
* it...Try and restart the stopped jobs. |
* it...Try and restart the stopped jobs. |
*/ |
*/ |
jobFull = FALSE; |
jobFull = false; |
JobRestartJobs(); |
JobRestartJobs(); |
return FALSE; |
return false; |
} else { |
} else { |
return TRUE; |
return true; |
} |
} |
} else { |
} else { |
return FALSE; |
return false; |
} |
} |
} |
} |
|
|
|
|
* and shellName appropriately. |
* and shellName appropriately. |
* |
* |
* Results: |
* Results: |
* FAILURE if the specification was incorrect. |
* false if the specification was incorrect. |
* |
* |
* Side Effects: |
* Side Effects: |
* commandShell points to a Shell structure (either predefined or |
* commandShell points to a Shell structure (either predefined or |
|
|
* errFlag Flag to turn error checking on at the start |
* errFlag Flag to turn error checking on at the start |
* hasErrCtl True if shell has error checking control |
* hasErrCtl True if shell has error checking control |
* check Command to turn on error checking if hasErrCtl |
* check Command to turn on error checking if hasErrCtl |
* is TRUE or template of command to echo a command |
* is true or template of command to echo a command |
* for which error checking is off if hasErrCtl is |
* for which error checking is off if hasErrCtl is |
* FALSE. |
* false. |
* ignore Command to turn off error checking if hasErrCtl |
* ignore Command to turn off error checking if hasErrCtl |
* is TRUE or template of command to execute a |
* is true or template of command to execute a |
* command so as to ignore any errors it returns if |
* command so as to ignore any errors it returns if |
* hasErrCtl is FALSE. |
* hasErrCtl is false. |
*----------------------------------------------------------------------- |
*----------------------------------------------------------------------- |
*/ |
*/ |
ReturnStatus |
bool |
Job_ParseShell(line) |
Job_ParseShell(line) |
char *line; /* The shell spec */ |
char *line; /* The shell spec */ |
{ |
{ |
|
|
int argc; |
int argc; |
char *path; |
char *path; |
Shell newShell; |
Shell newShell; |
Boolean fullSpec = FALSE; |
bool fullSpec = false; |
|
|
while (isspace(*line)) { |
while (isspace(*line)) { |
line++; |
line++; |
|
|
Parse_Error(PARSE_FATAL, "Unknown keyword \"%s\"", |
Parse_Error(PARSE_FATAL, "Unknown keyword \"%s\"", |
*argv); |
*argv); |
free(words); |
free(words); |
return FAILURE; |
return false; |
} |
} |
fullSpec = TRUE; |
fullSpec = true; |
} |
} |
} |
} |
|
|
|
|
*/ |
*/ |
if (newShell.name == NULL) { |
if (newShell.name == NULL) { |
Parse_Error(PARSE_FATAL, "Neither path nor name specified"); |
Parse_Error(PARSE_FATAL, "Neither path nor name specified"); |
return FAILURE; |
return false; |
} else { |
} else { |
commandShell = JobMatchShell(newShell.name); |
commandShell = JobMatchShell(newShell.name); |
shellName = newShell.name; |
shellName = newShell.name; |
|
|
} else { |
} else { |
/* |
/* |
* The user provided a path. If s/he gave nothing else (fullSpec is |
* The user provided a path. If s/he gave nothing else (fullSpec is |
* FALSE), try and find a matching shell in the ones we know of. |
* false), try and find a matching shell in the ones we know of. |
* Else we just take the specification at its word and copy it |
* Else we just take the specification at its word and copy it |
* to a new location. In either case, we need to record the |
* to a new location. In either case, we need to record the |
* path the user gave for the shell. |
* path the user gave for the shell. |
|
|
} |
} |
|
|
if (commandShell->echoOn && commandShell->echoOff) { |
if (commandShell->echoOn && commandShell->echoOff) { |
commandShell->hasEchoCtl = TRUE; |
commandShell->hasEchoCtl = true; |
} |
} |
|
|
if (!commandShell->hasErrCtl) { |
if (!commandShell->hasErrCtl) { |
|
|
* shell specification... |
* shell specification... |
*/ |
*/ |
free(words); |
free(words); |
return SUCCESS; |
return true; |
} |
} |
|
|
/*- |
/*- |
|
|
#endif |
#endif |
|
|
if (runINTERRUPT && !touchFlag) { |
if (runINTERRUPT && !touchFlag) { |
interrupt = Targ_FindNode(".INTERRUPT", NULL, TARG_NOCREATE); |
interrupt = Targ_FindNode(".INTERRUPT", TARG_NOCREATE); |
if (interrupt != NULL) { |
if (interrupt != NULL) { |
ignoreErrors = FALSE; |
ignoreErrors = false; |
|
|
JobStart(interrupt, JOB_IGNDOTS, (Job *)0); |
JobStart(interrupt, JOB_IGNDOTS, (Job *)0); |
while (nJobs) { |
while (nJobs) { |
|
|
* Memory is freed |
* Memory is freed |
*----------------------------------------------------------------------- |
*----------------------------------------------------------------------- |
*/ |
*/ |
|
#ifdef CLEANUP |
void |
void |
Job_End() |
Job_End() |
{ |
{ |
#ifdef CLEANUP |
|
efree(shellArgv); |
efree(shellArgv); |
#endif |
|
} |
} |
|
#endif |
|
|
/*- |
/*- |
*----------------------------------------------------------------------- |
*----------------------------------------------------------------------- |