1da2e3ebdSchin /***********************************************************************
2da2e3ebdSchin *                                                                      *
3da2e3ebdSchin *               This software is part of the ast package               *
4*b30d1939SAndy Fiddaman *          Copyright (c) 1982-2012 AT&T Intellectual Property          *
5da2e3ebdSchin *                      and is licensed under the                       *
6*b30d1939SAndy Fiddaman *                 Eclipse Public License, Version 1.0                  *
77c2fbfb3SApril Chin *                    by AT&T Intellectual Property                     *
8da2e3ebdSchin *                                                                      *
9da2e3ebdSchin *                A copy of the License is available at                 *
10*b30d1939SAndy Fiddaman *          http://www.eclipse.org/org/documents/epl-v10.html           *
11*b30d1939SAndy Fiddaman *         (with md5 checksum b35adb5213ca9657e911e9befb180842)         *
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"
38*b30d1939SAndy Fiddaman #include	"ulimit.h"
39da2e3ebdSchin 
40da2e3ebdSchin #define abortsig(sig)	(sig==SIGABRT || sig==SIGBUS || sig==SIGILL || sig==SIGSEGV)
41da2e3ebdSchin 
42da2e3ebdSchin static char	indone;
43*b30d1939SAndy Fiddaman static int	cursig = -1;
44da2e3ebdSchin 
45da2e3ebdSchin #if !_std_malloc
46da2e3ebdSchin #   include	<vmalloc.h>
47da2e3ebdSchin #endif
48da2e3ebdSchin #if  defined(VMFL) && (VMALLOC_VERSION>=20031205L)
49da2e3ebdSchin     /*
50da2e3ebdSchin      * This exception handler is called after vmalloc() unlocks the region
51da2e3ebdSchin      */
malloc_done(Vmalloc_t * vm,int type,Void_t * val,Vmdisc_t * dp)52da2e3ebdSchin     static int malloc_done(Vmalloc_t* vm, int type, Void_t* val, Vmdisc_t* dp)
53da2e3ebdSchin     {
54da2e3ebdSchin 	dp->exceptf = 0;
55da2e3ebdSchin 	sh_exit(SH_EXITSIG);
56da2e3ebdSchin 	return(0);
57da2e3ebdSchin     }
58da2e3ebdSchin #endif
59da2e3ebdSchin 
60da2e3ebdSchin /*
61da2e3ebdSchin  * Most signals caught or ignored by the shell come here
62da2e3ebdSchin */
sh_fault(register int sig)63da2e3ebdSchin void	sh_fault(register int sig)
64da2e3ebdSchin {
657c2fbfb3SApril Chin 	register Shell_t	*shp = sh_getinterp();
667c2fbfb3SApril Chin 	register int 		flag=0;
677c2fbfb3SApril Chin 	register char		*trap;
687c2fbfb3SApril Chin 	register struct checkpt	*pp = (struct checkpt*)shp->jmplist;
69da2e3ebdSchin 	int	action=0;
70da2e3ebdSchin 	/* reset handler */
71da2e3ebdSchin 	if(!(sig&SH_TRAP))
72da2e3ebdSchin 		signal(sig, sh_fault);
73da2e3ebdSchin 	sig &= ~SH_TRAP;
74da2e3ebdSchin #ifdef SIGWINCH
75da2e3ebdSchin 	if(sig==SIGWINCH)
76da2e3ebdSchin 	{
77da2e3ebdSchin 		int rows=0, cols=0;
78da2e3ebdSchin 		int32_t v;
79da2e3ebdSchin 		astwinsize(2,&rows,&cols);
80da2e3ebdSchin 		if(v = cols)
817c2fbfb3SApril Chin 			nv_putval(COLUMNS, (char*)&v, NV_INT32|NV_RDONLY);
82da2e3ebdSchin 		if(v = rows)
837c2fbfb3SApril Chin 			nv_putval(LINES, (char*)&v, NV_INT32|NV_RDONLY);
847c2fbfb3SApril Chin 		shp->winch++;
85da2e3ebdSchin 	}
86da2e3ebdSchin #endif  /* SIGWINCH */
87*b30d1939SAndy Fiddaman 	trap = shp->st.trapcom[sig];
887c2fbfb3SApril Chin 	if(shp->savesig)
89da2e3ebdSchin 	{
90da2e3ebdSchin 		/* critical region, save and process later */
91*b30d1939SAndy Fiddaman 		if(!(shp->sigflag[sig]&SH_SIGIGNORE))
92*b30d1939SAndy Fiddaman 			shp->savesig = sig;
937c2fbfb3SApril Chin 		return;
947c2fbfb3SApril Chin 	}
957c2fbfb3SApril Chin 	if(sig==SIGALRM && shp->bltinfun==b_sleep)
967c2fbfb3SApril Chin 	{
977c2fbfb3SApril Chin 		if(trap && *trap)
987c2fbfb3SApril Chin 		{
997c2fbfb3SApril Chin 			shp->trapnote |= SH_SIGTRAP;
1007c2fbfb3SApril Chin 			shp->sigflag[sig] |= SH_SIGTRAP;
1017c2fbfb3SApril Chin 		}
1027c2fbfb3SApril Chin 		return;
1037c2fbfb3SApril Chin 	}
104*b30d1939SAndy Fiddaman 	if(shp->subshell && trap && sig!=SIGINT && sig!=SIGQUIT && sig!=SIGWINCH && sig!=SIGCONT)
1057c2fbfb3SApril Chin 	{
1067c2fbfb3SApril Chin 		shp->exitval = SH_EXITSIG|sig;
1077c2fbfb3SApril Chin 		sh_subfork();
1087c2fbfb3SApril Chin 		shp->exitval = 0;
109da2e3ebdSchin 		return;
110da2e3ebdSchin 	}
111da2e3ebdSchin 	/* handle ignored signals */
1127c2fbfb3SApril Chin 	if(trap && *trap==0)
113da2e3ebdSchin 		return;
1147c2fbfb3SApril Chin 	flag = shp->sigflag[sig]&~SH_SIGOFF;
115da2e3ebdSchin 	if(!trap)
116da2e3ebdSchin 	{
1177c2fbfb3SApril Chin 		if(sig==SIGINT && (shp->trapnote&SH_SIGIGNORE))
1187c2fbfb3SApril Chin 			return;
119da2e3ebdSchin 		if(flag&SH_SIGIGNORE)
120*b30d1939SAndy Fiddaman 		{
121*b30d1939SAndy Fiddaman 			if(shp->subshell)
122*b30d1939SAndy Fiddaman 				shp->ignsig = sig;
123*b30d1939SAndy Fiddaman 			sigrelease(sig);
124da2e3ebdSchin 			return;
125*b30d1939SAndy Fiddaman 		}
126da2e3ebdSchin 		if(flag&SH_SIGDONE)
127da2e3ebdSchin 		{
128da2e3ebdSchin 			void *ptr=0;
1297c2fbfb3SApril Chin 			if((flag&SH_SIGINTERACTIVE) && sh_isstate(SH_INTERACTIVE) && !sh_isstate(SH_FORKED) && ! shp->subshell)
130da2e3ebdSchin 			{
131da2e3ebdSchin 				/* check for TERM signal between fork/exec */
132da2e3ebdSchin 				if(sig==SIGTERM && job.in_critical)
1337c2fbfb3SApril Chin 					shp->trapnote |= SH_SIGTERM;
134da2e3ebdSchin 				return;
135da2e3ebdSchin 			}
1367c2fbfb3SApril Chin 			shp->lastsig = sig;
137da2e3ebdSchin 			sigrelease(sig);
138*b30d1939SAndy Fiddaman 			if(pp->mode != SH_JMPSUB)
139*b30d1939SAndy Fiddaman 			{
140*b30d1939SAndy Fiddaman 				if(pp->mode < SH_JMPSUB)
141*b30d1939SAndy Fiddaman 					pp->mode = shp->subshell?SH_JMPSUB:SH_JMPFUN;
142*b30d1939SAndy Fiddaman 				else
143*b30d1939SAndy Fiddaman 					pp->mode = SH_JMPEXIT;
144*b30d1939SAndy Fiddaman 			}
145*b30d1939SAndy Fiddaman 			if(shp->subshell)
146*b30d1939SAndy Fiddaman 				sh_exit(SH_EXITSIG);
147da2e3ebdSchin 			if(sig==SIGABRT || (abortsig(sig) && (ptr = malloc(1))))
148da2e3ebdSchin 			{
149da2e3ebdSchin 				if(ptr)
150da2e3ebdSchin 					free(ptr);
151*b30d1939SAndy Fiddaman 				sh_done(shp,sig);
152da2e3ebdSchin 			}
153da2e3ebdSchin 			/* mark signal and continue */
1547c2fbfb3SApril Chin 			shp->trapnote |= SH_SIGSET;
155*b30d1939SAndy Fiddaman 			if(sig <= shp->gd->sigmax)
1567c2fbfb3SApril Chin 				shp->sigflag[sig] |= SH_SIGSET;
157da2e3ebdSchin #if  defined(VMFL) && (VMALLOC_VERSION>=20031205L)
158da2e3ebdSchin 			if(abortsig(sig))
159da2e3ebdSchin 			{
160da2e3ebdSchin 				/* abort inside malloc, process when malloc returns */
161da2e3ebdSchin 				/* VMFL defined when using vmalloc() */
162da2e3ebdSchin 				Vmdisc_t* dp = vmdisc(Vmregion,0);
163da2e3ebdSchin 				if(dp)
164da2e3ebdSchin 					dp->exceptf = malloc_done;
165da2e3ebdSchin 			}
166da2e3ebdSchin #endif
167da2e3ebdSchin 			return;
168da2e3ebdSchin 		}
169da2e3ebdSchin 	}
170da2e3ebdSchin 	errno = 0;
171*b30d1939SAndy Fiddaman 	if(pp->mode==SH_JMPCMD || (pp->mode==1 && shp->bltinfun) && !(flag&SH_SIGIGNORE))
1727c2fbfb3SApril Chin 		shp->lastsig = sig;
173da2e3ebdSchin 	if(trap)
174da2e3ebdSchin 	{
175da2e3ebdSchin 		/*
176da2e3ebdSchin 		 * propogate signal to foreground group
177da2e3ebdSchin 		 */
178da2e3ebdSchin 		if(sig==SIGHUP && job.curpgid)
179da2e3ebdSchin 			killpg(job.curpgid,SIGHUP);
180da2e3ebdSchin 		flag = SH_SIGTRAP;
181da2e3ebdSchin 	}
182da2e3ebdSchin 	else
183da2e3ebdSchin 	{
1847c2fbfb3SApril Chin 		shp->lastsig = sig;
185da2e3ebdSchin 		flag = SH_SIGSET;
186da2e3ebdSchin #ifdef SIGTSTP
187da2e3ebdSchin 		if(sig==SIGTSTP)
188da2e3ebdSchin 		{
1897c2fbfb3SApril Chin 			shp->trapnote |= SH_SIGTSTP;
190da2e3ebdSchin 			if(pp->mode==SH_JMPCMD && sh_isstate(SH_STOPOK))
191da2e3ebdSchin 			{
192da2e3ebdSchin 				sigrelease(sig);
193da2e3ebdSchin 				sh_exit(SH_EXITSIG);
194*b30d1939SAndy Fiddaman 				return;
195da2e3ebdSchin 			}
196da2e3ebdSchin 		}
197da2e3ebdSchin #endif /* SIGTSTP */
198da2e3ebdSchin 	}
199da2e3ebdSchin #ifdef ERROR_NOTIFY
2007c2fbfb3SApril Chin 	if((error_info.flags&ERROR_NOTIFY) && shp->bltinfun)
2017c2fbfb3SApril Chin 		action = (*shp->bltinfun)(-sig,(char**)0,(void*)0);
202da2e3ebdSchin 	if(action>0)
203da2e3ebdSchin 		return;
2047c2fbfb3SApril Chin #endif
2057c2fbfb3SApril Chin 	if(shp->bltinfun && shp->bltindata.notify)
2067c2fbfb3SApril Chin 	{
2077c2fbfb3SApril Chin 		shp->bltindata.sigset = 1;
2087c2fbfb3SApril Chin 		return;
2097c2fbfb3SApril Chin 	}
2107c2fbfb3SApril Chin 	shp->trapnote |= flag;
211*b30d1939SAndy Fiddaman 	if(sig <= shp->gd->sigmax)
2127c2fbfb3SApril Chin 		shp->sigflag[sig] |= flag;
213da2e3ebdSchin 	if(pp->mode==SH_JMPCMD && sh_isstate(SH_STOPOK))
214da2e3ebdSchin 	{
215da2e3ebdSchin 		if(action<0)
216da2e3ebdSchin 			return;
217da2e3ebdSchin 		sigrelease(sig);
218da2e3ebdSchin 		sh_exit(SH_EXITSIG);
219da2e3ebdSchin 	}
220da2e3ebdSchin }
221da2e3ebdSchin 
222da2e3ebdSchin /*
223da2e3ebdSchin  * initialize signal handling
224da2e3ebdSchin  */
sh_siginit(void * ptr)2257c2fbfb3SApril Chin void sh_siginit(void *ptr)
226da2e3ebdSchin {
2277c2fbfb3SApril Chin 	Shell_t	*shp = (Shell_t*)ptr;
22834f9b3eeSRoland Mainz 	register int sig, n;
229da2e3ebdSchin 	register const struct shtable2	*tp = shtab_signals;
230da2e3ebdSchin 	sig_begin();
231da2e3ebdSchin 	/* find the largest signal number in the table */
23234f9b3eeSRoland Mainz #if defined(SIGRTMIN) && defined(SIGRTMAX)
23334f9b3eeSRoland Mainz 	if ((n = SIGRTMIN) > 0 && (sig = SIGRTMAX) > n && sig < SH_TRAP)
23434f9b3eeSRoland Mainz 	{
235*b30d1939SAndy Fiddaman 		shp->gd->sigruntime[SH_SIGRTMIN] = n;
236*b30d1939SAndy Fiddaman 		shp->gd->sigruntime[SH_SIGRTMAX] = sig;
23734f9b3eeSRoland Mainz 	}
23834f9b3eeSRoland Mainz #endif /* SIGRTMIN && SIGRTMAX */
23934f9b3eeSRoland Mainz 	n = SIGTERM;
240da2e3ebdSchin 	while(*tp->sh_name)
241da2e3ebdSchin 	{
24234f9b3eeSRoland Mainz 		sig = (tp->sh_number&((1<<SH_SIGBITS)-1));
24334f9b3eeSRoland Mainz 		if (!(sig-- & SH_TRAP))
24434f9b3eeSRoland Mainz 		{
24534f9b3eeSRoland Mainz 			if ((tp->sh_number>>SH_SIGBITS) & SH_SIGRUNTIME)
246*b30d1939SAndy Fiddaman 				sig = shp->gd->sigruntime[sig];
24734f9b3eeSRoland Mainz 			if(sig>n && sig<SH_TRAP)
24834f9b3eeSRoland Mainz 				n = sig;
24934f9b3eeSRoland Mainz 		}
250da2e3ebdSchin 		tp++;
251da2e3ebdSchin 	}
252*b30d1939SAndy Fiddaman 	shp->gd->sigmax = n++;
2537c2fbfb3SApril Chin 	shp->st.trapcom = (char**)calloc(n,sizeof(char*));
2547c2fbfb3SApril Chin 	shp->sigflag = (unsigned char*)calloc(n,1);
255*b30d1939SAndy Fiddaman 	shp->gd->sigmsg = (char**)calloc(n,sizeof(char*));
256da2e3ebdSchin 	for(tp=shtab_signals; sig=tp->sh_number; tp++)
257da2e3ebdSchin 	{
258da2e3ebdSchin 		n = (sig>>SH_SIGBITS);
259*b30d1939SAndy Fiddaman 		if((sig &= ((1<<SH_SIGBITS)-1)) > (shp->gd->sigmax+1))
260da2e3ebdSchin 			continue;
261da2e3ebdSchin 		sig--;
2627c2fbfb3SApril Chin 		if(n&SH_SIGRUNTIME)
263*b30d1939SAndy Fiddaman 			sig = shp->gd->sigruntime[sig];
264da2e3ebdSchin 		if(sig>=0)
265da2e3ebdSchin 		{
2667c2fbfb3SApril Chin 			shp->sigflag[sig] = n;
267da2e3ebdSchin 			if(*tp->sh_name)
268*b30d1939SAndy Fiddaman 				shp->gd->sigmsg[sig] = (char*)tp->sh_value;
269da2e3ebdSchin 		}
270da2e3ebdSchin 	}
271da2e3ebdSchin }
272da2e3ebdSchin 
273da2e3ebdSchin /*
274da2e3ebdSchin  * Turn on trap handler for signal <sig>
275da2e3ebdSchin  */
sh_sigtrap(register int sig)276da2e3ebdSchin void	sh_sigtrap(register int sig)
277da2e3ebdSchin {
278da2e3ebdSchin 	register int flag;
279da2e3ebdSchin 	void (*fun)(int);
280da2e3ebdSchin 	sh.st.otrapcom = 0;
281da2e3ebdSchin 	if(sig==0)
282da2e3ebdSchin 		sh_sigdone();
283da2e3ebdSchin 	else if(!((flag=sh.sigflag[sig])&(SH_SIGFAULT|SH_SIGOFF)))
284da2e3ebdSchin 	{
285da2e3ebdSchin 		/* don't set signal if already set or off by parent */
286da2e3ebdSchin 		if((fun=signal(sig,sh_fault))==SIG_IGN)
287da2e3ebdSchin 		{
288da2e3ebdSchin 			signal(sig,SIG_IGN);
289da2e3ebdSchin 			flag |= SH_SIGOFF;
290da2e3ebdSchin 		}
291da2e3ebdSchin 		else
292da2e3ebdSchin 		{
293da2e3ebdSchin 			flag |= SH_SIGFAULT;
294da2e3ebdSchin 			if(sig==SIGALRM && fun!=SIG_DFL && fun!=sh_fault)
295da2e3ebdSchin 				signal(sig,fun);
296da2e3ebdSchin 		}
297da2e3ebdSchin 		flag &= ~(SH_SIGSET|SH_SIGTRAP);
298da2e3ebdSchin 		sh.sigflag[sig] = flag;
299da2e3ebdSchin 	}
300da2e3ebdSchin }
301da2e3ebdSchin 
302da2e3ebdSchin /*
303da2e3ebdSchin  * set signal handler so sh_done is called for all caught signals
304da2e3ebdSchin  */
sh_sigdone(void)305da2e3ebdSchin void	sh_sigdone(void)
306da2e3ebdSchin {
307*b30d1939SAndy Fiddaman 	register int 	flag, sig = shgd->sigmax;
308da2e3ebdSchin 	sh.sigflag[0] |= SH_SIGFAULT;
309*b30d1939SAndy Fiddaman 	for(sig=shgd->sigmax; sig>0; sig--)
310da2e3ebdSchin 	{
311da2e3ebdSchin 		flag = sh.sigflag[sig];
312da2e3ebdSchin 		if((flag&(SH_SIGDONE|SH_SIGIGNORE|SH_SIGINTERACTIVE)) && !(flag&(SH_SIGFAULT|SH_SIGOFF)))
313da2e3ebdSchin 			sh_sigtrap(sig);
314da2e3ebdSchin 	}
315da2e3ebdSchin }
316da2e3ebdSchin 
317da2e3ebdSchin /*
318da2e3ebdSchin  * Restore to default signals
319da2e3ebdSchin  * Free the trap strings if mode is non-zero
320da2e3ebdSchin  * If mode>1 then ignored traps cause signal to be ignored
321da2e3ebdSchin  */
sh_sigreset(register int mode)322da2e3ebdSchin void	sh_sigreset(register int mode)
323da2e3ebdSchin {
324da2e3ebdSchin 	register char	*trap;
325da2e3ebdSchin 	register int 	flag, sig=sh.st.trapmax;
326da2e3ebdSchin 	while(sig-- > 0)
327da2e3ebdSchin 	{
328da2e3ebdSchin 		if(trap=sh.st.trapcom[sig])
329da2e3ebdSchin 		{
330da2e3ebdSchin 			flag  = sh.sigflag[sig]&~(SH_SIGTRAP|SH_SIGSET);
331da2e3ebdSchin 			if(*trap)
332da2e3ebdSchin 			{
333da2e3ebdSchin 				if(mode)
334da2e3ebdSchin 					free(trap);
335da2e3ebdSchin 				sh.st.trapcom[sig] = 0;
336da2e3ebdSchin 			}
337da2e3ebdSchin 			else if(sig && mode>1)
338da2e3ebdSchin 			{
33934f9b3eeSRoland Mainz 				if(sig!=SIGCHLD)
34034f9b3eeSRoland Mainz 					signal(sig,SIG_IGN);
341da2e3ebdSchin 				flag &= ~SH_SIGFAULT;
342da2e3ebdSchin 				flag |= SH_SIGOFF;
343da2e3ebdSchin 			}
344da2e3ebdSchin 			sh.sigflag[sig] = flag;
345da2e3ebdSchin 		}
346da2e3ebdSchin 	}
3477c2fbfb3SApril Chin 	for(sig=SH_DEBUGTRAP-1;sig>=0;sig--)
348da2e3ebdSchin 	{
349da2e3ebdSchin 		if(trap=sh.st.trap[sig])
350da2e3ebdSchin 		{
351da2e3ebdSchin 			if(mode)
352da2e3ebdSchin 				free(trap);
353da2e3ebdSchin 			sh.st.trap[sig] = 0;
354da2e3ebdSchin 		}
355da2e3ebdSchin 
356da2e3ebdSchin 	}
357da2e3ebdSchin 	sh.st.trapcom[0] = 0;
358da2e3ebdSchin 	if(mode)
359da2e3ebdSchin 		sh.st.trapmax = 0;
360da2e3ebdSchin 	sh.trapnote=0;
361da2e3ebdSchin }
362da2e3ebdSchin 
363da2e3ebdSchin /*
364da2e3ebdSchin  * free up trap if set and restore signal handler if modified
365da2e3ebdSchin  */
sh_sigclear(register int sig)366da2e3ebdSchin void	sh_sigclear(register int sig)
367da2e3ebdSchin {
368da2e3ebdSchin 	register int flag = sh.sigflag[sig];
369da2e3ebdSchin 	register char *trap;
370da2e3ebdSchin 	sh.st.otrapcom=0;
371da2e3ebdSchin 	if(!(flag&SH_SIGFAULT))
372da2e3ebdSchin 		return;
373da2e3ebdSchin 	flag &= ~(SH_SIGTRAP|SH_SIGSET);
374da2e3ebdSchin 	if(trap=sh.st.trapcom[sig])
375da2e3ebdSchin 	{
3763e14f97fSRoger A. Faulkner 		if(!sh.subshell)
3773e14f97fSRoger A. Faulkner 			free(trap);
378da2e3ebdSchin 		sh.st.trapcom[sig]=0;
379da2e3ebdSchin 	}
380da2e3ebdSchin 	sh.sigflag[sig] = flag;
381da2e3ebdSchin }
382da2e3ebdSchin 
383da2e3ebdSchin /*
384da2e3ebdSchin  * check for traps
385da2e3ebdSchin  */
386da2e3ebdSchin 
sh_chktrap(Shell_t * shp)387*b30d1939SAndy Fiddaman void	sh_chktrap(Shell_t* shp)
388da2e3ebdSchin {
389*b30d1939SAndy Fiddaman 	register int 	sig=shp->st.trapmax;
390da2e3ebdSchin 	register char *trap;
391*b30d1939SAndy Fiddaman 	if(!(shp->trapnote&~SH_SIGIGNORE))
392da2e3ebdSchin 		sig=0;
393*b30d1939SAndy Fiddaman 	shp->trapnote &= ~SH_SIGTRAP;
394da2e3ebdSchin 	/* execute errexit trap first */
395*b30d1939SAndy Fiddaman 	if(sh_isstate(SH_ERREXIT) && shp->exitval)
396da2e3ebdSchin 	{
397*b30d1939SAndy Fiddaman 		int	sav_trapnote = shp->trapnote;
398*b30d1939SAndy Fiddaman 		shp->trapnote &= ~SH_SIGSET;
399*b30d1939SAndy Fiddaman 		if(shp->st.trap[SH_ERRTRAP])
4007c2fbfb3SApril Chin 		{
401*b30d1939SAndy Fiddaman 			trap = shp->st.trap[SH_ERRTRAP];
402*b30d1939SAndy Fiddaman 			shp->st.trap[SH_ERRTRAP] = 0;
4037c2fbfb3SApril Chin 			sh_trap(trap,0);
404*b30d1939SAndy Fiddaman 			shp->st.trap[SH_ERRTRAP] = trap;
4057c2fbfb3SApril Chin 		}
406*b30d1939SAndy Fiddaman 		shp->trapnote = sav_trapnote;
407da2e3ebdSchin 		if(sh_isoption(SH_ERREXIT))
408da2e3ebdSchin 		{
409*b30d1939SAndy Fiddaman 			struct checkpt	*pp = (struct checkpt*)shp->jmplist;
410da2e3ebdSchin 			pp->mode = SH_JMPEXIT;
411*b30d1939SAndy Fiddaman 			sh_exit(shp->exitval);
412da2e3ebdSchin 		}
413da2e3ebdSchin 	}
414*b30d1939SAndy Fiddaman 	if(shp->sigflag[SIGALRM]&SH_SIGALRM)
415*b30d1939SAndy Fiddaman 		sh_timetraps(shp);
41634f9b3eeSRoland Mainz #ifdef SHOPT_BGX
417*b30d1939SAndy Fiddaman 	if((shp->sigflag[SIGCHLD]&SH_SIGTRAP) && shp->st.trapcom[SIGCHLD])
418*b30d1939SAndy Fiddaman 		job_chldtrap(shp,shp->st.trapcom[SIGCHLD],1);
41934f9b3eeSRoland Mainz #endif /* SHOPT_BGX */
4203e14f97fSRoger A. Faulkner 	while(--sig>=0)
421da2e3ebdSchin 	{
422*b30d1939SAndy Fiddaman 		if(sig==cursig)
423*b30d1939SAndy Fiddaman 			continue;
4243e14f97fSRoger A. Faulkner #ifdef SHOPT_BGX
4253e14f97fSRoger A. Faulkner 		if(sig==SIGCHLD)
4263e14f97fSRoger A. Faulkner 			continue;
4273e14f97fSRoger A. Faulkner #endif /* SHOPT_BGX */
428*b30d1939SAndy Fiddaman 		if(shp->sigflag[sig]&SH_SIGTRAP)
429da2e3ebdSchin 		{
430*b30d1939SAndy Fiddaman 			shp->sigflag[sig] &= ~SH_SIGTRAP;
431*b30d1939SAndy Fiddaman 			if(trap=shp->st.trapcom[sig])
43234f9b3eeSRoland Mainz 			{
433*b30d1939SAndy Fiddaman 				cursig = sig;
43434f9b3eeSRoland Mainz  				sh_trap(trap,0);
435*b30d1939SAndy Fiddaman 				cursig = -1;
43634f9b3eeSRoland Mainz  			}
437da2e3ebdSchin 		}
438da2e3ebdSchin 	}
439da2e3ebdSchin }
440da2e3ebdSchin 
441da2e3ebdSchin 
442da2e3ebdSchin /*
443da2e3ebdSchin  * parse and execute the given trap string, stream or tree depending on mode
444da2e3ebdSchin  * mode==0 for string, mode==1 for stream, mode==2 for parse tree
445da2e3ebdSchin  */
sh_trap(const char * trap,int mode)446da2e3ebdSchin int sh_trap(const char *trap, int mode)
447da2e3ebdSchin {
4487c2fbfb3SApril Chin 	Shell_t	*shp = sh_getinterp();
4497c2fbfb3SApril Chin 	int	jmpval, savxit = shp->exitval;
450da2e3ebdSchin 	int	was_history = sh_isstate(SH_HISTORY);
451da2e3ebdSchin 	int	was_verbose = sh_isstate(SH_VERBOSE);
452da2e3ebdSchin 	int	staktop = staktell();
453da2e3ebdSchin 	char	*savptr = stakfreeze(0);
4543e14f97fSRoger A. Faulkner 	char	ifstable[256];
455da2e3ebdSchin 	struct	checkpt buff;
456da2e3ebdSchin 	Fcin_t	savefc;
457da2e3ebdSchin 	fcsave(&savefc);
4583e14f97fSRoger A. Faulkner 	memcpy(ifstable,shp->ifstable,sizeof(ifstable));
459da2e3ebdSchin 	sh_offstate(SH_HISTORY);
460da2e3ebdSchin 	sh_offstate(SH_VERBOSE);
4617c2fbfb3SApril Chin 	shp->intrap++;
462*b30d1939SAndy Fiddaman 	sh_pushcontext(shp,&buff,SH_JMPTRAP);
463da2e3ebdSchin 	jmpval = sigsetjmp(buff.buff,0);
464da2e3ebdSchin 	if(jmpval == 0)
465da2e3ebdSchin 	{
466da2e3ebdSchin 		if(mode==2)
467da2e3ebdSchin 			sh_exec((Shnode_t*)trap,sh_isstate(SH_ERREXIT));
468da2e3ebdSchin 		else
469da2e3ebdSchin 		{
470da2e3ebdSchin 			Sfio_t *sp;
471da2e3ebdSchin 			if(mode)
472da2e3ebdSchin 				sp = (Sfio_t*)trap;
473da2e3ebdSchin 			else
474da2e3ebdSchin 				sp = sfopen(NIL(Sfio_t*),trap,"s");
475da2e3ebdSchin 			sh_eval(sp,0);
476da2e3ebdSchin 		}
477da2e3ebdSchin 	}
478da2e3ebdSchin 	else if(indone)
479da2e3ebdSchin 	{
480da2e3ebdSchin 		if(jmpval==SH_JMPSCRIPT)
481da2e3ebdSchin 			indone=0;
482da2e3ebdSchin 		else
483da2e3ebdSchin 		{
484da2e3ebdSchin 			if(jmpval==SH_JMPEXIT)
4857c2fbfb3SApril Chin 				savxit = shp->exitval;
486da2e3ebdSchin 			jmpval=SH_JMPTRAP;
487da2e3ebdSchin 		}
488da2e3ebdSchin 	}
489*b30d1939SAndy Fiddaman 	sh_popcontext(shp,&buff);
4907c2fbfb3SApril Chin 	shp->intrap--;
4917c2fbfb3SApril Chin 	sfsync(shp->outpool);
4927c2fbfb3SApril Chin 	if(!shp->indebug && jmpval!=SH_JMPEXIT && jmpval!=SH_JMPFUN)
4937c2fbfb3SApril Chin 		shp->exitval=savxit;
494da2e3ebdSchin 	stakset(savptr,staktop);
495da2e3ebdSchin 	fcrestore(&savefc);
4963e14f97fSRoger A. Faulkner 	memcpy(shp->ifstable,ifstable,sizeof(ifstable));
497da2e3ebdSchin 	if(was_history)
498da2e3ebdSchin 		sh_onstate(SH_HISTORY);
499da2e3ebdSchin 	if(was_verbose)
500da2e3ebdSchin 		sh_onstate(SH_VERBOSE);
501da2e3ebdSchin 	exitset();
50234f9b3eeSRoland Mainz 	if(jmpval>SH_JMPTRAP && (((struct checkpt*)shp->jmpbuffer)->prev || ((struct checkpt*)shp->jmpbuffer)->mode==SH_JMPSCRIPT))
5037c2fbfb3SApril Chin 		siglongjmp(*shp->jmplist,jmpval);
5047c2fbfb3SApril Chin 	return(shp->exitval);
505da2e3ebdSchin }
506da2e3ebdSchin 
507da2e3ebdSchin /*
508da2e3ebdSchin  * exit the current scope and jump to an earlier one based on pp->mode
509da2e3ebdSchin  */
sh_exit(register int xno)510da2e3ebdSchin void sh_exit(register int xno)
511da2e3ebdSchin {
512*b30d1939SAndy Fiddaman 	Shell_t *shp = sh_getinterp();
5137c2fbfb3SApril Chin 	register struct checkpt	*pp = (struct checkpt*)shp->jmplist;
514da2e3ebdSchin 	register int		sig=0;
515da2e3ebdSchin 	register Sfio_t*	pool;
5167c2fbfb3SApril Chin 	shp->exitval=xno;
517da2e3ebdSchin 	if(xno==SH_EXITSIG)
5187c2fbfb3SApril Chin 		shp->exitval |= (sig=shp->lastsig);
519*b30d1939SAndy Fiddaman 	if(pp && pp->mode>1)
520*b30d1939SAndy Fiddaman 		cursig = -1;
521da2e3ebdSchin #ifdef SIGTSTP
522*b30d1939SAndy Fiddaman 	if(shp->trapnote&SH_SIGTSTP && job.jobcontrol)
523da2e3ebdSchin 	{
524da2e3ebdSchin 		/* ^Z detected by the shell */
5257c2fbfb3SApril Chin 		shp->trapnote = 0;
5267c2fbfb3SApril Chin 		shp->sigflag[SIGTSTP] = 0;
5277c2fbfb3SApril Chin 		if(!shp->subshell && sh_isstate(SH_MONITOR) && !sh_isstate(SH_STOPOK))
528da2e3ebdSchin 			return;
529da2e3ebdSchin 		if(sh_isstate(SH_TIMING))
530da2e3ebdSchin 			return;
531da2e3ebdSchin 		/* Handles ^Z for shell builtins, subshells, and functs */
5327c2fbfb3SApril Chin 		shp->lastsig = 0;
533da2e3ebdSchin 		sh_onstate(SH_MONITOR);
534da2e3ebdSchin 		sh_offstate(SH_STOPOK);
5357c2fbfb3SApril Chin 		shp->trapnote = 0;
536*b30d1939SAndy Fiddaman 		shp->forked = 1;
537*b30d1939SAndy Fiddaman 		if(!shp->subshell && (sig=sh_fork(shp,0,NIL(int*))))
538da2e3ebdSchin 		{
539da2e3ebdSchin 			job.curpgid = 0;
540da2e3ebdSchin 			job.parent = (pid_t)-1;
541da2e3ebdSchin 			job_wait(sig);
542*b30d1939SAndy Fiddaman 			shp->forked = 0;
543da2e3ebdSchin 			job.parent = 0;
5447c2fbfb3SApril Chin 			shp->sigflag[SIGTSTP] = 0;
545da2e3ebdSchin 			/* wait for child to stop */
5467c2fbfb3SApril Chin 			shp->exitval = (SH_EXITSIG|SIGTSTP);
547da2e3ebdSchin 			/* return to prompt mode */
548da2e3ebdSchin 			pp->mode = SH_JMPERREXIT;
549da2e3ebdSchin 		}
550da2e3ebdSchin 		else
551da2e3ebdSchin 		{
5527c2fbfb3SApril Chin 			if(shp->subshell)
553da2e3ebdSchin 				sh_subfork();
554da2e3ebdSchin 			/* child process, put to sleep */
555da2e3ebdSchin 			sh_offstate(SH_STOPOK);
556da2e3ebdSchin 			sh_offstate(SH_MONITOR);
5577c2fbfb3SApril Chin 			shp->sigflag[SIGTSTP] = 0;
558da2e3ebdSchin 			/* stop child job */
559da2e3ebdSchin 			killpg(job.curpgid,SIGTSTP);
560da2e3ebdSchin 			/* child resumes */
561da2e3ebdSchin 			job_clear();
5627c2fbfb3SApril Chin 			shp->exitval = (xno&SH_EXITMASK);
563da2e3ebdSchin 			return;
564da2e3ebdSchin 		}
565da2e3ebdSchin 	}
566da2e3ebdSchin #endif /* SIGTSTP */
567da2e3ebdSchin 	/* unlock output pool */
568da2e3ebdSchin 	sh_offstate(SH_NOTRACK);
5697c2fbfb3SApril Chin 	if(!(pool=sfpool(NIL(Sfio_t*),shp->outpool,SF_WRITE)))
5707c2fbfb3SApril Chin 		pool = shp->outpool; /* can't happen? */
571da2e3ebdSchin 	sfclrlock(pool);
572da2e3ebdSchin #ifdef SIGPIPE
5737c2fbfb3SApril Chin 	if(shp->lastsig==SIGPIPE)
574da2e3ebdSchin 		sfpurge(pool);
575da2e3ebdSchin #endif /* SIGPIPE */
576da2e3ebdSchin 	sfclrlock(sfstdin);
577da2e3ebdSchin 	if(!pp)
5787c2fbfb3SApril Chin 		sh_done(shp,sig);
5797c2fbfb3SApril Chin 	shp->prefix = 0;
5807c2fbfb3SApril Chin #if SHOPT_TYPEDEF
5817c2fbfb3SApril Chin 	shp->mktype = 0;
5827c2fbfb3SApril Chin #endif /* SHOPT_TYPEDEF*/
583*b30d1939SAndy Fiddaman 	if(job.in_critical)
584*b30d1939SAndy Fiddaman 		job_unlock();
585da2e3ebdSchin 	if(pp->mode == SH_JMPSCRIPT && !pp->prev)
5867c2fbfb3SApril Chin 		sh_done(shp,sig);
5877c2fbfb3SApril Chin 	if(pp->mode)
5887c2fbfb3SApril Chin 		siglongjmp(pp->buff,pp->mode);
5897c2fbfb3SApril Chin }
5907c2fbfb3SApril Chin 
array_notify(Namval_t * np,void * data)5917c2fbfb3SApril Chin static void array_notify(Namval_t *np, void *data)
5927c2fbfb3SApril Chin {
5937c2fbfb3SApril Chin 	Namarr_t	*ap = nv_arrayptr(np);
5947c2fbfb3SApril Chin 	NOT_USED(data);
5957c2fbfb3SApril Chin 	if(ap && ap->fun)
5967c2fbfb3SApril Chin 		(*ap->fun)(np, 0, NV_AFREE);
597da2e3ebdSchin }
598da2e3ebdSchin 
599da2e3ebdSchin /*
600da2e3ebdSchin  * This is the exit routine for the shell
601da2e3ebdSchin  */
602da2e3ebdSchin 
sh_done(void * ptr,register int sig)6037c2fbfb3SApril Chin void sh_done(void *ptr, register int sig)
604da2e3ebdSchin {
6057c2fbfb3SApril Chin 	Shell_t	*shp = (Shell_t*)ptr;
606da2e3ebdSchin 	register char *t;
6077c2fbfb3SApril Chin 	register int savxit = shp->exitval;
6087c2fbfb3SApril Chin 	shp->trapnote = 0;
609da2e3ebdSchin 	indone=1;
61034f9b3eeSRoland Mainz 	if(sig)
61134f9b3eeSRoland Mainz 		savxit = SH_EXITSIG|sig;
6127c2fbfb3SApril Chin 	if(shp->userinit)
6137c2fbfb3SApril Chin 		(*shp->userinit)(shp, -1);
6147c2fbfb3SApril Chin 	if(t=shp->st.trapcom[0])
615da2e3ebdSchin 	{
6167c2fbfb3SApril Chin 		shp->st.trapcom[0]=0; /*should free but not long */
6177c2fbfb3SApril Chin 		shp->oldexit = savxit;
618da2e3ebdSchin 		sh_trap(t,0);
6197c2fbfb3SApril Chin 		savxit = shp->exitval;
620da2e3ebdSchin 	}
621da2e3ebdSchin 	else
622da2e3ebdSchin 	{
623da2e3ebdSchin 		/* avoid recursive call for set -e */
624da2e3ebdSchin 		sh_offstate(SH_ERREXIT);
625*b30d1939SAndy Fiddaman 		sh_chktrap(shp);
626da2e3ebdSchin 	}
6277c2fbfb3SApril Chin 	nv_scan(shp->var_tree,array_notify,(void*)0,NV_ARRAY,NV_ARRAY);
6287c2fbfb3SApril Chin 	sh_freeup(shp);
629da2e3ebdSchin #if SHOPT_ACCT
630da2e3ebdSchin 	sh_accend();
631da2e3ebdSchin #endif	/* SHOPT_ACCT */
632da2e3ebdSchin #if SHOPT_VSH || SHOPT_ESH
633*b30d1939SAndy Fiddaman 	if(mbwide()||sh_isoption(SH_EMACS)||sh_isoption(SH_VI)||sh_isoption(SH_GMACS))
634da2e3ebdSchin 		tty_cooked(-1);
635da2e3ebdSchin #endif
636da2e3ebdSchin #ifdef JOBS
6377c2fbfb3SApril Chin 	if((sh_isoption(SH_INTERACTIVE) && shp->login_sh) || (!sh_isoption(SH_INTERACTIVE) && (sig==SIGHUP)))
638*b30d1939SAndy Fiddaman 		job_walk(sfstderr, job_hup, SIGHUP, NIL(char**));
639da2e3ebdSchin #endif	/* JOBS */
6407c2fbfb3SApril Chin 	job_close(shp);
6417c2fbfb3SApril Chin 	if(nv_search("VMTRACE", shp->var_tree,0))
642da2e3ebdSchin 		strmatch((char*)0,(char*)0);
643da2e3ebdSchin 	sfsync((Sfio_t*)sfstdin);
6447c2fbfb3SApril Chin 	sfsync((Sfio_t*)shp->outpool);
645da2e3ebdSchin 	sfsync((Sfio_t*)sfstdout);
64634f9b3eeSRoland Mainz 	if(savxit&SH_EXITSIG)
64734f9b3eeSRoland Mainz 		sig = savxit&SH_EXITMASK;
648da2e3ebdSchin 	if(sig)
649da2e3ebdSchin 	{
650da2e3ebdSchin 		/* generate fault termination code */
651*b30d1939SAndy Fiddaman 		if(RLIMIT_CORE!=RLIMIT_UNKNOWN)
652*b30d1939SAndy Fiddaman 		{
653*b30d1939SAndy Fiddaman #ifdef _lib_getrlimit
654*b30d1939SAndy Fiddaman 			struct rlimit rlp;
655*b30d1939SAndy Fiddaman 			getrlimit(RLIMIT_CORE,&rlp);
656*b30d1939SAndy Fiddaman 			rlp.rlim_cur = 0;
657*b30d1939SAndy Fiddaman 			setrlimit(RLIMIT_CORE,&rlp);
658*b30d1939SAndy Fiddaman #else
659*b30d1939SAndy Fiddaman 			vlimit(RLIMIT_CORE,0);
660*b30d1939SAndy Fiddaman #endif
661*b30d1939SAndy Fiddaman 		}
662da2e3ebdSchin 		signal(sig,SIG_DFL);
663da2e3ebdSchin 		sigrelease(sig);
664da2e3ebdSchin 		kill(getpid(),sig);
665da2e3ebdSchin 		pause();
666da2e3ebdSchin 	}
667da2e3ebdSchin #if SHOPT_KIA
668da2e3ebdSchin 	if(sh_isoption(SH_NOEXEC))
6697c2fbfb3SApril Chin 		kiaclose((Lex_t*)shp->lex_context);
670da2e3ebdSchin #endif /* SHOPT_KIA */
671da2e3ebdSchin 	exit(savxit&SH_EXITMASK);
672da2e3ebdSchin }
673da2e3ebdSchin 
674