version 1.39, 2000/12/27 19:07:58 |
version 1.40, 2001/05/03 13:41:06 |
|
|
|
/* $OpenPackages$ */ |
/* $OpenBSD$ */ |
/* $OpenBSD$ */ |
/* $NetBSD: job.c,v 1.16 1996/11/06 17:59:08 christos Exp $ */ |
/* $NetBSD: job.c,v 1.16 1996/11/06 17:59:08 christos Exp $ */ |
|
|
|
|
* handle the creation etc. of our child processes. |
* handle the creation etc. of our child processes. |
* |
* |
* Interface: |
* Interface: |
* Job_Make Start the creation of the given target. |
* Job_Make Start the creation of the given target. |
* |
* |
* Job_CatchChildren Check for and handle the termination of any |
* Job_CatchChildren Check for and handle the termination of any |
* children. This must be called reasonably |
* children. This must be called reasonably |
* 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. |
* Should also be called fairly frequently to |
* Should also be called fairly frequently to |
* keep the user informed of what's going on. |
* keep the user informed of what's going on. |
* If no output is waiting, it will block for |
* If no output is waiting, it will block for |
* a time given by the SEL_* constants, below, |
* a time given by the SEL_* constants, below, |
* or until output is ready. |
* or until output is ready. |
* |
* |
* Job_Init Called to intialize this module. in addition, |
* Job_Init Called to intialize this module. in addition, |
* any commands attached to the .BEGIN target |
* any commands attached to the .BEGIN target |
* are executed before this function returns. |
* are executed before this function returns. |
* Hence, the makefile must have been parsed |
* Hence, the makefile must have been parsed |
* before this function is called. |
* before this function is called. |
* |
* |
* 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. |
* FAILURE 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 |
* which have been/were attached to the .END |
* which have been/were attached to the .END |
* target. It should only be called when the |
* target. It should only be called when the |
* job table is empty. |
* job table is empty. |
* |
* |
* Job_AbortAll Abort all currently running jobs. It doesn't |
* Job_AbortAll Abort all currently running jobs. It doesn't |
* handle output or do anything for the jobs, |
* handle output or do anything for the jobs, |
* just kills them. It should only be called in |
* just kills them. It should only be called in |
* an emergency, as it were. |
* an emergency, as it were. |
* |
* |
* Job_CheckCommands Verify that the commands for a target are |
* Job_CheckCommands Verify that the commands for a target are |
* ok. Provide them if necessary and possible. |
* ok. Provide them if necessary and possible. |
* |
* |
* Job_Touch Update a target without really updating it. |
* Job_Touch Update a target without really updating it. |
* |
* |
* Job_Wait Wait for all currently-running jobs to finish. |
* Job_Wait Wait for all currently-running jobs to finish. |
*/ |
*/ |
|
|
#include <sys/types.h> |
#include <sys/types.h> |
|
|
#endif |
#endif |
#endif /* not lint */ |
#endif /* not lint */ |
|
|
|
|
/* |
/* |
* error handling variables |
* error handling variables |
*/ |
*/ |
static int errors = 0; /* number of errors reported */ |
static int errors = 0; /* number of errors reported */ |
static int aborting = 0; /* why is the make aborting? */ |
static int aborting = 0; /* why is the make aborting? */ |
#define ABORT_ERROR 1 /* Because of an error */ |
#define ABORT_ERROR 1 /* Because of an error */ |
#define ABORT_INTERRUPT 2 /* Because it was interrupted */ |
#define ABORT_INTERRUPT 2 /* Because it was interrupted */ |
#define ABORT_WAIT 3 /* Waiting for jobs to finish */ |
#define ABORT_WAIT 3 /* Waiting for jobs to finish */ |
|
|
/* |
/* |
* XXX: Avoid SunOS bug... FILENO() is fp->_file, and file |
* XXX: Avoid SunOS bug... FILENO() is fp->_file, and file |
|
|
* .END target but we keep it around to avoid having to search for it |
* .END target but we keep it around to avoid having to search for it |
* all the time. |
* all the time. |
*/ |
*/ |
static GNode *postCommands; /* node containing commands to execute when |
static GNode *postCommands; /* node containing commands to execute when |
* everything else is done */ |
* everything else is done */ |
static int numCommands; /* The number of commands actually printed |
static int numCommands; /* The number of commands actually printed |
* for a target. Should this number be |
* for a target. Should this number be |
* 0, no shell will be executed. */ |
* 0, no shell will be executed. */ |
|
|
/* |
/* |
* Return values from JobStart. |
* Return values from JobStart. |
*/ |
*/ |
#define JOB_RUNNING 0 /* Job is running */ |
#define JOB_RUNNING 0 /* Job is running */ |
#define JOB_ERROR 1 /* Error in starting the job */ |
#define JOB_ERROR 1 /* Error in starting the job */ |
#define JOB_FINISHED 2 /* The job is already finished */ |
#define JOB_FINISHED 2 /* The job is already finished */ |
#define JOB_STOPPED 3 /* The job is stopped */ |
#define JOB_STOPPED 3 /* The job is stopped */ |
|
|
/* |
/* |
* tfile is used to build temp file names to store shell commands to |
* tfile is the name of a file into which all shell commands are put. It is |
* execute. |
* used over by removing it before the child shell is executed. The XXXXXXXXXX |
|
* in the string are replaced by mkstemp(3). |
*/ |
*/ |
static char tfile[sizeof(TMPPAT)]; |
static char tfile[sizeof(TMPPAT)]; |
|
|
|
|
/* |
/* |
* Descriptions for various shells. |
* Descriptions for various shells. |
*/ |
*/ |
static Shell shells[] = { |
static Shell shells[] = { |
/* |
/* |
* CSH description. The csh can do echo control by playing |
* CSH description. The csh can do echo control by playing |
* with the setting of the 'echo' shell variable. Sadly, |
* with the setting of the 'echo' shell variable. Sadly, |
|
|
* UNKNOWN. |
* UNKNOWN. |
*/ |
*/ |
{ |
{ |
(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 Shell *commandShell = &shells[DEFSHELL];/* this is the shell to |
static Shell *commandShell = &shells[DEFSHELL];/* this is the shell to |
* which we pass all |
* which we pass all |
* commands in the Makefile. |
* commands in the Makefile. |
* It is set by the |
* It is set by the |
* Job_ParseShell function */ |
* Job_ParseShell function */ |
static char *shellPath = NULL, /* full pathname of |
static char *shellPath = NULL, /* full pathname of |
* executable image */ |
* executable image */ |
*shellName = NULL, /* last component of shell */ |
*shellName = NULL, /* last component of shell */ |
*shellArgv = NULL; /* Custom shell args */ |
*shellArgv = NULL; /* Custom shell args */ |
|
|
|
|
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; /* 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 Boolean 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 */ |
#ifndef RMT_WILL_WATCH |
#ifndef RMT_WILL_WATCH |
static fd_set *outputsp; /* Set of descriptors of pipes connected to |
static fd_set *outputsp; /* Set of descriptors of pipes connected to |
* the output channels of children */ |
* the output channels of children */ |
static int outputsn; |
static int outputsn; |
#endif |
#endif |
|
|
STATIC GNode *lastNode; /* The node for which output was most recently |
STATIC GNode *lastNode; /* The node for which output was most recently |
* produced. */ |
* produced. */ |
STATIC 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 |
* job when it's not the most-recent job heard |
* from */ |
* from */ |
|
|
#ifdef REMOTE |
#ifdef REMOTE |
# define TARG_FMT "--- %s at %s ---\n" /* Default format */ |
# define TARG_FMT "--- %s at %s ---\n" /* Default format */ |
# define MESSAGE(fp, gn) \ |
# define MESSAGE(fp, gn) \ |
(void) fprintf(fp, targFmt, gn->name, gn->rem.hname); |
(void)fprintf(fp, targFmt, gn->name, gn->rem.hname); |
#else |
#else |
# define TARG_FMT "--- %s ---\n" /* Default format */ |
# define TARG_FMT "--- %s ---\n" /* Default format */ |
# define MESSAGE(fp, gn) \ |
# define MESSAGE(fp, gn) \ |
(void) fprintf(fp, targFmt, gn->name); |
(void)fprintf(fp, targFmt, gn->name); |
#endif |
#endif |
|
|
/* |
/* |
|
|
|
|
|
|
#if defined(USE_PGRP) && defined(SYSV) |
#if defined(USE_PGRP) && defined(SYSV) |
# define KILL(pid, sig) killpg(-(pid), (sig)) |
# define KILL(pid, sig) killpg(-(pid), (sig)) |
#else |
#else |
# if defined(USE_PGRP) |
# if defined(USE_PGRP) |
# define KILL(pid, sig) killpg((pid), (sig)) |
# define KILL(pid, sig) killpg((pid), (sig)) |
|
|
#define W_SETEXITSTATUS(st, val) W_SETMASKED(st, val, WEXITSTATUS) |
#define W_SETEXITSTATUS(st, val) W_SETMASKED(st, val, WEXITSTATUS) |
|
|
|
|
static void JobCondPassSig __P((void *, void *)); |
static void JobCondPassSig(void *, void *); |
static void JobPassSig __P((int)); |
static void JobPassSig(int); |
static int JobCmpPid __P((void *, void *)); |
static int JobCmpPid(void *, void *); |
static int JobPrintCommand __P((void *, void *)); |
static int JobPrintCommand(void *, void *); |
static void JobSaveCommand __P((void *, void *)); |
static void JobSaveCommand(void *, void *); |
static void JobClose __P((Job *)); |
static void JobClose(Job *); |
#ifdef REMOTE |
#ifdef REMOTE |
static int JobCmpRmtID __P((Job *, void *)); |
static int JobCmpRmtID(Job *, int); |
# ifdef RMT_WILL_WATCH |
# ifdef RMT_WILL_WATCH |
static void JobLocalInput __P((int, Job *)); |
static void JobLocalInput(int, Job *); |
# endif |
# endif |
#else |
#else |
static void JobFinish __P((Job *, int *)); |
static void JobFinish(Job *, int *); |
static void JobExec __P((Job *, char **)); |
static void JobExec(Job *, char **); |
#endif |
#endif |
static void JobMakeArgv __P((Job *, char **)); |
static void JobMakeArgv(Job *, char **); |
static void JobRestart __P((Job *)); |
static void JobRestart(Job *); |
static int JobStart __P((GNode *, int, Job *)); |
static int JobStart(GNode *, int, Job *); |
static char *JobOutput __P((Job *, char *, char *, int)); |
static char *JobOutput(Job *, char *, char *, int); |
static void JobDoOutput __P((Job *, Boolean)); |
static void JobDoOutput(Job *, Boolean); |
static Shell *JobMatchShell __P((char *)); |
static Shell *JobMatchShell(char *); |
static void JobInterrupt __P((int, int)); |
static void JobInterrupt(int, int); |
static void JobRestartJobs __P((void)); |
static void JobRestartJobs(void); |
|
|
/*- |
/*- |
*----------------------------------------------------------------------- |
*----------------------------------------------------------------------- |
|
|
* |
* |
* Side Effects: |
* Side Effects: |
* None, except the job may bite it. |
* None, except the job may bite it. |
* |
|
*----------------------------------------------------------------------- |
*----------------------------------------------------------------------- |
*/ |
*/ |
static void |
static void |
JobCondPassSig(jobp, signop) |
JobCondPassSig(jobp, signop) |
void *jobp; /* Job to biff */ |
void *jobp; /* Job to biff */ |
void *signop; /* Signal to send it */ |
void *signop; /* Signal to send it */ |
{ |
{ |
Job *job = (Job *) jobp; |
Job *job = (Job *)jobp; |
int signo = *(int *) signop; |
int signo = *(int *)signop; |
#ifdef RMT_WANTS_SIGNALS |
#ifdef RMT_WANTS_SIGNALS |
if (job->flags & JOB_REMOTE) { |
if (job->flags & JOB_REMOTE) { |
(void) Rmt_Signal(job, signo); |
(void)Rmt_Signal(job, signo); |
} else { |
} else { |
KILL(job->pid, signo); |
KILL(job->pid, signo); |
} |
} |
|
|
* job as well. |
* job as well. |
*/ |
*/ |
if (DEBUG(JOB)) { |
if (DEBUG(JOB)) { |
(void) fprintf(stdout, |
(void)fprintf(stdout, |
"JobCondPassSig passing signal %d to child %d.\n", |
"JobCondPassSig passing signal %d to child %d.\n", |
signo, job->pid); |
signo, job->pid); |
(void) fflush(stdout); |
(void)fflush(stdout); |
} |
} |
KILL(job->pid, signo); |
KILL(job->pid, signo); |
#endif |
#endif |
|
|
* Pass a signal on to all remote jobs and to all local jobs if |
* Pass a signal on to all remote jobs and to all local jobs if |
* USE_PGRP is defined, then die ourselves. |
* USE_PGRP is defined, then die ourselves. |
* |
* |
* Results: |
|
* None. |
|
* |
|
* Side Effects: |
* Side Effects: |
* We die by the same signal. |
* We die by the same signal. |
* |
|
*----------------------------------------------------------------------- |
*----------------------------------------------------------------------- |
*/ |
*/ |
static void |
static void |
JobPassSig(signo) |
JobPassSig(signo) |
int signo; /* The signal number we've received */ |
int signo; /* The signal number we've received */ |
{ |
{ |
sigset_t nmask, omask; |
sigset_t nmask, omask; |
struct sigaction act; |
struct sigaction act; |
|
|
if (DEBUG(JOB)) { |
if (DEBUG(JOB)) { |
(void) fprintf(stdout, "JobPassSig(%d) called.\n", signo); |
(void)fprintf(stdout, "JobPassSig(%d) called.\n", signo); |
(void) fflush(stdout); |
(void)fflush(stdout); |
} |
} |
Lst_ForEach(&jobs, JobCondPassSig, &signo); |
Lst_ForEach(&jobs, JobCondPassSig, &signo); |
|
|
|
|
*/ |
*/ |
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); |
} |
} |
|
|
|
|
sigaction(signo, &act, NULL); |
sigaction(signo, &act, NULL); |
|
|
if (DEBUG(JOB)) { |
if (DEBUG(JOB)) { |
(void) fprintf(stdout, |
(void)fprintf(stdout, |
"JobPassSig passing signal to self, mask = %x.\n", |
"JobPassSig passing signal to self, mask = %x.\n", |
~0 & ~(1 << (signo-1))); |
~0 & ~(1 << (signo-1))); |
(void) fflush(stdout); |
(void)fflush(stdout); |
} |
} |
(void) signal(signo, SIG_DFL); |
(void)signal(signo, SIG_DFL); |
|
|
(void) KILL(getpid(), signo); |
(void)KILL(getpid(), signo); |
|
|
signo = SIGCONT; |
signo = SIGCONT; |
Lst_ForEach(&jobs, JobCondPassSig, &signo); |
Lst_ForEach(&jobs, JobCondPassSig, &signo); |
|
|
(void) sigprocmask(SIG_SETMASK, &omask, NULL); |
(void)sigprocmask(SIG_SETMASK, &omask, NULL); |
sigprocmask(SIG_SETMASK, &omask, NULL); |
sigprocmask(SIG_SETMASK, &omask, NULL); |
act.sa_handler = JobPassSig; |
act.sa_handler = JobPassSig; |
sigaction(signo, &act, NULL); |
sigaction(signo, &act, NULL); |
|
|
* |
* |
* Results: |
* Results: |
* 0 if the pid's match |
* 0 if the pid's match |
* |
|
* Side Effects: |
|
* None |
|
*----------------------------------------------------------------------- |
*----------------------------------------------------------------------- |
*/ |
*/ |
static int |
static int |
|
|
#ifdef REMOTE |
#ifdef REMOTE |
/*- |
/*- |
*----------------------------------------------------------------------- |
*----------------------------------------------------------------------- |
* JobCmpRmtID -- |
* JobCmpRmtID -- |
* Compare the rmtID of the job with the given rmtID and return 0 if they |
* Compare the rmtID of the job with the given rmtID and return 0 if they |
* are equal. |
* are equal. |
* |
* |
* Results: |
* Results: |
* 0 if the rmtID's match |
* 0 if the rmtID's match |
* |
|
* Side Effects: |
|
* None. |
|
*----------------------------------------------------------------------- |
*----------------------------------------------------------------------- |
*/ |
*/ |
static int |
static int |
JobCmpRmtID(job, rmtID) |
JobCmpRmtID(job, rmtID) |
void *job; /* job to examine */ |
void *job; /* job to examine */ |
void *rmtID; /* remote id desired */ |
void *rmtID; /* remote id desired */ |
{ |
{ |
return *(int *) rmtID - *(int *) job->rmtID; |
return *(int *)rmtID - *(int *)job->rmtID; |
} |
} |
#endif |
#endif |
|
|
|
|
* made and return non-zero to signal that the end of the commands |
* made and return non-zero to signal that the end of the commands |
* was reached. These commands are later attached to the postCommands |
* was reached. These commands are later attached to the postCommands |
* node and executed by Job_End when all things are done. |
* node and executed by Job_End when all things are done. |
* This function is called from JobStart via Lst_ForEach. |
* This function is called from JobStart via Lst_Find |
* |
* |
* Results: |
* Results: |
* Always 1, unless the command was "..." |
* Always 1, unless the command was "..." |
|
|
*/ |
*/ |
static int |
static int |
JobPrintCommand(cmdp, jobp) |
JobPrintCommand(cmdp, jobp) |
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 |
Boolean 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 |
Boolean 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 |
Boolean 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 |
* command */ |
* command */ |
char *cmdStart; /* Start of expanded command */ |
char *cmdStart; /* Start of expanded command */ |
LstNode cmdNode; /* Node for replacing the command */ |
LstNode cmdNode; /* Node for replacing the command */ |
char *cmd = (char *) cmdp; |
char *cmd = (char *)cmdp; |
Job *job = (Job *) jobp; |
Job *job = (Job *)jobp; |
|
|
noSpecials = (noExecute && !(job->node->type & OP_MAKE)); |
noSpecials = (noExecute && !(job->node->type & OP_MAKE)); |
|
|
|
|
} |
} |
|
|
#define DBPRINTF(fmt, arg) if (DEBUG(JOB)) { \ |
#define DBPRINTF(fmt, arg) if (DEBUG(JOB)) { \ |
(void) fprintf(stdout, fmt, arg); \ |
(void)fprintf(stdout, fmt, arg); \ |
(void) fflush(stdout); \ |
(void)fflush(stdout); \ |
} \ |
} \ |
(void) fprintf(job->cmdFILE, fmt, arg); \ |
(void)fprintf(job->cmdFILE, fmt, arg); \ |
(void) fflush(job->cmdFILE); |
(void)fflush(job->cmdFILE); |
|
|
numCommands += 1; |
numCommands += 1; |
|
|
/* |
/* 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); |
|
|
* Check for leading @' and -'s to control echoing and error checking. |
* Check for leading @' and -'s to control echoing and error checking. |
*/ |
*/ |
for (;; cmd++) { |
for (;; cmd++) { |
if (*cmd == '@') |
if (*cmd == '@') |
shutUp = TRUE; |
shutUp = DEBUG(LOUD) ? FALSE : TRUE; |
else if (*cmd == '-') |
else if (*cmd == '-') |
errOff = TRUE; |
errOff = TRUE; |
else if (*cmd != '+') |
else if (*cmd != '+') |
break; |
break; |
} |
} |
|
|
while (isspace((unsigned char) *cmd)) |
while (isspace(*cmd)) |
cmd++; |
cmd++; |
|
|
if (shutUp) { |
if (shutUp) { |
|
|
* |
* |
* Side Effects: |
* Side Effects: |
* The command is tacked onto the end of postCommands's commands list. |
* The command is tacked onto the end of postCommands's commands list. |
* |
|
*----------------------------------------------------------------------- |
*----------------------------------------------------------------------- |
*/ |
*/ |
static void |
static void |
JobSaveCommand(cmd, gn) |
JobSaveCommand(cmd, gn) |
void *cmd; |
void *cmd; |
void *gn; |
void *gn; |
{ |
{ |
char *result; |
GNode *g = (GNode *)gn; |
|
char *result; |
|
|
result = Var_Subst((char *)cmd, &((GNode *)gn)->context, FALSE); |
result = Var_Subst((char *)cmd, &g->context, FALSE); |
Lst_AtEnd(&postCommands->commands, result); |
Lst_AtEnd(&postCommands->commands, result); |
} |
} |
|
|
|
|
* JobClose -- |
* JobClose -- |
* Called to close both input and output pipes when a job is finished. |
* Called to close both input and output pipes when a job is finished. |
* |
* |
* Results: |
|
* Nada |
|
* |
|
* Side Effects: |
* Side Effects: |
* The file descriptors associated with the job are closed. |
* The file descriptors associated with the job are closed. |
* |
|
*----------------------------------------------------------------------- |
*----------------------------------------------------------------------- |
*/ |
*/ |
static void |
static void |
|
|
FD_CLR(job->inPipe, outputsp); |
FD_CLR(job->inPipe, outputsp); |
#endif |
#endif |
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); |
} |
} |
} |
} |
|
|
* or something, jstat.w_status is 0 and when called from |
* or something, jstat.w_status is 0 and when called from |
* Job_CatchChildren, the status is zeroed if it s/b ignored. |
* Job_CatchChildren, the status is zeroed if it s/b ignored. |
* |
* |
* Results: |
|
* None |
|
* |
|
* Side Effects: |
* Side Effects: |
* Some nodes may be put on the toBeMade queue. |
* Some nodes may be put on the toBeMade queue. |
* Final commands for the job are placed on postCommands. |
* Final commands for the job are placed on postCommands. |
|
|
/*ARGSUSED*/ |
/*ARGSUSED*/ |
static void |
static void |
JobFinish(job, status) |
JobFinish(job, status) |
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; |
Boolean done; |
|
|
if ((WIFEXITED(*status) && |
if ((WIFEXITED(*status) && |
(((WEXITSTATUS(*status) != 0) && !(job->flags & JOB_IGNERR)))) || |
WEXITSTATUS(*status) != 0 && !(job->flags & JOB_IGNERR)) || |
(WIFSIGNALED(*status) && (WTERMSIG(*status) != SIGCONT))) |
(WIFSIGNALED(*status) && WTERMSIG(*status) != SIGCONT)) |
{ |
{ |
/* |
/* |
* If it exited non-zero and either we're doing things our |
* If it exited non-zero and either we're doing things our |
|
|
#endif |
#endif |
JobClose(job); |
JobClose(job); |
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 (done || |
if (done || |
WIFSTOPPED(*status) || |
WIFSTOPPED(*status) || |
(WIFSIGNALED(*status) && (WTERMSIG(*status) == SIGCONT)) || |
(WIFSIGNALED(*status) && WTERMSIG(*status) == SIGCONT) || |
DEBUG(JOB)) |
DEBUG(JOB)) |
{ |
{ |
FILE *out; |
FILE *out; |
|
|
|
|
if (WIFEXITED(*status)) { |
if (WIFEXITED(*status)) { |
if (DEBUG(JOB)) { |
if (DEBUG(JOB)) { |
(void) fprintf(stdout, "Process %d exited.\n", job->pid); |
(void)fprintf(stdout, "Process %d exited.\n", job->pid); |
(void) fflush(stdout); |
(void)fflush(stdout); |
} |
} |
if (WEXITSTATUS(*status) != 0) { |
if (WEXITSTATUS(*status) != 0) { |
if (usePipes && job->node != lastNode) { |
if (usePipes && job->node != lastNode) { |
MESSAGE(out, job->node); |
MESSAGE(out, job->node); |
lastNode = job->node; |
lastNode = job->node; |
} |
} |
(void) fprintf(out, "*** Error code %d%s\n", |
(void)fprintf(out, "*** Error code %d%s\n", |
WEXITSTATUS(*status), |
WEXITSTATUS(*status), |
(job->flags & JOB_IGNERR) ? "(ignored)" : ""); |
(job->flags & JOB_IGNERR) ? "(ignored)" : ""); |
|
|
|
|
MESSAGE(out, job->node); |
MESSAGE(out, job->node); |
lastNode = job->node; |
lastNode = job->node; |
} |
} |
(void) fprintf(out, "*** Completed successfully\n"); |
(void)fprintf(out, "*** Completed successfully\n"); |
} |
} |
} else if (WIFSTOPPED(*status)) { |
} else if (WIFSTOPPED(*status)) { |
if (DEBUG(JOB)) { |
if (DEBUG(JOB)) { |
(void) fprintf(stdout, "Process %d stopped.\n", job->pid); |
(void)fprintf(stdout, "Process %d stopped.\n", job->pid); |
(void) fflush(stdout); |
(void)fflush(stdout); |
} |
} |
if (usePipes && job->node != lastNode) { |
if (usePipes && job->node != lastNode) { |
MESSAGE(out, job->node); |
MESSAGE(out, job->node); |
lastNode = job->node; |
lastNode = job->node; |
} |
} |
if (!(job->flags & JOB_REMIGRATE)) { |
if (!(job->flags & JOB_REMIGRATE)) { |
(void) fprintf(out, "*** Stopped -- signal %d\n", |
(void)fprintf(out, "*** Stopped -- signal %d\n", |
WSTOPSIG(*status)); |
WSTOPSIG(*status)); |
} |
} |
job->flags |= JOB_RESUME; |
job->flags |= JOB_RESUME; |
|
|
if (job->flags & JOB_REMIGRATE) |
if (job->flags & JOB_REMIGRATE) |
JobRestart(job); |
JobRestart(job); |
#endif |
#endif |
(void) fflush(out); |
(void)fflush(out); |
return; |
return; |
} else if (WTERMSIG(*status) == SIGCONT) { |
} else if (WTERMSIG(*status) == SIGCONT) { |
/* |
/* |
|
|
MESSAGE(out, job->node); |
MESSAGE(out, job->node); |
lastNode = job->node; |
lastNode = job->node; |
} |
} |
(void) fprintf(out, "*** Continued\n"); |
(void)fprintf(out, "*** Continued\n"); |
} |
} |
if (!(job->flags & JOB_CONTINUING)) { |
if (!(job->flags & JOB_CONTINUING)) { |
if (DEBUG(JOB)) { |
if (DEBUG(JOB)) { |
(void) fprintf(stdout, |
(void)fprintf(stdout, |
"Warning: process %d was not continuing.\n", |
"Warning: process %d was not continuing.\n", |
job->pid); |
job->pid); |
(void) fflush(stdout); |
(void)fflush(stdout); |
} |
} |
#ifdef notdef |
#ifdef notdef |
/* |
/* |
* We don't really want to restart a job from scratch just |
* We don't really want to restart a job from scratch just |
* because it continued, especially not without killing the |
* because it continued, especially not without killing the |
* continuing process! That's why this is ifdef'ed out. |
* continuing process! That's why this is ifdef'ed out. |
* FD - 9/17/90 |
* FD - 9/17/90 |
*/ |
*/ |
JobRestart(job); |
JobRestart(job); |
#endif |
#endif |
} |
} |
job->flags &= ~JOB_CONTINUING; |
job->flags &= ~JOB_CONTINUING; |
Lst_AtEnd(&jobs, job); |
Lst_AtEnd(&jobs, job); |
nJobs += 1; |
nJobs += 1; |
if (!(job->flags & JOB_REMOTE)) { |
if (!(job->flags & JOB_REMOTE)) { |
if (DEBUG(JOB)) { |
if (DEBUG(JOB)) { |
(void) fprintf(stdout, |
(void)fprintf(stdout, |
"Process %d is continuing locally.\n", |
"Process %d is continuing locally.\n", |
job->pid); |
job->pid); |
(void) fflush(stdout); |
(void)fflush(stdout); |
} |
} |
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); |
} |
} |
} |
} |
(void) fflush(out); |
(void)fflush(out); |
return; |
return; |
} else { |
} else { |
if (usePipes && job->node != lastNode) { |
if (usePipes && job->node != lastNode) { |
MESSAGE(out, job->node); |
MESSAGE(out, job->node); |
lastNode = job->node; |
lastNode = job->node; |
} |
} |
(void) fprintf(out, "*** Signal %d\n", WTERMSIG(*status)); |
(void)fprintf(out, "*** Signal %d\n", WTERMSIG(*status)); |
} |
} |
|
|
(void) fflush(out); |
(void)fflush(out); |
} |
} |
|
|
/* |
/* |
|
|
* try and restart the job on the next command. If JobStart says it's |
* 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. |
* ok, it's ok. If there's an error, this puppy is done. |
*/ |
*/ |
if (compatMake && (WIFEXITED(*status) && |
if (compatMake && WIFEXITED(*status) && job->node->current != NULL) { |
!Lst_IsAtEnd(&job->node->commands))) { |
|
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; |
|
|
done = FALSE; |
done = FALSE; |
break; |
break; |
} |
} |
} else { |
} else |
done = TRUE; |
done = TRUE; |
} |
|
|
|
|
|
if (done && |
if (done && |
(aborting != ABORT_ERROR) && |
aborting != ABORT_ERROR && |
(aborting != ABORT_INTERRUPT) && |
aborting != ABORT_INTERRUPT && |
(*status == 0)) |
*status == 0) { |
{ |
/* As long as we aren't aborting and the job didn't return a non-zero |
/* |
|
* As long as we aren't aborting and the job didn't return a non-zero |
|
* status that we shouldn't ignore, we call Make_Update to update |
* status that we shouldn't ignore, we call Make_Update to update |
* the parents. In addition, any saved commands for the node are placed |
* the parents. In addition, any saved commands for the node are placed |
* on the .END target. |
* on the .END target. */ |
*/ |
|
Lst_ForEachFrom(job->tailCmds, JobSaveCommand, job->node); |
Lst_ForEachFrom(job->tailCmds, JobSaveCommand, job->node); |
job->node->made = MADE; |
job->node->made = MADE; |
Make_Update(job->node); |
Make_Update(job->node); |
|
|
/* |
/* |
* Set aborting if any error. |
* Set aborting if any error. |
*/ |
*/ |
if (errors && !keepgoing && (aborting != ABORT_INTERRUPT)) { |
if (errors && !keepgoing && aborting != ABORT_INTERRUPT) { |
/* |
/* |
* If we found any errors in this batch of children and the -k flag |
* If we found any errors in this batch of children and the -k flag |
* wasn't given, we set the aborting flag so no more jobs get |
* wasn't given, we set the aborting flag so no more jobs get |
|
|
aborting = ABORT_ERROR; |
aborting = ABORT_ERROR; |
} |
} |
|
|
if ((aborting == ABORT_ERROR) && Job_Empty()) |
if (aborting == ABORT_ERROR && Job_Empty()) { |
/* |
/* |
* If we are aborting and the job table is now empty, we finish. |
* If we are aborting and the job table is now empty, we finish. |
*/ |
*/ |
|
(void)eunlink(tfile); |
Finish(errors); |
Finish(errors); |
|
} |
} |
} |
|
|
/*- |
/*- |
|
|
* Touch the given target. Called by JobStart when the -t flag was |
* Touch the given target. Called by JobStart when the -t flag was |
* given |
* given |
* |
* |
* Results: |
|
* None |
|
* |
|
* Side Effects: |
* Side Effects: |
* The data modification of the file is changed. In addition, if the |
* The data modification of the file is changed. In addition, if the |
* file did not exist, it is created. |
* file did not exist, it is created. |
|
|
*/ |
*/ |
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 */ |
Boolean 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 */ |
|
|
if (gn->type & (OP_JOIN|OP_USE|OP_EXEC|OP_OPTIONAL)) { |
if (gn->type & (OP_JOIN|OP_USE|OP_EXEC|OP_OPTIONAL)) { |
/* |
/* |
|
|
} |
} |
|
|
if (!silent) { |
if (!silent) { |
(void) fprintf(stdout, "touch %s\n", gn->name); |
(void)fprintf(stdout, "touch %s\n", gn->name); |
(void) fflush(stdout); |
(void)fflush(stdout); |
} |
} |
|
|
if (noExecute) { |
if (noExecute) { |
|
|
} else if (gn->type & OP_LIB) { |
} else if (gn->type & OP_LIB) { |
Arch_TouchLib(gn); |
Arch_TouchLib(gn); |
} else { |
} else { |
char *file = gn->path ? gn->path : gn->name; |
const char *file = gn->path != NULL ? gn->path : gn->name; |
|
|
if (set_times(file) == -1) { |
if (set_times(file) == -1){ |
streamID = open(file, O_RDWR | O_CREAT, 0666); |
streamID = open(file, O_RDWR | O_CREAT, 0666); |
|
|
if (streamID >= 0) { |
if (streamID >= 0) { |
|
|
* modification time, then close the file. |
* modification time, then close the file. |
*/ |
*/ |
if (read(streamID, &c, 1) == 1) { |
if (read(streamID, &c, 1) == 1) { |
(void) lseek(streamID, 0, SEEK_SET); |
(void)lseek(streamID, 0, SEEK_SET); |
(void) write(streamID, &c, 1); |
(void)write(streamID, &c, 1); |
} |
} |
|
|
(void) close(streamID); |
(void)close(streamID); |
} else { |
} else { |
(void) fprintf(stdout, "*** couldn't touch %s: %s", |
(void)fprintf(stdout, "*** couldn't touch %s: %s", |
file, strerror(errno)); |
file, strerror(errno)); |
(void) fflush(stdout); |
(void)fflush(stdout); |
} |
} |
} |
} |
} |
} |
|
|
*/ |
*/ |
Boolean |
Boolean |
Job_CheckCommands(gn, abortProc) |
Job_CheckCommands(gn, abortProc) |
GNode *gn; /* The target whose commands need |
GNode *gn; /* The target whose commands need |
* verifying */ |
* verifying */ |
void (*abortProc) __P((char *, ...)); |
void (*abortProc)(char *, ...); |
/* Function to abort with message */ |
/* Function to abort with message */ |
{ |
{ |
if (OP_NOP(gn->type) && Lst_IsEmpty(&gn->commands) && |
if (OP_NOP(gn->type) && Lst_IsEmpty(&gn->commands) && |
|
|
* No commands. Look for .DEFAULT rule from which we might infer |
* No commands. Look for .DEFAULT rule from which we might infer |
* commands |
* commands |
*/ |
*/ |
if ((DEFAULT != NULL) && !Lst_IsEmpty(&DEFAULT->commands)) { |
if (DEFAULT != NULL && !Lst_IsEmpty(&DEFAULT->commands)) { |
/* |
/* |
* Make only looks for a .DEFAULT if the node was never the |
* Make only looks for a .DEFAULT if the node was never the |
* target of an operator, so that's what we do too. If |
* target of an operator, so that's what we do too. If |
|
|
static const char msg[] = "make: don't know how to make"; |
static const char msg[] = "make: don't know how to make"; |
|
|
if (gn->type & OP_OPTIONAL) { |
if (gn->type & OP_OPTIONAL) { |
(void) fprintf(stdout, "%s %s(ignored)\n", msg, gn->name); |
(void)fprintf(stdout, "%s %s(ignored)\n", msg, gn->name); |
(void) fflush(stdout); |
(void)fflush(stdout); |
} 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_GLOBAL)); |
Var_Value(".CURDIR")); |
return FALSE; |
return FALSE; |
} |
} |
} |
} |
|
|
* JobLocalInput -- |
* JobLocalInput -- |
* Handle a pipe becoming readable. Callback function for Rmt_Watch |
* Handle a pipe becoming readable. Callback function for Rmt_Watch |
* |
* |
* Results: |
|
* None |
|
* |
|
* Side Effects: |
* Side Effects: |
* JobDoOutput is called. |
* JobDoOutput is called. |
* |
|
*----------------------------------------------------------------------- |
*----------------------------------------------------------------------- |
*/ |
*/ |
/*ARGSUSED*/ |
/*ARGSUSED*/ |
static void |
static void |
JobLocalInput(stream, job) |
JobLocalInput(stream, job) |
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); |
} |
} |
|
|
* Execute the shell for the given job. Called from JobStart and |
* Execute the shell for the given job. Called from JobStart and |
* JobRestart. |
* JobRestart. |
* |
* |
* Results: |
|
* None. |
|
* |
|
* Side Effects: |
* Side Effects: |
* A shell is executed, outputs is altered and the Job structure added |
* A shell is executed, outputs is altered and the Job structure added |
* to the job table. |
* to the job table. |
* |
|
*----------------------------------------------------------------------- |
*----------------------------------------------------------------------- |
*/ |
*/ |
static void |
static void |
JobExec(job, argv) |
JobExec(job, argv) |
Job *job; /* Job to execute */ |
Job *job; /* Job to execute */ |
char **argv; |
char **argv; |
{ |
{ |
int cpid; /* ID of new child */ |
int cpid; /* ID of new child */ |
|
|
if (DEBUG(JOB)) { |
if (DEBUG(JOB)) { |
int i; |
int i; |
|
|
(void) fprintf(stdout, "Running %s %sly\n", job->node->name, |
(void)fprintf(stdout, "Running %s %sly\n", job->node->name, |
job->flags&JOB_REMOTE?"remote":"local"); |
job->flags&JOB_REMOTE?"remote":"local"); |
(void) fprintf(stdout, "\tCommand: "); |
(void)fprintf(stdout, "\tCommand: "); |
for (i = 0; argv[i] != NULL; i++) { |
for (i = 0; argv[i] != NULL; i++) { |
(void) fprintf(stdout, "%s ", argv[i]); |
(void)fprintf(stdout, "%s ", argv[i]); |
} |
} |
(void) fprintf(stdout, "\n"); |
(void)fprintf(stdout, "\n"); |
(void) fflush(stdout); |
(void)fflush(stdout); |
} |
} |
|
|
/* |
/* |
|
|
* banner with their name in it never appears). This is an attempt to |
* banner with their name in it never appears). This is an attempt to |
* provide that feedback, even if nothing follows it. |
* provide that feedback, even if nothing follows it. |
*/ |
*/ |
if ((lastNode != job->node) && (job->flags & JOB_FIRST) && |
if (lastNode != job->node && (job->flags & JOB_FIRST) && |
!(job->flags & JOB_SILENT)) { |
!(job->flags & JOB_SILENT)) { |
MESSAGE(stdout, job->node); |
MESSAGE(stdout, job->node); |
lastNode = job->node; |
lastNode = job->node; |
|
|
*/ |
*/ |
if (dup2(FILENO(job->cmdFILE), 0) == -1) |
if (dup2(FILENO(job->cmdFILE), 0) == -1) |
Punt("Cannot dup2: %s", strerror(errno)); |
Punt("Cannot dup2: %s", strerror(errno)); |
(void) fcntl(0, F_SETFD, 0); |
(void)fcntl(0, F_SETFD, 0); |
(void) lseek(0, 0, SEEK_SET); |
(void)lseek(0, 0, SEEK_SET); |
|
|
if (usePipes) { |
if (usePipes) { |
/* |
/* |
|
|
* it before routing the shell's error output to the same place as |
* it before routing the shell's error output to the same place as |
* its standard output. |
* its standard output. |
*/ |
*/ |
(void) fcntl(1, F_SETFD, 0); |
(void)fcntl(1, F_SETFD, 0); |
if (dup2(1, 2) == -1) |
if (dup2(1, 2) == -1) |
Punt("Cannot dup2: %s", strerror(errno)); |
Punt("Cannot dup2: %s", strerror(errno)); |
|
|
|
|
* by killing its process family, but not commit suicide. |
* by killing its process family, but not commit suicide. |
*/ |
*/ |
# if defined(SYSV) |
# if defined(SYSV) |
(void) setsid(); |
(void)setsid(); |
# else |
# else |
(void) setpgid(0, getpid()); |
(void)setpgid(0, getpid()); |
# endif |
# endif |
#endif /* USE_PGRP */ |
#endif /* USE_PGRP */ |
|
|
|
|
Rmt_Exec(shellPath, argv, FALSE); |
Rmt_Exec(shellPath, argv, FALSE); |
} else |
} else |
#endif /* REMOTE */ |
#endif /* REMOTE */ |
(void) execv(shellPath, argv); |
(void)execv(shellPath, argv); |
|
|
(void) write(2, "Could not execute shell\n", |
(void)write(2, "Could not execute shell\n", |
sizeof("Could not execute shell")); |
sizeof("Could not execute shell")); |
_exit(1); |
_exit(1); |
} else { |
} else { |
|
|
* XXX: Used to not happen if REMOTE. Why? |
* XXX: Used to not happen if REMOTE. Why? |
*/ |
*/ |
if (job->cmdFILE != NULL && job->cmdFILE != stdout) { |
if (job->cmdFILE != NULL && job->cmdFILE != stdout) { |
(void) fclose(job->cmdFILE); |
(void)fclose(job->cmdFILE); |
job->cmdFILE = NULL; |
job->cmdFILE = NULL; |
} |
} |
} |
} |
#ifdef REMOTE |
#ifdef REMOTE |
(void) sigsetmask(omask); |
(void)sigsetmask(omask); |
#endif |
#endif |
} |
} |
|
|
|
|
*----------------------------------------------------------------------- |
*----------------------------------------------------------------------- |
* JobMakeArgv -- |
* JobMakeArgv -- |
* Create the argv needed to execute the shell for a given job. |
* Create the argv needed to execute the shell for a given job. |
* |
|
* |
|
* Results: |
|
* |
|
* Side Effects: |
|
* |
|
*----------------------------------------------------------------------- |
*----------------------------------------------------------------------- |
*/ |
*/ |
static void |
static void |
JobMakeArgv(job, argv) |
JobMakeArgv(job, argv) |
Job *job; |
Job *job; |
char **argv; |
char **argv; |
{ |
{ |
int argc; |
int argc; |
static char args[10]; /* For merged arguments */ |
static char args[10]; /* For merged arguments */ |
|
|
argv[0] = shellName; |
argv[0] = shellName; |
argc = 1; |
argc = 1; |
|
|
if ((commandShell->exit && (*commandShell->exit != '-')) || |
if ((commandShell->exit && *commandShell->exit != '-') || |
(commandShell->echo && (*commandShell->echo != '-'))) |
(commandShell->echo && *commandShell->echo != '-')) |
{ |
{ |
/* |
/* |
* At least one of the flags doesn't have a minus before it, so |
* At least one of the flags doesn't have a minus before it, so |
|
|
* JobRestart -- |
* JobRestart -- |
* Restart a job that stopped for some reason. |
* Restart a job that stopped for some reason. |
* |
* |
* Results: |
|
* None. |
|
* |
|
* Side Effects: |
* Side Effects: |
* jobFull will be set if the job couldn't be run. |
* jobFull will be set if the job couldn't be run. |
* |
|
*----------------------------------------------------------------------- |
*----------------------------------------------------------------------- |
*/ |
*/ |
static void |
static void |
JobRestart(job) |
JobRestart(job) |
Job *job; /* Job to restart */ |
Job *job; /* Job to restart */ |
{ |
{ |
#ifdef REMOTE |
#ifdef REMOTE |
int host; |
int host; |
|
|
verboseRemigrates || |
verboseRemigrates || |
#endif |
#endif |
DEBUG(JOB)) { |
DEBUG(JOB)) { |
(void) fprintf(stdout, "*** remigrating %x(%s)\n", |
(void)fprintf(stdout, "*** remigrating %x(%s)\n", |
job->pid, job->node->name); |
job->pid, job->node->name); |
(void) fflush(stdout); |
(void)fflush(stdout); |
} |
} |
|
|
#ifdef REMOTE |
#ifdef REMOTE |
if (!Rmt_ReExport(job->pid, job->node, &host)) { |
if (!Rmt_ReExport(job->pid, job->node, &host)) { |
if (verboseRemigrates || DEBUG(JOB)) { |
if (verboseRemigrates || DEBUG(JOB)) { |
(void) fprintf(stdout, "*** couldn't migrate...\n"); |
(void)fprintf(stdout, "*** couldn't migrate...\n"); |
(void) fflush(stdout); |
(void)fflush(stdout); |
} |
} |
#endif |
#endif |
if (nLocal != maxLocal) { |
if (nLocal != maxLocal) { |
|
|
verboseRemigrates || |
verboseRemigrates || |
#endif |
#endif |
DEBUG(JOB)) { |
DEBUG(JOB)) { |
(void) fprintf(stdout, "*** resuming on local machine\n"); |
(void)fprintf(stdout, "*** resuming on local machine\n"); |
(void) fflush(stdout); |
(void)fflush(stdout); |
} |
} |
KILL(job->pid, SIGCONT); |
KILL(job->pid, SIGCONT); |
nLocal +=1; |
nLocal +=1; |
|
|
verboseRemigrates || |
verboseRemigrates || |
#endif |
#endif |
DEBUG(JOB)) { |
DEBUG(JOB)) { |
(void) fprintf(stdout, "*** holding\n"); |
(void)fprintf(stdout, "*** holding\n"); |
(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); |
} |
} |
return; |
return; |
} |
} |
|
|
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); |
} |
} |
} |
} |
} else if (job->flags & JOB_RESTART) { |
} else if (job->flags & JOB_RESTART) { |
|
|
JobMakeArgv(job, argv); |
JobMakeArgv(job, argv); |
|
|
if (DEBUG(JOB)) { |
if (DEBUG(JOB)) { |
(void) fprintf(stdout, "Restarting %s...", job->node->name); |
(void)fprintf(stdout, "Restarting %s...", job->node->name); |
(void) fflush(stdout); |
(void)fflush(stdout); |
} |
} |
#ifdef REMOTE |
#ifdef REMOTE |
if ((job->node->type&OP_NOEXPORT) || |
if ((job->node->type&OP_NOEXPORT) || |
(nLocal < maxLocal && runLocalFirst) |
(nLocal < maxLocal && runLocalFirst) |
# ifdef RMT_NO_EXEC |
# ifdef RMT_NO_EXEC |
|| !Rmt_Export(shellPath, argv, job) |
|| !Rmt_Export(shellPath, argv, job) |
# else |
# else |
|
|
# endif |
# endif |
#endif |
#endif |
{ |
{ |
if (((nLocal >= maxLocal) && !(job->flags & JOB_SPECIAL))) { |
if (nLocal >= maxLocal && !(job->flags & JOB_SPECIAL)) { |
/* |
/* |
* Can't be exported and not allowed to run locally -- put it |
* Can't be exported and not allowed to run locally -- put it |
* back on the hold queue and mark the table full |
* back on the hold queue and mark the table full |
*/ |
*/ |
if (DEBUG(JOB)) { |
if (DEBUG(JOB)) { |
(void) fprintf(stdout, "holding\n"); |
(void)fprintf(stdout, "holding\n"); |
(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); |
} |
} |
return; |
return; |
} else { |
} else { |
|
|
* Job may be run locally. |
* Job may be run locally. |
*/ |
*/ |
if (DEBUG(JOB)) { |
if (DEBUG(JOB)) { |
(void) fprintf(stdout, "running locally\n"); |
(void)fprintf(stdout, "running locally\n"); |
(void) fflush(stdout); |
(void)fflush(stdout); |
} |
} |
job->flags &= ~JOB_REMOTE; |
job->flags &= ~JOB_REMOTE; |
} |
} |
|
|
* Can be exported. Hooray! |
* Can be exported. Hooray! |
*/ |
*/ |
if (DEBUG(JOB)) { |
if (DEBUG(JOB)) { |
(void) fprintf(stdout, "exporting\n"); |
(void)fprintf(stdout, "exporting\n"); |
(void) fflush(stdout); |
(void)fflush(stdout); |
} |
} |
job->flags |= JOB_REMOTE; |
job->flags |= JOB_REMOTE; |
} |
} |
|
|
* we don't know... |
* we don't know... |
*/ |
*/ |
if (DEBUG(JOB)) { |
if (DEBUG(JOB)) { |
(void) fprintf(stdout, "Resuming %s...", job->node->name); |
(void)fprintf(stdout, "Resuming %s...", job->node->name); |
(void) fflush(stdout); |
(void)fflush(stdout); |
} |
} |
if (((job->flags & JOB_REMOTE) || |
if (((job->flags & JOB_REMOTE) || |
(nLocal < maxLocal) || |
nLocal < maxLocal || |
#ifdef REMOTE |
#ifdef REMOTE |
(((job->flags & JOB_SPECIAL) && |
((job->flags & JOB_SPECIAL) && |
(job->node->type & OP_NOEXPORT)) && |
(job->node->type & OP_NOEXPORT) && |
(maxLocal == 0))) && |
maxLocal == 0) |
#else |
#else |
((job->flags & JOB_SPECIAL) && |
((job->flags & JOB_SPECIAL) && |
(maxLocal == 0))) && |
maxLocal == 0) |
#endif |
#endif |
(nJobs != maxJobs)) |
) && nJobs != maxJobs) |
{ |
{ |
/* |
/* |
* If the job is remote, it's ok to resume it as long as the |
* If the job is remote, it's ok to resume it as long as the |
|
|
error = !Rmt_Signal(job, SIGCONT); |
error = !Rmt_Signal(job, SIGCONT); |
} else |
} else |
#endif /* RMT_WANTS_SIGNALS */ |
#endif /* RMT_WANTS_SIGNALS */ |
error = (KILL(job->pid, SIGCONT) != 0); |
error = KILL(job->pid, SIGCONT) != 0; |
|
|
if (!error) { |
if (!error) { |
/* |
/* |
|
|
|
|
job->flags &= ~(JOB_RESUME|JOB_CONTINUING); |
job->flags &= ~(JOB_RESUME|JOB_CONTINUING); |
if (DEBUG(JOB)) { |
if (DEBUG(JOB)) { |
(void) fprintf(stdout, "done\n"); |
(void)fprintf(stdout, "done\n"); |
(void) fflush(stdout); |
(void)fflush(stdout); |
} |
} |
} else { |
} else { |
Error("couldn't resume %s: %s", |
Error("couldn't resume %s: %s", |
|
|
* place the job back on the list of stopped jobs. |
* place the job back on the list of stopped jobs. |
*/ |
*/ |
if (DEBUG(JOB)) { |
if (DEBUG(JOB)) { |
(void) fprintf(stdout, "table full\n"); |
(void)fprintf(stdout, "table full\n"); |
(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); |
} |
} |
} |
} |
} |
} |
|
|
*/ |
*/ |
static int |
static int |
JobStart(gn, flags, previous) |
JobStart(gn, flags, previous) |
GNode *gn; /* target to create */ |
GNode *gn; /* target to create */ |
int flags; /* flags for the job to override normal ones. |
int flags; /* flags for the job to override normal ones. |
* e.g. JOB_SPECIAL or JOB_IGNDOTS */ |
* e.g. JOB_SPECIAL or JOB_IGNDOTS */ |
Job *previous; /* The previous Job structure for this node, |
Job *previous; /* The previous Job structure for this node, |
* if any. */ |
* if any. */ |
{ |
{ |
register 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 */ |
Boolean cmdsOK; /* true if the nodes commands were all right */ |
Boolean local; /* Set true if the job was run locally */ |
Boolean local; /* Set true if the job was run locally */ |
Boolean noExec; /* Set true if we decide not to run the job */ |
Boolean noExec; /* Set true if we decide not to run the job */ |
int tfd; /* where to stash those pesky commands */ |
|
|
|
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); |
job = previous; |
job = previous; |
} else { |
} else { |
job = (Job *) emalloc(sizeof(Job)); |
job = emalloc(sizeof(Job)); |
if (job == NULL) { |
if (job == NULL) { |
Punt("JobStart out of memory"); |
Punt("JobStart out of memory"); |
} |
} |
|
|
DieHorribly(); |
DieHorribly(); |
} |
} |
|
|
(void) strcpy(tfile, TMPPAT); |
job->cmdFILE = fopen(tfile, "w+"); |
if ((tfd = mkstemp(tfile)) == -1) |
|
Punt("Cannot create temp file: %s", strerror(errno)); |
|
job->cmdFILE = fdopen(tfd, "w+"); |
|
eunlink(tfile); |
|
if (job->cmdFILE == NULL) { |
if (job->cmdFILE == NULL) { |
close(tfd); |
|
Punt("Could not open %s", tfile); |
Punt("Could not open %s", tfile); |
} |
} |
(void) 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 |
* Send the commands to the command file, flush all its buffers then |
* rewind and remove the thing. |
* rewind and remove the thing. |
|
|
* per shell. |
* per shell. |
*/ |
*/ |
if (compatMake) { |
if (compatMake) { |
LstNode ln; |
|
/* |
/* |
* Be compatible: If this is the first time for this node, |
* Be compatible: If this is the first time for this node, |
* verify its commands are ok and open the commands list for |
* verify its commands are ok and open the commands list for |
|
|
* ellipsis, note that there's nothing more to execute. |
* ellipsis, note that there's nothing more to execute. |
*/ |
*/ |
if ((job->flags&JOB_FIRST)) |
if ((job->flags&JOB_FIRST)) |
Lst_Open(&gn->commands); |
gn->current = Lst_First(&gn->commands); |
ln = Lst_Next(&gn->commands); |
else |
|
gn->current = Lst_Succ(gn->current); |
|
|
if ((ln == NULL) || !JobPrintCommand(Lst_Datum(ln), job)) { |
if (gn->current == NULL || |
|
!JobPrintCommand(Lst_Datum(gn->current), job)) { |
noExec = TRUE; |
noExec = TRUE; |
Lst_Close(&gn->commands); |
gn->current = NULL; |
} |
} |
if (noExec && !(job->flags & JOB_FIRST)) { |
if (noExec && !(job->flags & JOB_FIRST)) { |
/* |
/* |
|
|
* not -- just let the user know they're bad and keep going. It |
* not -- just let the user know they're bad and keep going. It |
* doesn't do any harm in this case and may do some good. |
* doesn't do any harm in this case and may do some good. |
*/ |
*/ |
if (cmdsOK) |
if (cmdsOK) { |
Lst_Find(&gn->commands, JobPrintCommand, job); |
Lst_Find(&gn->commands, JobPrintCommand, job); |
|
} |
/* |
/* |
* Don't execute the shell, thank you. |
* Don't execute the shell, thank you. |
*/ |
*/ |
|
|
* up the graph. |
* up the graph. |
*/ |
*/ |
job->cmdFILE = stdout; |
job->cmdFILE = stdout; |
Job_Touch(gn, job->flags&JOB_SILENT); |
Job_Touch(gn, job->flags&JOB_SILENT); |
noExec = TRUE; |
noExec = TRUE; |
} |
} |
|
|
|
|
* Unlink and close the command file if we opened one |
* Unlink and close the command file if we opened one |
*/ |
*/ |
if (job->cmdFILE != stdout) { |
if (job->cmdFILE != stdout) { |
|
(void)eunlink(tfile); |
if (job->cmdFILE != NULL) |
if (job->cmdFILE != NULL) |
(void) fclose(job->cmdFILE); |
(void)fclose(job->cmdFILE); |
} else { |
} else { |
(void) fflush(stdout); |
(void)fflush(stdout); |
} |
} |
|
|
/* |
/* |
|
|
*/ |
*/ |
if (cmdsOK) { |
if (cmdsOK) { |
if (aborting == 0) { |
if (aborting == 0) { |
Lst_ForEachFrom(job->tailCmds, JobSaveCommand, job->node); |
Lst_ForEachFrom(job->tailCmds, JobSaveCommand, job->node); |
Make_Update(job->node); |
Make_Update(job->node); |
} |
} |
free(job); |
free(job); |
|
|
return JOB_ERROR; |
return JOB_ERROR; |
} |
} |
} else { |
} else { |
(void) fflush(job->cmdFILE); |
(void)fflush(job->cmdFILE); |
|
(void)eunlink(tfile); |
} |
} |
|
|
/* |
/* |
|
|
Punt("Cannot create pipe: %s", strerror(errno)); |
Punt("Cannot create pipe: %s", strerror(errno)); |
job->inPipe = fd[0]; |
job->inPipe = fd[0]; |
job->outPipe = fd[1]; |
job->outPipe = fd[1]; |
(void) fcntl(job->inPipe, F_SETFD, 1); |
(void)fcntl(job->inPipe, F_SETFD, 1); |
(void) fcntl(job->outPipe, F_SETFD, 1); |
(void)fcntl(job->outPipe, F_SETFD, 1); |
} else { |
} else { |
(void) fprintf(stdout, "Remaking `%s'\n", gn->name); |
(void)fprintf(stdout, "Remaking `%s'\n", gn->name); |
(void) fflush(stdout); |
(void)fflush(stdout); |
(void) strcpy(job->outFile, TMPPAT); |
(void)strcpy(job->outFile, TMPPAT); |
if ((job->outFd = mkstemp(job->outFile)) == -1) |
if ((job->outFd = mkstemp(job->outFile)) == -1) |
Punt("Cannot create temp file: %s", strerror(errno)); |
Punt("Cannot create temp file: %s", strerror(errno)); |
(void) fcntl(job->outFd, F_SETFD, 1); |
(void)fcntl(job->outFd, F_SETFD, 1); |
} |
} |
} |
} |
|
|
|
|
#endif |
#endif |
local = TRUE; |
local = TRUE; |
|
|
if (local && (((nLocal >= maxLocal) && |
if (local && nLocal >= maxLocal && |
!(job->flags & JOB_SPECIAL) && |
!(job->flags & JOB_SPECIAL) && |
#ifdef REMOTE |
#ifdef REMOTE |
(!(gn->type & OP_NOEXPORT) || (maxLocal != 0)) |
(!(gn->type & OP_NOEXPORT) || maxLocal != 0) |
#else |
#else |
(maxLocal != 0) |
maxLocal != 0 |
#endif |
#endif |
))) |
) |
{ |
{ |
/* |
/* |
* The job can only be run locally, but we've hit the limit of |
* The job can only be run locally, but we've hit the limit of |
|
|
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"); |
(void) fflush(stdout); |
(void)fflush(stdout); |
} |
} |
job->flags |= JOB_RESTART; |
job->flags |= JOB_RESTART; |
Lst_AtEnd(&stoppedJobs, job); |
Lst_AtEnd(&stoppedJobs, job); |
} else { |
} else { |
if ((nLocal >= maxLocal) && local) { |
if (nLocal >= maxLocal && local) { |
/* |
/* |
* 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); |
} |
} |
} |
} |
JobExec(job, argv); |
JobExec(job, argv); |
} |
} |
return(JOB_RUNNING); |
return JOB_RUNNING; |
} |
} |
|
|
static char * |
static char * |
JobOutput(job, cp, endp, msg) |
JobOutput(job, cp, endp, msg) |
register Job *job; |
Job *job; |
register char *cp, *endp; |
char *cp, *endp; |
int msg; |
int msg; |
{ |
{ |
register char *ecp; |
char *ecp; |
|
|
if (commandShell->noPrint) { |
if (commandShell->noPrint) { |
ecp = strstr(cp, commandShell->noPrint); |
ecp = strstr(cp, commandShell->noPrint); |
|
|
* however, since the non-printable comes after it, |
* however, since the non-printable comes after it, |
* there must be a newline, so we don't print one. |
* there must be a newline, so we don't print one. |
*/ |
*/ |
(void) fprintf(stdout, "%s", cp); |
(void)fprintf(stdout, "%s", cp); |
(void) fflush(stdout); |
(void)fflush(stdout); |
} |
} |
cp = ecp + commandShell->noPLen; |
cp = ecp + commandShell->noPLen; |
if (cp != endp) { |
if (cp != endp) { |
|
|
|
|
/*- |
/*- |
*----------------------------------------------------------------------- |
*----------------------------------------------------------------------- |
* JobDoOutput -- |
* JobDoOutput -- |
* This function is called at different times depending on |
* This function is called at different times depending on |
* whether the user has specified that output is to be collected |
* whether the user has specified that output is to be collected |
* via pipes or temporary files. In the former case, we are called |
* via pipes or temporary files. In the former case, we are called |
|
|
* alone on the line (the character after it is not \0 or \n), we |
* alone on the line (the character after it is not \0 or \n), we |
* do print whatever follows it. |
* do print whatever follows it. |
* |
* |
* Results: |
|
* None |
|
* |
|
* Side Effects: |
* Side Effects: |
* curPos may be shifted as may the contents of outBuf. |
* curPos may be shifted as may the contents of outBuf. |
*----------------------------------------------------------------------- |
*----------------------------------------------------------------------- |
*/ |
*/ |
STATIC void |
STATIC void |
JobDoOutput(job, finish) |
JobDoOutput(job, finish) |
register 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 |
Boolean 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 */ |
Boolean gotNL = FALSE; /* true if got a newline */ |
Boolean fbuf; /* true if our buffer filled up */ |
Boolean fbuf; /* true if our buffer filled up */ |
register int nr; /* number of bytes read */ |
int nr; /* number of bytes read */ |
register int i; /* auxiliary index into outBuf */ |
int i; /* auxiliary index into outBuf */ |
register int max; /* limit for i (end of current data) */ |
int max; /* limit for i (end of current data) */ |
int nRead; /* (Temporary) number of bytes read */ |
int nRead; /* (Temporary) number of bytes read */ |
|
|
FILE *oFILE; /* Stream pointer to shell's output file */ |
FILE *oFILE; /* Stream pointer to shell's output file */ |
char inLine[132]; |
char inLine[132]; |
|
|
|
|
if (usePipes) { |
if (usePipes) { |
|
|
|
|
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 (nRead < 0) { |
if (nRead == -1) { |
if (DEBUG(JOB)) { |
if (DEBUG(JOB)) { |
perror("JobDoOutput(piperead)"); |
perror("JobDoOutput(piperead)"); |
} |
} |
|
|
* output remaining in the buffer. |
* output remaining in the buffer. |
* Also clear the 'finish' flag so we stop looping. |
* Also clear the 'finish' flag so we stop looping. |
*/ |
*/ |
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; |
|
|
MESSAGE(stdout, job->node); |
MESSAGE(stdout, job->node); |
lastNode = job->node; |
lastNode = job->node; |
} |
} |
(void) fprintf(stdout, "%s%s", cp, gotNL ? "\n" : ""); |
(void)fprintf(stdout, "%s%s", cp, gotNL ? "\n" : ""); |
(void) fflush(stdout); |
(void)fflush(stdout); |
} |
} |
} |
} |
if (i < max - 1) { |
if (i < max - 1) { |
/* shift the remaining characters down */ |
/* shift the remaining characters down */ |
(void) 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); |
job->curPos = max - (i + 1); |
|
|
} else { |
} else { |
|
|
*/ |
*/ |
oFILE = fopen(job->outFile, "r"); |
oFILE = fopen(job->outFile, "r"); |
if (oFILE != NULL) { |
if (oFILE != NULL) { |
(void) fprintf(stdout, "Results of making %s:\n", job->node->name); |
(void)fprintf(stdout, "Results of making %s:\n", job->node->name); |
(void) fflush(stdout); |
(void)fflush(stdout); |
while (fgets(inLine, sizeof(inLine), oFILE) != NULL) { |
while (fgets(inLine, sizeof(inLine), oFILE) != NULL) { |
register char *cp, *endp, *oendp; |
char *cp, *endp, *oendp; |
|
|
cp = inLine; |
cp = inLine; |
oendp = endp = inLine + strlen(inLine); |
oendp = endp = inLine + strlen(inLine); |
|
|
* we know there's no newline at the end, so we add one of |
* we know there's no newline at the end, so we add one of |
* our own free will. |
* our own free will. |
*/ |
*/ |
(void) fprintf(stdout, "%s", cp); |
(void)fprintf(stdout, "%s", cp); |
(void) fflush(stdout); |
(void)fflush(stdout); |
if (endp != oendp) { |
if (endp != oendp) { |
(void) fprintf(stdout, "\n"); |
(void)fprintf(stdout, "\n"); |
(void) fflush(stdout); |
(void)fflush(stdout); |
} |
} |
} |
} |
(void) fclose(oFILE); |
(void)fclose(oFILE); |
(void) eunlink(job->outFile); |
(void)eunlink(job->outFile); |
} |
} |
} |
} |
} |
} |
|
|
* Job_CatchChildren -- |
* Job_CatchChildren -- |
* Handle the exit of a child. Called from Make_Make. |
* Handle the exit of a child. Called from Make_Make. |
* |
* |
* Results: |
|
* none. |
|
* |
|
* Side Effects: |
* Side Effects: |
* The job descriptor is removed from the list of children. |
* The job descriptor is removed from the list of children. |
* |
* |
|
|
* caller, until there are no more children to report. For each |
* caller, until there are no more children to report. For each |
* job, call JobFinish to finish things off. This will take care of |
* job, call JobFinish to finish things off. This will take care of |
* putting jobs on the stoppedJobs queue. |
* putting jobs on the stoppedJobs queue. |
* |
|
*----------------------------------------------------------------------- |
*----------------------------------------------------------------------- |
*/ |
*/ |
void |
void |
Job_CatchChildren(block) |
Job_CatchChildren(block) |
Boolean block; /* TRUE if should block on the wait. */ |
Boolean block; /* TRUE if should block on the wait. */ |
{ |
{ |
int pid; /* pid of dead child */ |
int pid; /* pid of dead child */ |
register Job *job; /* job descriptor for dead child */ |
Job *job; /* job descriptor for dead child */ |
LstNode jnode; /* list element for finding job */ |
LstNode jnode; /* list element for finding job */ |
int status; /* Exit/termination status */ |
int status; /* Exit/termination status */ |
|
|
/* |
/* |
* Don't even bother if we know there's no one around. |
* Don't even bother if we know there's no one around. |
|
|
(block?0:WNOHANG)|WUNTRACED)) > 0) |
(block?0:WNOHANG)|WUNTRACED)) > 0) |
{ |
{ |
if (DEBUG(JOB)) { |
if (DEBUG(JOB)) { |
(void) fprintf(stdout, "Process %d exited or stopped.\n", pid); |
(void)fprintf(stdout, "Process %d exited or stopped.\n", pid); |
(void) fflush(stdout); |
(void)fflush(stdout); |
} |
} |
|
|
|
|
|
|
Lst_Remove(&jobs, jnode); |
Lst_Remove(&jobs, jnode); |
nJobs -= 1; |
nJobs -= 1; |
if (jobFull && DEBUG(JOB)) { |
if (jobFull && DEBUG(JOB)) { |
(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)) { |
(void) fprintf(stdout, |
(void)fprintf(stdout, |
"Job queue has one fewer local process.\n"); |
"Job queue has one fewer local process.\n"); |
(void) fflush(stdout); |
(void)fflush(stdout); |
} |
} |
nLocal -= 1; |
nLocal -= 1; |
} |
} |
|
|
* just spinning when there's nothing to do and the reaping |
* just spinning when there's nothing to do and the reaping |
* of a child can wait for a while. |
* of a child can wait for a while. |
* |
* |
* Results: |
|
* None |
|
* |
|
* Side Effects: |
* Side Effects: |
* Output is read from pipes if we're piping. |
* Output is read from pipes if we're piping. |
* ----------------------------------------------------------------------- |
* ----------------------------------------------------------------------- |
|
|
void |
void |
Job_CatchOutput() |
Job_CatchOutput() |
{ |
{ |
int nfds; |
int nfds; |
struct timeval timeout; |
struct timeval timeout; |
register LstNode ln; |
LstNode ln; |
register Job *job; |
Job *job; |
#ifdef RMT_WILL_WATCH |
#ifdef RMT_WILL_WATCH |
int pnJobs; /* Previous nJobs */ |
int pnJobs; /* Previous nJobs */ |
#endif |
#endif |
|
|
(void) fflush(stdout); |
(void)fflush(stdout); |
#ifdef RMT_WILL_WATCH |
#ifdef RMT_WILL_WATCH |
pnJobs = nJobs; |
pnJobs = nJobs; |
|
|
|
|
free(readfdsp); |
free(readfdsp); |
return; |
return; |
} else { |
} else { |
Lst_Open(&jobs); |
for (ln = Lst_First(&jobs); nfds && ln != NULL; ln = Lst_Adv(ln)) { |
while (nfds && (ln = Lst_Next(&jobs)) != NULL) { |
|
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; |
} |
} |
} |
} |
Lst_Close(&jobs); |
|
} |
} |
free(readfdsp); |
free(readfdsp); |
} |
} |
|
|
* Start the creation of a target. Basically a front-end for |
* Start the creation of a target. Basically a front-end for |
* JobStart used by the Make module. |
* JobStart used by the Make module. |
* |
* |
* Results: |
|
* None. |
|
* |
|
* Side Effects: |
* Side Effects: |
* Another job is started. |
* Another job is started. |
* |
|
*----------------------------------------------------------------------- |
*----------------------------------------------------------------------- |
*/ |
*/ |
void |
void |
Job_Make(gn) |
Job_Make(gn) |
GNode *gn; |
GNode *gn; |
{ |
{ |
(void) JobStart(gn, 0, NULL); |
(void)JobStart(gn, 0, NULL); |
} |
} |
|
|
/*- |
/*- |
|
|
* Job_Init -- |
* Job_Init -- |
* Initialize the process module |
* Initialize the process module |
* |
* |
* Results: |
|
* none |
|
* |
|
* Side Effects: |
* Side Effects: |
* lists and counters are initialized |
* lists and counters are initialized |
*----------------------------------------------------------------------- |
*----------------------------------------------------------------------- |
*/ |
*/ |
void |
void |
Job_Init(maxproc, maxlocal) |
Job_Init(maxproc, maxlocal) |
int maxproc; /* the greatest number of jobs which may be |
int maxproc; /* the greatest number of jobs which may be |
* running at one time */ |
* running at one time */ |
int maxlocal; /* the greatest number of local jobs which may |
int maxlocal; /* the greatest number of local jobs which may |
* be running at once. */ |
* be running at once. */ |
{ |
{ |
GNode *begin; /* node for commands to do at the very start */ |
GNode *begin; /* node for commands to do at the very start */ |
|
int tfd; |
|
|
|
(void)strcpy(tfile, TMPPAT); |
|
if ((tfd = mkstemp(tfile)) == -1) |
|
Punt("Cannot create temp file: %s", strerror(errno)); |
|
else |
|
(void)close(tfd); |
|
|
Lst_Init(&jobs); |
Lst_Init(&jobs); |
Lst_Init(&stoppedJobs); |
Lst_Init(&stoppedJobs); |
maxJobs = maxproc; |
maxJobs = maxproc; |
maxLocal = maxlocal; |
maxLocal = maxlocal; |
nJobs = 0; |
nJobs = 0; |
nLocal = 0; |
nLocal = 0; |
jobFull = FALSE; |
jobFull = FALSE; |
|
|
aborting = 0; |
aborting = 0; |
errors = 0; |
errors = 0; |
|
|
lastNode = NULL; |
lastNode = NULL; |
|
|
|
|
* JobPassSig will take care of calling JobInterrupt if appropriate. |
* JobPassSig will take care of calling JobInterrupt if appropriate. |
*/ |
*/ |
if (signal(SIGINT, SIG_IGN) != SIG_IGN) { |
if (signal(SIGINT, SIG_IGN) != SIG_IGN) { |
(void) signal(SIGINT, JobPassSig); |
(void)signal(SIGINT, JobPassSig); |
} |
} |
if (signal(SIGHUP, SIG_IGN) != SIG_IGN) { |
if (signal(SIGHUP, SIG_IGN) != SIG_IGN) { |
(void) signal(SIGHUP, JobPassSig); |
(void)signal(SIGHUP, JobPassSig); |
} |
} |
if (signal(SIGQUIT, SIG_IGN) != SIG_IGN) { |
if (signal(SIGQUIT, SIG_IGN) != SIG_IGN) { |
(void) signal(SIGQUIT, JobPassSig); |
(void)signal(SIGQUIT, JobPassSig); |
} |
} |
if (signal(SIGTERM, SIG_IGN) != SIG_IGN) { |
if (signal(SIGTERM, SIG_IGN) != SIG_IGN) { |
(void) signal(SIGTERM, JobPassSig); |
(void)signal(SIGTERM, JobPassSig); |
} |
} |
/* |
/* |
* There are additional signals that need to be caught and passed if |
* There are additional signals that need to be caught and passed if |
|
|
*/ |
*/ |
#if defined(RMT_WANTS_SIGNALS) || defined(USE_PGRP) |
#if defined(RMT_WANTS_SIGNALS) || defined(USE_PGRP) |
if (signal(SIGTSTP, SIG_IGN) != SIG_IGN) { |
if (signal(SIGTSTP, SIG_IGN) != SIG_IGN) { |
(void) signal(SIGTSTP, JobPassSig); |
(void)signal(SIGTSTP, JobPassSig); |
} |
} |
if (signal(SIGTTOU, SIG_IGN) != SIG_IGN) { |
if (signal(SIGTTOU, SIG_IGN) != SIG_IGN) { |
(void) signal(SIGTTOU, JobPassSig); |
(void)signal(SIGTTOU, JobPassSig); |
} |
} |
if (signal(SIGTTIN, SIG_IGN) != SIG_IGN) { |
if (signal(SIGTTIN, SIG_IGN) != SIG_IGN) { |
(void) signal(SIGTTIN, JobPassSig); |
(void)signal(SIGTTIN, JobPassSig); |
} |
} |
if (signal(SIGWINCH, SIG_IGN) != SIG_IGN) { |
if (signal(SIGWINCH, SIG_IGN) != SIG_IGN) { |
(void) signal(SIGWINCH, JobPassSig); |
(void)signal(SIGWINCH, JobPassSig); |
} |
} |
#endif |
#endif |
|
|
begin = Targ_FindNode(".BEGIN", TARG_NOCREATE); |
begin = Targ_FindNode(".BEGIN", NULL, 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", TARG_CREATE); |
postCommands = Targ_FindNode(".END", NULL, TARG_CREATE); |
} |
} |
|
|
/*- |
/*- |
|
|
* |
* |
* Results: |
* Results: |
* TRUE if the job table is full, FALSE otherwise |
* TRUE if the job table is full, FALSE otherwise |
* Side Effects: |
|
* None. |
|
*----------------------------------------------------------------------- |
*----------------------------------------------------------------------- |
*/ |
*/ |
Boolean |
Boolean |
Job_Full() |
Job_Full() |
{ |
{ |
return(aborting || jobFull); |
return aborting || jobFull; |
} |
} |
|
|
/*- |
/*- |
*----------------------------------------------------------------------- |
*----------------------------------------------------------------------- |
* Job_Empty -- |
* Job_Empty -- |
* See if the job table is empty. Because the local concurrency may |
* See if the job table is empty. Because the local concurrency may |
* be set to 0, it is possible for the job table to become empty, |
* be set to 0, it is possible for the job table to become empty, |
* while the list of stoppedJobs remains non-empty. In such a case, |
* while the list of stoppedJobs remains non-empty. In such a case, |
* 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. |
* |
|
* Side Effects: |
|
* None. |
|
* |
|
* ----------------------------------------------------------------------- |
* ----------------------------------------------------------------------- |
*/ |
*/ |
Boolean |
Boolean |
|
|
*/ |
*/ |
jobFull = FALSE; |
jobFull = FALSE; |
JobRestartJobs(); |
JobRestartJobs(); |
return(FALSE); |
return FALSE; |
} else { |
} else { |
return(TRUE); |
return TRUE; |
} |
} |
} else { |
} else { |
return(FALSE); |
return FALSE; |
} |
} |
} |
} |
|
|
|
|
* |
* |
* Results: |
* Results: |
* A pointer to the Shell structure. |
* A pointer to the Shell structure. |
* |
|
* Side Effects: |
|
* None. |
|
* |
|
*----------------------------------------------------------------------- |
*----------------------------------------------------------------------- |
*/ |
*/ |
static Shell * |
static Shell * |
JobMatchShell(name) |
JobMatchShell(name) |
char *name; /* Final component of shell path */ |
char *name; /* Final component of shell path */ |
{ |
{ |
register Shell *sh; /* Pointer into shells table */ |
Shell *sh; /* Pointer into shells table */ |
Shell *match; /* Longest-matching shell */ |
Shell *match; /* Longest-matching shell */ |
register char *cp1, |
char *cp1, |
*cp2; |
*cp2; |
char *eoname; |
char *eoname; |
|
|
|
|
match = sh; |
match = sh; |
} |
} |
} |
} |
return(match == NULL ? sh : match); |
return match == NULL ? sh : match; |
} |
} |
|
|
/*- |
/*- |
|
|
* provides the functionality it does in C. Each word consists of |
* provides the functionality it does in C. Each word consists of |
* keyword and value separated by an equal sign. There should be no |
* keyword and value separated by an equal sign. There should be no |
* unnecessary spaces in the word. The keywords are as follows: |
* unnecessary spaces in the word. The keywords are as follows: |
* name Name of shell. |
* name Name of shell. |
* path Location of shell. Overrides "name" if given |
* path Location of shell. Overrides "name" if given |
* quiet Command to turn off echoing. |
* quiet Command to turn off echoing. |
* echo Command to turn echoing on |
* echo Command to turn echoing on |
* filter Result of turning off echoing that shouldn't be |
* filter Result of turning off echoing that shouldn't be |
* printed. |
* printed. |
* echoFlag Flag to turn echoing on at the start |
* echoFlag Flag to turn echoing on at the start |
* 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 |
ReturnStatus |
Job_ParseShell(line) |
Job_ParseShell(line) |
char *line; /* The shell spec */ |
char *line; /* The shell spec */ |
{ |
{ |
char **words; |
char **words; |
int wordCount; |
int wordCount; |
register char **argv; |
char **argv; |
register int argc; |
int argc; |
char *path; |
char *path; |
Shell newShell; |
Shell newShell; |
Boolean fullSpec = FALSE; |
Boolean fullSpec = FALSE; |
|
|
while (isspace(*line)) { |
while (isspace(*line)) { |
line++; |
line++; |
} |
} |
|
|
efree(shellArgv); |
efree(shellArgv); |
|
|
words = brk_string(line, &wordCount, TRUE, &shellArgv); |
|
|
|
|
words = brk_string(line, &wordCount, &shellArgv); |
|
|
memset(&newShell, 0, sizeof(newShell)); |
memset(&newShell, 0, sizeof(newShell)); |
|
|
/* |
/* |
|
|
newShell.exit = &argv[0][8]; |
newShell.exit = &argv[0][8]; |
} else if (strncmp(*argv, "hasErrCtl=", 10) == 0) { |
} else if (strncmp(*argv, "hasErrCtl=", 10) == 0) { |
char c = argv[0][10]; |
char c = argv[0][10]; |
newShell.hasErrCtl = !((c != 'Y') && (c != 'y') && |
newShell.hasErrCtl = !(c != 'Y' && c != 'y' && |
(c != 'T') && (c != 't')); |
c != 'T' && c != 't'); |
} else if (strncmp(*argv, "check=", 6) == 0) { |
} else if (strncmp(*argv, "check=", 6) == 0) { |
newShell.errCheck = &argv[0][6]; |
newShell.errCheck = &argv[0][6]; |
} else if (strncmp(*argv, "ignore=", 7) == 0) { |
} else if (strncmp(*argv, "ignore=", 7) == 0) { |
|
|
Parse_Error(PARSE_FATAL, "Unknown keyword \"%s\"", |
Parse_Error(PARSE_FATAL, "Unknown keyword \"%s\"", |
*argv); |
*argv); |
free(words); |
free(words); |
return(FAILURE); |
return FAILURE; |
} |
} |
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 FAILURE; |
} else { |
} else { |
commandShell = JobMatchShell(newShell.name); |
commandShell = JobMatchShell(newShell.name); |
shellName = newShell.name; |
shellName = newShell.name; |
|
|
if (!fullSpec) { |
if (!fullSpec) { |
commandShell = JobMatchShell(shellName); |
commandShell = JobMatchShell(shellName); |
} else { |
} else { |
commandShell = (Shell *) emalloc(sizeof(Shell)); |
commandShell = emalloc(sizeof(Shell)); |
*commandShell = newShell; |
*commandShell = newShell; |
} |
} |
} |
} |
|
|
* JobInterrupt -- |
* JobInterrupt -- |
* Handle the receipt of an interrupt. |
* Handle the receipt of an interrupt. |
* |
* |
* Results: |
|
* None |
|
* |
|
* Side Effects: |
* Side Effects: |
* All children are killed. Another job will be started if the |
* All children are killed. Another job will be started if the |
* .INTERRUPT target was given. |
* .INTERRUPT target was given. |
|
|
*/ |
*/ |
static void |
static void |
JobInterrupt(runINTERRUPT, signo) |
JobInterrupt(runINTERRUPT, signo) |
int runINTERRUPT; /* Non-zero if commands for the .INTERRUPT |
int runINTERRUPT; /* Non-zero if commands for the .INTERRUPT |
* target should be executed */ |
* target should be executed */ |
int signo; /* signal received */ |
int signo; /* signal received */ |
{ |
{ |
LstNode ln; /* element in job table */ |
LstNode ln; /* element in job table */ |
Job *job; /* job descriptor in that element */ |
Job *job; /* job descriptor in that element */ |
GNode *interrupt; /* the node describing the .INTERRUPT target */ |
GNode *interrupt; /* the node describing the .INTERRUPT target */ |
|
|
aborting = ABORT_INTERRUPT; |
aborting = ABORT_INTERRUPT; |
|
|
Lst_Open(&jobs); |
for (ln = Lst_First(&jobs); ln != NULL; ln = Lst_Adv(ln)) { |
while ((ln = Lst_Next(&jobs)) != NULL) { |
|
job = (Job *)Lst_Datum(ln); |
job = (Job *)Lst_Datum(ln); |
|
|
if (!Targ_Precious(job->node)) { |
if (!Targ_Precious(job->node)) { |
char *file = (job->node->path == NULL ? |
const char *file = job->node->path == NULL ? |
job->node->name : |
job->node->name : |
job->node->path); |
job->node->path; |
if (!noExecute && eunlink(file) != -1) { |
if (!noExecute && eunlink(file) != -1) { |
Error("*** %s removed", file); |
Error("*** %s removed", file); |
} |
} |
|
|
#else |
#else |
if (job->pid) { |
if (job->pid) { |
if (DEBUG(JOB)) { |
if (DEBUG(JOB)) { |
(void) fprintf(stdout, |
(void)fprintf(stdout, |
"JobInterrupt passing signal to child %d.\n", |
"JobInterrupt passing signal to child %d.\n", |
job->pid); |
job->pid); |
(void) fflush(stdout); |
(void)fflush(stdout); |
} |
} |
KILL(job->pid, signo); |
KILL(job->pid, signo); |
} |
} |
|
|
} |
} |
|
|
#ifdef REMOTE |
#ifdef REMOTE |
Lst_Open(&stoppedJobs); |
for (ln = Lst_First(&stoppedJobs); ln != NULL; ln = Lst_Adv(ln)) { |
while ((ln = Lst_Next(&stoppedJobs)) != NULL) { |
|
job = (Job *)Lst_Datum(ln); |
job = (Job *)Lst_Datum(ln); |
|
|
if (job->flags & JOB_RESTART) { |
if (job->flags & JOB_RESTART) { |
if (DEBUG(JOB)) { |
if (DEBUG(JOB)) { |
(void) fprintf(stdout, "%s%s", |
(void)fprintf(stdout, "%s%s", |
"JobInterrupt skipping job on stopped queue", |
"JobInterrupt skipping job on stopped queue", |
"-- it was waiting to be restarted.\n"); |
"-- it was waiting to be restarted.\n"); |
(void) fflush(stdout); |
(void)fflush(stdout); |
} |
} |
continue; |
continue; |
} |
} |
if (!Targ_Precious(job->node)) { |
if (!Targ_Precious(job->node)) { |
char *file = (job->node->path == NULL ? |
char *file = job->node->path == NULL ? |
job->node->name : |
job->node->name : |
job->node->path); |
job->node->path; |
if (eunlink(file) == 0) { |
if (eunlink(file) == 0) { |
Error("*** %s removed", file); |
Error("*** %s removed", file); |
} |
} |
|
|
* Resume the thing so it will take the signal. |
* Resume the thing so it will take the signal. |
*/ |
*/ |
if (DEBUG(JOB)) { |
if (DEBUG(JOB)) { |
(void) fprintf(stdout, |
(void)fprintf(stdout, |
"JobInterrupt passing CONT to stopped child %d.\n", |
"JobInterrupt passing CONT to stopped child %d.\n", |
job->pid); |
job->pid); |
(void) fflush(stdout); |
(void)fflush(stdout); |
} |
} |
KILL(job->pid, SIGCONT); |
KILL(job->pid, SIGCONT); |
#ifdef RMT_WANTS_SIGNALS |
#ifdef RMT_WANTS_SIGNALS |
|
|
} |
} |
} else if (job->pid) { |
} else if (job->pid) { |
if (DEBUG(JOB)) { |
if (DEBUG(JOB)) { |
(void) fprintf(stdout, |
(void)fprintf(stdout, |
"JobInterrupt passing interrupt to stopped child %d.\n", |
"JobInterrupt passing interrupt to stopped child %d.\n", |
job->pid); |
job->pid); |
(void) fflush(stdout); |
(void)fflush(stdout); |
} |
} |
KILL(job->pid, SIGINT); |
KILL(job->pid, SIGINT); |
} |
} |
#endif /* RMT_WANTS_SIGNALS */ |
#endif /* RMT_WANTS_SIGNALS */ |
} |
} |
#endif |
#endif |
Lst_Close(&stoppedJobs); |
|
|
|
if (runINTERRUPT && !touchFlag) { |
if (runINTERRUPT && !touchFlag) { |
interrupt = Targ_FindNode(".INTERRUPT", TARG_NOCREATE); |
interrupt = Targ_FindNode(".INTERRUPT", NULL, TARG_NOCREATE); |
if (interrupt != NULL) { |
if (interrupt != NULL) { |
ignoreErrors = FALSE; |
ignoreErrors = FALSE; |
|
|
|
|
} |
} |
} |
} |
} |
} |
|
(void)eunlink(tfile); |
exit(signo); |
exit(signo); |
} |
} |
|
|
|
|
* |
* |
* Results: |
* Results: |
* Number of errors reported. |
* Number of errors reported. |
|
* |
|
* Side Effects: |
|
* The process' temporary file (tfile) is removed if it still |
|
* existed. |
*----------------------------------------------------------------------- |
*----------------------------------------------------------------------- |
*/ |
*/ |
int |
int |
|
|
} |
} |
} |
} |
} |
} |
return(errors); |
(void)eunlink(tfile); |
|
return errors; |
} |
} |
|
|
/*- |
/*- |
|
|
* Job_End -- |
* Job_End -- |
* Cleanup any memory used by the jobs module |
* Cleanup any memory used by the jobs module |
* |
* |
* Results: |
|
* None. |
|
* |
|
* Side Effects: |
* Side Effects: |
* Memory is freed |
* Memory is freed |
*----------------------------------------------------------------------- |
*----------------------------------------------------------------------- |
|
|
efree(shellArgv); |
efree(shellArgv); |
#endif |
#endif |
} |
} |
|
|
/*- |
/*- |
*----------------------------------------------------------------------- |
*----------------------------------------------------------------------- |
* Job_Wait -- |
* Job_Wait -- |
* Waits for all running jobs to finish and returns. Sets 'aborting' |
* Waits for all running jobs to finish and returns. Sets 'aborting' |
* to ABORT_WAIT to prevent other jobs from starting. |
* to ABORT_WAIT to prevent other jobs from starting. |
* |
* |
* Results: |
|
* None. |
|
* |
|
* Side Effects: |
* Side Effects: |
* Currently running jobs finish. |
* Currently running jobs finish. |
* |
* |
|
|
* This function is to be called only in the event of a major |
* This function is to be called only in the event of a major |
* error. Most definitely NOT to be called from JobInterrupt. |
* error. Most definitely NOT to be called from JobInterrupt. |
* |
* |
* Results: |
|
* None |
|
* |
|
* Side Effects: |
* Side Effects: |
* All children are killed, not just the firstborn |
* All children are killed, not just the firstborn |
*----------------------------------------------------------------------- |
*----------------------------------------------------------------------- |
|
|
void |
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 */ |
Job *job; /* the job descriptor in that element */ |
int foo; |
int foo; |
|
|
aborting = ABORT_ERROR; |
aborting = ABORT_ERROR; |
|
|
if (nJobs) { |
if (nJobs) { |
|
for (ln = Lst_First(&jobs); ln != NULL; ln = Lst_Adv(ln)) { |
Lst_Open(&jobs); |
|
while ((ln = Lst_Next(&jobs)) != NULL) { |
|
job = (Job *)Lst_Datum(ln); |
job = (Job *)Lst_Datum(ln); |
|
|
/* |
/* |
|
|
*/ |
*/ |
while (waitpid((pid_t) -1, &foo, WNOHANG) > 0) |
while (waitpid((pid_t) -1, &foo, WNOHANG) > 0) |
continue; |
continue; |
|
(void)eunlink(tfile); |
} |
} |
|
|
#ifdef REMOTE |
#ifdef REMOTE |
|
|
* Handle the eviction of a child. Called from RmtStatusChange. |
* Handle the eviction of a child. Called from RmtStatusChange. |
* Flags the child as remigratable and then suspends it. |
* Flags the child as remigratable and then suspends it. |
* |
* |
* Results: |
|
* none. |
|
* |
|
* Side Effects: |
* Side Effects: |
* The job descriptor is flagged for remigration. |
* The job descriptor is flagged for remigration. |
* |
|
*----------------------------------------------------------------------- |
*----------------------------------------------------------------------- |
*/ |
*/ |
void |
void |
JobFlagForMigration(hostID) |
JobFlagForMigration(hostID) |
int hostID; /* ID of host we used, for matching children. */ |
int hostID; /* ID of host we used, for matching children. */ |
{ |
{ |
register Job *job; /* job descriptor for dead child */ |
Job *job; /* job descriptor for dead child */ |
LstNode jnode; /* list element for finding job */ |
LstNode jnode; /* list element for finding job */ |
|
|
if (DEBUG(JOB)) { |
if (DEBUG(JOB)) { |
(void) fprintf(stdout, "JobFlagForMigration(%d) called.\n", hostID); |
(void)fprintf(stdout, "JobFlagForMigration(%d) called.\n", hostID); |
(void) fflush(stdout); |
(void)fflush(stdout); |
} |
} |
jnode = Lst_Find(&jobs, JobCmpRmtID, &hostID); |
jnode = Lst_Find(&jobs, JobCmpRmtID, &hostID); |
|
|
|
|
job = (Job *)Lst_Datum(jnode); |
job = (Job *)Lst_Datum(jnode); |
|
|
if (DEBUG(JOB)) { |
if (DEBUG(JOB)) { |
(void) fprintf(stdout, |
(void)fprintf(stdout, |
"JobFlagForMigration(%d) found job '%s'.\n", hostID, |
"JobFlagForMigration(%d) found job '%s'.\n", hostID, |
job->node->name); |
job->node->name); |
(void) fflush(stdout); |
(void)fflush(stdout); |
} |
} |
|
|
KILL(job->pid, SIGSTOP); |
KILL(job->pid, SIGSTOP); |
|
|
} |
} |
|
|
#endif |
#endif |
|
|
/*- |
/*- |
*----------------------------------------------------------------------- |
*----------------------------------------------------------------------- |
* JobRestartJobs -- |
* JobRestartJobs -- |
|
|
* Note that this tries to restart them regardless of pending errors. |
* Note that this tries to restart them regardless of pending errors. |
* It's not good to leave stopped jobs lying around! |
* It's not good to leave stopped jobs lying around! |
* |
* |
* Results: |
|
* None. |
|
* |
|
* Side Effects: |
* Side Effects: |
* Resumes(and possibly migrates) jobs. |
* Resumes(and possibly migrates) jobs. |
* |
|
*----------------------------------------------------------------------- |
*----------------------------------------------------------------------- |
*/ |
*/ |
static void |
static void |
|
|
{ |
{ |
Job *job; |
Job *job; |
|
|
while (!jobFull && (job = (Job *)Lst_DeQueue(&stoppedJobs)) != NULL) { |
while (!jobFull && (job = (Job *)Lst_DeQueue(&stoppedJobs)) != NULL) { |
if (DEBUG(JOB)) { |
if (DEBUG(JOB)) { |
(void) fprintf(stdout, |
(void)fprintf(stdout, |
"Job queue is not full. Restarting a stopped job.\n"); |
"Job queue is not full. Restarting a stopped job.\n"); |
(void) fflush(stdout); |
(void)fflush(stdout); |
} |
} |
JobRestart(job); |
JobRestart(job); |
} |
} |