1da2e3ebchin/***********************************************************************
2da2e3ebchin*                                                                      *
3da2e3ebchin*               This software is part of the ast package               *
43e14f97Roger A. Faulkner*          Copyright (c) 1982-2010 AT&T Intellectual Property          *
5da2e3ebchin*                      and is licensed under the                       *
6da2e3ebchin*                  Common Public License, Version 1.0                  *
77c2fbfbApril Chin*                    by AT&T Intellectual Property                     *
8da2e3ebchin*                                                                      *
9da2e3ebchin*                A copy of the License is available at                 *
10da2e3ebchin*            http://www.opensource.org/licenses/cpl1.0.txt             *
11da2e3ebchin*         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
12da2e3ebchin*                                                                      *
13da2e3ebchin*              Information and Software Systems Research               *
14da2e3ebchin*                            AT&T Research                             *
15da2e3ebchin*                           Florham Park NJ                            *
16da2e3ebchin*                                                                      *
17da2e3ebchin*                  David Korn <dgk@research.att.com>                   *
18da2e3ebchin*                                                                      *
19da2e3ebchin***********************************************************************/
20da2e3ebchin#pragma prototyped
21da2e3ebchin/*
22da2e3ebchin * Fault handling routines
23da2e3ebchin *
24da2e3ebchin *   David Korn
25da2e3ebchin *   AT&T Labs
26da2e3ebchin *
27da2e3ebchin */
28da2e3ebchin
29da2e3ebchin#include	"defs.h"
30da2e3ebchin#include	<fcin.h>
31da2e3ebchin#include	"io.h"
32da2e3ebchin#include	"history.h"
337c2fbfbApril Chin#include	"shlex.h"
34da2e3ebchin#include	"variables.h"
35da2e3ebchin#include	"jobs.h"
36da2e3ebchin#include	"path.h"
377c2fbfbApril Chin#include	"builtins.h"
38da2e3ebchin
39da2e3ebchin#define abortsig(sig)	(sig==SIGABRT || sig==SIGBUS || sig==SIGILL || sig==SIGSEGV)
40da2e3ebchin
41da2e3ebchinstatic char	indone;
42da2e3ebchin
43da2e3ebchin#if !_std_malloc
44da2e3ebchin#   include	<vmalloc.h>
45da2e3ebchin#endif
46da2e3ebchin#if  defined(VMFL) && (VMALLOC_VERSION>=20031205L)
47da2e3ebchin    /*
48da2e3ebchin     * This exception handler is called after vmalloc() unlocks the region
49da2e3ebchin     */
50da2e3ebchin    static int malloc_done(Vmalloc_t* vm, int type, Void_t* val, Vmdisc_t* dp)
51da2e3ebchin    {
52da2e3ebchin	dp->exceptf = 0;
53da2e3ebchin	sh_exit(SH_EXITSIG);
54da2e3ebchin	return(0);
55da2e3ebchin    }
56da2e3ebchin#endif
57da2e3ebchin
58da2e3ebchin/*
59da2e3ebchin * Most signals caught or ignored by the shell come here
60da2e3ebchin*/
61da2e3ebchinvoid	sh_fault(register int sig)
62da2e3ebchin{
637c2fbfbApril Chin	register Shell_t	*shp = sh_getinterp();
647c2fbfbApril Chin	register int 		flag=0;
657c2fbfbApril Chin	register char		*trap;
667c2fbfbApril Chin	register struct checkpt	*pp = (struct checkpt*)shp->jmplist;
67da2e3ebchin	int	action=0;
68da2e3ebchin	/* reset handler */
69da2e3ebchin	if(!(sig&SH_TRAP))
70da2e3ebchin		signal(sig, sh_fault);
71da2e3ebchin	sig &= ~SH_TRAP;
72da2e3ebchin#ifdef SIGWINCH
73da2e3ebchin	if(sig==SIGWINCH)
74da2e3ebchin	{
75da2e3ebchin		int rows=0, cols=0;
76da2e3ebchin		int32_t v;
77da2e3ebchin		astwinsize(2,&rows,&cols);
78da2e3ebchin		if(v = cols)
797c2fbfbApril Chin			nv_putval(COLUMNS, (char*)&v, NV_INT32|NV_RDONLY);
80da2e3ebchin		if(v = rows)
817c2fbfbApril Chin			nv_putval(LINES, (char*)&v, NV_INT32|NV_RDONLY);
827c2fbfbApril Chin		shp->winch++;
83da2e3ebchin	}
84da2e3ebchin#endif  /* SIGWINCH */
857c2fbfbApril Chin	if(shp->savesig)
86da2e3ebchin	{
87da2e3ebchin		/* critical region, save and process later */
887c2fbfbApril Chin		shp->savesig = sig;
897c2fbfbApril Chin		return;
907c2fbfbApril Chin	}
917c2fbfbApril Chin	trap = shp->st.trapcom[sig];
927c2fbfbApril Chin	if(sig==SIGALRM && shp->bltinfun==b_sleep)
937c2fbfbApril Chin	{
947c2fbfbApril Chin		if(trap && *trap)
957c2fbfbApril Chin		{
967c2fbfbApril Chin			shp->trapnote |= SH_SIGTRAP;
977c2fbfbApril Chin			shp->sigflag[sig] |= SH_SIGTRAP;
987c2fbfbApril Chin		}
997c2fbfbApril Chin		return;
1007c2fbfbApril Chin	}
10134f9b3eRoland Mainz	if(shp->subshell && sig!=SIGINT && sig!=SIGQUIT && sig!=SIGWINCH && sig!=SIGCONT)
1027c2fbfbApril Chin	{
1037c2fbfbApril Chin		shp->exitval = SH_EXITSIG|sig;
1047c2fbfbApril Chin		sh_subfork();
1057c2fbfbApril Chin		shp->exitval = 0;
106da2e3ebchin		return;
107da2e3ebchin	}
108da2e3ebchin	/* handle ignored signals */
1097c2fbfbApril Chin	if(trap && *trap==0)
110da2e3ebchin		return;
1117c2fbfbApril Chin	flag = shp->sigflag[sig]&~SH_SIGOFF;
112da2e3ebchin	if(!trap)
113da2e3ebchin	{
1147c2fbfbApril Chin		if(sig==SIGINT && (shp->trapnote&SH_SIGIGNORE))
1157c2fbfbApril Chin			return;
116da2e3ebchin		if(flag&SH_SIGIGNORE)
117da2e3ebchin			return;
118da2e3ebchin		if(flag&SH_SIGDONE)
119da2e3ebchin		{
120da2e3ebchin			void *ptr=0;
1217c2fbfbApril Chin			if((flag&SH_SIGINTERACTIVE) && sh_isstate(SH_INTERACTIVE) && !sh_isstate(SH_FORKED) && ! shp->subshell)
122da2e3ebchin			{
123da2e3ebchin				/* check for TERM signal between fork/exec */
124da2e3ebchin				if(sig==SIGTERM && job.in_critical)
1257c2fbfbApril Chin					shp->trapnote |= SH_SIGTERM;
126da2e3ebchin				return;
127da2e3ebchin			}
1287c2fbfbApril Chin			shp->lastsig = sig;
129da2e3ebchin			sigrelease(sig);
130da2e3ebchin			if(pp->mode < SH_JMPFUN)
131da2e3ebchin				pp->mode = SH_JMPFUN;
132da2e3ebchin			else
133da2e3ebchin				pp->mode = SH_JMPEXIT;
134da2e3ebchin			if(sig==SIGABRT || (abortsig(sig) && (ptr = malloc(1))))
135da2e3ebchin			{
136da2e3ebchin				if(ptr)
137da2e3ebchin					free(ptr);
1387c2fbfbApril Chin				if(!shp->subshell)
1397c2fbfbApril Chin					sh_done(shp,sig);
140da2e3ebchin				sh_exit(SH_EXITSIG);
141da2e3ebchin			}
142da2e3ebchin			/* mark signal and continue */
1437c2fbfbApril Chin			shp->trapnote |= SH_SIGSET;
14434f9b3eRoland Mainz			if(sig <= shp->sigmax)
1457c2fbfbApril Chin				shp->sigflag[sig] |= SH_SIGSET;
146da2e3ebchin#if  defined(VMFL) && (VMALLOC_VERSION>=20031205L)
147da2e3ebchin			if(abortsig(sig))
148da2e3ebchin			{
149da2e3ebchin				/* abort inside malloc, process when malloc returns */
150da2e3ebchin				/* VMFL defined when using vmalloc() */
151da2e3ebchin				Vmdisc_t* dp = vmdisc(Vmregion,0);
152da2e3ebchin				if(dp)
153da2e3ebchin					dp->exceptf = malloc_done;
154da2e3ebchin			}
155da2e3ebchin#endif
156da2e3ebchin			return;
157da2e3ebchin		}
158da2e3ebchin	}
159da2e3ebchin	errno = 0;
160da2e3ebchin	if(pp->mode==SH_JMPCMD)
1617c2fbfbApril Chin		shp->lastsig = sig;
162da2e3ebchin	if(trap)
163da2e3ebchin	{
164da2e3ebchin		/*
165da2e3ebchin		 * propogate signal to foreground group
166da2e3ebchin		 */
167da2e3ebchin		if(sig==SIGHUP && job.curpgid)
168da2e3ebchin			killpg(job.curpgid,SIGHUP);
169da2e3ebchin		flag = SH_SIGTRAP;
170da2e3ebchin	}
171da2e3ebchin	else
172da2e3ebchin	{
1737c2fbfbApril Chin		shp->lastsig = sig;
174da2e3ebchin		flag = SH_SIGSET;
175da2e3ebchin#ifdef SIGTSTP
176da2e3ebchin		if(sig==SIGTSTP)
177da2e3ebchin		{
1787c2fbfbApril Chin			shp->trapnote |= SH_SIGTSTP;
179da2e3ebchin			if(pp->mode==SH_JMPCMD && sh_isstate(SH_STOPOK))
180da2e3ebchin			{
181da2e3ebchin				sigrelease(sig);
182da2e3ebchin				sh_exit(SH_EXITSIG);
183da2e3ebchin				flag = 0;
184da2e3ebchin			}
185da2e3ebchin		}
186da2e3ebchin#endif /* SIGTSTP */
187da2e3ebchin	}
188da2e3ebchin#ifdef ERROR_NOTIFY
1897c2fbfbApril Chin	if((error_info.flags&ERROR_NOTIFY) && shp->bltinfun)
1907c2fbfbApril Chin		action = (*shp->bltinfun)(-sig,(char**)0,(void*)0);
191da2e3ebchin	if(action>0)
192da2e3ebchin		return;
1937c2fbfbApril Chin#endif
1947c2fbfbApril Chin	if(shp->bltinfun && shp->bltindata.notify)
1957c2fbfbApril Chin	{
1967c2fbfbApril Chin		shp->bltindata.sigset = 1;
1977c2fbfbApril Chin		return;
1987c2fbfbApril Chin	}
1997c2fbfbApril Chin	shp->trapnote |= flag;
20034f9b3eRoland Mainz	if(sig <= shp->sigmax)
2017c2fbfbApril Chin		shp->sigflag[sig] |= flag;
202da2e3ebchin	if(pp->mode==SH_JMPCMD && sh_isstate(SH_STOPOK))
203da2e3ebchin	{
204da2e3ebchin		if(action<0)
205da2e3ebchin			return;
206da2e3ebchin		sigrelease(sig);
207da2e3ebchin		sh_exit(SH_EXITSIG);
208da2e3ebchin	}
209da2e3ebchin}
210da2e3ebchin
211da2e3ebchin/*
212da2e3ebchin * initialize signal handling
213da2e3ebchin */
2147c2fbfbApril Chinvoid sh_siginit(void *ptr)
215da2e3ebchin{
2167c2fbfbApril Chin	Shell_t	*shp = (Shell_t*)ptr;
21734f9b3eRoland Mainz	register int sig, n;
218da2e3ebchin	register const struct shtable2	*tp = shtab_signals;
219da2e3ebchin	sig_begin();
220da2e3ebchin	/* find the largest signal number in the table */
22134f9b3eRoland Mainz#if defined(SIGRTMIN) && defined(SIGRTMAX)
22234f9b3eRoland Mainz	if ((n = SIGRTMIN) > 0 && (sig = SIGRTMAX) > n && sig < SH_TRAP)
22334f9b3eRoland Mainz	{
22434f9b3eRoland Mainz		shp->sigruntime[SH_SIGRTMIN] = n;
22534f9b3eRoland Mainz		shp->sigruntime[SH_SIGRTMAX] = sig;
22634f9b3eRoland Mainz	}
22734f9b3eRoland Mainz#endif /* SIGRTMIN && SIGRTMAX */
22834f9b3eRoland Mainz	n = SIGTERM;
229da2e3ebchin	while(*tp->sh_name)
230da2e3ebchin	{
23134f9b3eRoland Mainz		sig = (tp->sh_number&((1<<SH_SIGBITS)-1));
23234f9b3eRoland Mainz		if (!(sig-- & SH_TRAP))
23334f9b3eRoland Mainz		{
23434f9b3eRoland Mainz			if ((tp->sh_number>>SH_SIGBITS) & SH_SIGRUNTIME)
23534f9b3eRoland Mainz				sig = shp->sigruntime[sig];
23634f9b3eRoland Mainz			if(sig>n && sig<SH_TRAP)
23734f9b3eRoland Mainz				n = sig;
23834f9b3eRoland Mainz		}
239da2e3ebchin		tp++;
240da2e3ebchin	}
2417c2fbfbApril Chin	shp->sigmax = n++;
2427c2fbfbApril Chin	shp->st.trapcom = (char**)calloc(n,sizeof(char*));
2437c2fbfbApril Chin	shp->sigflag = (unsigned char*)calloc(n,1);
2447c2fbfbApril Chin	shp->sigmsg = (char**)calloc(n,sizeof(char*));
245da2e3ebchin	for(tp=shtab_signals; sig=tp->sh_number; tp++)
246da2e3ebchin	{
247da2e3ebchin		n = (sig>>SH_SIGBITS);
24834f9b3eRoland Mainz		if((sig &= ((1<<SH_SIGBITS)-1)) > (shp->sigmax+1))
249da2e3ebchin			continue;
250da2e3ebchin		sig--;
2517c2fbfbApril Chin		if(n&SH_SIGRUNTIME)
2527c2fbfbApril Chin			sig = shp->sigruntime[sig];
253da2e3ebchin		if(sig>=0)
254da2e3ebchin		{
2557c2fbfbApril Chin			shp->sigflag[sig] = n;
256da2e3ebchin			if(*tp->sh_name)
2577c2fbfbApril Chin				shp->sigmsg[sig] = (char*)tp->sh_value;
258da2e3ebchin		}
259da2e3ebchin	}
260da2e3ebchin}
261da2e3ebchin
262da2e3ebchin/*
263da2e3ebchin * Turn on trap handler for signal <sig>
264da2e3ebchin */
265da2e3ebchinvoid	sh_sigtrap(register int sig)
266da2e3ebchin{
267da2e3ebchin	register int flag;
268da2e3ebchin	void (*fun)(int);
269da2e3ebchin	sh.st.otrapcom = 0;
270da2e3ebchin	if(sig==0)
271da2e3ebchin		sh_sigdone();
272da2e3ebchin	else if(!((flag=sh.sigflag[sig])&(SH_SIGFAULT|SH_SIGOFF)))
273da2e3ebchin	{
274da2e3ebchin		/* don't set signal if already set or off by parent */
275da2e3ebchin		if((fun=signal(sig,sh_fault))==SIG_IGN)
276da2e3ebchin		{
277da2e3ebchin			signal(sig,SIG_IGN);
278da2e3ebchin			flag |= SH_SIGOFF;
279da2e3ebchin		}
280da2e3ebchin		else
281da2e3ebchin		{
282da2e3ebchin			flag |= SH_SIGFAULT;
283da2e3ebchin			if(sig==SIGALRM && fun!=SIG_DFL && fun!=sh_fault)
284da2e3ebchin				signal(sig,fun);
285da2e3ebchin		}
286da2e3ebchin		flag &= ~(SH_SIGSET|SH_SIGTRAP);
287da2e3ebchin		sh.sigflag[sig] = flag;
288da2e3ebchin	}
289da2e3ebchin}
290da2e3ebchin
291da2e3ebchin/*
292da2e3ebchin * set signal handler so sh_done is called for all caught signals
293da2e3ebchin */
294da2e3ebchinvoid	sh_sigdone(void)
295da2e3ebchin{
296da2e3ebchin	register int 	flag, sig = sh.sigmax;
297da2e3ebchin	sh.sigflag[0] |= SH_SIGFAULT;
29834f9b3eRoland Mainz	for(sig=sh.sigmax; sig>0; sig--)
299da2e3ebchin	{
300da2e3ebchin		flag = sh.sigflag[sig];
301da2e3ebchin		if((flag&(SH_SIGDONE|SH_SIGIGNORE|SH_SIGINTERACTIVE)) && !(flag&(SH_SIGFAULT|SH_SIGOFF)))
302da2e3ebchin			sh_sigtrap(sig);
303da2e3ebchin	}
304da2e3ebchin}
305da2e3ebchin
306da2e3ebchin/*
307da2e3ebchin * Restore to default signals
308da2e3ebchin * Free the trap strings if mode is non-zero
309da2e3ebchin * If mode>1 then ignored traps cause signal to be ignored
310da2e3ebchin */
311da2e3ebchinvoid	sh_sigreset(register int mode)
312da2e3ebchin{
313da2e3ebchin	register char	*trap;
314da2e3ebchin	register int 	flag, sig=sh.st.trapmax;
315da2e3ebchin	while(sig-- > 0)
316da2e3ebchin	{
317da2e3ebchin		if(trap=sh.st.trapcom[sig])
318da2e3ebchin		{
319da2e3ebchin			flag  = sh.sigflag[sig]&~(SH_SIGTRAP|SH_SIGSET);
320da2e3ebchin			if(*trap)
321da2e3ebchin			{
322da2e3ebchin				if(mode)
323da2e3ebchin					free(trap);
324da2e3ebchin				sh.st.trapcom[sig] = 0;
325da2e3ebchin			}
326da2e3ebchin			else if(sig && mode>1)
327da2e3ebchin			{
32834f9b3eRoland Mainz				if(sig!=SIGCHLD)
32934f9b3eRoland Mainz					signal(sig,SIG_IGN);
330da2e3ebchin				flag &= ~SH_SIGFAULT;
331da2e3ebchin				flag |= SH_SIGOFF;
332da2e3ebchin			}
333da2e3ebchin			sh.sigflag[sig] = flag;
334da2e3ebchin		}
335da2e3ebchin	}
3367c2fbfbApril Chin	for(sig=SH_DEBUGTRAP-1;sig>=0;sig--)
337da2e3ebchin	{
338da2e3ebchin		if(trap=sh.st.trap[sig])
339da2e3ebchin		{
340da2e3ebchin			if(mode)
341da2e3ebchin				free(trap);
342da2e3ebchin			sh.st.trap[sig] = 0;
343da2e3ebchin		}
344da2e3ebchin
345da2e3ebchin	}
346da2e3ebchin	sh.st.trapcom[0] = 0;
347da2e3ebchin	if(mode)
348da2e3ebchin		sh.st.trapmax = 0;
349da2e3ebchin	sh.trapnote=0;
350da2e3ebchin}
351da2e3ebchin
352da2e3ebchin/*
353da2e3ebchin * free up trap if set and restore signal handler if modified
354da2e3ebchin */
355da2e3ebchinvoid	sh_sigclear(register int sig)
356da2e3ebchin{
357da2e3ebchin	register int flag = sh.sigflag[sig];
358da2e3ebchin	register char *trap;
359da2e3ebchin	sh.st.otrapcom=0;
360da2e3ebchin	if(!(flag&SH_SIGFAULT))
361da2e3ebchin		return;
362da2e3ebchin	flag &= ~(SH_SIGTRAP|SH_SIGSET);
363da2e3ebchin	if(trap=sh.st.trapcom[sig])
364da2e3ebchin	{
3653e14f97Roger A. Faulkner		if(!sh.subshell)
3663e14f97Roger A. Faulkner			free(trap);
367da2e3ebchin		sh.st.trapcom[sig]=0;
368da2e3ebchin	}
369da2e3ebchin	sh.sigflag[sig] = flag;
370da2e3ebchin}
371da2e3ebchin
372da2e3ebchin/*
373da2e3ebchin * check for traps
374da2e3ebchin */
375da2e3ebchin
376da2e3ebchinvoid	sh_chktrap(void)
377da2e3ebchin{
378da2e3ebchin	register int 	sig=sh.st.trapmax;
379da2e3ebchin	register char *trap;
3807c2fbfbApril Chin	if(!(sh.trapnote&~SH_SIGIGNORE))
381da2e3ebchin		sig=0;
382da2e3ebchin	sh.trapnote &= ~SH_SIGTRAP;
383da2e3ebchin	/* execute errexit trap first */
384da2e3ebchin	if(sh_isstate(SH_ERREXIT) && sh.exitval)
385da2e3ebchin	{
386da2e3ebchin		int	sav_trapnote = sh.trapnote;
387da2e3ebchin		sh.trapnote &= ~SH_SIGSET;
388da2e3ebchin		if(sh.st.trap[SH_ERRTRAP])
3897c2fbfbApril Chin		{
3907c2fbfbApril Chin			trap = sh.st.trap[SH_ERRTRAP];
3917c2fbfbApril Chin			sh.st.trap[SH_ERRTRAP] = 0;
3927c2fbfbApril Chin			sh_trap(trap,0);
3937c2fbfbApril Chin			sh.st.trap[SH_ERRTRAP] = trap;
3947c2fbfbApril Chin		}
395da2e3ebchin		sh.trapnote = sav_trapnote;
396da2e3ebchin		if(sh_isoption(SH_ERREXIT))
397da2e3ebchin		{
398da2e3ebchin			struct checkpt	*pp = (struct checkpt*)sh.jmplist;
399da2e3ebchin			pp->mode = SH_JMPEXIT;
400da2e3ebchin			sh_exit(sh.exitval);
401da2e3ebchin		}
402da2e3ebchin	}
403da2e3ebchin	if(sh.sigflag[SIGALRM]&SH_SIGALRM)
404da2e3ebchin		sh_timetraps();
40534f9b3eRoland Mainz#ifdef SHOPT_BGX
40634f9b3eRoland Mainz	if((sh.sigflag[SIGCHLD]&SH_SIGTRAP) && sh.st.trapcom[SIGCHLD])
40734f9b3eRoland Mainz		job_chldtrap(&sh,sh.st.trapcom[SIGCHLD],1);
40834f9b3eRoland Mainz#endif /* SHOPT_BGX */
4093e14f97Roger A. Faulkner	while(--sig>=0)
410da2e3ebchin	{
4113e14f97Roger A. Faulkner#ifdef SHOPT_BGX
4123e14f97Roger A. Faulkner		if(sig==SIGCHLD)
4133e14f97Roger A. Faulkner			continue;
4143e14f97Roger A. Faulkner#endif /* SHOPT_BGX */
415da2e3ebchin		if(sh.sigflag[sig]&SH_SIGTRAP)
416da2e3ebchin		{
417da2e3ebchin			sh.sigflag[sig] &= ~SH_SIGTRAP;
418da2e3ebchin			if(trap=sh.st.trapcom[sig])
41934f9b3eRoland Mainz			{
42034f9b3eRoland Mainz				Sfio_t *fp;
421