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