14887Schin /***********************************************************************
24887Schin *                                                                      *
34887Schin *               This software is part of the ast package               *
4*10898Sroland.mainz@nrubsig.org *          Copyright (c) 1982-2009 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      */
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 */
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 	}
101*10898Sroland.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;
144*10898Sroland.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;
200*10898Sroland.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  */
2148462SApril.Chin@Sun.COM void sh_siginit(void *ptr)
2154887Schin {
2168462SApril.Chin@Sun.COM 	Shell_t	*shp = (Shell_t*)ptr;
217*10898Sroland.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 */
221*10898Sroland.mainz@nrubsig.org #if defined(SIGRTMIN) && defined(SIGRTMAX)
222*10898Sroland.mainz@nrubsig.org 	if ((n = SIGRTMIN) > 0 && (sig = SIGRTMAX) > n && sig < SH_TRAP)
223*10898Sroland.mainz@nrubsig.org 	{
224*10898Sroland.mainz@nrubsig.org 		shp->sigruntime[SH_SIGRTMIN] = n;
225*10898Sroland.mainz@nrubsig.org 		shp->sigruntime[SH_SIGRTMAX] = sig;
226*10898Sroland.mainz@nrubsig.org 	}
227*10898Sroland.mainz@nrubsig.org #endif /* SIGRTMIN && SIGRTMAX */
228*10898Sroland.mainz@nrubsig.org 	n = SIGTERM;
2294887Schin 	while(*tp->sh_name)
2304887Schin 	{
231*10898Sroland.mainz@nrubsig.org 		sig = (tp->sh_number&((1<<SH_SIGBITS)-1));
232*10898Sroland.mainz@nrubsig.org 		if (!(sig-- & SH_TRAP))
233*10898Sroland.mainz@nrubsig.org 		{
234*10898Sroland.mainz@nrubsig.org 			if ((tp->sh_number>>SH_SIGBITS) & SH_SIGRUNTIME)
235*10898Sroland.mainz@nrubsig.org 				sig = shp->sigruntime[sig];
236*10898Sroland.mainz@nrubsig.org 			if(sig>n && sig<SH_TRAP)
237*10898Sroland.mainz@nrubsig.org 				n = sig;
238*10898Sroland.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);
248*10898Sroland.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  */
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  */
2944887Schin void	sh_sigdone(void)
2954887Schin {
2964887Schin 	register int 	flag, sig = sh.sigmax;
2974887Schin 	sh.sigflag[0] |= SH_SIGFAULT;
298*10898Sroland.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  */
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 			{
328*10898Sroland.mainz@nrubsig.org 				if(sig!=SIGCHLD)
329*10898Sroland.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  */
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 	{
3654887Schin 		free(trap);
3664887Schin 		sh.st.trapcom[sig]=0;
3674887Schin 	}
3684887Schin 	sh.sigflag[sig] = flag;
3694887Schin }
3704887Schin 
3714887Schin /*
3724887Schin  * check for traps
3734887Schin  */
3744887Schin 
3754887Schin void	sh_chktrap(void)
3764887Schin {
3774887Schin 	register int 	sig=sh.st.trapmax;
3784887Schin 	register char *trap;
3798462SApril.Chin@Sun.COM 	if(!(sh.trapnote&~SH_SIGIGNORE))
3804887Schin 		sig=0;
3814887Schin 	sh.trapnote &= ~SH_SIGTRAP;
3824887Schin 	/* execute errexit trap first */
3834887Schin 	if(sh_isstate(SH_ERREXIT) && sh.exitval)
3844887Schin 	{
3854887Schin 		int	sav_trapnote = sh.trapnote;
3864887Schin 		sh.trapnote &= ~SH_SIGSET;
3874887Schin 		if(sh.st.trap[SH_ERRTRAP])
3888462SApril.Chin@Sun.COM 		{
3898462SApril.Chin@Sun.COM 			trap = sh.st.trap[SH_ERRTRAP];
3908462SApril.Chin@Sun.COM 			sh.st.trap[SH_ERRTRAP] = 0;
3918462SApril.Chin@Sun.COM 			sh_trap(trap,0);
3928462SApril.Chin@Sun.COM 			sh.st.trap[SH_ERRTRAP] = trap;
3938462SApril.Chin@Sun.COM 		}
3944887Schin 		sh.trapnote = sav_trapnote;
3954887Schin 		if(sh_isoption(SH_ERREXIT))
3964887Schin 		{
3974887Schin 			struct checkpt	*pp = (struct checkpt*)sh.jmplist;
3984887Schin 			pp->mode = SH_JMPEXIT;
3994887Schin 			sh_exit(sh.exitval);
4004887Schin 		}
4014887Schin 	}
4024887Schin 	if(sh.sigflag[SIGALRM]&SH_SIGALRM)
4034887Schin 		sh_timetraps();
404*10898Sroland.mainz@nrubsig.org #ifdef SHOPT_BGX
405*10898Sroland.mainz@nrubsig.org 	if((sh.sigflag[SIGCHLD]&SH_SIGTRAP) && sh.st.trapcom[SIGCHLD])
406*10898Sroland.mainz@nrubsig.org 		job_chldtrap(&sh,sh.st.trapcom[SIGCHLD],1);
407*10898Sroland.mainz@nrubsig.org 	while(--sig>=0 && sig!=SIGCHLD)
408*10898Sroland.mainz@nrubsig.org #else
4094887Schin 	while(--sig>=0)
410*10898Sroland.mainz@nrubsig.org #endif /* SHOPT_BGX */
4114887Schin 	{
4124887Schin 		if(sh.sigflag[sig]&SH_SIGTRAP)
4134887Schin 		{
4144887Schin 			sh.sigflag[sig] &= ~SH_SIGTRAP;
4154887Schin 			if(trap=sh.st.trapcom[sig])
416*10898Sroland.mainz@nrubsig.org 			{
417*10898Sroland.mainz@nrubsig.org 				Sfio_t *fp;
418*10898Sroland.mainz@nrubsig.org 				if(sig==SIGPIPE && (fp=sfpool((Sfio_t*)0,sh.outpool,SF_WRITE)) && sferror(fp))
419*10898Sroland.mainz@nrubsig.org 					sfclose(fp);
420*10898Sroland.mainz@nrubsig.org  				sh.oldexit = SH_EXITSIG|sig;
421*10898Sroland.mainz@nrubsig.org  				sh_trap(trap,0);
422*10898Sroland.mainz@nrubsig.org  			}
4234887Schin 		}
4244887Schin 	}
4254887Schin }
4264887Schin 
4274887Schin 
4284887Schin /*
4294887Schin  * parse and execute the given trap string, stream or tree depending on mode
4304887Schin  * mode==0 for string, mode==1 for stream, mode==2 for parse tree
4314887Schin  */
4324887Schin int sh_trap(const char *trap, int mode)
4334887Schin {
4348462SApril.Chin@Sun.COM 	Shell_t	*shp = sh_getinterp();
4358462SApril.Chin@Sun.COM 	int	jmpval, savxit = shp->exitval;
4364887Schin 	int	was_history = sh_isstate(SH_HISTORY);
4374887Schin 	int	was_verbose = sh_isstate(SH_VERBOSE);
4384887Schin 	int	staktop = staktell();
4394887Schin 	char	*savptr = stakfreeze(0);
4404887Schin 	struct	checkpt buff;
4414887Schin 	Fcin_t	savefc;
4424887Schin 	fcsave(&savefc);
4434887Schin 	sh_offstate(SH_HISTORY);
4444887Schin 	sh_offstate(SH_VERBOSE);
4458462SApril.Chin@Sun.COM 	shp->intrap++;
4464887Schin 	sh_pushcontext(&buff,SH_JMPTRAP);
4474887Schin 	jmpval = sigsetjmp(buff.buff,0);
4484887Schin 	if(jmpval == 0)
4494887Schin 	{
4504887Schin 		if(mode==2)
4514887Schin 			sh_exec((Shnode_t*)trap,sh_isstate(SH_ERREXIT));
4524887Schin 		else
4534887Schin 		{
4544887Schin 			Sfio_t *sp;
4554887Schin 			if(mode)
4564887Schin 				sp = (Sfio_t*)trap;
4574887Schin 			else
4584887Schin 				sp = sfopen(NIL(Sfio_t*),trap,"s");
4594887Schin 			sh_eval(sp,0);
4604887Schin 		}
4614887Schin 	}
4624887Schin 	else if(indone)
4634887Schin 	{
4644887Schin 		if(jmpval==SH_JMPSCRIPT)
4654887Schin 			indone=0;
4664887Schin 		else
4674887Schin 		{
4684887Schin 			if(jmpval==SH_JMPEXIT)
4698462SApril.Chin@Sun.COM 				savxit = shp->exitval;
4704887Schin 			jmpval=SH_JMPTRAP;
4714887Schin 		}
4724887Schin 	}
4734887Schin 	sh_popcontext(&buff);
4748462SApril.Chin@Sun.COM 	shp->intrap--;
4758462SApril.Chin@Sun.COM 	sfsync(shp->outpool);
4768462SApril.Chin@Sun.COM 	if(!shp->indebug && jmpval!=SH_JMPEXIT && jmpval!=SH_JMPFUN)
4778462SApril.Chin@Sun.COM 		shp->exitval=savxit;
4784887Schin 	stakset(savptr,staktop);
4794887Schin 	fcrestore(&savefc);
4804887Schin 	if(was_history)
4814887Schin 		sh_onstate(SH_HISTORY);
4824887Schin 	if(was_verbose)
4834887Schin 		sh_onstate(SH_VERBOSE);
4844887Schin 	exitset();
485*10898Sroland.mainz@nrubsig.org 	if(jmpval>SH_JMPTRAP && (((struct checkpt*)shp->jmpbuffer)->prev || ((struct checkpt*)shp->jmpbuffer)->mode==SH_JMPSCRIPT))
4868462SApril.Chin@Sun.COM 		siglongjmp(*shp->jmplist,jmpval);
4878462SApril.Chin@Sun.COM 	return(shp->exitval);
4884887Schin }
4894887Schin 
4904887Schin /*
4914887Schin  * exit the current scope and jump to an earlier one based on pp->mode
4924887Schin  */
4934887Schin void sh_exit(register int xno)
4944887Schin {
4958462SApril.Chin@Sun.COM 	Shell_t	*shp = &sh;
4968462SApril.Chin@Sun.COM 	register struct checkpt	*pp = (struct checkpt*)shp->jmplist;
4974887Schin 	register int		sig=0;
4984887Schin 	register Sfio_t*	pool;
4998462SApril.Chin@Sun.COM 	shp->exitval=xno;
5004887Schin 	if(xno==SH_EXITSIG)
5018462SApril.Chin@Sun.COM 		shp->exitval |= (sig=shp->lastsig);
5024887Schin #ifdef SIGTSTP
5038462SApril.Chin@Sun.COM 	if(shp->trapnote&SH_SIGTSTP)
5044887Schin 	{
5054887Schin 		/* ^Z detected by the shell */
5068462SApril.Chin@Sun.COM 		shp->trapnote = 0;
5078462SApril.Chin@Sun.COM 		shp->sigflag[SIGTSTP] = 0;
5088462SApril.Chin@Sun.COM 		if(!shp->subshell && sh_isstate(SH_MONITOR) && !sh_isstate(SH_STOPOK))
5094887Schin 			return;
5104887Schin 		if(sh_isstate(SH_TIMING))
5114887Schin 			return;
5124887Schin 		/* Handles ^Z for shell builtins, subshells, and functs */
5138462SApril.Chin@Sun.COM 		shp->lastsig = 0;
5144887Schin 		sh_onstate(SH_MONITOR);
5154887Schin 		sh_offstate(SH_STOPOK);
5168462SApril.Chin@Sun.COM 		shp->trapnote = 0;
5178462SApril.Chin@Sun.COM 		if(!shp->subshell && (sig=sh_fork(0,NIL(int*))))
5184887Schin 		{
5194887Schin 			job.curpgid = 0;
5204887Schin 			job.parent = (pid_t)-1;
5214887Schin 			job_wait(sig);
5224887Schin 			job.parent = 0;
5238462SApril.Chin@Sun.COM 			shp->sigflag[SIGTSTP] = 0;
5244887Schin 			/* wait for child to stop */
5258462SApril.Chin@Sun.COM 			shp->exitval = (SH_EXITSIG|SIGTSTP);
5264887Schin 			/* return to prompt mode */
5274887Schin 			pp->mode = SH_JMPERREXIT;
5284887Schin 		}
5294887Schin 		else
5304887Schin 		{
5318462SApril.Chin@Sun.COM 			if(shp->subshell)
5324887Schin 				sh_subfork();
5334887Schin 			/* child process, put to sleep */
5344887Schin 			sh_offstate(SH_STOPOK);
5354887Schin 			sh_offstate(SH_MONITOR);
5368462SApril.Chin@Sun.COM 			shp->sigflag[SIGTSTP] = 0;
5374887Schin 			/* stop child job */
5384887Schin 			killpg(job.curpgid,SIGTSTP);
5394887Schin 			/* child resumes */
5404887Schin 			job_clear();
5418462SApril.Chin@Sun.COM 			shp->forked = 1;
5428462SApril.Chin@Sun.COM 			shp->exitval = (xno&SH_EXITMASK);
5434887Schin 			return;
5444887Schin 		}
5454887Schin 	}
5464887Schin #endif /* SIGTSTP */
5474887Schin 	/* unlock output pool */
5484887Schin 	sh_offstate(SH_NOTRACK);
5498462SApril.Chin@Sun.COM 	if(!(pool=sfpool(NIL(Sfio_t*),shp->outpool,SF_WRITE)))
5508462SApril.Chin@Sun.COM 		pool = shp->outpool; /* can't happen? */
5514887Schin 	sfclrlock(pool);
5524887Schin #ifdef SIGPIPE
5538462SApril.Chin@Sun.COM 	if(shp->lastsig==SIGPIPE)
5544887Schin 		sfpurge(pool);
5554887Schin #endif /* SIGPIPE */
5564887Schin 	sfclrlock(sfstdin);
5574887Schin 	if(!pp)
5588462SApril.Chin@Sun.COM 		sh_done(shp,sig);
5598462SApril.Chin@Sun.COM 	shp->prefix = 0;
5608462SApril.Chin@Sun.COM #if SHOPT_TYPEDEF
5618462SApril.Chin@Sun.COM 	shp->mktype = 0;
5628462SApril.Chin@Sun.COM #endif /* SHOPT_TYPEDEF*/
5634887Schin 	if(pp->mode == SH_JMPSCRIPT && !pp->prev)
5648462SApril.Chin@Sun.COM 		sh_done(shp,sig);
5658462SApril.Chin@Sun.COM 	if(pp->mode)
5668462SApril.Chin@Sun.COM 		siglongjmp(pp->buff,pp->mode);
5678462SApril.Chin@Sun.COM }
5688462SApril.Chin@Sun.COM 
5698462SApril.Chin@Sun.COM static void array_notify(Namval_t *np, void *data)
5708462SApril.Chin@Sun.COM {
5718462SApril.Chin@Sun.COM 	Namarr_t	*ap = nv_arrayptr(np);
5728462SApril.Chin@Sun.COM 	NOT_USED(data);
5738462SApril.Chin@Sun.COM 	if(ap && ap->fun)
5748462SApril.Chin@Sun.COM 		(*ap->fun)(np, 0, NV_AFREE);
5754887Schin }
5764887Schin 
5774887Schin /*
5784887Schin  * This is the exit routine for the shell
5794887Schin  */
5804887Schin 
5818462SApril.Chin@Sun.COM void sh_done(void *ptr, register int sig)
5824887Schin {
5838462SApril.Chin@Sun.COM 	Shell_t	*shp = (Shell_t*)ptr;
5844887Schin 	register char *t;
5858462SApril.Chin@Sun.COM 	register int savxit = shp->exitval;
5868462SApril.Chin@Sun.COM 	shp->trapnote = 0;
5874887Schin 	indone=1;
588*10898Sroland.mainz@nrubsig.org 	if(sig)
589*10898Sroland.mainz@nrubsig.org 		savxit = SH_EXITSIG|sig;
5908462SApril.Chin@Sun.COM 	if(shp->userinit)
5918462SApril.Chin@Sun.COM 		(*shp->userinit)(shp, -1);
5928462SApril.Chin@Sun.COM 	if(t=shp->st.trapcom[0])
5934887Schin 	{
5948462SApril.Chin@Sun.COM 		shp->st.trapcom[0]=0; /*should free but not long */
5958462SApril.Chin@Sun.COM 		shp->oldexit = savxit;
5964887Schin 		sh_trap(t,0);
5978462SApril.Chin@Sun.COM 		savxit = shp->exitval;
5984887Schin 	}
5994887Schin 	else
6004887Schin 	{
6014887Schin 		/* avoid recursive call for set -e */
6024887Schin 		sh_offstate(SH_ERREXIT);
6034887Schin 		sh_chktrap();
6044887Schin 	}
6058462SApril.Chin@Sun.COM 	nv_scan(shp->var_tree,array_notify,(void*)0,NV_ARRAY,NV_ARRAY);
6068462SApril.Chin@Sun.COM 	sh_freeup(shp);
6074887Schin #if SHOPT_ACCT
6084887Schin 	sh_accend();
6094887Schin #endif	/* SHOPT_ACCT */
6104887Schin #if SHOPT_VSH || SHOPT_ESH
6114887Schin 	if(sh_isoption(SH_EMACS)||sh_isoption(SH_VI)||sh_isoption(SH_GMACS))
6124887Schin 		tty_cooked(-1);
6134887Schin #endif
6144887Schin #ifdef JOBS
6158462SApril.Chin@Sun.COM 	if((sh_isoption(SH_INTERACTIVE) && shp->login_sh) || (!sh_isoption(SH_INTERACTIVE) && (sig==SIGHUP)))
6164887Schin 		job_walk(sfstderr,job_terminate,SIGHUP,NIL(char**));
6174887Schin #endif	/* JOBS */
6188462SApril.Chin@Sun.COM 	job_close(shp);
6198462SApril.Chin@Sun.COM 	if(nv_search("VMTRACE", shp->var_tree,0))
6204887Schin 		strmatch((char*)0,(char*)0);
6214887Schin 	sfsync((Sfio_t*)sfstdin);
6228462SApril.Chin@Sun.COM 	sfsync((Sfio_t*)shp->outpool);
6234887Schin 	sfsync((Sfio_t*)sfstdout);
624*10898Sroland.mainz@nrubsig.org 	if(savxit&SH_EXITSIG)
625*10898Sroland.mainz@nrubsig.org 		sig = savxit&SH_EXITMASK;
6264887Schin 	if(sig)
6274887Schin 	{
6284887Schin 		/* generate fault termination code */
6294887Schin 		signal(sig,SIG_DFL);
6304887Schin 		sigrelease(sig);
6314887Schin 		kill(getpid(),sig);
6324887Schin 		pause();
6334887Schin 	}
6344887Schin #if SHOPT_KIA
6354887Schin 	if(sh_isoption(SH_NOEXEC))
6368462SApril.Chin@Sun.COM 		kiaclose((Lex_t*)shp->lex_context);
6374887Schin #endif /* SHOPT_KIA */
6384887Schin 	exit(savxit&SH_EXITMASK);
6394887Schin }
6404887Schin 
641