mirror of
git://git.code.sf.net/p/cdesktopenv/code
synced 2025-03-09 15:50:02 +00:00
This trap failed to be restored correctly when being trapped in a subshell, causing corruption or a crash when restoring the parent shell environment's trap upon leaving the subshell. Thanks to Koichi Nakashima for the report and reproducer. src/cmd/ksh93/sh/fault.c: sh_sigreset(): - Fix an off-by-one error in the loop that restores the pseudosignal traps. src/cmd/ksh93/tests/basic.sh: - Test overwriting the main shell trap in a subshell for all pseudosignals. Makes progress on: https://github.com/ksh93/ksh/issues/155
677 lines
15 KiB
C
677 lines
15 KiB
C
/***********************************************************************
|
|
* *
|
|
* This software is part of the ast package *
|
|
* Copyright (c) 1982-2012 AT&T Intellectual Property *
|
|
* and is licensed under the *
|
|
* Eclipse Public License, Version 1.0 *
|
|
* by AT&T Intellectual Property *
|
|
* *
|
|
* A copy of the License is available at *
|
|
* http://www.eclipse.org/org/documents/epl-v10.html *
|
|
* (with md5 checksum b35adb5213ca9657e911e9befb180842) *
|
|
* *
|
|
* Information and Software Systems Research *
|
|
* AT&T Research *
|
|
* Florham Park NJ *
|
|
* *
|
|
* David Korn <dgk@research.att.com> *
|
|
* *
|
|
***********************************************************************/
|
|
#pragma prototyped
|
|
/*
|
|
* Fault handling routines
|
|
*
|
|
* David Korn
|
|
* AT&T Labs
|
|
*
|
|
*/
|
|
|
|
#include "defs.h"
|
|
#include <fcin.h>
|
|
#include "io.h"
|
|
#include "history.h"
|
|
#include "shlex.h"
|
|
#include "variables.h"
|
|
#include "jobs.h"
|
|
#include "path.h"
|
|
#include "builtins.h"
|
|
#include "ulimit.h"
|
|
|
|
#define abortsig(sig) (sig==SIGABRT || sig==SIGBUS || sig==SIGILL || sig==SIGSEGV)
|
|
|
|
static char indone;
|
|
static int cursig = -1;
|
|
|
|
#if !_std_malloc
|
|
# include <vmalloc.h>
|
|
#endif
|
|
#if defined(VMFL)
|
|
/*
|
|
* This exception handler is called after vmalloc() unlocks the region
|
|
*/
|
|
static int malloc_done(Vmalloc_t* vm, int type, Void_t* val, Vmdisc_t* dp)
|
|
{
|
|
dp->exceptf = 0;
|
|
sh_exit(SH_EXITSIG);
|
|
return(0);
|
|
}
|
|
#endif
|
|
|
|
/*
|
|
* Most signals caught or ignored by the shell come here
|
|
*/
|
|
void sh_fault(register int sig)
|
|
{
|
|
register Shell_t *shp = sh_getinterp();
|
|
register int flag=0;
|
|
register char *trap;
|
|
register struct checkpt *pp = (struct checkpt*)shp->jmplist;
|
|
int action=0;
|
|
/* reset handler */
|
|
if(!(sig&SH_TRAP))
|
|
signal(sig, sh_fault);
|
|
sig &= ~SH_TRAP;
|
|
#ifdef SIGWINCH
|
|
if(sig==SIGWINCH)
|
|
{
|
|
int rows=0, cols=0;
|
|
int32_t v;
|
|
astwinsize(2,&rows,&cols);
|
|
if(v = cols)
|
|
nv_putval(COLUMNS, (char*)&v, NV_INT32|NV_RDONLY);
|
|
if(v = rows)
|
|
nv_putval(LINES, (char*)&v, NV_INT32|NV_RDONLY);
|
|
shp->winch++;
|
|
}
|
|
#endif /* SIGWINCH */
|
|
trap = shp->st.trapcom[sig];
|
|
if(shp->savesig)
|
|
{
|
|
/* critical region, save and process later */
|
|
if(!(shp->sigflag[sig]&SH_SIGIGNORE))
|
|
shp->savesig = sig;
|
|
return;
|
|
}
|
|
if(sig==SIGALRM && shp->bltinfun==b_sleep)
|
|
{
|
|
if(trap && *trap)
|
|
{
|
|
shp->trapnote |= SH_SIGTRAP;
|
|
shp->sigflag[sig] |= SH_SIGTRAP;
|
|
}
|
|
return;
|
|
}
|
|
if(shp->subshell && trap && sig!=SIGINT && sig!=SIGQUIT && sig!=SIGWINCH && sig!=SIGCONT)
|
|
{
|
|
shp->exitval = SH_EXITSIG|sig;
|
|
sh_subfork();
|
|
shp->exitval = 0;
|
|
return;
|
|
}
|
|
/* handle ignored signals */
|
|
if(trap && *trap==0)
|
|
return;
|
|
flag = shp->sigflag[sig]&~SH_SIGOFF;
|
|
if(!trap)
|
|
{
|
|
if(sig==SIGINT && (shp->trapnote&SH_SIGIGNORE))
|
|
return;
|
|
if(flag&SH_SIGIGNORE)
|
|
{
|
|
if(shp->subshell)
|
|
shp->ignsig = sig;
|
|
sigrelease(sig);
|
|
return;
|
|
}
|
|
if(flag&SH_SIGDONE)
|
|
{
|
|
void *ptr=0;
|
|
if((flag&SH_SIGINTERACTIVE) && sh_isstate(SH_INTERACTIVE) && !sh_isstate(SH_FORKED) && ! shp->subshell)
|
|
{
|
|
/* check for TERM signal between fork/exec */
|
|
if(sig==SIGTERM && job.in_critical)
|
|
shp->trapnote |= SH_SIGTERM;
|
|
return;
|
|
}
|
|
shp->lastsig = sig;
|
|
sigrelease(sig);
|
|
if(pp->mode != SH_JMPSUB)
|
|
{
|
|
if(pp->mode < SH_JMPSUB)
|
|
pp->mode = shp->subshell?SH_JMPSUB:SH_JMPFUN;
|
|
else
|
|
pp->mode = SH_JMPEXIT;
|
|
}
|
|
if(shp->subshell)
|
|
sh_exit(SH_EXITSIG);
|
|
if(sig==SIGABRT || (abortsig(sig) && (ptr = malloc(1))))
|
|
{
|
|
if(ptr)
|
|
free(ptr);
|
|
sh_done(shp,sig);
|
|
}
|
|
/* mark signal and continue */
|
|
shp->trapnote |= SH_SIGSET;
|
|
if(sig <= shp->gd->sigmax)
|
|
shp->sigflag[sig] |= SH_SIGSET;
|
|
#if defined(VMFL)
|
|
if(abortsig(sig))
|
|
{
|
|
/* abort inside malloc, process when malloc returns */
|
|
/* VMFL defined when using vmalloc() */
|
|
Vmdisc_t* dp = vmdisc(Vmregion,0);
|
|
if(dp)
|
|
dp->exceptf = malloc_done;
|
|
}
|
|
#endif
|
|
return;
|
|
}
|
|
}
|
|
errno = 0;
|
|
if(pp->mode==SH_JMPCMD || (pp->mode==1 && shp->bltinfun) && !(flag&SH_SIGIGNORE))
|
|
shp->lastsig = sig;
|
|
if(trap)
|
|
{
|
|
/*
|
|
* propagate signal to foreground group
|
|
*/
|
|
if(sig==SIGHUP && job.curpgid)
|
|
killpg(job.curpgid,SIGHUP);
|
|
flag = SH_SIGTRAP;
|
|
}
|
|
else
|
|
{
|
|
shp->lastsig = sig;
|
|
flag = SH_SIGSET;
|
|
#ifdef SIGTSTP
|
|
if(sig==SIGTSTP)
|
|
{
|
|
shp->trapnote |= SH_SIGTSTP;
|
|
if(pp->mode==SH_JMPCMD && sh_isstate(SH_STOPOK))
|
|
{
|
|
sigrelease(sig);
|
|
sh_exit(SH_EXITSIG);
|
|
return;
|
|
}
|
|
}
|
|
#endif /* SIGTSTP */
|
|
}
|
|
#ifdef ERROR_NOTIFY
|
|
if((error_info.flags&ERROR_NOTIFY) && shp->bltinfun)
|
|
action = (*shp->bltinfun)(-sig,(char**)0,(void*)0);
|
|
if(action>0)
|
|
return;
|
|
#endif
|
|
if(shp->bltinfun && shp->bltindata.notify)
|
|
{
|
|
shp->bltindata.sigset = 1;
|
|
return;
|
|
}
|
|
shp->trapnote |= flag;
|
|
if(sig <= shp->gd->sigmax)
|
|
shp->sigflag[sig] |= flag;
|
|
if(pp->mode==SH_JMPCMD && sh_isstate(SH_STOPOK))
|
|
{
|
|
if(action<0)
|
|
return;
|
|
sigrelease(sig);
|
|
sh_exit(SH_EXITSIG);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* initialize signal handling
|
|
*/
|
|
void sh_siginit(void *ptr)
|
|
{
|
|
Shell_t *shp = (Shell_t*)ptr;
|
|
register int sig, n;
|
|
register const struct shtable2 *tp = shtab_signals;
|
|
sig_begin();
|
|
/* find the largest signal number in the table */
|
|
#if defined(SIGRTMIN) && defined(SIGRTMAX)
|
|
if ((n = SIGRTMIN) > 0 && (sig = SIGRTMAX) > n && sig < SH_TRAP)
|
|
{
|
|
shp->gd->sigruntime[SH_SIGRTMIN] = n;
|
|
shp->gd->sigruntime[SH_SIGRTMAX] = sig;
|
|
}
|
|
#endif /* SIGRTMIN && SIGRTMAX */
|
|
n = SIGTERM;
|
|
while(*tp->sh_name)
|
|
{
|
|
sig = (tp->sh_number&((1<<SH_SIGBITS)-1));
|
|
if (!(sig-- & SH_TRAP))
|
|
{
|
|
if ((tp->sh_number>>SH_SIGBITS) & SH_SIGRUNTIME)
|
|
sig = shp->gd->sigruntime[sig];
|
|
if(sig>n && sig<SH_TRAP)
|
|
n = sig;
|
|
}
|
|
tp++;
|
|
}
|
|
shp->gd->sigmax = n++;
|
|
shp->st.trapcom = (char**)calloc(n,sizeof(char*));
|
|
shp->sigflag = (unsigned char*)calloc(n,1);
|
|
shp->gd->sigmsg = (char**)calloc(n,sizeof(char*));
|
|
for(tp=shtab_signals; sig=tp->sh_number; tp++)
|
|
{
|
|
n = (sig>>SH_SIGBITS);
|
|
if((sig &= ((1<<SH_SIGBITS)-1)) > (shp->gd->sigmax+1))
|
|
continue;
|
|
sig--;
|
|
if(n&SH_SIGRUNTIME)
|
|
sig = shp->gd->sigruntime[sig];
|
|
if(sig>=0)
|
|
{
|
|
shp->sigflag[sig] = n;
|
|
if(*tp->sh_name)
|
|
shp->gd->sigmsg[sig] = (char*)tp->sh_value;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Turn on trap handler for signal <sig>
|
|
*/
|
|
void sh_sigtrap(register int sig)
|
|
{
|
|
register int flag;
|
|
void (*fun)(int);
|
|
sh.st.otrapcom = 0;
|
|
if(sig==0)
|
|
sh_sigdone();
|
|
else if(!((flag=sh.sigflag[sig])&(SH_SIGFAULT|SH_SIGOFF)))
|
|
{
|
|
/* don't set signal if already set or off by parent */
|
|
if((fun=signal(sig,sh_fault))==SIG_IGN)
|
|
{
|
|
signal(sig,SIG_IGN);
|
|
flag |= SH_SIGOFF;
|
|
}
|
|
else
|
|
{
|
|
flag |= SH_SIGFAULT;
|
|
if(sig==SIGALRM && fun!=SIG_DFL && fun!=sh_fault)
|
|
signal(sig,fun);
|
|
}
|
|
flag &= ~(SH_SIGSET|SH_SIGTRAP);
|
|
sh.sigflag[sig] = flag;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* set signal handler so sh_done is called for all caught signals
|
|
*/
|
|
void sh_sigdone(void)
|
|
{
|
|
register int flag, sig = shgd->sigmax;
|
|
sh.sigflag[0] |= SH_SIGFAULT;
|
|
for(sig=shgd->sigmax; sig>0; sig--)
|
|
{
|
|
flag = sh.sigflag[sig];
|
|
if((flag&(SH_SIGDONE|SH_SIGIGNORE|SH_SIGINTERACTIVE)) && !(flag&(SH_SIGFAULT|SH_SIGOFF)))
|
|
sh_sigtrap(sig);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Restore to default signals
|
|
* Free the trap strings if mode is non-zero
|
|
* If mode>1 then ignored traps cause signal to be ignored
|
|
*/
|
|
void sh_sigreset(register int mode)
|
|
{
|
|
register char *trap;
|
|
register int flag, sig=sh.st.trapmax;
|
|
while(sig-- > 0)
|
|
{
|
|
if(trap=sh.st.trapcom[sig])
|
|
{
|
|
flag = sh.sigflag[sig]&~(SH_SIGTRAP|SH_SIGSET);
|
|
if(*trap)
|
|
{
|
|
if(mode)
|
|
free(trap);
|
|
sh.st.trapcom[sig] = 0;
|
|
}
|
|
else if(sig && mode>1)
|
|
{
|
|
if(sig!=SIGCHLD)
|
|
signal(sig,SIG_IGN);
|
|
flag &= ~SH_SIGFAULT;
|
|
flag |= SH_SIGOFF;
|
|
}
|
|
sh.sigflag[sig] = flag;
|
|
}
|
|
}
|
|
for(sig=SH_DEBUGTRAP; sig>=0; sig--)
|
|
{
|
|
if(trap=sh.st.trap[sig])
|
|
{
|
|
if(mode)
|
|
free(trap);
|
|
sh.st.trap[sig] = 0;
|
|
}
|
|
|
|
}
|
|
sh.st.trapcom[0] = 0;
|
|
if(mode)
|
|
sh.st.trapmax = 0;
|
|
sh.trapnote=0;
|
|
}
|
|
|
|
/*
|
|
* free up trap if set and restore signal handler if modified
|
|
*/
|
|
void sh_sigclear(register int sig)
|
|
{
|
|
register int flag = sh.sigflag[sig];
|
|
register char *trap;
|
|
sh.st.otrapcom=0;
|
|
if(!(flag&SH_SIGFAULT))
|
|
return;
|
|
flag &= ~(SH_SIGTRAP|SH_SIGSET);
|
|
if(trap=sh.st.trapcom[sig])
|
|
{
|
|
if(!sh.subshell)
|
|
free(trap);
|
|
sh.st.trapcom[sig]=0;
|
|
}
|
|
sh.sigflag[sig] = flag;
|
|
}
|
|
|
|
/*
|
|
* check for traps
|
|
*/
|
|
|
|
void sh_chktrap(Shell_t* shp)
|
|
{
|
|
register int sig=shp->st.trapmax;
|
|
register char *trap;
|
|
if(!(shp->trapnote&~SH_SIGIGNORE))
|
|
sig=0;
|
|
shp->trapnote &= ~SH_SIGTRAP;
|
|
/* execute errexit trap first */
|
|
if(sh_isstate(SH_ERREXIT) && shp->exitval)
|
|
{
|
|
int sav_trapnote = shp->trapnote;
|
|
shp->trapnote &= ~SH_SIGSET;
|
|
if(shp->st.trap[SH_ERRTRAP])
|
|
{
|
|
trap = shp->st.trap[SH_ERRTRAP];
|
|
shp->st.trap[SH_ERRTRAP] = 0;
|
|
sh_trap(trap,0);
|
|
shp->st.trap[SH_ERRTRAP] = trap;
|
|
}
|
|
shp->trapnote = sav_trapnote;
|
|
if(sh_isoption(SH_ERREXIT))
|
|
{
|
|
struct checkpt *pp = (struct checkpt*)shp->jmplist;
|
|
pp->mode = SH_JMPEXIT;
|
|
sh_exit(shp->exitval);
|
|
}
|
|
}
|
|
if(shp->sigflag[SIGALRM]&SH_SIGALRM)
|
|
sh_timetraps(shp);
|
|
#ifdef SHOPT_BGX
|
|
if((shp->sigflag[SIGCHLD]&SH_SIGTRAP) && shp->st.trapcom[SIGCHLD])
|
|
job_chldtrap(shp,shp->st.trapcom[SIGCHLD],1);
|
|
#endif /* SHOPT_BGX */
|
|
while(--sig>=0)
|
|
{
|
|
if(sig==cursig)
|
|
continue;
|
|
#ifdef SHOPT_BGX
|
|
if(sig==SIGCHLD)
|
|
continue;
|
|
#endif /* SHOPT_BGX */
|
|
if(shp->sigflag[sig]&SH_SIGTRAP)
|
|
{
|
|
shp->sigflag[sig] &= ~SH_SIGTRAP;
|
|
if(trap=shp->st.trapcom[sig])
|
|
{
|
|
cursig = sig;
|
|
sh_trap(trap,0);
|
|
cursig = -1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* parse and execute the given trap string, stream or tree depending on mode
|
|
* mode==0 for string, mode==1 for stream, mode==2 for parse tree
|
|
*/
|
|
int sh_trap(const char *trap, int mode)
|
|
{
|
|
Shell_t *shp = sh_getinterp();
|
|
int jmpval, savxit = shp->exitval;
|
|
int was_history = sh_isstate(SH_HISTORY);
|
|
int was_verbose = sh_isstate(SH_VERBOSE);
|
|
int staktop = staktell();
|
|
char *savptr = stakfreeze(0);
|
|
char ifstable[256];
|
|
struct checkpt buff;
|
|
Fcin_t savefc;
|
|
fcsave(&savefc);
|
|
memcpy(ifstable,shp->ifstable,sizeof(ifstable));
|
|
sh_offstate(SH_HISTORY);
|
|
sh_offstate(SH_VERBOSE);
|
|
shp->intrap++;
|
|
sh_pushcontext(shp,&buff,SH_JMPTRAP);
|
|
jmpval = sigsetjmp(buff.buff,0);
|
|
if(jmpval == 0)
|
|
{
|
|
if(mode==2)
|
|
sh_exec((Shnode_t*)trap,sh_isstate(SH_ERREXIT));
|
|
else
|
|
{
|
|
Sfio_t *sp;
|
|
if(mode)
|
|
sp = (Sfio_t*)trap;
|
|
else
|
|
sp = sfopen(NIL(Sfio_t*),trap,"s");
|
|
sh_eval(sp,0);
|
|
}
|
|
}
|
|
else if(indone)
|
|
{
|
|
if(jmpval==SH_JMPSCRIPT)
|
|
indone=0;
|
|
else
|
|
{
|
|
if(jmpval==SH_JMPEXIT)
|
|
savxit = shp->exitval;
|
|
jmpval=SH_JMPTRAP;
|
|
}
|
|
}
|
|
sh_popcontext(shp,&buff);
|
|
shp->intrap--;
|
|
sfsync(shp->outpool);
|
|
if(jmpval!=SH_JMPEXIT && jmpval!=SH_JMPFUN)
|
|
shp->exitval=savxit;
|
|
stakset(savptr,staktop);
|
|
fcrestore(&savefc);
|
|
memcpy(shp->ifstable,ifstable,sizeof(ifstable));
|
|
if(was_history)
|
|
sh_onstate(SH_HISTORY);
|
|
if(was_verbose)
|
|
sh_onstate(SH_VERBOSE);
|
|
exitset();
|
|
if(jmpval>SH_JMPTRAP && (((struct checkpt*)shp->jmpbuffer)->prev || ((struct checkpt*)shp->jmpbuffer)->mode==SH_JMPSCRIPT))
|
|
siglongjmp(*shp->jmplist,jmpval);
|
|
return(shp->exitval);
|
|
}
|
|
|
|
/*
|
|
* exit the current scope and jump to an earlier one based on pp->mode
|
|
*/
|
|
void sh_exit(register int xno)
|
|
{
|
|
Shell_t *shp = sh_getinterp();
|
|
register struct checkpt *pp = (struct checkpt*)shp->jmplist;
|
|
register int sig=0;
|
|
register Sfio_t* pool;
|
|
shp->exitval=xno;
|
|
if(xno==SH_EXITSIG)
|
|
shp->exitval |= (sig=shp->lastsig);
|
|
if(pp && pp->mode>1)
|
|
cursig = -1;
|
|
#ifdef SIGTSTP
|
|
if((shp->trapnote&SH_SIGTSTP) && job.jobcontrol)
|
|
{
|
|
/* ^Z detected by the shell */
|
|
shp->trapnote = 0;
|
|
shp->sigflag[SIGTSTP] = 0;
|
|
if(!shp->subshell && sh_isstate(SH_MONITOR) && !sh_isstate(SH_STOPOK))
|
|
return;
|
|
if(sh_isstate(SH_TIMING))
|
|
return;
|
|
/* Handles ^Z for shell builtins, subshells, and functs */
|
|
shp->lastsig = 0;
|
|
sh_onstate(SH_MONITOR);
|
|
sh_offstate(SH_STOPOK);
|
|
shp->trapnote = 0;
|
|
shp->forked = 1;
|
|
if(!shp->subshell && (sig=sh_fork(shp,0,NIL(int*))))
|
|
{
|
|
job.curpgid = 0;
|
|
job.parent = (pid_t)-1;
|
|
job_wait(sig);
|
|
shp->forked = 0;
|
|
job.parent = 0;
|
|
shp->sigflag[SIGTSTP] = 0;
|
|
/* wait for child to stop */
|
|
shp->exitval = (SH_EXITSIG|SIGTSTP);
|
|
/* return to prompt mode */
|
|
pp->mode = SH_JMPERREXIT;
|
|
}
|
|
else
|
|
{
|
|
if(shp->subshell)
|
|
sh_subfork();
|
|
/* child process, put to sleep */
|
|
sh_offstate(SH_STOPOK);
|
|
sh_offstate(SH_MONITOR);
|
|
shp->sigflag[SIGTSTP] = 0;
|
|
/* stop child job */
|
|
killpg(job.curpgid,SIGTSTP);
|
|
/* child resumes */
|
|
job_clear();
|
|
shp->exitval = (xno&SH_EXITMASK);
|
|
return;
|
|
}
|
|
}
|
|
#endif /* SIGTSTP */
|
|
/* unlock output pool */
|
|
sh_offstate(SH_NOTRACK);
|
|
if(!(pool=sfpool(NIL(Sfio_t*),shp->outpool,SF_WRITE)))
|
|
pool = shp->outpool; /* can't happen? */
|
|
sfclrlock(pool);
|
|
#ifdef SIGPIPE
|
|
if(shp->lastsig==SIGPIPE)
|
|
sfpurge(pool);
|
|
#endif /* SIGPIPE */
|
|
sfclrlock(sfstdin);
|
|
if(!pp)
|
|
sh_done(shp,sig);
|
|
shp->prefix = 0;
|
|
#if SHOPT_TYPEDEF
|
|
shp->mktype = 0;
|
|
#endif /* SHOPT_TYPEDEF*/
|
|
if(job.in_critical)
|
|
job_unlock();
|
|
if(pp->mode == SH_JMPSCRIPT && !pp->prev)
|
|
sh_done(shp,sig);
|
|
if(pp->mode)
|
|
siglongjmp(pp->buff,pp->mode);
|
|
}
|
|
|
|
static void array_notify(Namval_t *np, void *data)
|
|
{
|
|
Namarr_t *ap = nv_arrayptr(np);
|
|
NOT_USED(data);
|
|
if(ap && ap->fun)
|
|
(*ap->fun)(np, 0, NV_AFREE);
|
|
}
|
|
|
|
/*
|
|
* This is the exit routine for the shell
|
|
*/
|
|
|
|
void sh_done(void *ptr, register int sig)
|
|
{
|
|
Shell_t *shp = (Shell_t*)ptr;
|
|
register char *t;
|
|
register int savxit = shp->exitval;
|
|
shp->trapnote = 0;
|
|
indone=1;
|
|
if(sig)
|
|
savxit = SH_EXITSIG|sig;
|
|
if(shp->userinit)
|
|
(*shp->userinit)(shp, -1);
|
|
if(t=shp->st.trapcom[0])
|
|
{
|
|
shp->st.trapcom[0]=0; /*should free but not long */
|
|
sh_trap(t,0);
|
|
savxit = shp->exitval;
|
|
}
|
|
else
|
|
{
|
|
/* avoid recursive call for set -e */
|
|
sh_offstate(SH_ERREXIT);
|
|
sh_chktrap(shp);
|
|
}
|
|
nv_scan(shp->var_tree,array_notify,(void*)0,NV_ARRAY,NV_ARRAY);
|
|
sh_freeup(shp);
|
|
#if SHOPT_ACCT
|
|
sh_accend();
|
|
#endif /* SHOPT_ACCT */
|
|
#if SHOPT_VSH || SHOPT_ESH
|
|
if(mbwide()||sh_isoption(SH_EMACS)||sh_isoption(SH_VI)||sh_isoption(SH_GMACS))
|
|
tty_cooked(-1);
|
|
#endif
|
|
#ifdef JOBS
|
|
if((sh_isoption(SH_INTERACTIVE) && shp->login_sh) || (!sh_isoption(SH_INTERACTIVE) && (sig==SIGHUP)))
|
|
job_walk(sfstderr, job_hup, SIGHUP, NIL(char**));
|
|
#endif /* JOBS */
|
|
job_close(shp);
|
|
if(nv_search("VMTRACE", shp->var_tree,0))
|
|
strmatch((char*)0,(char*)0);
|
|
sfsync((Sfio_t*)sfstdin);
|
|
sfsync((Sfio_t*)shp->outpool);
|
|
sfsync((Sfio_t*)sfstdout);
|
|
if(savxit&SH_EXITSIG && (savxit&SH_EXITMASK) == shp->lastsig)
|
|
sig = savxit&SH_EXITMASK;
|
|
if(sig)
|
|
{
|
|
/* generate fault termination code */
|
|
if(RLIMIT_CORE!=RLIMIT_UNKNOWN)
|
|
{
|
|
#ifdef _lib_getrlimit
|
|
struct rlimit rlp;
|
|
getrlimit(RLIMIT_CORE,&rlp);
|
|
rlp.rlim_cur = 0;
|
|
setrlimit(RLIMIT_CORE,&rlp);
|
|
#else
|
|
vlimit(RLIMIT_CORE,0);
|
|
#endif
|
|
}
|
|
signal(sig,SIG_DFL);
|
|
sigrelease(sig);
|
|
kill(shgd->current_pid,sig);
|
|
pause();
|
|
}
|
|
#if SHOPT_KIA
|
|
if(sh_isoption(SH_NOEXEC))
|
|
kiaclose((Lex_t*)shp->lex_context);
|
|
#endif /* SHOPT_KIA */
|
|
|
|
/* Exit with portable 8-bit status (128 + signum) if last child process exits due to signal */
|
|
if (savxit & SH_EXITSIG)
|
|
savxit -= SH_EXITSIG + 128;
|
|
|
|
exit(savxit&SH_EXITMASK);
|
|
}
|
|
|