14887Schin /***********************************************************************
24887Schin *                                                                      *
34887Schin *               This software is part of the ast package               *
4*8462SApril.Chin@Sun.COM *          Copyright (c) 1982-2008 AT&T Intellectual Property          *
54887Schin *                      and is licensed under the                       *
64887Schin *                  Common Public License, Version 1.0                  *
7*8462SApril.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"
33*8462SApril.Chin@Sun.COM #include	"shlex.h"
344887Schin #include	"variables.h"
354887Schin #include	"jobs.h"
364887Schin #include	"path.h"
37*8462SApril.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 {
63*8462SApril.Chin@Sun.COM 	register Shell_t	*shp = sh_getinterp();
64*8462SApril.Chin@Sun.COM 	register int 		flag=0;
65*8462SApril.Chin@Sun.COM 	register char		*trap;
66*8462SApril.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)
79*8462SApril.Chin@Sun.COM 			nv_putval(COLUMNS, (char*)&v, NV_INT32|NV_RDONLY);
804887Schin 		if(v = rows)
81*8462SApril.Chin@Sun.COM 			nv_putval(LINES, (char*)&v, NV_INT32|NV_RDONLY);
82*8462SApril.Chin@Sun.COM 		shp->winch++;
834887Schin 	}
844887Schin #endif  /* SIGWINCH */
85*8462SApril.Chin@Sun.COM 	if(shp->savesig)
864887Schin 	{
874887Schin 		/* critical region, save and process later */
88*8462SApril.Chin@Sun.COM 		shp->savesig = sig;
89*8462SApril.Chin@Sun.COM 		return;
90*8462SApril.Chin@Sun.COM 	}
91*8462SApril.Chin@Sun.COM 	trap = shp->st.trapcom[sig];
92*8462SApril.Chin@Sun.COM 	if(sig==SIGALRM && shp->bltinfun==b_sleep)
93*8462SApril.Chin@Sun.COM 	{
94*8462SApril.Chin@Sun.COM 		if(trap && *trap)
95*8462SApril.Chin@Sun.COM 		{
96*8462SApril.Chin@Sun.COM 			shp->trapnote |= SH_SIGTRAP;
97*8462SApril.Chin@Sun.COM 			shp->sigflag[sig] |= SH_SIGTRAP;
98*8462SApril.Chin@Sun.COM 		}
994887Schin 		return;
1004887Schin 	}
101*8462SApril.Chin@Sun.COM 	if(shp->subshell && sig!=SIGINT && sig!=SIGQUIT && sig!=SIGWINCH)
102*8462SApril.Chin@Sun.COM 	{
103*8462SApril.Chin@Sun.COM 		shp->exitval = SH_EXITSIG|sig;
104*8462SApril.Chin@Sun.COM 		sh_subfork();
105*8462SApril.Chin@Sun.COM 		shp->exitval = 0;
106*8462SApril.Chin@Sun.COM 		return;
107*8462SApril.Chin@Sun.COM 	}
1084887Schin 	/* handle ignored signals */
109*8462SApril.Chin@Sun.COM 	if(trap && *trap==0)
1104887Schin 		return;
111*8462SApril.Chin@Sun.COM 	flag = shp->sigflag[sig]&~SH_SIGOFF;
1124887Schin 	if(!trap)
1134887Schin 	{
114*8462SApril.Chin@Sun.COM 		if(sig==SIGINT && (shp->trapnote&SH_SIGIGNORE))
115*8462SApril.Chin@Sun.COM 			return;
1164887Schin 		if(flag&SH_SIGIGNORE)
1174887Schin 			return;
1184887Schin 		if(flag&SH_SIGDONE)
1194887Schin 		{
1204887Schin 			void *ptr=0;
121*8462SApril.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)
125*8462SApril.Chin@Sun.COM 					shp->trapnote |= SH_SIGTERM;
1264887Schin 				return;
1274887Schin 			}
128*8462SApril.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);
138*8462SApril.Chin@Sun.COM 				if(!shp->subshell)
139*8462SApril.Chin@Sun.COM 					sh_done(shp,sig);
1404887Schin 				sh_exit(SH_EXITSIG);
1414887Schin 			}
1424887Schin 			/* mark signal and continue */
143*8462SApril.Chin@Sun.COM 			shp->trapnote |= SH_SIGSET;
144*8462SApril.Chin@Sun.COM 			if(sig < shp->sigmax)
145*8462SApril.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)
161*8462SApril.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 	{
173*8462SApril.Chin@Sun.COM 		shp->lastsig = sig;
1744887Schin 		flag = SH_SIGSET;
1754887Schin #ifdef SIGTSTP
1764887Schin 		if(sig==SIGTSTP)
1774887Schin 		{
178*8462SApril.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
189*8462SApril.Chin@Sun.COM 	/* This is obsolete */
190*8462SApril.Chin@Sun.COM 	if((error_info.flags&ERROR_NOTIFY) && shp->bltinfun)
191*8462SApril.Chin@Sun.COM 		action = (*shp->bltinfun)(-sig,(char**)0,(void*)0);
1924887Schin 	if(action>0)
1934887Schin 		return;
194*8462SApril.Chin@Sun.COM #endif
195*8462SApril.Chin@Sun.COM 	if(shp->bltinfun && shp->bltindata.notify)
196*8462SApril.Chin@Sun.COM 	{
197*8462SApril.Chin@Sun.COM 		shp->bltindata.sigset = 1;
198*8462SApril.Chin@Sun.COM 		return;
199*8462SApril.Chin@Sun.COM 	}
200*8462SApril.Chin@Sun.COM 	shp->trapnote |= flag;
201*8462SApril.Chin@Sun.COM 	if(sig < shp->sigmax)
202*8462SApril.Chin@Sun.COM 		shp->sigflag[sig] |= flag;
2034887Schin 	if(pp->mode==SH_JMPCMD && sh_isstate(SH_STOPOK))
2044887Schin 	{
2054887Schin 		if(action<0)
2064887Schin 			return;
2074887Schin 		sigrelease(sig);
2084887Schin 		sh_exit(SH_EXITSIG);
2094887Schin 	}
2104887Schin }
2114887Schin 
2124887Schin /*
2134887Schin  * initialize signal handling
2144887Schin  */
215*8462SApril.Chin@Sun.COM void sh_siginit(void *ptr)
2164887Schin {
217*8462SApril.Chin@Sun.COM 	Shell_t	*shp = (Shell_t*)ptr;
2184887Schin 	register int sig, n=SIGTERM+1;
2194887Schin 	register const struct shtable2	*tp = shtab_signals;
2204887Schin 	sig_begin();
2214887Schin 	/* find the largest signal number in the table */
222*8462SApril.Chin@Sun.COM #ifdef SIGRTMIN
223*8462SApril.Chin@Sun.COM 	shp->sigruntime[SH_SIGRTMIN] = SIGRTMIN;
224*8462SApril.Chin@Sun.COM #endif /* SIGRTMIN */
225*8462SApril.Chin@Sun.COM #ifdef SIGRTMAX
226*8462SApril.Chin@Sun.COM 	shp->sigruntime[SH_SIGRTMAX] = SIGRTMAX;
227*8462SApril.Chin@Sun.COM #endif /* SIGRTMAX */
2284887Schin 	while(*tp->sh_name)
2294887Schin 	{
230*8462SApril.Chin@Sun.COM 		sig = tp->sh_number&((1<<SH_SIGBITS)-1);
231*8462SApril.Chin@Sun.COM 		if ((tp->sh_number>>SH_SIGBITS) & SH_SIGRUNTIME)
232*8462SApril.Chin@Sun.COM 			sig = shp->sigruntime[sig-1];
233*8462SApril.Chin@Sun.COM 		if(sig>n && sig<SH_TRAP)
2344887Schin 			n = sig;
2354887Schin 		tp++;
2364887Schin 	}
237*8462SApril.Chin@Sun.COM 	shp->sigmax = n++;
238*8462SApril.Chin@Sun.COM 	shp->st.trapcom = (char**)calloc(n,sizeof(char*));
239*8462SApril.Chin@Sun.COM 	shp->sigflag = (unsigned char*)calloc(n,1);
240*8462SApril.Chin@Sun.COM 	shp->sigmsg = (char**)calloc(n,sizeof(char*));
2414887Schin 	for(tp=shtab_signals; sig=tp->sh_number; tp++)
2424887Schin 	{
2434887Schin 		n = (sig>>SH_SIGBITS);
244*8462SApril.Chin@Sun.COM 		if((sig &= ((1<<SH_SIGBITS)-1)) > shp->sigmax)
2454887Schin 			continue;
2464887Schin 		sig--;
247*8462SApril.Chin@Sun.COM 		if(n&SH_SIGRUNTIME)
248*8462SApril.Chin@Sun.COM 			sig = shp->sigruntime[sig];
2494887Schin 		if(sig>=0)
2504887Schin 		{
251*8462SApril.Chin@Sun.COM 			shp->sigflag[sig] = n;
2524887Schin 			if(*tp->sh_name)
253*8462SApril.Chin@Sun.COM 				shp->sigmsg[sig] = (char*)tp->sh_value;
2544887Schin 		}
2554887Schin 	}
2564887Schin }
2574887Schin 
2584887Schin /*
2594887Schin  * Turn on trap handler for signal <sig>
2604887Schin  */
2614887Schin void	sh_sigtrap(register int sig)
2624887Schin {
2634887Schin 	register int flag;
2644887Schin 	void (*fun)(int);
2654887Schin 	sh.st.otrapcom = 0;
2664887Schin 	if(sig==0)
2674887Schin 		sh_sigdone();
2684887Schin 	else if(!((flag=sh.sigflag[sig])&(SH_SIGFAULT|SH_SIGOFF)))
2694887Schin 	{
2704887Schin 		/* don't set signal if already set or off by parent */
2714887Schin 		if((fun=signal(sig,sh_fault))==SIG_IGN)
2724887Schin 		{
2734887Schin 			signal(sig,SIG_IGN);
2744887Schin 			flag |= SH_SIGOFF;
2754887Schin 		}
2764887Schin 		else
2774887Schin 		{
2784887Schin 			flag |= SH_SIGFAULT;
2794887Schin 			if(sig==SIGALRM && fun!=SIG_DFL && fun!=sh_fault)
2804887Schin 				signal(sig,fun);
2814887Schin 		}
2824887Schin 		flag &= ~(SH_SIGSET|SH_SIGTRAP);
2834887Schin 		sh.sigflag[sig] = flag;
2844887Schin 	}
2854887Schin }
2864887Schin 
2874887Schin /*
2884887Schin  * set signal handler so sh_done is called for all caught signals
2894887Schin  */
2904887Schin void	sh_sigdone(void)
2914887Schin {
2924887Schin 	register int 	flag, sig = sh.sigmax;
2934887Schin 	sh.sigflag[0] |= SH_SIGFAULT;
2944887Schin 	while(--sig>0)
2954887Schin 	{
2964887Schin 		flag = sh.sigflag[sig];
2974887Schin 		if((flag&(SH_SIGDONE|SH_SIGIGNORE|SH_SIGINTERACTIVE)) && !(flag&(SH_SIGFAULT|SH_SIGOFF)))
2984887Schin 			sh_sigtrap(sig);
2994887Schin 	}
3004887Schin }
3014887Schin 
3024887Schin /*
3034887Schin  * Restore to default signals
3044887Schin  * Free the trap strings if mode is non-zero
3054887Schin  * If mode>1 then ignored traps cause signal to be ignored
3064887Schin  */
3074887Schin void	sh_sigreset(register int mode)
3084887Schin {
3094887Schin 	register char	*trap;
3104887Schin 	register int 	flag, sig=sh.st.trapmax;
3114887Schin 	while(sig-- > 0)
3124887Schin 	{
3134887Schin 		if(trap=sh.st.trapcom[sig])
3144887Schin 		{
3154887Schin 			flag  = sh.sigflag[sig]&~(SH_SIGTRAP|SH_SIGSET);
3164887Schin 			if(*trap)
3174887Schin 			{
3184887Schin 				if(mode)
3194887Schin 					free(trap);
3204887Schin 				sh.st.trapcom[sig] = 0;
3214887Schin 			}
3224887Schin 			else if(sig && mode>1)
3234887Schin 			{
3244887Schin 				signal(sig,SIG_IGN);
3254887Schin 				flag &= ~SH_SIGFAULT;
3264887Schin 				flag |= SH_SIGOFF;
3274887Schin 			}
3284887Schin 			sh.sigflag[sig] = flag;
3294887Schin 		}
3304887Schin 	}
331*8462SApril.Chin@Sun.COM 	for(sig=SH_DEBUGTRAP-1;sig>=0;sig--)
3324887Schin 	{
3334887Schin 		if(trap=sh.st.trap[sig])
3344887Schin 		{
3354887Schin 			if(mode)
3364887Schin 				free(trap);
3374887Schin 			sh.st.trap[sig] = 0;
3384887Schin 		}
3394887Schin 
3404887Schin 	}
3414887Schin 	sh.st.trapcom[0] = 0;
3424887Schin 	if(mode)
3434887Schin 		sh.st.trapmax = 0;
3444887Schin 	sh.trapnote=0;
3454887Schin }
3464887Schin 
3474887Schin /*
3484887Schin  * free up trap if set and restore signal handler if modified
3494887Schin  */
3504887Schin void	sh_sigclear(register int sig)
3514887Schin {
3524887Schin 	register int flag = sh.sigflag[sig];
3534887Schin 	register char *trap;
3544887Schin 	sh.st.otrapcom=0;
3554887Schin 	if(!(flag&SH_SIGFAULT))
3564887Schin 		return;
3574887Schin 	flag &= ~(SH_SIGTRAP|SH_SIGSET);
3584887Schin 	if(trap=sh.st.trapcom[sig])
3594887Schin 	{
3604887Schin 		free(trap);
3614887Schin 		sh.st.trapcom[sig]=0;
3624887Schin 	}
3634887Schin 	sh.sigflag[sig] = flag;
3644887Schin }
3654887Schin 
3664887Schin /*
3674887Schin  * check for traps
3684887Schin  */
3694887Schin 
3704887Schin void	sh_chktrap(void)
3714887Schin {
3724887Schin 	register int 	sig=sh.st.trapmax;
3734887Schin 	register char *trap;
374*8462SApril.Chin@Sun.COM 	if(!(sh.trapnote&~SH_SIGIGNORE))
3754887Schin 		sig=0;
3764887Schin 	sh.trapnote &= ~SH_SIGTRAP;
3774887Schin 	/* execute errexit trap first */
3784887Schin 	if(sh_isstate(SH_ERREXIT) && sh.exitval)
3794887Schin 	{
3804887Schin 		int	sav_trapnote = sh.trapnote;
3814887Schin 		sh.trapnote &= ~SH_SIGSET;
3824887Schin 		if(sh.st.trap[SH_ERRTRAP])
383*8462SApril.Chin@Sun.COM 		{
384*8462SApril.Chin@Sun.COM 			trap = sh.st.trap[SH_ERRTRAP];
385*8462SApril.Chin@Sun.COM 			sh.st.trap[SH_ERRTRAP] = 0;
386*8462SApril.Chin@Sun.COM 			sh_trap(trap,0);
387*8462SApril.Chin@Sun.COM 			sh.st.trap[SH_ERRTRAP] = trap;
388*8462SApril.Chin@Sun.COM 		}
3894887Schin 		sh.trapnote = sav_trapnote;
3904887Schin 		if(sh_isoption(SH_ERREXIT))
3914887Schin 		{
3924887Schin 			struct checkpt	*pp = (struct checkpt*)sh.jmplist;
3934887Schin 			pp->mode = SH_JMPEXIT;
3944887Schin 			sh_exit(sh.exitval);
3954887Schin 		}
3964887Schin 	}
3974887Schin 	if(sh.sigflag[SIGALRM]&SH_SIGALRM)
3984887Schin 		sh_timetraps();
3994887Schin 	while(--sig>=0)
4004887Schin 	{
4014887Schin 		if(sh.sigflag[sig]&SH_SIGTRAP)
4024887Schin 		{
4034887Schin 			sh.sigflag[sig] &= ~SH_SIGTRAP;
4044887Schin 			if(trap=sh.st.trapcom[sig])
4054887Schin 				sh_trap(trap,0);
4064887Schin 		}
4074887Schin 	}
4084887Schin }
4094887Schin 
4104887Schin 
4114887Schin /*
4124887Schin  * parse and execute the given trap string, stream or tree depending on mode
4134887Schin  * mode==0 for string, mode==1 for stream, mode==2 for parse tree
4144887Schin  */
4154887Schin int sh_trap(const char *trap, int mode)
4164887Schin {
417*8462SApril.Chin@Sun.COM 	Shell_t	*shp = sh_getinterp();
418*8462SApril.Chin@Sun.COM 	int	jmpval, savxit = shp->exitval;
4194887Schin 	int	was_history = sh_isstate(SH_HISTORY);
4204887Schin 	int	was_verbose = sh_isstate(SH_VERBOSE);
4214887Schin 	int	staktop = staktell();
4224887Schin 	char	*savptr = stakfreeze(0);
4234887Schin 	struct	checkpt buff;
4244887Schin 	Fcin_t	savefc;
4254887Schin 	fcsave(&savefc);
4264887Schin 	sh_offstate(SH_HISTORY);
4274887Schin 	sh_offstate(SH_VERBOSE);
428*8462SApril.Chin@Sun.COM 	shp->intrap++;
4294887Schin 	sh_pushcontext(&buff,SH_JMPTRAP);
4304887Schin 	jmpval = sigsetjmp(buff.buff,0);
4314887Schin 	if(jmpval == 0)
4324887Schin 	{
4334887Schin 		if(mode==2)
4344887Schin 			sh_exec((Shnode_t*)trap,sh_isstate(SH_ERREXIT));
4354887Schin 		else
4364887Schin 		{
4374887Schin 			Sfio_t *sp;
4384887Schin 			if(mode)
4394887Schin 				sp = (Sfio_t*)trap;
4404887Schin 			else
4414887Schin 				sp = sfopen(NIL(Sfio_t*),trap,"s");
4424887Schin 			sh_eval(sp,0);
4434887Schin 		}
4444887Schin 	}
4454887Schin 	else if(indone)
4464887Schin 	{
4474887Schin 		if(jmpval==SH_JMPSCRIPT)
4484887Schin 			indone=0;
4494887Schin 		else
4504887Schin 		{
4514887Schin 			if(jmpval==SH_JMPEXIT)
452*8462SApril.Chin@Sun.COM 				savxit = shp->exitval;
4534887Schin 			jmpval=SH_JMPTRAP;
4544887Schin 		}
4554887Schin 	}
4564887Schin 	sh_popcontext(&buff);
457*8462SApril.Chin@Sun.COM 	shp->intrap--;
458*8462SApril.Chin@Sun.COM 	sfsync(shp->outpool);
459*8462SApril.Chin@Sun.COM 	if(!shp->indebug && jmpval!=SH_JMPEXIT && jmpval!=SH_JMPFUN)
460*8462SApril.Chin@Sun.COM 		shp->exitval=savxit;
4614887Schin 	stakset(savptr,staktop);
4624887Schin 	fcrestore(&savefc);
4634887Schin 	if(was_history)
4644887Schin 		sh_onstate(SH_HISTORY);
4654887Schin 	if(was_verbose)
4664887Schin 		sh_onstate(SH_VERBOSE);
4674887Schin 	exitset();
4684887Schin 	if(jmpval>SH_JMPTRAP)
469*8462SApril.Chin@Sun.COM 		siglongjmp(*shp->jmplist,jmpval);
470*8462SApril.Chin@Sun.COM 	return(shp->exitval);
4714887Schin }
4724887Schin 
4734887Schin /*
4744887Schin  * exit the current scope and jump to an earlier one based on pp->mode
4754887Schin  */
4764887Schin void sh_exit(register int xno)
4774887Schin {
478*8462SApril.Chin@Sun.COM 	Shell_t	*shp = &sh;
479*8462SApril.Chin@Sun.COM 	register struct checkpt	*pp = (struct checkpt*)shp->jmplist;
4804887Schin 	register int		sig=0;
4814887Schin 	register Sfio_t*	pool;
482*8462SApril.Chin@Sun.COM 	shp->exitval=xno;
4834887Schin 	if(xno==SH_EXITSIG)
484*8462SApril.Chin@Sun.COM 		shp->exitval |= (sig=shp->lastsig);
4854887Schin #ifdef SIGTSTP
486*8462SApril.Chin@Sun.COM 	if(shp->trapnote&SH_SIGTSTP)
4874887Schin 	{
4884887Schin 		/* ^Z detected by the shell */
489*8462SApril.Chin@Sun.COM 		shp->trapnote = 0;
490*8462SApril.Chin@Sun.COM 		shp->sigflag[SIGTSTP] = 0;
491*8462SApril.Chin@Sun.COM 		if(!shp->subshell && sh_isstate(SH_MONITOR) && !sh_isstate(SH_STOPOK))
4924887Schin 			return;
4934887Schin 		if(sh_isstate(SH_TIMING))
4944887Schin 			return;
4954887Schin 		/* Handles ^Z for shell builtins, subshells, and functs */
496*8462SApril.Chin@Sun.COM 		shp->lastsig = 0;
4974887Schin 		sh_onstate(SH_MONITOR);
4984887Schin 		sh_offstate(SH_STOPOK);
499*8462SApril.Chin@Sun.COM 		shp->trapnote = 0;
500*8462SApril.Chin@Sun.COM 		if(!shp->subshell && (sig=sh_fork(0,NIL(int*))))
5014887Schin 		{
5024887Schin 			job.curpgid = 0;
5034887Schin 			job.parent = (pid_t)-1;
5044887Schin 			job_wait(sig);
5054887Schin 			job.parent = 0;
506*8462SApril.Chin@Sun.COM 			shp->sigflag[SIGTSTP] = 0;
5074887Schin 			/* wait for child to stop */
508*8462SApril.Chin@Sun.COM 			shp->exitval = (SH_EXITSIG|SIGTSTP);
5094887Schin 			/* return to prompt mode */
5104887Schin 			pp->mode = SH_JMPERREXIT;
5114887Schin 		}
5124887Schin 		else
5134887Schin 		{
514*8462SApril.Chin@Sun.COM 			if(shp->subshell)
5154887Schin 				sh_subfork();
5164887Schin 			/* child process, put to sleep */
5174887Schin 			sh_offstate(SH_STOPOK);
5184887Schin 			sh_offstate(SH_MONITOR);
519*8462SApril.Chin@Sun.COM 			shp->sigflag[SIGTSTP] = 0;
5204887Schin 			/* stop child job */
5214887Schin 			killpg(job.curpgid,SIGTSTP);
5224887Schin 			/* child resumes */
5234887Schin 			job_clear();
524*8462SApril.Chin@Sun.COM 			shp->forked = 1;
525*8462SApril.Chin@Sun.COM 			shp->exitval = (xno&SH_EXITMASK);
5264887Schin 			return;
5274887Schin 		}
5284887Schin 	}
5294887Schin #endif /* SIGTSTP */
5304887Schin 	/* unlock output pool */
5314887Schin 	sh_offstate(SH_NOTRACK);
532*8462SApril.Chin@Sun.COM 	if(!(pool=sfpool(NIL(Sfio_t*),shp->outpool,SF_WRITE)))
533*8462SApril.Chin@Sun.COM 		pool = shp->outpool; /* can't happen? */
5344887Schin 	sfclrlock(pool);
5354887Schin #ifdef SIGPIPE
536*8462SApril.Chin@Sun.COM 	if(shp->lastsig==SIGPIPE)
5374887Schin 		sfpurge(pool);
5384887Schin #endif /* SIGPIPE */
5394887Schin 	sfclrlock(sfstdin);
5404887Schin 	if(!pp)
541*8462SApril.Chin@Sun.COM 		sh_done(shp,sig);
542*8462SApril.Chin@Sun.COM 	shp->prefix = 0;
543*8462SApril.Chin@Sun.COM #if SHOPT_TYPEDEF
544*8462SApril.Chin@Sun.COM 	shp->mktype = 0;
545*8462SApril.Chin@Sun.COM #endif /* SHOPT_TYPEDEF*/
5464887Schin 	if(pp->mode == SH_JMPSCRIPT && !pp->prev)
547*8462SApril.Chin@Sun.COM 		sh_done(shp,sig);
548*8462SApril.Chin@Sun.COM 	if(pp->mode)
549*8462SApril.Chin@Sun.COM 		siglongjmp(pp->buff,pp->mode);
550*8462SApril.Chin@Sun.COM }
551*8462SApril.Chin@Sun.COM 
552*8462SApril.Chin@Sun.COM static void array_notify(Namval_t *np, void *data)
553*8462SApril.Chin@Sun.COM {
554*8462SApril.Chin@Sun.COM 	Namarr_t	*ap = nv_arrayptr(np);
555*8462SApril.Chin@Sun.COM 	NOT_USED(data);
556*8462SApril.Chin@Sun.COM 	if(ap && ap->fun)
557*8462SApril.Chin@Sun.COM 		(*ap->fun)(np, 0, NV_AFREE);
5584887Schin }
5594887Schin 
5604887Schin /*
5614887Schin  * This is the exit routine for the shell
5624887Schin  */
5634887Schin 
564*8462SApril.Chin@Sun.COM void sh_done(void *ptr, register int sig)
5654887Schin {
566*8462SApril.Chin@Sun.COM 	Shell_t	*shp = (Shell_t*)ptr;
5674887Schin 	register char *t;
568*8462SApril.Chin@Sun.COM 	register int savxit = shp->exitval;
569*8462SApril.Chin@Sun.COM 	shp->trapnote = 0;
5704887Schin 	indone=1;
5714887Schin 	if(sig==0)
572*8462SApril.Chin@Sun.COM 		sig = shp->lastsig;
573*8462SApril.Chin@Sun.COM 	if(shp->userinit)
574*8462SApril.Chin@Sun.COM 		(*shp->userinit)(shp, -1);
575*8462SApril.Chin@Sun.COM 	if(t=shp->st.trapcom[0])
5764887Schin 	{
577*8462SApril.Chin@Sun.COM 		shp->st.trapcom[0]=0; /*should free but not long */
578*8462SApril.Chin@Sun.COM 		shp->oldexit = savxit;
5794887Schin 		sh_trap(t,0);
580*8462SApril.Chin@Sun.COM 		savxit = shp->exitval;
5814887Schin 	}
5824887Schin 	else
5834887Schin 	{
5844887Schin 		/* avoid recursive call for set -e */
5854887Schin 		sh_offstate(SH_ERREXIT);
5864887Schin 		sh_chktrap();
5874887Schin 	}
588*8462SApril.Chin@Sun.COM 	nv_scan(shp->var_tree,array_notify,(void*)0,NV_ARRAY,NV_ARRAY);
589*8462SApril.Chin@Sun.COM 	sh_freeup(shp);
5904887Schin #if SHOPT_ACCT
5914887Schin 	sh_accend();
5924887Schin #endif	/* SHOPT_ACCT */
5934887Schin #if SHOPT_VSH || SHOPT_ESH
5944887Schin 	if(sh_isoption(SH_EMACS)||sh_isoption(SH_VI)||sh_isoption(SH_GMACS))
5954887Schin 		tty_cooked(-1);
5964887Schin #endif
5974887Schin #ifdef JOBS
598*8462SApril.Chin@Sun.COM 	if((sh_isoption(SH_INTERACTIVE) && shp->login_sh) || (!sh_isoption(SH_INTERACTIVE) && (sig==SIGHUP)))
5994887Schin 		job_walk(sfstderr,job_terminate,SIGHUP,NIL(char**));
6004887Schin #endif	/* JOBS */
601*8462SApril.Chin@Sun.COM 	job_close(shp);
602*8462SApril.Chin@Sun.COM 	if(nv_search("VMTRACE", shp->var_tree,0))
6034887Schin 		strmatch((char*)0,(char*)0);
6044887Schin 	sfsync((Sfio_t*)sfstdin);
605*8462SApril.Chin@Sun.COM 	sfsync((Sfio_t*)shp->outpool);
6064887Schin 	sfsync((Sfio_t*)sfstdout);
6074887Schin 	if(sig)
6084887Schin 	{
6094887Schin 		/* generate fault termination code */
6104887Schin 		signal(sig,SIG_DFL);
6114887Schin 		sigrelease(sig);
6124887Schin 		kill(getpid(),sig);
6134887Schin 		pause();
6144887Schin 	}
6154887Schin #if SHOPT_KIA
6164887Schin 	if(sh_isoption(SH_NOEXEC))
617*8462SApril.Chin@Sun.COM 		kiaclose((Lex_t*)shp->lex_context);
6184887Schin #endif /* SHOPT_KIA */
6194887Schin 	exit(savxit&SH_EXITMASK);
6204887Schin }
6214887Schin 
622