Files
seta75D 7c4988eac0 Init
2021-10-11 19:38:01 -03:00

403 lines
7.2 KiB
C
Executable File

#ident "@(#)fault.c 1.14 95/03/23 SMI" /* From AT&T Toolchest */
/*
* UNIX shell
*
* S. R. Bourne
* Rewritten by David Korn
* AT&T Bell Laboratories
*
*/
#include "defs.h"
#include "jobs.h"
#include "sym.h"
#include "timeout.h"
#ifdef SIGSTRINGS
extern char *strsignal(int);
#endif /* SIGSTRINGS */
/* ======== fault handling routines ======== */
#ifndef JOBS
# undef SIGCHLD
#endif /* JOBS */
/*
* Stop messages for jobs(1) under XPG4
*/
static char *xpg4_sigstop = "Stopped (SIGSTOP)";
static char *xpg4_sigtstp = "Stopped (SIGTSTP)";
static char *xpg4_sigttin = "Stopped (SIGTTIN)";
static char *xpg4_sigttou = "Stopped (SIGTTOU)";
void sh_fault(sig)
register int sig;
{
register int flag;
#ifdef OLDTERMIO
/* This .1 sec delay eliminates break key problems on 3b consoles */
# ifdef _poll_
if(sig==2)
poll("",0,100);
# endif /* _poll_ */
#endif /* OLDTERMIO */
#ifdef apollo
/*
* Since this routine only handles SIGCHLD, make SIGCLD look like
* a SIGCHLD. Since both signals are defined on an apollo.
*/
if(sig==SIGCLD)
sig = SIGCHLD;
#endif /* apollo */
#ifdef SIGCHLD
if(sig==SIGCHLD)
{
job.waitsafe++;
if(st.trapcom[SIGCHLD])
{
sh.trapnote |= SIGSLOW;
# ifndef SIG_NORESTART
if(st.intfn)
{
sigrelease(sig);
(*st.intfn)();
}
# endif /* SIG_NORESTART */
}
if (is_option(NOTIFY)) {
int save_outp = sh.curout; /* Save output stream */
p_setout(ERRIO);
job_walk(job_list,N_FLAG,(char**)0);
p_setout(save_outp); /* Restore the output stream */
}
return;
}
#endif /* SIGCHLD */
signal(sig, sh_fault);
if(sig==SIGALRM)
{
if((st.states&WAITING) && sh_timeout>0)
{
if(st.states&GRACE)
{
/* force exit */
st.states &= ~GRACE;
st.states |= FORKED;
sh_fail(e_timeout,NIL);
}
else
{
st.states |= GRACE;
alarm((unsigned)TGRACE);
p_str(e_timewarn,NL);
p_flush();
}
}
}
else
{
if(st.trapcom[sig])
flag = TRAPSET;
else
{
sh.lastsig = sig;
flag = SIGSET;
}
sh.trapnote |= flag;
st.trapflg[sig] |= flag;
if(sig <= SIGQUIT)
sh.trapnote |= SIGSLOW;
}
#ifndef SIG_NORESTART
/* This is needed because interrupted reads automatically restart */
if(st.intfn)
{
sigrelease(sig);
(*st.intfn)();
}
#endif /* SIG_NORESTART */
}
void sig_init()
{
register int i;
register int n;
register const struct sysnod *syscan = sig_names;
#ifdef SIGSTRINGS
register char *sd;
#endif /* SIGSTRINGS */
sig_begin();
while(*syscan->sysnam)
{
n = syscan->sysval;
i = n&((1<<SIGBITS)-1);
n >>= SIGBITS;
st.trapflg[--i] = (n&~SIGIGNORE);
if(n&SIGFAULT)
signal(i,(VOID(*)())sh_fault);
else if(n&SIGIGNORE)
sig_ignore(i);
else if(n&SIGCAUGHT)
sig_ontrap(i);
else if(n&SIGDONE)
{
sh.trapnote |= SIGBEGIN;
if(signal(i,(VOID(*)())sh_done)==SIG_IGN)
{
sig_ignore(i);
st.trapflg[i] = SIGOFF;
}
else
st.trapflg[i] = SIGMOD|SIGDONE;
sh.trapnote &= ~SIGBEGIN;
}
syscan++;
}
#ifndef SIGSTRINGS
for(syscan=sig_messages; n=syscan->sysval; syscan++)
{
if(n > NSIG+1)
continue;
if(*syscan->sysnam)
sh.sigmsg[n-1] = (char*)syscan->sysnam;
}
#else /* SIGSTRINGS */
for (n = 1; n < NSIG; n++) {
sd = strsignal(n);
if (sd)
sh.sigmsg[n] = sd;
}
/* XPG4: Job stop messages */
sh.sigmsg[SIGSTOP] = xpg4_sigstop;
sh.sigmsg[SIGTSTP] = xpg4_sigtstp;
sh.sigmsg[SIGTTIN] = xpg4_sigttin;
sh.sigmsg[SIGTTOU] = xpg4_sigttou;
#endif /* SIGSTRINGS */
}
/*
* set signal n to ignore
* returns 1 if signal was already ignored, 0 otherwise
*/
int sig_ignore(n)
register int n;
{
if(n < MAXTRAP-1 && !(st.trapflg[n]&SIGIGNORE))
{
if(signal(n,SIG_IGN) != SIG_IGN)
{
st.trapflg[n] |= SIGIGNORE;
st.trapflg[n] &= ~SIGFAULT;
return(0);
}
st.trapflg[n] = SIGOFF;
}
return(1);
}
/*
* Turn on trap handler for signal <n>
*/
void sig_ontrap(n)
register int n;
{
register int flag;
if(n==DEBUGTRAP)
sh.trapnote |= TRAPSET;
/* don't do anything if already set or off by parent */
else if(!(st.trapflg[n]&(SIGFAULT|SIGOFF)))
{
flag = st.trapflg[n];
if(signal(n,(VOID(*)())sh_fault)==SIG_IGN)
{
/* has it been set to ignore by shell */
if(flag&SIGIGNORE)
flag |= SIGFAULT;
else
{
/* It ignored already, keep it ignored */
sig_ignore(n);
flag = SIGOFF;
}
}
else
flag |= SIGFAULT;
flag &= ~(SIGSET|TRAPSET|SIGIGNORE|SIGMOD);
st.trapflg[n] = flag;
}
}
/*
* Restore to default signals
* Do not free the trap strings if flag is non-zero
*/
void sig_reset(flag)
{
register int i;
register char *t;
i=MAXTRAP;
while(i--)
{
t=st.trapcom[i];
if(t==0 || *t)
{
if(flag)
st.trapcom[i] = 0; /* don't free the traps */
sig_clear(i);
}
st.trapflg[i] &= ~(TRAPSET|SIGSET);
}
sh.trapnote=0;
}
/*
* reset traps at start of function execution
* keep track of which traps are caught by caller in case they are modified
* flag==0 before function, flag==1 after function
*/
void sig_funset(flag)
{
register int i;
register char *tp;
i=MAXTRAP;
while(i--)
{
tp = st.trapcom[i];
if(flag==0)
{
if(tp && *tp==0)
st.trapflg[i] = SIGOFF;
else
{
if(tp)
st.trapflg[i] |= SIGCAUGHT;
st.trapflg[i] &= ~(TRAPSET|SIGSET);
}
st.trapcom[i] = 0;
}
else if(tp)
sig_clear(i);
}
sh.trapnote = 0;
}
/*
* free up trap if set and restore signal handler if modified
*/
void sig_clear(n)
register int n;
{
register int flag = st.trapflg[n];
register char *t;
if(t=st.trapcom[n])
{
free(t);
st.trapcom[n]=0;
flag &= ~(TRAPSET|SIGSET);
}
if(flag&(SIGFAULT|SIGMOD|SIGIGNORE))
{
if(flag&SIGCAUGHT)
{
if(flag&(SIGMOD|SIGIGNORE))
signal(n, sh_fault);
}
else if((flag&SIGDONE))
{
if(t || (flag&SIGIGNORE))
signal(n, sh_done);
}
else
signal(n, SIG_DFL);
flag &= ~(SIGMOD|SIGFAULT|SIGIGNORE);
if(flag&SIGCAUGHT)
flag |= SIGFAULT;
else if(flag&SIGDONE)
flag |= SIGMOD;
}
st.trapflg[n] = flag;
if(n==SIGTERM && (st.states&INTFLG) && !(st.states&FORKED))
sig_ignore(SIGTERM);
}
/*
* check for traps
*/
void sh_chktrap()
{
register int i=MAXTRAP;
register char *t;
#ifdef JOBS
if(job.waitsafe)
job_wait((pid_t)0);
#endif /* JOBS */
/* process later if doing command substitution */
if(st.subflag)
return;
sh.trapnote &= ~(TRAPSET|SIGSLOW);
if((st.states&ERRFLG) && sh.exitval)
{
if(st.trapcom[ERRTRAP])
st.trapflg[ERRTRAP] = TRAPSET;
if(is_option(ERRFLG))
sh_exit(sh.exitval);
}
while(--i)
{
if(st.trapflg[i]&TRAPSET)
{
st.trapflg[i] &= ~TRAPSET;
if(t=st.trapcom[i])
{
int savxit=sh.exitval;
int sav_trapnote = sh.trapnote;
int savintrap = sh.intrap;
if(i==ERRTRAP)
sh.trapnote &= ~SIGSET;
sh.intrap = i + 1;
sh_eval(t);
sh.intrap = savintrap;
p_flush();
sh.exitval=savxit;
exitset();
sh.trapnote = sav_trapnote;
}
}
}
if(st.trapcom[DEBUGTRAP])
{
st.trapflg[DEBUGTRAP] |= TRAPSET;
sh.trapnote |= TRAPSET;
}
}
#ifdef signal
void
(*nsignal(sig, act))()
int sig;
void (*act)();
{
struct sigaction sa, osa;
sa.sa_handler = act;
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_RESTART;
if (sig == SIGCHLD) {
sa.sa_flags |= SA_NOCLDSTOP;
if (act == SIG_IGN)
sa.sa_flags |= SA_NOCLDWAIT;
}
if (sigaction(sig, &sa, &osa) < 0)
return ((void (*)())-1);
return (osa.sa_handler);
}
#endif