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