xref: /titanic_51/usr/src/lib/libshell/common/sh/fault.c (revision 3e14f97f673e8a630f076077de35afdd43dc1587)
1da2e3ebdSchin /***********************************************************************
2da2e3ebdSchin *                                                                      *
3da2e3ebdSchin *               This software is part of the ast package               *
4*3e14f97fSRoger A. Faulkner *          Copyright (c) 1982-2010 AT&T Intellectual Property          *
5da2e3ebdSchin *                      and is licensed under the                       *
6da2e3ebdSchin *                  Common Public License, Version 1.0                  *
77c2fbfb3SApril Chin *                    by AT&T Intellectual Property                     *
8da2e3ebdSchin *                                                                      *
9da2e3ebdSchin *                A copy of the License is available at                 *
10da2e3ebdSchin *            http://www.opensource.org/licenses/cpl1.0.txt             *
11da2e3ebdSchin *         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
12da2e3ebdSchin *                                                                      *
13da2e3ebdSchin *              Information and Software Systems Research               *
14da2e3ebdSchin *                            AT&T Research                             *
15da2e3ebdSchin *                           Florham Park NJ                            *
16da2e3ebdSchin *                                                                      *
17da2e3ebdSchin *                  David Korn <dgk@research.att.com>                   *
18da2e3ebdSchin *                                                                      *
19da2e3ebdSchin ***********************************************************************/
20da2e3ebdSchin #pragma prototyped
21da2e3ebdSchin /*
22da2e3ebdSchin  * Fault handling routines
23da2e3ebdSchin  *
24da2e3ebdSchin  *   David Korn
25da2e3ebdSchin  *   AT&T Labs
26da2e3ebdSchin  *
27da2e3ebdSchin  */
28da2e3ebdSchin 
29da2e3ebdSchin #include	"defs.h"
30da2e3ebdSchin #include	<fcin.h>
31da2e3ebdSchin #include	"io.h"
32da2e3ebdSchin #include	"history.h"
337c2fbfb3SApril Chin #include	"shlex.h"
34da2e3ebdSchin #include	"variables.h"
35da2e3ebdSchin #include	"jobs.h"
36da2e3ebdSchin #include	"path.h"
377c2fbfb3SApril Chin #include	"builtins.h"
38da2e3ebdSchin 
39da2e3ebdSchin #define abortsig(sig)	(sig==SIGABRT || sig==SIGBUS || sig==SIGILL || sig==SIGSEGV)
40da2e3ebdSchin 
41da2e3ebdSchin static char	indone;
42da2e3ebdSchin 
43da2e3ebdSchin #if !_std_malloc
44da2e3ebdSchin #   include	<vmalloc.h>
45da2e3ebdSchin #endif
46da2e3ebdSchin #if  defined(VMFL) && (VMALLOC_VERSION>=20031205L)
47da2e3ebdSchin     /*
48da2e3ebdSchin      * This exception handler is called after vmalloc() unlocks the region
49da2e3ebdSchin      */
malloc_done(Vmalloc_t * vm,int type,Void_t * val,Vmdisc_t * dp)50da2e3ebdSchin     static int malloc_done(Vmalloc_t* vm, int type, Void_t* val, Vmdisc_t* dp)
51da2e3ebdSchin     {
52da2e3ebdSchin 	dp->exceptf = 0;
53da2e3ebdSchin 	sh_exit(SH_EXITSIG);
54da2e3ebdSchin 	return(0);
55da2e3ebdSchin     }
56da2e3ebdSchin #endif
57da2e3ebdSchin 
58da2e3ebdSchin /*
59da2e3ebdSchin  * Most signals caught or ignored by the shell come here
60da2e3ebdSchin */
sh_fault(register int sig)61da2e3ebdSchin void	sh_fault(register int sig)
62da2e3ebdSchin {
637c2fbfb3SApril Chin 	register Shell_t	*shp = sh_getinterp();
64da2e3ebdSchin 	register int 		flag=0;
65da2e3ebdSchin 	register char		*trap;
667c2fbfb3SApril Chin 	register struct checkpt	*pp = (struct checkpt*)shp->jmplist;
67da2e3ebdSchin 	int	action=0;
68da2e3ebdSchin 	/* reset handler */
69da2e3ebdSchin 	if(!(sig&SH_TRAP))
70da2e3ebdSchin 		signal(sig, sh_fault);
71da2e3ebdSchin 	sig &= ~SH_TRAP;
72da2e3ebdSchin #ifdef SIGWINCH
73da2e3ebdSchin 	if(sig==SIGWINCH)
74da2e3ebdSchin 	{
75da2e3ebdSchin 		int rows=0, cols=0;
76da2e3ebdSchin 		int32_t v;
77da2e3ebdSchin 		astwinsize(2,&rows,&cols);
78da2e3ebdSchin 		if(v = cols)
797c2fbfb3SApril Chin 			nv_putval(COLUMNS, (char*)&v, NV_INT32|NV_RDONLY);
80da2e3ebdSchin 		if(v = rows)
817c2fbfb3SApril Chin 			nv_putval(LINES, (char*)&v, NV_INT32|NV_RDONLY);
827c2fbfb3SApril Chin 		shp->winch++;
83da2e3ebdSchin 	}
84da2e3ebdSchin #endif  /* SIGWINCH */
857c2fbfb3SApril Chin 	if(shp->savesig)
86da2e3ebdSchin 	{
87da2e3ebdSchin 		/* critical region, save and process later */
887c2fbfb3SApril Chin 		shp->savesig = sig;
89da2e3ebdSchin 		return;
90da2e3ebdSchin 	}
917c2fbfb3SApril Chin 	trap = shp->st.trapcom[sig];
927c2fbfb3SApril Chin 	if(sig==SIGALRM && shp->bltinfun==b_sleep)
937c2fbfb3SApril Chin 	{
947c2fbfb3SApril Chin 		if(trap && *trap)
957c2fbfb3SApril Chin 		{
967c2fbfb3SApril Chin 			shp->trapnote |= SH_SIGTRAP;
977c2fbfb3SApril Chin 			shp->sigflag[sig] |= SH_SIGTRAP;
987c2fbfb3SApril Chin 		}
99da2e3ebdSchin 		return;
1007c2fbfb3SApril Chin 	}
10134f9b3eeSRoland Mainz 	if(shp->subshell && sig!=SIGINT && sig!=SIGQUIT && sig!=SIGWINCH && sig!=SIGCONT)
1027c2fbfb3SApril Chin 	{
1037c2fbfb3SApril Chin 		shp->exitval = SH_EXITSIG|sig;
1047c2fbfb3SApril Chin 		sh_subfork();
1057c2fbfb3SApril Chin 		shp->exitval = 0;
1067c2fbfb3SApril Chin 		return;
1077c2fbfb3SApril Chin 	}
1087c2fbfb3SApril Chin 	/* handle ignored signals */
1097c2fbfb3SApril Chin 	if(trap && *trap==0)
1107c2fbfb3SApril Chin 		return;
1117c2fbfb3SApril Chin 	flag = shp->sigflag[sig]&~SH_SIGOFF;
112da2e3ebdSchin 	if(!trap)
113da2e3ebdSchin 	{
1147c2fbfb3SApril Chin 		if(sig==SIGINT && (shp->trapnote&SH_SIGIGNORE))
1157c2fbfb3SApril Chin 			return;
116da2e3ebdSchin 		if(flag&SH_SIGIGNORE)
117da2e3ebdSchin 			return;
118da2e3ebdSchin 		if(flag&SH_SIGDONE)
119da2e3ebdSchin 		{
120da2e3ebdSchin 			void *ptr=0;
1217c2fbfb3SApril Chin 			if((flag&SH_SIGINTERACTIVE) && sh_isstate(SH_INTERACTIVE) && !sh_isstate(SH_FORKED) && ! shp->subshell)
122da2e3ebdSchin 			{
123da2e3ebdSchin 				/* check for TERM signal between fork/exec */
124da2e3ebdSchin 				if(sig==SIGTERM && job.in_critical)
1257c2fbfb3SApril Chin 					shp->trapnote |= SH_SIGTERM;
126da2e3ebdSchin 				return;
127da2e3ebdSchin 			}
1287c2fbfb3SApril Chin 			shp->lastsig = sig;
129da2e3ebdSchin 			sigrelease(sig);
130da2e3ebdSchin 			if(pp->mode < SH_JMPFUN)
131da2e3ebdSchin 				pp->mode = SH_JMPFUN;
132da2e3ebdSchin 			else
133da2e3ebdSchin 				pp->mode = SH_JMPEXIT;
134da2e3ebdSchin 			if(sig==SIGABRT || (abortsig(sig) && (ptr = malloc(1))))
135da2e3ebdSchin 			{
136da2e3ebdSchin 				if(ptr)
137da2e3ebdSchin 					free(ptr);
1387c2fbfb3SApril Chin 				if(!shp->subshell)
1397c2fbfb3SApril Chin 					sh_done(shp,sig);
140da2e3ebdSchin 				sh_exit(SH_EXITSIG);
141da2e3ebdSchin 			}
142da2e3ebdSchin 			/* mark signal and continue */
1437c2fbfb3SApril Chin 			shp->trapnote |= SH_SIGSET;
14434f9b3eeSRoland Mainz 			if(sig <= shp->sigmax)
1457c2fbfb3SApril Chin 				shp->sigflag[sig] |= SH_SIGSET;
146da2e3ebdSchin #if  defined(VMFL) && (VMALLOC_VERSION>=20031205L)
147da2e3ebdSchin 			if(abortsig(sig))
148da2e3ebdSchin 			{
149da2e3ebdSchin 				/* abort inside malloc, process when malloc returns */
150da2e3ebdSchin 				/* VMFL defined when using vmalloc() */
151da2e3ebdSchin 				Vmdisc_t* dp = vmdisc(Vmregion,0);
152da2e3ebdSchin 				if(dp)
153da2e3ebdSchin 					dp->exceptf = malloc_done;
154da2e3ebdSchin 			}
155da2e3ebdSchin #endif
156da2e3ebdSchin 			return;
157da2e3ebdSchin 		}
158da2e3ebdSchin 	}
159da2e3ebdSchin 	errno = 0;
160da2e3ebdSchin 	if(pp->mode==SH_JMPCMD)
1617c2fbfb3SApril Chin 		shp->lastsig = sig;
162da2e3ebdSchin 	if(trap)
163da2e3ebdSchin 	{
164da2e3ebdSchin 		/*
165da2e3ebdSchin 		 * propogate signal to foreground group
166da2e3ebdSchin 		 */
167da2e3ebdSchin 		if(sig==SIGHUP && job.curpgid)
168da2e3ebdSchin 			killpg(job.curpgid,SIGHUP);
169da2e3ebdSchin 		flag = SH_SIGTRAP;
170da2e3ebdSchin 	}
171da2e3ebdSchin 	else
172da2e3ebdSchin 	{
1737c2fbfb3SApril Chin 		shp->lastsig = sig;
174da2e3ebdSchin 		flag = SH_SIGSET;
175da2e3ebdSchin #ifdef SIGTSTP
176da2e3ebdSchin 		if(sig==SIGTSTP)
177da2e3ebdSchin 		{
1787c2fbfb3SApril Chin 			shp->trapnote |= SH_SIGTSTP;
179da2e3ebdSchin 			if(pp->mode==SH_JMPCMD && sh_isstate(SH_STOPOK))
180da2e3ebdSchin 			{
181da2e3ebdSchin 				sigrelease(sig);
182da2e3ebdSchin 				sh_exit(SH_EXITSIG);
183da2e3ebdSchin 				flag = 0;
184da2e3ebdSchin 			}
185da2e3ebdSchin 		}
186da2e3ebdSchin #endif /* SIGTSTP */
187da2e3ebdSchin 	}
188da2e3ebdSchin #ifdef ERROR_NOTIFY
1897c2fbfb3SApril Chin 	if((error_info.flags&ERROR_NOTIFY) && shp->bltinfun)
1907c2fbfb3SApril Chin 		action = (*shp->bltinfun)(-sig,(char**)0,(void*)0);
191da2e3ebdSchin 	if(action>0)
192da2e3ebdSchin 		return;
1937c2fbfb3SApril Chin #endif
1947c2fbfb3SApril Chin 	if(shp->bltinfun && shp->bltindata.notify)
1957c2fbfb3SApril Chin 	{
1967c2fbfb3SApril Chin 		shp->bltindata.sigset = 1;
1977c2fbfb3SApril Chin 		return;
1987c2fbfb3SApril Chin 	}
1997c2fbfb3SApril Chin 	shp->trapnote |= flag;
20034f9b3eeSRoland Mainz 	if(sig <= shp->sigmax)
2017c2fbfb3SApril Chin 		shp->sigflag[sig] |= flag;
202da2e3ebdSchin 	if(pp->mode==SH_JMPCMD && sh_isstate(SH_STOPOK))
203da2e3ebdSchin 	{
204da2e3ebdSchin 		if(action<0)
205da2e3ebdSchin 			return;
206da2e3ebdSchin 		sigrelease(sig);
207da2e3ebdSchin 		sh_exit(SH_EXITSIG);
208da2e3ebdSchin 	}
209da2e3ebdSchin }
210da2e3ebdSchin 
211da2e3ebdSchin /*
212da2e3ebdSchin  * initialize signal handling
213da2e3ebdSchin  */
sh_siginit(void * ptr)2147c2fbfb3SApril Chin void sh_siginit(void *ptr)
215da2e3ebdSchin {
2167c2fbfb3SApril Chin 	Shell_t	*shp = (Shell_t*)ptr;
21734f9b3eeSRoland Mainz 	register int sig, n;
218da2e3ebdSchin 	register const struct shtable2	*tp = shtab_signals;
219da2e3ebdSchin 	sig_begin();
220da2e3ebdSchin 	/* find the largest signal number in the table */
22134f9b3eeSRoland Mainz #if defined(SIGRTMIN) && defined(SIGRTMAX)
22234f9b3eeSRoland Mainz 	if ((n = SIGRTMIN) > 0 && (sig = SIGRTMAX) > n && sig < SH_TRAP)
22334f9b3eeSRoland Mainz 	{
22434f9b3eeSRoland Mainz 		shp->sigruntime[SH_SIGRTMIN] = n;
22534f9b3eeSRoland Mainz 		shp->sigruntime[SH_SIGRTMAX] = sig;
22634f9b3eeSRoland Mainz 	}
22734f9b3eeSRoland Mainz #endif /* SIGRTMIN && SIGRTMAX */
22834f9b3eeSRoland Mainz 	n = SIGTERM;
229da2e3ebdSchin 	while(*tp->sh_name)
230da2e3ebdSchin 	{
23134f9b3eeSRoland Mainz 		sig = (tp->sh_number&((1<<SH_SIGBITS)-1));
23234f9b3eeSRoland Mainz 		if (!(sig-- & SH_TRAP))
23334f9b3eeSRoland Mainz 		{
2347c2fbfb3SApril Chin 			if ((tp->sh_number>>SH_SIGBITS) & SH_SIGRUNTIME)
23534f9b3eeSRoland Mainz 				sig = shp->sigruntime[sig];
2367c2fbfb3SApril Chin 			if(sig>n && sig<SH_TRAP)
237da2e3ebdSchin 				n = sig;
23834f9b3eeSRoland Mainz 		}
239da2e3ebdSchin 		tp++;
240da2e3ebdSchin 	}
2417c2fbfb3SApril Chin 	shp->sigmax = n++;
2427c2fbfb3SApril Chin 	shp->st.trapcom = (char**)calloc(n,sizeof(char*));
2437c2fbfb3SApril Chin 	shp->sigflag = (unsigned char*)calloc(n,1);
2447c2fbfb3SApril Chin 	shp->sigmsg = (char**)calloc(n,sizeof(char*));
245da2e3ebdSchin 	for(tp=shtab_signals; sig=tp->sh_number; tp++)
246da2e3ebdSchin 	{
247da2e3ebdSchin 		n = (sig>>SH_SIGBITS);
24834f9b3eeSRoland Mainz 		if((sig &= ((1<<SH_SIGBITS)-1)) > (shp->sigmax+1))
249da2e3ebdSchin 			continue;
250da2e3ebdSchin 		sig--;
2517c2fbfb3SApril Chin 		if(n&SH_SIGRUNTIME)
2527c2fbfb3SApril Chin 			sig = shp->sigruntime[sig];
253da2e3ebdSchin 		if(sig>=0)
254da2e3ebdSchin 		{
2557c2fbfb3SApril Chin 			shp->sigflag[sig] = n;
256da2e3ebdSchin 			if(*tp->sh_name)
2577c2fbfb3SApril Chin 				shp->sigmsg[sig] = (char*)tp->sh_value;
258da2e3ebdSchin 		}
259da2e3ebdSchin 	}
260da2e3ebdSchin }
261da2e3ebdSchin 
262da2e3ebdSchin /*
263da2e3ebdSchin  * Turn on trap handler for signal <sig>
264da2e3ebdSchin  */
sh_sigtrap(register int sig)265da2e3ebdSchin void	sh_sigtrap(register int sig)
266da2e3ebdSchin {
267da2e3ebdSchin 	register int flag;
268da2e3ebdSchin 	void (*fun)(int);
269da2e3ebdSchin 	sh.st.otrapcom = 0;
270da2e3ebdSchin 	if(sig==0)
271da2e3ebdSchin 		sh_sigdone();
272da2e3ebdSchin 	else if(!((flag=sh.sigflag[sig])&(SH_SIGFAULT|SH_SIGOFF)))
273da2e3ebdSchin 	{
274da2e3ebdSchin 		/* don't set signal if already set or off by parent */
275da2e3ebdSchin 		if((fun=signal(sig,sh_fault))==SIG_IGN)
276da2e3ebdSchin 		{
277da2e3ebdSchin 			signal(sig,SIG_IGN);
278da2e3ebdSchin 			flag |= SH_SIGOFF;
279da2e3ebdSchin 		}
280da2e3ebdSchin 		else
281da2e3ebdSchin 		{
282da2e3ebdSchin 			flag |= SH_SIGFAULT;
283da2e3ebdSchin 			if(sig==SIGALRM && fun!=SIG_DFL && fun!=sh_fault)
284da2e3ebdSchin 				signal(sig,fun);
285da2e3ebdSchin 		}
286da2e3ebdSchin 		flag &= ~(SH_SIGSET|SH_SIGTRAP);
287da2e3ebdSchin 		sh.sigflag[sig] = flag;
288da2e3ebdSchin 	}
289da2e3ebdSchin }
290da2e3ebdSchin 
291da2e3ebdSchin /*
292da2e3ebdSchin  * set signal handler so sh_done is called for all caught signals
293da2e3ebdSchin  */
sh_sigdone(void)294da2e3ebdSchin void	sh_sigdone(void)
295da2e3ebdSchin {
296da2e3ebdSchin 	register int 	flag, sig = sh.sigmax;
297da2e3ebdSchin 	sh.sigflag[0] |= SH_SIGFAULT;
29834f9b3eeSRoland Mainz 	for(sig=sh.sigmax; sig>0; sig--)
299da2e3ebdSchin 	{
300da2e3ebdSchin 		flag = sh.sigflag[sig];
301da2e3ebdSchin 		if((flag&(SH_SIGDONE|SH_SIGIGNORE|SH_SIGINTERACTIVE)) && !(flag&(SH_SIGFAULT|SH_SIGOFF)))
302da2e3ebdSchin 			sh_sigtrap(sig);
303da2e3ebdSchin 	}
304da2e3ebdSchin }
305da2e3ebdSchin 
306da2e3ebdSchin /*
307da2e3ebdSchin  * Restore to default signals
308da2e3ebdSchin  * Free the trap strings if mode is non-zero
309da2e3ebdSchin  * If mode>1 then ignored traps cause signal to be ignored
310da2e3ebdSchin  */
sh_sigreset(register int mode)311da2e3ebdSchin void	sh_sigreset(register int mode)
312da2e3ebdSchin {
313da2e3ebdSchin 	register char	*trap;
314da2e3ebdSchin 	register int 	flag, sig=sh.st.trapmax;
315da2e3ebdSchin 	while(sig-- > 0)
316da2e3ebdSchin 	{
317da2e3ebdSchin 		if(trap=sh.st.trapcom[sig])
318da2e3ebdSchin 		{
319da2e3ebdSchin 			flag  = sh.sigflag[sig]&~(SH_SIGTRAP|SH_SIGSET);
320da2e3ebdSchin 			if(*trap)
321da2e3ebdSchin 			{
322da2e3ebdSchin 				if(mode)
323da2e3ebdSchin 					free(trap);
324da2e3ebdSchin 				sh.st.trapcom[sig] = 0;
325da2e3ebdSchin 			}
326da2e3ebdSchin 			else if(sig && mode>1)
327da2e3ebdSchin 			{
32834f9b3eeSRoland Mainz 				if(sig!=SIGCHLD)
329da2e3ebdSchin 					signal(sig,SIG_IGN);
330da2e3ebdSchin 				flag &= ~SH_SIGFAULT;
331da2e3ebdSchin 				flag |= SH_SIGOFF;
332da2e3ebdSchin 			}
333da2e3ebdSchin 			sh.sigflag[sig] = flag;
334da2e3ebdSchin 		}
335da2e3ebdSchin 	}
3367c2fbfb3SApril Chin 	for(sig=SH_DEBUGTRAP-1;sig>=0;sig--)
337da2e3ebdSchin 	{
338da2e3ebdSchin 		if(trap=sh.st.trap[sig])
339da2e3ebdSchin 		{
340da2e3ebdSchin 			if(mode)
341da2e3ebdSchin 				free(trap);
342da2e3ebdSchin 			sh.st.trap[sig] = 0;
343da2e3ebdSchin 		}
344da2e3ebdSchin 
345da2e3ebdSchin 	}
346da2e3ebdSchin 	sh.st.trapcom[0] = 0;
347da2e3ebdSchin 	if(mode)
348da2e3ebdSchin 		sh.st.trapmax = 0;
349da2e3ebdSchin 	sh.trapnote=0;
350da2e3ebdSchin }
351da2e3ebdSchin 
352da2e3ebdSchin /*
353da2e3ebdSchin  * free up trap if set and restore signal handler if modified
354da2e3ebdSchin  */
sh_sigclear(register int sig)355da2e3ebdSchin void	sh_sigclear(register int sig)
356da2e3ebdSchin {
357da2e3ebdSchin 	register int flag = sh.sigflag[sig];
358da2e3ebdSchin 	register char *trap;
359da2e3ebdSchin 	sh.st.otrapcom=0;
360da2e3ebdSchin 	if(!(flag&SH_SIGFAULT))
361da2e3ebdSchin 		return;
362da2e3ebdSchin 	flag &= ~(SH_SIGTRAP|SH_SIGSET);
363da2e3ebdSchin 	if(trap=sh.st.trapcom[sig])
364da2e3ebdSchin 	{
365*3e14f97fSRoger A. Faulkner 		if(!sh.subshell)
366da2e3ebdSchin 			free(trap);
367da2e3ebdSchin 		sh.st.trapcom[sig]=0;
368da2e3ebdSchin 	}
369da2e3ebdSchin 	sh.sigflag[sig] = flag;
370da2e3ebdSchin }
371da2e3ebdSchin 
372da2e3ebdSchin /*
373da2e3ebdSchin  * check for traps
374da2e3ebdSchin  */
375da2e3ebdSchin 
sh_chktrap(void)376da2e3ebdSchin void	sh_chktrap(void)
377da2e3ebdSchin {
378da2e3ebdSchin 	register int 	sig=sh.st.trapmax;
379da2e3ebdSchin 	register char *trap;
3807c2fbfb3SApril Chin 	if(!(sh.trapnote&~SH_SIGIGNORE))
381da2e3ebdSchin 		sig=0;
382da2e3ebdSchin 	sh.trapnote &= ~SH_SIGTRAP;
383da2e3ebdSchin 	/* execute errexit trap first */
384da2e3ebdSchin 	if(sh_isstate(SH_ERREXIT) && sh.exitval)
385da2e3ebdSchin 	{
386da2e3ebdSchin 		int	sav_trapnote = sh.trapnote;
387da2e3ebdSchin 		sh.trapnote &= ~SH_SIGSET;
388da2e3ebdSchin 		if(sh.st.trap[SH_ERRTRAP])
3897c2fbfb3SApril Chin 		{
3907c2fbfb3SApril Chin 			trap = sh.st.trap[SH_ERRTRAP];
3917c2fbfb3SApril Chin 			sh.st.trap[SH_ERRTRAP] = 0;
3927c2fbfb3SApril Chin 			sh_trap(trap,0);
3937c2fbfb3SApril Chin 			sh.st.trap[SH_ERRTRAP] = trap;
3947c2fbfb3SApril Chin 		}
395da2e3ebdSchin 		sh.trapnote = sav_trapnote;
396da2e3ebdSchin 		if(sh_isoption(SH_ERREXIT))
397da2e3ebdSchin 		{
398da2e3ebdSchin 			struct checkpt	*pp = (struct checkpt*)sh.jmplist;
399da2e3ebdSchin 			pp->mode = SH_JMPEXIT;
400da2e3ebdSchin 			sh_exit(sh.exitval);
401da2e3ebdSchin 		}
402da2e3ebdSchin 	}
403da2e3ebdSchin 	if(sh.sigflag[SIGALRM]&SH_SIGALRM)
404da2e3ebdSchin 		sh_timetraps();
40534f9b3eeSRoland Mainz #ifdef SHOPT_BGX
40634f9b3eeSRoland Mainz 	if((sh.sigflag[SIGCHLD]&SH_SIGTRAP) && sh.st.trapcom[SIGCHLD])
40734f9b3eeSRoland Mainz 		job_chldtrap(&sh,sh.st.trapcom[SIGCHLD],1);
40834f9b3eeSRoland Mainz #endif /* SHOPT_BGX */
409*3e14f97fSRoger A. Faulkner 	while(--sig>=0)
410da2e3ebdSchin 	{
411*3e14f97fSRoger A. Faulkner #ifdef SHOPT_BGX
412*3e14f97fSRoger A. Faulkner 		if(sig==SIGCHLD)
413*3e14f97fSRoger A. Faulkner 			continue;
414*3e14f97fSRoger A. Faulkner #endif /* SHOPT_BGX */
415da2e3ebdSchin 		if(sh.sigflag[sig]&SH_SIGTRAP)
416da2e3ebdSchin 		{
417da2e3ebdSchin 			sh.sigflag[sig] &= ~SH_SIGTRAP;
418da2e3ebdSchin 			if(trap=sh.st.trapcom[sig])
41934f9b3eeSRoland Mainz 			{
42034f9b3eeSRoland Mainz 				Sfio_t *fp;
42134f9b3eeSRoland Mainz 				if(sig==SIGPIPE && (fp=sfpool((Sfio_t*)0,sh.outpool,SF_WRITE)) && sferror(fp))
42234f9b3eeSRoland Mainz 					sfclose(fp);
42334f9b3eeSRoland Mainz  				sh.oldexit = SH_EXITSIG|sig;
424da2e3ebdSchin  				sh_trap(trap,0);
425da2e3ebdSchin  			}
426da2e3ebdSchin 		}
427da2e3ebdSchin 	}
42834f9b3eeSRoland Mainz }
429da2e3ebdSchin 
430da2e3ebdSchin 
431da2e3ebdSchin /*
432da2e3ebdSchin  * parse and execute the given trap string, stream or tree depending on mode
433da2e3ebdSchin  * mode==0 for string, mode==1 for stream, mode==2 for parse tree
434da2e3ebdSchin  */
sh_trap(const char * trap,int mode)435da2e3ebdSchin int sh_trap(const char *trap, int mode)
436da2e3ebdSchin {
4377c2fbfb3SApril Chin 	Shell_t	*shp = sh_getinterp();
4387c2fbfb3SApril Chin 	int	jmpval, savxit = shp->exitval;
439da2e3ebdSchin 	int	was_history = sh_isstate(SH_HISTORY);
440da2e3ebdSchin 	int	was_verbose = sh_isstate(SH_VERBOSE);
441da2e3ebdSchin 	int	staktop = staktell();
442da2e3ebdSchin 	char	*savptr = stakfreeze(0);
443*3e14f97fSRoger A. Faulkner 	char	ifstable[256];
444da2e3ebdSchin 	struct	checkpt buff;
445da2e3ebdSchin 	Fcin_t	savefc;
446da2e3ebdSchin 	fcsave(&savefc);
447*3e14f97fSRoger A. Faulkner 	memcpy(ifstable,shp->ifstable,sizeof(ifstable));
448da2e3ebdSchin 	sh_offstate(SH_HISTORY);
449da2e3ebdSchin 	sh_offstate(SH_VERBOSE);
4507c2fbfb3SApril Chin 	shp->intrap++;
451da2e3ebdSchin 	sh_pushcontext(&buff,SH_JMPTRAP);
452da2e3ebdSchin 	jmpval = sigsetjmp(buff.buff,0);
453da2e3ebdSchin 	if(jmpval == 0)
454da2e3ebdSchin 	{
455da2e3ebdSchin 		if(mode==2)
456da2e3ebdSchin 			sh_exec((Shnode_t*)trap,sh_isstate(SH_ERREXIT));
457da2e3ebdSchin 		else
458da2e3ebdSchin 		{
459da2e3ebdSchin 			Sfio_t *sp;
460da2e3ebdSchin 			if(mode)
461da2e3ebdSchin 				sp = (Sfio_t*)trap;
462da2e3ebdSchin 			else
463da2e3ebdSchin 				sp = sfopen(NIL(Sfio_t*),trap,"s");
464da2e3ebdSchin 			sh_eval(sp,0);
465da2e3ebdSchin 		}
466da2e3ebdSchin 	}
467da2e3ebdSchin 	else if(indone)
468da2e3ebdSchin 	{
469da2e3ebdSchin 		if(jmpval==SH_JMPSCRIPT)
470da2e3ebdSchin 			indone=0;
471da2e3ebdSchin 		else
472da2e3ebdSchin 		{
473da2e3ebdSchin 			if(jmpval==SH_JMPEXIT)
4747c2fbfb3SApril Chin 				savxit = shp->exitval;
475da2e3ebdSchin 			jmpval=SH_JMPTRAP;
476da2e3ebdSchin 		}
477da2e3ebdSchin 	}
478da2e3ebdSchin 	sh_popcontext(&buff);
4797c2fbfb3SApril Chin 	shp->intrap--;
4807c2fbfb3SApril Chin 	sfsync(shp->outpool);
4817c2fbfb3SApril Chin 	if(!shp->indebug && jmpval!=SH_JMPEXIT && jmpval!=SH_JMPFUN)
4827c2fbfb3SApril Chin 		shp->exitval=savxit;
483da2e3ebdSchin 	stakset(savptr,staktop);
484da2e3ebdSchin 	fcrestore(&savefc);
485*3e14f97fSRoger A. Faulkner 	memcpy(shp->ifstable,ifstable,sizeof(ifstable));
486da2e3ebdSchin 	if(was_history)
487da2e3ebdSchin 		sh_onstate(SH_HISTORY);
488da2e3ebdSchin 	if(was_verbose)
489da2e3ebdSchin 		sh_onstate(SH_VERBOSE);
490da2e3ebdSchin 	exitset();
49134f9b3eeSRoland Mainz 	if(jmpval>SH_JMPTRAP && (((struct checkpt*)shp->jmpbuffer)->prev || ((struct checkpt*)shp->jmpbuffer)->mode==SH_JMPSCRIPT))
4927c2fbfb3SApril Chin 		siglongjmp(*shp->jmplist,jmpval);
4937c2fbfb3SApril Chin 	return(shp->exitval);
494da2e3ebdSchin }
495da2e3ebdSchin 
496da2e3ebdSchin /*
497da2e3ebdSchin  * exit the current scope and jump to an earlier one based on pp->mode
498da2e3ebdSchin  */
sh_exit(register int xno)499da2e3ebdSchin void sh_exit(register int xno)
500da2e3ebdSchin {
5017c2fbfb3SApril Chin 	Shell_t	*shp = &sh;
5027c2fbfb3SApril Chin 	register struct checkpt	*pp = (struct checkpt*)shp->jmplist;
503da2e3ebdSchin 	register int		sig=0;
504da2e3ebdSchin 	register Sfio_t*	pool;
5057c2fbfb3SApril Chin 	shp->exitval=xno;
506da2e3ebdSchin 	if(xno==SH_EXITSIG)
5077c2fbfb3SApril Chin 		shp->exitval |= (sig=shp->lastsig);
508da2e3ebdSchin #ifdef SIGTSTP
5097c2fbfb3SApril Chin 	if(shp->trapnote&SH_SIGTSTP)
510da2e3ebdSchin 	{
511da2e3ebdSchin 		/* ^Z detected by the shell */
5127c2fbfb3SApril Chin 		shp->trapnote = 0;
5137c2fbfb3SApril Chin 		shp->sigflag[SIGTSTP] = 0;
5147c2fbfb3SApril Chin 		if(!shp->subshell && sh_isstate(SH_MONITOR) && !sh_isstate(SH_STOPOK))
515da2e3ebdSchin 			return;
516da2e3ebdSchin 		if(sh_isstate(SH_TIMING))
517da2e3ebdSchin 			return;
518da2e3ebdSchin 		/* Handles ^Z for shell builtins, subshells, and functs */
5197c2fbfb3SApril Chin 		shp->lastsig = 0;
520da2e3ebdSchin 		sh_onstate(SH_MONITOR);
521da2e3ebdSchin 		sh_offstate(SH_STOPOK);
5227c2fbfb3SApril Chin 		shp->trapnote = 0;
5237c2fbfb3SApril Chin 		if(!shp->subshell && (sig=sh_fork(0,NIL(int*))))
524da2e3ebdSchin 		{
525da2e3ebdSchin 			job.curpgid = 0;
526da2e3ebdSchin 			job.parent = (pid_t)-1;
527da2e3ebdSchin 			job_wait(sig);
528da2e3ebdSchin 			job.parent = 0;
5297c2fbfb3SApril Chin 			shp->sigflag[SIGTSTP] = 0;
530da2e3ebdSchin 			/* wait for child to stop */
5317c2fbfb3SApril Chin 			shp->exitval = (SH_EXITSIG|SIGTSTP);
532da2e3ebdSchin 			/* return to prompt mode */
533da2e3ebdSchin 			pp->mode = SH_JMPERREXIT;
534da2e3ebdSchin 		}
535da2e3ebdSchin 		else
536da2e3ebdSchin 		{
5377c2fbfb3SApril Chin 			if(shp->subshell)
538da2e3ebdSchin 				sh_subfork();
539da2e3ebdSchin 			/* child process, put to sleep */
540da2e3ebdSchin 			sh_offstate(SH_STOPOK);
541da2e3ebdSchin 			sh_offstate(SH_MONITOR);
5427c2fbfb3SApril Chin 			shp->sigflag[SIGTSTP] = 0;
543da2e3ebdSchin 			/* stop child job */
544da2e3ebdSchin 			killpg(job.curpgid,SIGTSTP);
545da2e3ebdSchin 			/* child resumes */
546da2e3ebdSchin 			job_clear();
5477c2fbfb3SApril Chin 			shp->forked = 1;
5487c2fbfb3SApril Chin 			shp->exitval = (xno&SH_EXITMASK);
549da2e3ebdSchin 			return;
550da2e3ebdSchin 		}
551da2e3ebdSchin 	}
552da2e3ebdSchin #endif /* SIGTSTP */
553da2e3ebdSchin 	/* unlock output pool */
554da2e3ebdSchin 	sh_offstate(SH_NOTRACK);
5557c2fbfb3SApril Chin 	if(!(pool=sfpool(NIL(Sfio_t*),shp->outpool,SF_WRITE)))
5567c2fbfb3SApril Chin 		pool = shp->outpool; /* can't happen? */
557da2e3ebdSchin 	sfclrlock(pool);
558da2e3ebdSchin #ifdef SIGPIPE
5597c2fbfb3SApril Chin 	if(shp->lastsig==SIGPIPE)
560da2e3ebdSchin 		sfpurge(pool);
561da2e3ebdSchin #endif /* SIGPIPE */
562da2e3ebdSchin 	sfclrlock(sfstdin);
563da2e3ebdSchin 	if(!pp)
5647c2fbfb3SApril Chin 		sh_done(shp,sig);
5657c2fbfb3SApril Chin 	shp->prefix = 0;
5667c2fbfb3SApril Chin #if SHOPT_TYPEDEF
5677c2fbfb3SApril Chin 	shp->mktype = 0;
5687c2fbfb3SApril Chin #endif /* SHOPT_TYPEDEF*/
569da2e3ebdSchin 	if(pp->mode == SH_JMPSCRIPT && !pp->prev)
5707c2fbfb3SApril Chin 		sh_done(shp,sig);
5717c2fbfb3SApril Chin 	if(pp->mode)
572da2e3ebdSchin 		siglongjmp(pp->buff,pp->mode);
573da2e3ebdSchin }
574da2e3ebdSchin 
array_notify(Namval_t * np,void * data)5757c2fbfb3SApril Chin static void array_notify(Namval_t *np, void *data)
5767c2fbfb3SApril Chin {
5777c2fbfb3SApril Chin 	Namarr_t	*ap = nv_arrayptr(np);
5787c2fbfb3SApril Chin 	NOT_USED(data);
5797c2fbfb3SApril Chin 	if(ap && ap->fun)
5807c2fbfb3SApril Chin 		(*ap->fun)(np, 0, NV_AFREE);
5817c2fbfb3SApril Chin }
5827c2fbfb3SApril Chin 
583da2e3ebdSchin /*
584da2e3ebdSchin  * This is the exit routine for the shell
585da2e3ebdSchin  */
586da2e3ebdSchin 
sh_done(void * ptr,register int sig)5877c2fbfb3SApril Chin void sh_done(void *ptr, register int sig)
588da2e3ebdSchin {
5897c2fbfb3SApril Chin 	Shell_t	*shp = (Shell_t*)ptr;
590da2e3ebdSchin 	register char *t;
5917c2fbfb3SApril Chin 	register int savxit = shp->exitval;
5927c2fbfb3SApril Chin 	shp->trapnote = 0;
593da2e3ebdSchin 	indone=1;
59434f9b3eeSRoland Mainz 	if(sig)
59534f9b3eeSRoland Mainz 		savxit = SH_EXITSIG|sig;
5967c2fbfb3SApril Chin 	if(shp->userinit)
5977c2fbfb3SApril Chin 		(*shp->userinit)(shp, -1);
5987c2fbfb3SApril Chin 	if(t=shp->st.trapcom[0])
599da2e3ebdSchin 	{
6007c2fbfb3SApril Chin 		shp->st.trapcom[0]=0; /*should free but not long */
6017c2fbfb3SApril Chin 		shp->oldexit = savxit;
602da2e3ebdSchin 		sh_trap(t,0);
6037c2fbfb3SApril Chin 		savxit = shp->exitval;
604da2e3ebdSchin 	}
605da2e3ebdSchin 	else
606da2e3ebdSchin 	{
607da2e3ebdSchin 		/* avoid recursive call for set -e */
608da2e3ebdSchin 		sh_offstate(SH_ERREXIT);
609da2e3ebdSchin 		sh_chktrap();
610da2e3ebdSchin 	}
6117c2fbfb3SApril Chin 	nv_scan(shp->var_tree,array_notify,(void*)0,NV_ARRAY,NV_ARRAY);
6127c2fbfb3SApril Chin 	sh_freeup(shp);
613da2e3ebdSchin #if SHOPT_ACCT
614da2e3ebdSchin 	sh_accend();
615da2e3ebdSchin #endif	/* SHOPT_ACCT */
616da2e3ebdSchin #if SHOPT_VSH || SHOPT_ESH
617da2e3ebdSchin 	if(sh_isoption(SH_EMACS)||sh_isoption(SH_VI)||sh_isoption(SH_GMACS))
618da2e3ebdSchin 		tty_cooked(-1);
619da2e3ebdSchin #endif
620da2e3ebdSchin #ifdef JOBS
6217c2fbfb3SApril Chin 	if((sh_isoption(SH_INTERACTIVE) && shp->login_sh) || (!sh_isoption(SH_INTERACTIVE) && (sig==SIGHUP)))
622da2e3ebdSchin 		job_walk(sfstderr,job_terminate,SIGHUP,NIL(char**));
623da2e3ebdSchin #endif	/* JOBS */
6247c2fbfb3SApril Chin 	job_close(shp);
6257c2fbfb3SApril Chin 	if(nv_search("VMTRACE", shp->var_tree,0))
626da2e3ebdSchin 		strmatch((char*)0,(char*)0);
627da2e3ebdSchin 	sfsync((Sfio_t*)sfstdin);
6287c2fbfb3SApril Chin 	sfsync((Sfio_t*)shp->outpool);
629da2e3ebdSchin 	sfsync((Sfio_t*)sfstdout);
63034f9b3eeSRoland Mainz 	if(savxit&SH_EXITSIG)
63134f9b3eeSRoland Mainz 		sig = savxit&SH_EXITMASK;
632da2e3ebdSchin 	if(sig)
633da2e3ebdSchin 	{
634da2e3ebdSchin 		/* generate fault termination code */
635da2e3ebdSchin 		signal(sig,SIG_DFL);
636da2e3ebdSchin 		sigrelease(sig);
637da2e3ebdSchin 		kill(getpid(),sig);
638da2e3ebdSchin 		pause();
639da2e3ebdSchin 	}
640da2e3ebdSchin #if SHOPT_KIA
641da2e3ebdSchin 	if(sh_isoption(SH_NOEXEC))
6427c2fbfb3SApril Chin 		kiaclose((Lex_t*)shp->lex_context);
643da2e3ebdSchin #endif /* SHOPT_KIA */
644da2e3ebdSchin 	exit(savxit&SH_EXITMASK);
645da2e3ebdSchin }
646da2e3ebdSchin 
647