version 1.92, 2007/10/06 19:34:32 |
version 1.93, 2007/10/09 09:32:03 |
|
|
* Each job has several things associated with it: |
* Each job has several things associated with it: |
* 1) The process id of the child shell |
* 1) The process id of the child shell |
* 2) The graph node describing the target being made by this job |
* 2) The graph node describing the target being made by this job |
* 3) A LstNode for the first command to be saved after the job |
* 3) An FILE* for writing out the commands. This is only |
* completes. This is NULL if there was no "..." in the job's |
|
* commands. |
|
* 4) An FILE* for writing out the commands. This is only |
|
* used before the job is actually started. |
* used before the job is actually started. |
* 5) Things used for handling the shell's output. |
* 4) Things used for handling the shell's output. |
* the output is being caught via a pipe and |
* the output is being caught via a pipe and |
* the descriptors of our pipe, an array in which output is line |
* the descriptors of our pipe, an array in which output is line |
* buffered and the current position in that buffer are all |
* buffered and the current position in that buffer are all |
* maintained for each job. |
* maintained for each job. |
* 6) An identifier provided by and for the exclusive use of the |
* 5) A word of flags which determine how the module handles errors, |
* Rmt module. |
|
* 7) A word of flags which determine how the module handles errors, |
|
* echoing, etc. for the job |
* echoing, etc. for the job |
* |
* |
* The job "table" is kept as a linked Lst in 'jobs', with the number of |
* The job "table" is kept as a linked Lst in 'jobs', with the number of |
|
|
#define W_SETEXITSTATUS(st, val) W_SETMASKED(st, val, WEXITSTATUS) |
#define W_SETEXITSTATUS(st, val) W_SETMASKED(st, val, WEXITSTATUS) |
|
|
|
|
static void JobCondPassSig(void *, void *); |
static void pass_signal_to_job(void *, void *); |
static void SigHandler(int); |
static void SigHandler(int); |
static void HandleSigs(void); |
static void handle_all_signals(void); |
static void JobPassSig(int); |
static void handle_signal(int); |
static int JobCmpPid(void *, void *); |
static int JobCmpPid(void *, void *); |
static int JobPrintCommand(LstNode, void *); |
static int JobPrintCommand(LstNode, void *); |
static void JobSaveCommand(void *, void *); |
static void JobSaveCommand(void *, void *); |
|
|
static void DBPRINTF(Job *, const char *, ...); |
static void DBPRINTF(Job *, const char *, ...); |
static void debug_printf(const char *, ...); |
static void debug_printf(const char *, ...); |
static FILE *new_command_file(void); |
static FILE *new_command_file(void); |
|
static void setup_signal(int); |
|
|
|
static volatile sig_atomic_t got_signal; |
|
|
static volatile sig_atomic_t got_SIGINT, got_SIGHUP, got_SIGQUIT, |
static volatile sig_atomic_t got_SIGINT, got_SIGHUP, got_SIGQUIT, |
got_SIGTERM; |
got_SIGTERM, got_SIGTSTP, got_SIGTTOU, got_SIGTTIN, got_SIGWINCH; |
#if defined(USE_PGRP) |
|
static volatile sig_atomic_t got_SIGTSTP, got_SIGTTOU, got_SIGTTIN, |
|
got_SIGWINCH; |
|
#endif |
|
|
|
|
|
#define TMPPAT "/tmp/makeXXXXXXXXXX" |
#define TMPPAT "/tmp/makeXXXXXXXXXX" |
|
|
static FILE * |
static FILE * |
|
|
switch(sig) { |
switch(sig) { |
case SIGINT: |
case SIGINT: |
got_SIGINT++; |
got_SIGINT++; |
|
got_signal = 1; |
break; |
break; |
case SIGHUP: |
case SIGHUP: |
got_SIGHUP++; |
got_SIGHUP++; |
|
got_signal = 1; |
break; |
break; |
case SIGQUIT: |
case SIGQUIT: |
got_SIGQUIT++; |
got_SIGQUIT++; |
|
got_signal = 1; |
break; |
break; |
case SIGTERM: |
case SIGTERM: |
got_SIGTERM++; |
got_SIGTERM++; |
|
got_signal = 1; |
break; |
break; |
#if defined(USE_PGRGP) |
#ifdef USE_PGRP |
case SIGTSTP: |
case SIGTSTP: |
got_SIGTSTP++; |
got_SIGTSTP++; |
|
got_signal = 1; |
break; |
break; |
case SIGTTOU: |
case SIGTTOU: |
got_SIGTTOU++; |
got_SIGTTOU++; |
|
got_signal = 1; |
break; |
break; |
case SIGTTIN: |
case SIGTTIN: |
got_SIGTTIN++; |
got_SIGTTIN++; |
|
got_signal = 1; |
break; |
break; |
case SIGWINCH: |
case SIGWINCH: |
got_SIGWINCH++; |
got_SIGWINCH++; |
|
got_signal = 1; |
break; |
break; |
#endif |
#endif |
} |
} |
} |
} |
|
|
static void |
static void |
HandleSigs() |
handle_all_signals() |
{ |
{ |
|
if (got_signal) |
|
got_signal = 0; |
|
else |
|
return; |
|
|
if (got_SIGINT) { |
if (got_SIGINT) { |
got_SIGINT=0; |
got_SIGINT=0; |
JobPassSig(SIGINT); |
handle_signal(SIGINT); |
} |
} |
if (got_SIGHUP) { |
if (got_SIGHUP) { |
got_SIGHUP=0; |
got_SIGHUP=0; |
JobPassSig(SIGHUP); |
handle_signal(SIGHUP); |
} |
} |
if (got_SIGQUIT) { |
if (got_SIGQUIT) { |
got_SIGQUIT=0; |
got_SIGQUIT=0; |
JobPassSig(SIGQUIT); |
handle_signal(SIGQUIT); |
} |
} |
if (got_SIGTERM) { |
if (got_SIGTERM) { |
got_SIGTERM=0; |
got_SIGTERM=0; |
JobPassSig(SIGTERM); |
handle_signal(SIGTERM); |
} |
} |
#if defined(USE_PGRP) |
|
if (got_SIGTSTP) { |
if (got_SIGTSTP) { |
got_SIGTSTP=0; |
got_SIGTSTP=0; |
JobPassSig(SIGTSTP); |
handle_signal(SIGTSTP); |
} |
} |
if (got_SIGTTOU) { |
if (got_SIGTTOU) { |
got_SIGTTOU=0; |
got_SIGTTOU=0; |
JobPassSig(SIGTTOU); |
handle_signal(SIGTTOU); |
} |
} |
if (got_SIGTTIN) { |
if (got_SIGTTIN) { |
got_SIGTTIN=0; |
got_SIGTTIN=0; |
JobPassSig(SIGTTIN); |
handle_signal(SIGTTIN); |
} |
} |
if (got_SIGWINCH) { |
if (got_SIGWINCH) { |
got_SIGWINCH=0; |
got_SIGWINCH=0; |
JobPassSig(SIGWINCH); |
handle_signal(SIGWINCH); |
} |
} |
#endif |
|
} |
} |
|
|
/*- |
/*- |
|
|
*----------------------------------------------------------------------- |
*----------------------------------------------------------------------- |
*/ |
*/ |
static void |
static void |
JobCondPassSig(void *jobp, /* Job to biff */ |
pass_signal_to_job(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; |
if (DEBUG(JOB)) { |
if (DEBUG(JOB)) { |
(void)fprintf(stdout, |
(void)fprintf(stdout, |
"JobCondPassSig passing signal %d to child %ld.\n", |
"pass_signal_to_job passing signal %d to child %ld.\n", |
signo, (long)job->pid); |
signo, (long)job->pid); |
(void)fflush(stdout); |
(void)fflush(stdout); |
} |
} |
|
|
*----------------------------------------------------------------------- |
*----------------------------------------------------------------------- |
*/ |
*/ |
static void |
static void |
JobPassSig(int signo) /* The signal number we've received */ |
handle_signal(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, "handle_signal(%d) called.\n", signo); |
(void)fflush(stdout); |
(void)fflush(stdout); |
} |
} |
Lst_ForEach(&jobs, JobCondPassSig, &signo); |
Lst_ForEach(&jobs, pass_signal_to_job, &signo); |
|
|
/* |
/* |
* Deal with proper cleanup based on the signal received. We only run |
* Deal with proper cleanup based on the signal received. We only run |
|
|
|
|
if (DEBUG(JOB)) { |
if (DEBUG(JOB)) { |
(void)fprintf(stdout, |
(void)fprintf(stdout, |
"JobPassSig passing signal to self, mask = %x.\n", |
"handle_signal passing signal to self, mask = %x.\n", |
~0 & ~(1 << (signo-1))); |
~0 & ~(1 << (signo-1))); |
(void)fflush(stdout); |
(void)fflush(stdout); |
} |
} |
|
|
(void)KILL(getpid(), signo); |
(void)KILL(getpid(), signo); |
|
|
signo = SIGCONT; |
signo = SIGCONT; |
Lst_ForEach(&jobs, JobCondPassSig, &signo); |
Lst_ForEach(&jobs, pass_signal_to_job, &signo); |
|
|
(void)sigprocmask(SIG_SETMASK, &omask, NULL); |
(void)sigprocmask(SIG_SETMASK, &omask, NULL); |
sigprocmask(SIG_SETMASK, &omask, NULL); |
sigprocmask(SIG_SETMASK, &omask, NULL); |
|
|
} |
} |
|
|
while ((pid = waitpid((pid_t) -1, &status, WNOHANG|WUNTRACED)) > 0) { |
while ((pid = waitpid((pid_t) -1, &status, WNOHANG|WUNTRACED)) > 0) { |
HandleSigs(); |
handle_all_signals(); |
debug_printf("Process %ld exited or stopped.\n", (long)pid); |
debug_printf("Process %ld exited or stopped.\n", (long)pid); |
|
|
jnode = Lst_Find(&jobs, JobCmpPid, &pid); |
jnode = Lst_Find(&jobs, JobCmpPid, &pid); |
|
|
timeout.tv_usec = SEL_USEC; |
timeout.tv_usec = SEL_USEC; |
|
|
nfds = select(outputsn+1, readfdsp, NULL, NULL, &timeout); |
nfds = select(outputsn+1, readfdsp, NULL, NULL, &timeout); |
HandleSigs(); |
handle_all_signals(); |
if (nfds > 0) { |
if (nfds > 0) { |
for (ln = Lst_First(&jobs); nfds && ln != NULL; |
for (ln = Lst_First(&jobs); nfds && ln != NULL; |
ln = Lst_Adv(ln)) { |
ln = Lst_Adv(ln)) { |
|
|
(void)JobStart(gn, 0); |
(void)JobStart(gn, 0); |
} |
} |
|
|
|
static void |
|
setup_signal(int sig) |
|
{ |
|
if (signal(sig, SIG_IGN) != SIG_IGN) { |
|
(void)signal(sig, SigHandler); |
|
} |
|
} |
|
|
/*- |
/*- |
*----------------------------------------------------------------------- |
*----------------------------------------------------------------------- |
* Job_Init -- |
* Job_Init -- |
|
|
* Catch the four signals that POSIX specifies if they aren't ignored. |
* Catch the four signals that POSIX specifies if they aren't ignored. |
* 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) { |
setup_signal(SIGINT); |
(void)signal(SIGINT, SigHandler); |
setup_signal(SIGHUP); |
} |
setup_signal(SIGQUIT); |
if (signal(SIGHUP, SIG_IGN) != SIG_IGN) { |
setup_signal(SIGTERM); |
(void)signal(SIGHUP, SigHandler); |
|
} |
|
if (signal(SIGQUIT, SIG_IGN) != SIG_IGN) { |
|
(void)signal(SIGQUIT, SigHandler); |
|
} |
|
if (signal(SIGTERM, SIG_IGN) != SIG_IGN) { |
|
(void)signal(SIGTERM, SigHandler); |
|
} |
|
/* |
/* |
* There are additional signals that need to be caught and passed if |
* There are additional signals that need to be caught and passed if |
* either the export system wants to be told directly of signals or if |
* either the export system wants to be told directly of signals or if |
|
|
* signals from the terminal driver as we own the terminal) |
* signals from the terminal driver as we own the terminal) |
*/ |
*/ |
#if defined(USE_PGRP) |
#if defined(USE_PGRP) |
if (signal(SIGTSTP, SIG_IGN) != SIG_IGN) { |
setup_signal(SIGTSTP); |
(void)signal(SIGTSTP, SigHandler); |
setup_signal(SIGTTOU); |
} |
setup_signal(SIGTTIN); |
if (signal(SIGTTOU, SIG_IGN) != SIG_IGN) { |
setup_signal(SIGWINCH); |
(void)signal(SIGTTOU, SigHandler); |
|
} |
|
if (signal(SIGTTIN, SIG_IGN) != SIG_IGN) { |
|
(void)signal(SIGTTIN, SigHandler); |
|
} |
|
if (signal(SIGWINCH, SIG_IGN) != SIG_IGN) { |
|
(void)signal(SIGWINCH, SigHandler); |
|
} |
|
#endif |
#endif |
|
|
if ((begin_node->type & OP_DUMMY) == 0) { |
if ((begin_node->type & OP_DUMMY) == 0) { |