14887Schin /***********************************************************************
24887Schin * *
34887Schin * This software is part of the ast package *
4*12068SRoger.Faulkner@Oracle.COM * Copyright (c) 1982-2010 AT&T Intellectual Property *
54887Schin * and is licensed under the *
64887Schin * Common Public License, Version 1.0 *
78462SApril.Chin@Sun.COM * by AT&T Intellectual Property *
84887Schin * *
94887Schin * A copy of the License is available at *
104887Schin * http://www.opensource.org/licenses/cpl1.0.txt *
114887Schin * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) *
124887Schin * *
134887Schin * Information and Software Systems Research *
144887Schin * AT&T Research *
154887Schin * Florham Park NJ *
164887Schin * *
174887Schin * David Korn <dgk@research.att.com> *
184887Schin * *
194887Schin ***********************************************************************/
204887Schin #pragma prototyped
214887Schin /*
224887Schin * Fault handling routines
234887Schin *
244887Schin * David Korn
254887Schin * AT&T Labs
264887Schin *
274887Schin */
284887Schin
294887Schin #include "defs.h"
304887Schin #include <fcin.h>
314887Schin #include "io.h"
324887Schin #include "history.h"
338462SApril.Chin@Sun.COM #include "shlex.h"
344887Schin #include "variables.h"
354887Schin #include "jobs.h"
364887Schin #include "path.h"
378462SApril.Chin@Sun.COM #include "builtins.h"
384887Schin
394887Schin #define abortsig(sig) (sig==SIGABRT || sig==SIGBUS || sig==SIGILL || sig==SIGSEGV)
404887Schin
414887Schin static char indone;
424887Schin
434887Schin #if !_std_malloc
444887Schin # include <vmalloc.h>
454887Schin #endif
464887Schin #if defined(VMFL) && (VMALLOC_VERSION>=20031205L)
474887Schin /*
484887Schin * This exception handler is called after vmalloc() unlocks the region
494887Schin */
malloc_done(Vmalloc_t * vm,int type,Void_t * val,Vmdisc_t * dp)504887Schin static int malloc_done(Vmalloc_t* vm, int type, Void_t* val, Vmdisc_t* dp)
514887Schin {
524887Schin dp->exceptf = 0;
534887Schin sh_exit(SH_EXITSIG);
544887Schin return(0);
554887Schin }
564887Schin #endif
574887Schin
584887Schin /*
594887Schin * Most signals caught or ignored by the shell come here
604887Schin */
sh_fault(register int sig)614887Schin void sh_fault(register int sig)
624887Schin {
638462SApril.Chin@Sun.COM register Shell_t *shp = sh_getinterp();
648462SApril.Chin@Sun.COM register int flag=0;
658462SApril.Chin@Sun.COM register char *trap;
668462SApril.Chin@Sun.COM register struct checkpt *pp = (struct checkpt*)shp->jmplist;
674887Schin int action=0;
684887Schin /* reset handler */
694887Schin if(!(sig&SH_TRAP))
704887Schin signal(sig, sh_fault);
714887Schin sig &= ~SH_TRAP;
724887Schin #ifdef SIGWINCH
734887Schin if(sig==SIGWINCH)
744887Schin {
754887Schin int rows=0, cols=0;
764887Schin int32_t v;
774887Schin astwinsize(2,&rows,&cols);
784887Schin if(v = cols)
798462SApril.Chin@Sun.COM nv_putval(COLUMNS, (char*)&v, NV_INT32|NV_RDONLY);
804887Schin if(v = rows)
818462SApril.Chin@Sun.COM nv_putval(LINES, (char*)&v, NV_INT32|NV_RDONLY);
828462SApril.Chin@Sun.COM shp->winch++;
834887Schin }
844887Schin #endif /* SIGWINCH */
858462SApril.Chin@Sun.COM if(shp->savesig)
864887Schin {
874887Schin /* critical region, save and process later */
888462SApril.Chin@Sun.COM shp->savesig = sig;
898462SApril.Chin@Sun.COM return;
908462SApril.Chin@Sun.COM }
918462SApril.Chin@Sun.COM trap = shp->st.trapcom[sig];
928462SApril.Chin@Sun.COM if(sig==SIGALRM && shp->bltinfun==b_sleep)
938462SApril.Chin@Sun.COM {
948462SApril.Chin@Sun.COM if(trap && *trap)
958462SApril.Chin@Sun.COM {
968462SApril.Chin@Sun.COM shp->trapnote |= SH_SIGTRAP;
978462SApril.Chin@Sun.COM shp->sigflag[sig] |= SH_SIGTRAP;
988462SApril.Chin@Sun.COM }
994887Schin return;
1004887Schin }
10110898Sroland.mainz@nrubsig.org if(shp->subshell && sig!=SIGINT && sig!=SIGQUIT && sig!=SIGWINCH && sig!=SIGCONT)
1028462SApril.Chin@Sun.COM {
1038462SApril.Chin@Sun.COM shp->exitval = SH_EXITSIG|sig;
1048462SApril.Chin@Sun.COM sh_subfork();
1058462SApril.Chin@Sun.COM shp->exitval = 0;
1068462SApril.Chin@Sun.COM return;
1078462SApril.Chin@Sun.COM }
1084887Schin /* handle ignored signals */
1098462SApril.Chin@Sun.COM if(trap && *trap==0)
1104887Schin return;
1118462SApril.Chin@Sun.COM flag = shp->sigflag[sig]&~SH_SIGOFF;
1124887Schin if(!trap)
1134887Schin {
1148462SApril.Chin@Sun.COM if(sig==SIGINT && (shp->trapnote&SH_SIGIGNORE))
1158462SApril.Chin@Sun.COM return;
1164887Schin if(flag&SH_SIGIGNORE)
1174887Schin return;
1184887Schin if(flag&SH_SIGDONE)
1194887Schin {
1204887Schin void *ptr=0;
1218462SApril.Chin@Sun.COM if((flag&SH_SIGINTERACTIVE) && sh_isstate(SH_INTERACTIVE) && !sh_isstate(SH_FORKED) && ! shp->subshell)
1224887Schin {
1234887Schin /* check for TERM signal between fork/exec */
1244887Schin if(sig==SIGTERM && job.in_critical)
1258462SApril.Chin@Sun.COM shp->trapnote |= SH_SIGTERM;
1264887Schin return;
1274887Schin }
1288462SApril.Chin@Sun.COM shp->lastsig = sig;
1294887Schin sigrelease(sig);
1304887Schin if(pp->mode < SH_JMPFUN)
1314887Schin pp->mode = SH_JMPFUN;
1324887Schin else
1334887Schin pp->mode = SH_JMPEXIT;
1344887Schin if(sig==SIGABRT || (abortsig(sig) && (ptr = malloc(1))))
1354887Schin {
1364887Schin if(ptr)
1374887Schin free(ptr);
1388462SApril.Chin@Sun.COM if(!shp->subshell)
1398462SApril.Chin@Sun.COM sh_done(shp,sig);
1404887Schin sh_exit(SH_EXITSIG);
1414887Schin }
1424887Schin /* mark signal and continue */
1438462SApril.Chin@Sun.COM shp->trapnote |= SH_SIGSET;
14410898Sroland.mainz@nrubsig.org if(sig <= shp->sigmax)
1458462SApril.Chin@Sun.COM shp->sigflag[sig] |= SH_SIGSET;
1464887Schin #if defined(VMFL) && (VMALLOC_VERSION>=20031205L)
1474887Schin if(abortsig(sig))
1484887Schin {
1494887Schin /* abort inside malloc, process when malloc returns */
1504887Schin /* VMFL defined when using vmalloc() */
1514887Schin Vmdisc_t* dp = vmdisc(Vmregion,0);
1524887Schin if(dp)
1534887Schin dp->exceptf = malloc_done;
1544887Schin }
1554887Schin #endif
1564887Schin return;
1574887Schin }
1584887Schin }
1594887Schin errno = 0;
1604887Schin if(pp->mode==SH_JMPCMD)
1618462SApril.Chin@Sun.COM shp->lastsig = sig;
1624887Schin if(trap)
1634887Schin {
1644887Schin /*
1654887Schin * propogate signal to foreground group
1664887Schin */
1674887Schin if(sig==SIGHUP && job.curpgid)
1684887Schin killpg(job.curpgid,SIGHUP);
1694887Schin flag = SH_SIGTRAP;
1704887Schin }
1714887Schin else
1724887Schin {
1738462SApril.Chin@Sun.COM shp->lastsig = sig;
1744887Schin flag = SH_SIGSET;
1754887Schin #ifdef SIGTSTP
1764887Schin if(sig==SIGTSTP)
1774887Schin {
1788462SApril.Chin@Sun.COM shp->trapnote |= SH_SIGTSTP;
1794887Schin if(pp->mode==SH_JMPCMD && sh_isstate(SH_STOPOK))
1804887Schin {
1814887Schin sigrelease(sig);
1824887Schin sh_exit(SH_EXITSIG);
1834887Schin flag = 0;
1844887Schin }
1854887Schin }
1864887Schin #endif /* SIGTSTP */
1874887Schin }
1884887Schin #ifdef ERROR_NOTIFY
1898462SApril.Chin@Sun.COM if((error_info.flags&ERROR_NOTIFY) && shp->bltinfun)
1908462SApril.Chin@Sun.COM action = (*shp->bltinfun)(-sig,(char**)0,(void*)0);
1914887Schin if(action>0)
1924887Schin return;
1938462SApril.Chin@Sun.COM #endif
1948462SApril.Chin@Sun.COM if(shp->bltinfun && shp->bltindata.notify)
1958462SApril.Chin@Sun.COM {
1968462SApril.Chin@Sun.COM shp->bltindata.sigset = 1;
1978462SApril.Chin@Sun.COM return;
1988462SApril.Chin@Sun.COM }
1998462SApril.Chin@Sun.COM shp->trapnote |= flag;
20010898Sroland.mainz@nrubsig.org if(sig <= shp->sigmax)
2018462SApril.Chin@Sun.COM shp->sigflag[sig] |= flag;
2024887Schin if(pp->mode==SH_JMPCMD && sh_isstate(SH_STOPOK))
2034887Schin {
2044887Schin if(action<0)
2054887Schin return;
2064887Schin sigrelease(sig);
2074887Schin sh_exit(SH_EXITSIG);
2084887Schin }
2094887Schin }
2104887Schin
2114887Schin /*
2124887Schin * initialize signal handling
2134887Schin */
sh_siginit(void * ptr)2148462SApril.Chin@Sun.COM void sh_siginit(void *ptr)
2154887Schin {
2168462SApril.Chin@Sun.COM Shell_t *shp = (Shell_t*)ptr;
21710898Sroland.mainz@nrubsig.org register int sig, n;
2184887Schin register const struct shtable2 *tp = shtab_signals;
2194887Schin sig_begin();
2204887Schin /* find the largest signal number in the table */
22110898Sroland.mainz@nrubsig.org #if defined(SIGRTMIN) && defined(SIGRTMAX)
22210898Sroland.mainz@nrubsig.org if ((n = SIGRTMIN) > 0 && (sig = SIGRTMAX) > n && sig < SH_TRAP)
22310898Sroland.mainz@nrubsig.org {
22410898Sroland.mainz@nrubsig.org shp->sigruntime[SH_SIGRTMIN] = n;
22510898Sroland.mainz@nrubsig.org shp->sigruntime[SH_SIGRTMAX] = sig;
22610898Sroland.mainz@nrubsig.org }
22710898Sroland.mainz@nrubsig.org #endif /* SIGRTMIN && SIGRTMAX */
22810898Sroland.mainz@nrubsig.org n = SIGTERM;
2294887Schin while(*tp->sh_name)
2304887Schin {
23110898Sroland.mainz@nrubsig.org sig = (tp->sh_number&((1<<SH_SIGBITS)-1));
23210898Sroland.mainz@nrubsig.org if (!(sig-- & SH_TRAP))
23310898Sroland.mainz@nrubsig.org {
23410898Sroland.mainz@nrubsig.org if ((tp->sh_number>>SH_SIGBITS) & SH_SIGRUNTIME)
23510898Sroland.mainz@nrubsig.org sig = shp->sigruntime[sig];
23610898Sroland.mainz@nrubsig.org if(sig>n && sig<SH_TRAP)
23710898Sroland.mainz@nrubsig.org n = sig;
23810898Sroland.mainz@nrubsig.org }
2394887Schin tp++;
2404887Schin }
2418462SApril.Chin@Sun.COM shp->sigmax = n++;
2428462SApril.Chin@Sun.COM shp->st.trapcom = (char**)calloc(n,sizeof(char*));
2438462SApril.Chin@Sun.COM shp->sigflag = (unsigned char*)calloc(n,1);
2448462SApril.Chin@Sun.COM shp->sigmsg = (char**)calloc(n,sizeof(char*));
2454887Schin for(tp=shtab_signals; sig=tp->sh_number; tp++)
2464887Schin {
2474887Schin n = (sig>>SH_SIGBITS);
24810898Sroland.mainz@nrubsig.org if((sig &= ((1<<SH_SIGBITS)-1)) > (shp->sigmax+1))
2494887Schin continue;
2504887Schin sig--;
2518462SApril.Chin@Sun.COM if(n&SH_SIGRUNTIME)
2528462SApril.Chin@Sun.COM sig = shp->sigruntime[sig];
2534887Schin if(sig>=0)
2544887Schin {
2558462SApril.Chin@Sun.COM shp->sigflag[sig] = n;
2564887Schin if(*tp->sh_name)
2578462SApril.Chin@Sun.COM shp->sigmsg[sig] = (char*)tp->sh_value;
2584887Schin }
2594887Schin }
2604887Schin }
2614887Schin
2624887Schin /*
2634887Schin * Turn on trap handler for signal <sig>
2644887Schin */
sh_sigtrap(register int sig)2654887Schin void sh_sigtrap(register int sig)
2664887Schin {
2674887Schin register int flag;
2684887Schin void (*fun)(int);
2694887Schin sh.st.otrapcom = 0;
2704887Schin if(sig==0)
2714887Schin sh_sigdone();
2724887Schin else if(!((flag=sh.sigflag[sig])&(SH_SIGFAULT|SH_SIGOFF)))
2734887Schin {
2744887Schin /* don't set signal if already set or off by parent */
2754887Schin if((fun=signal(sig,sh_fault))==SIG_IGN)
2764887Schin {
2774887Schin signal(sig,SIG_IGN);
2784887Schin flag |= SH_SIGOFF;
2794887Schin }
2804887Schin else
2814887Schin {
2824887Schin flag |= SH_SIGFAULT;
2834887Schin if(sig==SIGALRM && fun!=SIG_DFL && fun!=sh_fault)
2844887Schin signal(sig,fun);
2854887Schin }
2864887Schin flag &= ~(SH_SIGSET|SH_SIGTRAP);
2874887Schin sh.sigflag[sig] = flag;
2884887Schin }
2894887Schin }
2904887Schin
2914887Schin /*
2924887Schin * set signal handler so sh_done is called for all caught signals
2934887Schin */
sh_sigdone(void)2944887Schin void sh_sigdone(void)
2954887Schin {
2964887Schin register int flag, sig = sh.sigmax;
2974887Schin sh.sigflag[0] |= SH_SIGFAULT;
29810898Sroland.mainz@nrubsig.org for(sig=sh.sigmax; sig>0; sig--)
2994887Schin {
3004887Schin flag = sh.sigflag[sig];
3014887Schin if((flag&(SH_SIGDONE|SH_SIGIGNORE|SH_SIGINTERACTIVE)) && !(flag&(SH_SIGFAULT|SH_SIGOFF)))
3024887Schin sh_sigtrap(sig);
3034887Schin }
3044887Schin }
3054887Schin
3064887Schin /*
3074887Schin * Restore to default signals
3084887Schin * Free the trap strings if mode is non-zero
3094887Schin * If mode>1 then ignored traps cause signal to be ignored
3104887Schin */
sh_sigreset(register int mode)3114887Schin void sh_sigreset(register int mode)
3124887Schin {
3134887Schin register char *trap;
3144887Schin register int flag, sig=sh.st.trapmax;
3154887Schin while(sig-- > 0)
3164887Schin {
3174887Schin if(trap=sh.st.trapcom[sig])
3184887Schin {
3194887Schin flag = sh.sigflag[sig]&~(SH_SIGTRAP|SH_SIGSET);
3204887Schin if(*trap)
3214887Schin {
3224887Schin if(mode)
3234887Schin free(trap);
3244887Schin sh.st.trapcom[sig] = 0;
3254887Schin }
3264887Schin else if(sig && mode>1)
3274887Schin {
32810898Sroland.mainz@nrubsig.org if(sig!=SIGCHLD)
32910898Sroland.mainz@nrubsig.org signal(sig,SIG_IGN);
3304887Schin flag &= ~SH_SIGFAULT;
3314887Schin flag |= SH_SIGOFF;
3324887Schin }
3334887Schin sh.sigflag[sig] = flag;
3344887Schin }
3354887Schin }
3368462SApril.Chin@Sun.COM for(sig=SH_DEBUGTRAP-1;sig>=0;sig--)
3374887Schin {
3384887Schin if(trap=sh.st.trap[sig])
3394887Schin {
3404887Schin if(mode)
3414887Schin free(trap);
3424887Schin sh.st.trap[sig] = 0;
3434887Schin }
3444887Schin
3454887Schin }
3464887Schin sh.st.trapcom[0] = 0;
3474887Schin if(mode)
3484887Schin sh.st.trapmax = 0;
3494887Schin sh.trapnote=0;
3504887Schin }
3514887Schin
3524887Schin /*
3534887Schin * free up trap if set and restore signal handler if modified
3544887Schin */
sh_sigclear(register int sig)3554887Schin void sh_sigclear(register int sig)
3564887Schin {
3574887Schin register int flag = sh.sigflag[sig];
3584887Schin register char *trap;
3594887Schin sh.st.otrapcom=0;
3604887Schin if(!(flag&SH_SIGFAULT))
3614887Schin return;
3624887Schin flag &= ~(SH_SIGTRAP|SH_SIGSET);
3634887Schin if(trap=sh.st.trapcom[sig])
3644887Schin {
365*12068SRoger.Faulkner@Oracle.COM if(!sh.subshell)
366*12068SRoger.Faulkner@Oracle.COM free(trap);
3674887Schin sh.st.trapcom[sig]=0;
3684887Schin }
3694887Schin sh.sigflag[sig] = flag;
3704887Schin }
3714887Schin
3724887Schin /*
3734887Schin * check for traps
3744887Schin */
3754887Schin
sh_chktrap(void)3764887Schin void sh_chktrap(void)
3774887Schin {
3784887Schin register int sig=sh.st.trapmax;
3794887Schin register char *trap;
3808462SApril.Chin@Sun.COM if(!(sh.trapnote&~SH_SIGIGNORE))
3814887Schin sig=0;
3824887Schin sh.trapnote &= ~SH_SIGTRAP;
3834887Schin /* execute errexit trap first */
3844887Schin if(sh_isstate(SH_ERREXIT) && sh.exitval)
3854887Schin {
3864887Schin int sav_trapnote = sh.trapnote;
3874887Schin sh.trapnote &= ~SH_SIGSET;
3884887Schin if(sh.st.trap[SH_ERRTRAP])
3898462SApril.Chin@Sun.COM {
3908462SApril.Chin@Sun.COM trap = sh.st.trap[SH_ERRTRAP];
3918462SApril.Chin@Sun.COM sh.st.trap[SH_ERRTRAP] = 0;
3928462SApril.Chin@Sun.COM sh_trap(trap,0);
3938462SApril.Chin@Sun.COM sh.st.trap[SH_ERRTRAP] = trap;
3948462SApril.Chin@Sun.COM }
3954887Schin sh.trapnote = sav_trapnote;
3964887Schin if(sh_isoption(SH_ERREXIT))
3974887Schin {
3984887Schin struct checkpt *pp = (struct checkpt*)sh.jmplist;
3994887Schin pp->mode = SH_JMPEXIT;
4004887Schin sh_exit(sh.exitval);
4014887Schin }
4024887Schin }
4034887Schin if(sh.sigflag[SIGALRM]&SH_SIGALRM)
4044887Schin sh_timetraps();
40510898Sroland.mainz@nrubsig.org #ifdef SHOPT_BGX
40610898Sroland.mainz@nrubsig.org if((sh.sigflag[SIGCHLD]&SH_SIGTRAP) && sh.st.trapcom[SIGCHLD])
40710898Sroland.mainz@nrubsig.org job_chldtrap(&sh,sh.st.trapcom[SIGCHLD],1);
408*12068SRoger.Faulkner@Oracle.COM #endif /* SHOPT_BGX */
4094887Schin while(--sig>=0)
410*12068SRoger.Faulkner@Oracle.COM {
411*12068SRoger.Faulkner@Oracle.COM #ifdef SHOPT_BGX
412*12068SRoger.Faulkner@Oracle.COM if(sig==SIGCHLD)
413*12068SRoger.Faulkner@Oracle.COM continue;
41410898Sroland.mainz@nrubsig.org #endif /* SHOPT_BGX */
4154887Schin if(sh.sigflag[sig]&SH_SIGTRAP)
4164887Schin {
4174887Schin sh.sigflag[sig] &= ~SH_SIGTRAP;
4184887Schin if(trap=sh.st.trapcom[sig])
41910898Sroland.mainz@nrubsig.org {
42010898Sroland.mainz@nrubsig.org Sfio_t *fp;
42110898Sroland.mainz@nrubsig.org if(sig==SIGPIPE && (fp=sfpool((Sfio_t*)0,sh.outpool,SF_WRITE)) && sferror(fp))
42210898Sroland.mainz@nrubsig.org sfclose(fp);
42310898Sroland.mainz@nrubsig.org sh.oldexit = SH_EXITSIG|sig;
42410898Sroland.mainz@nrubsig.org sh_trap(trap,0);
42510898Sroland.mainz@nrubsig.org }
4264887Schin }
4274887Schin }
4284887Schin }
4294887Schin
4304887Schin
4314887Schin /*
4324887Schin * parse and execute the given trap string, stream or tree depending on mode
4334887Schin * mode==0 for string, mode==1 for stream, mode==2 for parse tree
4344887Schin */
sh_trap(const char * trap,int mode)4354887Schin int sh_trap(const char *trap, int mode)
4364887Schin {
4378462SApril.Chin@Sun.COM Shell_t *shp = sh_getinterp();
4388462SApril.Chin@Sun.COM int jmpval, savxit = shp->exitval;
4394887Schin int was_history = sh_isstate(SH_HISTORY);
4404887Schin int was_verbose = sh_isstate(SH_VERBOSE);
4414887Schin int staktop = staktell();
4424887Schin char *savptr = stakfreeze(0);
443*12068SRoger.Faulkner@Oracle.COM char ifstable[256];
4444887Schin struct checkpt buff;
4454887Schin Fcin_t savefc;
4464887Schin fcsave(&savefc);
447*12068SRoger.Faulkner@Oracle.COM memcpy(ifstable,shp->ifstable,sizeof(ifstable));
4484887Schin sh_offstate(SH_HISTORY);
4494887Schin sh_offstate(SH_VERBOSE);
4508462SApril.Chin@Sun.COM shp->intrap++;
4514887Schin sh_pushcontext(&buff,SH_JMPTRAP);
4524887Schin jmpval = sigsetjmp(buff.buff,0);
4534887Schin if(jmpval == 0)
4544887Schin {
4554887Schin if(mode==2)
4564887Schin sh_exec((Shnode_t*)trap,sh_isstate(SH_ERREXIT));
4574887Schin else
4584887Schin {
4594887Schin Sfio_t *sp;
4604887Schin if(mode)
4614887Schin sp = (Sfio_t*)trap;
4624887Schin else
4634887Schin sp = sfopen(NIL(Sfio_t*),trap,"s");
4644887Schin sh_eval(sp,0);
4654887Schin }
4664887Schin }
4674887Schin else if(indone)
4684887Schin {
4694887Schin if(jmpval==SH_JMPSCRIPT)
4704887Schin indone=0;
4714887Schin else
4724887Schin {
4734887Schin if(jmpval==SH_JMPEXIT)
4748462SApril.Chin@Sun.COM savxit = shp->exitval;
4754887Schin jmpval=SH_JMPTRAP;
4764887Schin }
4774887Schin }
4784887Schin sh_popcontext(&buff);
4798462SApril.Chin@Sun.COM shp->intrap--;
4808462SApril.Chin@Sun.COM sfsync(shp->outpool);
4818462SApril.Chin@Sun.COM if(!shp->indebug && jmpval!=SH_JMPEXIT && jmpval!=SH_JMPFUN)
4828462SApril.Chin@Sun.COM shp->exitval=savxit;
4834887Schin stakset(savptr,staktop);
4844887Schin fcrestore(&savefc);
485*12068SRoger.Faulkner@Oracle.COM memcpy(shp->ifstable,ifstable,sizeof(ifstable));
4864887Schin if(was_history)
4874887Schin sh_onstate(SH_HISTORY);
4884887Schin if(was_verbose)
4894887Schin sh_onstate(SH_VERBOSE);
4904887Schin exitset();
49110898Sroland.mainz@nrubsig.org if(jmpval>SH_JMPTRAP && (((struct checkpt*)shp->jmpbuffer)->prev || ((struct checkpt*)shp->jmpbuffer)->mode==SH_JMPSCRIPT))
4928462SApril.Chin@Sun.COM siglongjmp(*shp->jmplist,jmpval);
4938462SApril.Chin@Sun.COM return(shp->exitval);
4944887Schin }
4954887Schin
4964887Schin /*
4974887Schin * exit the current scope and jump to an earlier one based on pp->mode
4984887Schin */
sh_exit(register int xno)4994887Schin void sh_exit(register int xno)
5004887Schin {
5018462SApril.Chin@Sun.COM Shell_t *shp = &sh;
5028462SApril.Chin@Sun.COM register struct checkpt *pp = (struct checkpt*)shp->jmplist;
5034887Schin register int sig=0;
5044887Schin register Sfio_t* pool;
5058462SApril.Chin@Sun.COM shp->exitval=xno;
5064887Schin if(xno==SH_EXITSIG)
5078462SApril.Chin@Sun.COM shp->exitval |= (sig=shp->lastsig);
5084887Schin #ifdef SIGTSTP
5098462SApril.Chin@Sun.COM if(shp->trapnote&SH_SIGTSTP)
5104887Schin {
5114887Schin /* ^Z detected by the shell */
5128462SApril.Chin@Sun.COM shp->trapnote = 0;
5138462SApril.Chin@Sun.COM shp->sigflag[SIGTSTP] = 0;
5148462SApril.Chin@Sun.COM if(!shp->subshell && sh_isstate(SH_MONITOR) && !sh_isstate(SH_STOPOK))
5154887Schin return;
5164887Schin if(sh_isstate(SH_TIMING))
5174887Schin return;
5184887Schin /* Handles ^Z for shell builtins, subshells, and functs */
5198462SApril.Chin@Sun.COM shp->lastsig = 0;
5204887Schin sh_onstate(SH_MONITOR);
5214887Schin sh_offstate(SH_STOPOK);
5228462SApril.Chin@Sun.COM shp->trapnote = 0;
5238462SApril.Chin@Sun.COM if(!shp->subshell && (sig=sh_fork(0,NIL(int*))))
5244887Schin {
5254887Schin job.curpgid = 0;
5264887Schin job.parent = (pid_t)-1;
5274887Schin job_wait(sig);
5284887Schin job.parent = 0;
5298462SApril.Chin@Sun.COM shp->sigflag[SIGTSTP] = 0;
5304887Schin /* wait for child to stop */
5318462SApril.Chin@Sun.COM shp->exitval = (SH_EXITSIG|SIGTSTP);
5324887Schin /* return to prompt mode */
5334887Schin pp->mode = SH_JMPERREXIT;
5344887Schin }
5354887Schin else
5364887Schin {
5378462SApril.Chin@Sun.COM if(shp->subshell)
5384887Schin sh_subfork();
5394887Schin /* child process, put to sleep */
5404887Schin sh_offstate(SH_STOPOK);
5414887Schin sh_offstate(SH_MONITOR);
5428462SApril.Chin@Sun.COM shp->sigflag[SIGTSTP] = 0;
5434887Schin /* stop child job */
5444887Schin killpg(job.curpgid,SIGTSTP);
5454887Schin /* child resumes */
5464887Schin job_clear();
5478462SApril.Chin@Sun.COM shp->forked = 1;
5488462SApril.Chin@Sun.COM shp->exitval = (xno&SH_EXITMASK);
5494887Schin return;
5504887Schin }
5514887Schin }
5524887Schin #endif /* SIGTSTP */
5534887Schin /* unlock output pool */
5544887Schin sh_offstate(SH_NOTRACK);
5558462SApril.Chin@Sun.COM if(!(pool=sfpool(NIL(Sfio_t*),shp->outpool,SF_WRITE)))
5568462SApril.Chin@Sun.COM pool = shp->outpool; /* can't happen? */
5574887Schin sfclrlock(pool);
5584887Schin #ifdef SIGPIPE
5598462SApril.Chin@Sun.COM if(shp->lastsig==SIGPIPE)
5604887Schin sfpurge(pool);
5614887Schin #endif /* SIGPIPE */
5624887Schin sfclrlock(sfstdin);
5634887Schin if(!pp)
5648462SApril.Chin@Sun.COM sh_done(shp,sig);
5658462SApril.Chin@Sun.COM shp->prefix = 0;
5668462SApril.Chin@Sun.COM #if SHOPT_TYPEDEF
5678462SApril.Chin@Sun.COM shp->mktype = 0;
5688462SApril.Chin@Sun.COM #endif /* SHOPT_TYPEDEF*/
5694887Schin if(pp->mode == SH_JMPSCRIPT && !pp->prev)
5708462SApril.Chin@Sun.COM sh_done(shp,sig);
5718462SApril.Chin@Sun.COM if(pp->mode)
5728462SApril.Chin@Sun.COM siglongjmp(pp->buff,pp->mode);
5738462SApril.Chin@Sun.COM }
5748462SApril.Chin@Sun.COM
array_notify(Namval_t * np,void * data)5758462SApril.Chin@Sun.COM static void array_notify(Namval_t *np, void *data)
5768462SApril.Chin@Sun.COM {
5778462SApril.Chin@Sun.COM Namarr_t *ap = nv_arrayptr(np);
5788462SApril.Chin@Sun.COM NOT_USED(data);
5798462SApril.Chin@Sun.COM if(ap && ap->fun)
5808462SApril.Chin@Sun.COM (*ap->fun)(np, 0, NV_AFREE);
5814887Schin }
5824887Schin
5834887Schin /*
5844887Schin * This is the exit routine for the shell
5854887Schin */
5864887Schin
sh_done(void * ptr,register int sig)5878462SApril.Chin@Sun.COM void sh_done(void *ptr, register int sig)
5884887Schin {
5898462SApril.Chin@Sun.COM Shell_t *shp = (Shell_t*)ptr;
5904887Schin register char *t;
5918462SApril.Chin@Sun.COM register int savxit = shp->exitval;
5928462SApril.Chin@Sun.COM shp->trapnote = 0;
5934887Schin indone=1;
59410898Sroland.mainz@nrubsig.org if(sig)
59510898Sroland.mainz@nrubsig.org savxit = SH_EXITSIG|sig;
5968462SApril.Chin@Sun.COM if(shp->userinit)
5978462SApril.Chin@Sun.COM (*shp->userinit)(shp, -1);
5988462SApril.Chin@Sun.COM if(t=shp->st.trapcom[0])
5994887Schin {
6008462SApril.Chin@Sun.COM shp->st.trapcom[0]=0; /*should free but not long */
6018462SApril.Chin@Sun.COM shp->oldexit = savxit;
6024887Schin sh_trap(t,0);
6038462SApril.Chin@Sun.COM savxit = shp->exitval;
6044887Schin }
6054887Schin else
6064887Schin {
6074887Schin /* avoid recursive call for set -e */
6084887Schin sh_offstate(SH_ERREXIT);
6094887Schin sh_chktrap();
6104887Schin }
6118462SApril.Chin@Sun.COM nv_scan(shp->var_tree,array_notify,(void*)0,NV_ARRAY,NV_ARRAY);
6128462SApril.Chin@Sun.COM sh_freeup(shp);
6134887Schin #if SHOPT_ACCT
6144887Schin sh_accend();
6154887Schin #endif /* SHOPT_ACCT */
6164887Schin #if SHOPT_VSH || SHOPT_ESH
6174887Schin if(sh_isoption(SH_EMACS)||sh_isoption(SH_VI)||sh_isoption(SH_GMACS))
6184887Schin tty_cooked(-1);
6194887Schin #endif
6204887Schin #ifdef JOBS
6218462SApril.Chin@Sun.COM if((sh_isoption(SH_INTERACTIVE) && shp->login_sh) || (!sh_isoption(SH_INTERACTIVE) && (sig==SIGHUP)))
6224887Schin job_walk(sfstderr,job_terminate,SIGHUP,NIL(char**));
6234887Schin #endif /* JOBS */
6248462SApril.Chin@Sun.COM job_close(shp);
6258462SApril.Chin@Sun.COM if(nv_search("VMTRACE", shp->var_tree,0))
6264887Schin strmatch((char*)0,(char*)0);
6274887Schin sfsync((Sfio_t*)sfstdin);
6288462SApril.Chin@Sun.COM sfsync((Sfio_t*)shp->outpool);
6294887Schin sfsync((Sfio_t*)sfstdout);
63010898Sroland.mainz@nrubsig.org if(savxit&SH_EXITSIG)
63110898Sroland.mainz@nrubsig.org sig = savxit&SH_EXITMASK;
6324887Schin if(sig)
6334887Schin {
6344887Schin /* generate fault termination code */
6354887Schin signal(sig,SIG_DFL);
6364887Schin sigrelease(sig);
6374887Schin kill(getpid(),sig);
6384887Schin pause();
6394887Schin }
6404887Schin #if SHOPT_KIA
6414887Schin if(sh_isoption(SH_NOEXEC))
6428462SApril.Chin@Sun.COM kiaclose((Lex_t*)shp->lex_context);
6434887Schin #endif /* SHOPT_KIA */
6444887Schin exit(savxit&SH_EXITMASK);
6454887Schin }
6464887Schin
647