1 /***********************************************************************
3 * This software is part of the ast package *
4 * Copyright (c) 1982-2010 AT&T Intellectual Property *
5 * and is licensed under the *
6 * Common Public License, Version 1.0 *
7 * by AT&T Intellectual Property *
9 * A copy of the License is available at *
10 * http://www.opensource.org/licenses/cpl1.0.txt *
11 * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) *
13 * Information and Software Systems Research *
17 * David Korn <dgk@research.att.com> *
19 ***********************************************************************/
22 * Fault handling routines
34 #include "variables.h"
39 #define abortsig(sig) (sig==SIGABRT || sig==SIGBUS || sig==SIGILL || sig==SIGSEGV)
46 #if defined(VMFL) && (VMALLOC_VERSION>=20031205L)
48 * This exception handler is called after vmalloc() unlocks the region
50 static int malloc_done(Vmalloc_t
* vm
, int type
, Void_t
* val
, Vmdisc_t
* dp
)
59 * Most signals caught or ignored by the shell come here
61 void sh_fault(register int sig
)
63 register Shell_t
*shp
= sh_getinterp();
66 register struct checkpt
*pp
= (struct checkpt
*)shp
->jmplist
;
70 signal(sig
, sh_fault
);
77 astwinsize(2,&rows
,&cols
);
79 nv_putval(COLUMNS
, (char*)&v
, NV_INT32
|NV_RDONLY
);
81 nv_putval(LINES
, (char*)&v
, NV_INT32
|NV_RDONLY
);
87 /* critical region, save and process later */
91 trap
= shp
->st
.trapcom
[sig
];
92 if(sig
==SIGALRM
&& shp
->bltinfun
==b_sleep
)
96 shp
->trapnote
|= SH_SIGTRAP
;
97 shp
->sigflag
[sig
] |= SH_SIGTRAP
;
101 if(shp
->subshell
&& sig
!=SIGINT
&& sig
!=SIGQUIT
&& sig
!=SIGWINCH
&& sig
!=SIGCONT
)
103 shp
->exitval
= SH_EXITSIG
|sig
;
108 /* handle ignored signals */
111 flag
= shp
->sigflag
[sig
]&~SH_SIGOFF
;
114 if(sig
==SIGINT
&& (shp
->trapnote
&SH_SIGIGNORE
))
116 if(flag
&SH_SIGIGNORE
)
121 if((flag
&SH_SIGINTERACTIVE
) && sh_isstate(SH_INTERACTIVE
) && !sh_isstate(SH_FORKED
) && ! shp
->subshell
)
123 /* check for TERM signal between fork/exec */
124 if(sig
==SIGTERM
&& job
.in_critical
)
125 shp
->trapnote
|= SH_SIGTERM
;
130 if(pp
->mode
< SH_JMPFUN
)
131 pp
->mode
= SH_JMPFUN
;
133 pp
->mode
= SH_JMPEXIT
;
134 if(sig
==SIGABRT
|| (abortsig(sig
) && (ptr
= malloc(1))))
142 /* mark signal and continue */
143 shp
->trapnote
|= SH_SIGSET
;
144 if(sig
<= shp
->sigmax
)
145 shp
->sigflag
[sig
] |= SH_SIGSET
;
146 #if defined(VMFL) && (VMALLOC_VERSION>=20031205L)
149 /* abort inside malloc, process when malloc returns */
150 /* VMFL defined when using vmalloc() */
151 Vmdisc_t
* dp
= vmdisc(Vmregion
,0);
153 dp
->exceptf
= malloc_done
;
160 if(pp
->mode
==SH_JMPCMD
)
165 * propogate signal to foreground group
167 if(sig
==SIGHUP
&& job
.curpgid
)
168 killpg(job
.curpgid
,SIGHUP
);
178 shp
->trapnote
|= SH_SIGTSTP
;
179 if(pp
->mode
==SH_JMPCMD
&& sh_isstate(SH_STOPOK
))
189 if((error_info
.flags
&ERROR_NOTIFY
) && shp
->bltinfun
)
190 action
= (*shp
->bltinfun
)(-sig
,(char**)0,(void*)0);
194 if(shp
->bltinfun
&& shp
->bltindata
.notify
)
196 shp
->bltindata
.sigset
= 1;
199 shp
->trapnote
|= flag
;
200 if(sig
<= shp
->sigmax
)
201 shp
->sigflag
[sig
] |= flag
;
202 if(pp
->mode
==SH_JMPCMD
&& sh_isstate(SH_STOPOK
))
212 * initialize signal handling
214 void sh_siginit(void *ptr
)
216 Shell_t
*shp
= (Shell_t
*)ptr
;
218 register const struct shtable2
*tp
= shtab_signals
;
220 /* find the largest signal number in the table */
221 #if defined(SIGRTMIN) && defined(SIGRTMAX)
222 if ((n
= SIGRTMIN
) > 0 && (sig
= SIGRTMAX
) > n
&& sig
< SH_TRAP
)
224 shp
->sigruntime
[SH_SIGRTMIN
] = n
;
225 shp
->sigruntime
[SH_SIGRTMAX
] = sig
;
227 #endif /* SIGRTMIN && SIGRTMAX */
231 sig
= (tp
->sh_number
&((1<<SH_SIGBITS
)-1));
232 if (!(sig
-- & SH_TRAP
))
234 if ((tp
->sh_number
>>SH_SIGBITS
) & SH_SIGRUNTIME
)
235 sig
= shp
->sigruntime
[sig
];
236 if(sig
>n
&& sig
<SH_TRAP
)
242 shp
->st
.trapcom
= (char**)calloc(n
,sizeof(char*));
243 shp
->sigflag
= (unsigned char*)calloc(n
,1);
244 shp
->sigmsg
= (char**)calloc(n
,sizeof(char*));
245 for(tp
=shtab_signals
; sig
=tp
->sh_number
; tp
++)
247 n
= (sig
>>SH_SIGBITS
);
248 if((sig
&= ((1<<SH_SIGBITS
)-1)) > (shp
->sigmax
+1))
252 sig
= shp
->sigruntime
[sig
];
255 shp
->sigflag
[sig
] = n
;
257 shp
->sigmsg
[sig
] = (char*)tp
->sh_value
;
263 * Turn on trap handler for signal <sig>
265 void sh_sigtrap(register int sig
)
272 else if(!((flag
=sh
.sigflag
[sig
])&(SH_SIGFAULT
|SH_SIGOFF
)))
274 /* don't set signal if already set or off by parent */
275 if((fun
=signal(sig
,sh_fault
))==SIG_IGN
)
283 if(sig
==SIGALRM
&& fun
!=SIG_DFL
&& fun
!=sh_fault
)
286 flag
&= ~(SH_SIGSET
|SH_SIGTRAP
);
287 sh
.sigflag
[sig
] = flag
;
292 * set signal handler so sh_done is called for all caught signals
294 void sh_sigdone(void)
296 register int flag
, sig
= sh
.sigmax
;
297 sh
.sigflag
[0] |= SH_SIGFAULT
;
298 for(sig
=sh
.sigmax
; sig
>0; sig
--)
300 flag
= sh
.sigflag
[sig
];
301 if((flag
&(SH_SIGDONE
|SH_SIGIGNORE
|SH_SIGINTERACTIVE
)) && !(flag
&(SH_SIGFAULT
|SH_SIGOFF
)))
307 * Restore to default signals
308 * Free the trap strings if mode is non-zero
309 * If mode>1 then ignored traps cause signal to be ignored
311 void sh_sigreset(register int mode
)
314 register int flag
, sig
=sh
.st
.trapmax
;
317 if(trap
=sh
.st
.trapcom
[sig
])
319 flag
= sh
.sigflag
[sig
]&~(SH_SIGTRAP
|SH_SIGSET
);
324 sh
.st
.trapcom
[sig
] = 0;
326 else if(sig
&& mode
>1)
330 flag
&= ~SH_SIGFAULT
;
333 sh
.sigflag
[sig
] = flag
;
336 for(sig
=SH_DEBUGTRAP
-1;sig
>=0;sig
--)
338 if(trap
=sh
.st
.trap
[sig
])
346 sh
.st
.trapcom
[0] = 0;
353 * free up trap if set and restore signal handler if modified
355 void sh_sigclear(register int sig
)
357 register int flag
= sh
.sigflag
[sig
];
360 if(!(flag
&SH_SIGFAULT
))
362 flag
&= ~(SH_SIGTRAP
|SH_SIGSET
);
363 if(trap
=sh
.st
.trapcom
[sig
])
367 sh
.st
.trapcom
[sig
]=0;
369 sh
.sigflag
[sig
] = flag
;
376 void sh_chktrap(void)
378 register int sig
=sh
.st
.trapmax
;
380 if(!(sh
.trapnote
&~SH_SIGIGNORE
))
382 sh
.trapnote
&= ~SH_SIGTRAP
;
383 /* execute errexit trap first */
384 if(sh_isstate(SH_ERREXIT
) && sh
.exitval
)
386 int sav_trapnote
= sh
.trapnote
;
387 sh
.trapnote
&= ~SH_SIGSET
;
388 if(sh
.st
.trap
[SH_ERRTRAP
])
390 trap
= sh
.st
.trap
[SH_ERRTRAP
];
391 sh
.st
.trap
[SH_ERRTRAP
] = 0;
393 sh
.st
.trap
[SH_ERRTRAP
] = trap
;
395 sh
.trapnote
= sav_trapnote
;
396 if(sh_isoption(SH_ERREXIT
))
398 struct checkpt
*pp
= (struct checkpt
*)sh
.jmplist
;
399 pp
->mode
= SH_JMPEXIT
;
403 if(sh
.sigflag
[SIGALRM
]&SH_SIGALRM
)
406 if((sh
.sigflag
[SIGCHLD
]&SH_SIGTRAP
) && sh
.st
.trapcom
[SIGCHLD
])
407 job_chldtrap(&sh
,sh
.st
.trapcom
[SIGCHLD
],1);
408 #endif /* SHOPT_BGX */
414 #endif /* SHOPT_BGX */
415 if(sh
.sigflag
[sig
]&SH_SIGTRAP
)
417 sh
.sigflag
[sig
] &= ~SH_SIGTRAP
;
418 if(trap
=sh
.st
.trapcom
[sig
])
421 if(sig
==SIGPIPE
&& (fp
=sfpool((Sfio_t
*)0,sh
.outpool
,SF_WRITE
)) && sferror(fp
))
423 sh
.oldexit
= SH_EXITSIG
|sig
;
432 * parse and execute the given trap string, stream or tree depending on mode
433 * mode==0 for string, mode==1 for stream, mode==2 for parse tree
435 int sh_trap(const char *trap
, int mode
)
437 Shell_t
*shp
= sh_getinterp();
438 int jmpval
, savxit
= shp
->exitval
;
439 int was_history
= sh_isstate(SH_HISTORY
);
440 int was_verbose
= sh_isstate(SH_VERBOSE
);
441 int staktop
= staktell();
442 char *savptr
= stakfreeze(0);
447 memcpy(ifstable
,shp
->ifstable
,sizeof(ifstable
));
448 sh_offstate(SH_HISTORY
);
449 sh_offstate(SH_VERBOSE
);
451 sh_pushcontext(&buff
,SH_JMPTRAP
);
452 jmpval
= sigsetjmp(buff
.buff
,0);
456 sh_exec((Shnode_t
*)trap
,sh_isstate(SH_ERREXIT
));
463 sp
= sfopen(NIL(Sfio_t
*),trap
,"s");
469 if(jmpval
==SH_JMPSCRIPT
)
473 if(jmpval
==SH_JMPEXIT
)
474 savxit
= shp
->exitval
;
478 sh_popcontext(&buff
);
480 sfsync(shp
->outpool
);
481 if(!shp
->indebug
&& jmpval
!=SH_JMPEXIT
&& jmpval
!=SH_JMPFUN
)
483 stakset(savptr
,staktop
);
485 memcpy(shp
->ifstable
,ifstable
,sizeof(ifstable
));
487 sh_onstate(SH_HISTORY
);
489 sh_onstate(SH_VERBOSE
);
491 if(jmpval
>SH_JMPTRAP
&& (((struct checkpt
*)shp
->jmpbuffer
)->prev
|| ((struct checkpt
*)shp
->jmpbuffer
)->mode
==SH_JMPSCRIPT
))
492 siglongjmp(*shp
->jmplist
,jmpval
);
493 return(shp
->exitval
);
497 * exit the current scope and jump to an earlier one based on pp->mode
499 void sh_exit(register int xno
)
502 register struct checkpt
*pp
= (struct checkpt
*)shp
->jmplist
;
504 register Sfio_t
* pool
;
507 shp
->exitval
|= (sig
=shp
->lastsig
);
509 if(shp
->trapnote
&SH_SIGTSTP
)
511 /* ^Z detected by the shell */
513 shp
->sigflag
[SIGTSTP
] = 0;
514 if(!shp
->subshell
&& sh_isstate(SH_MONITOR
) && !sh_isstate(SH_STOPOK
))
516 if(sh_isstate(SH_TIMING
))
518 /* Handles ^Z for shell builtins, subshells, and functs */
520 sh_onstate(SH_MONITOR
);
521 sh_offstate(SH_STOPOK
);
523 if(!shp
->subshell
&& (sig
=sh_fork(0,NIL(int*))))
526 job
.parent
= (pid_t
)-1;
529 shp
->sigflag
[SIGTSTP
] = 0;
530 /* wait for child to stop */
531 shp
->exitval
= (SH_EXITSIG
|SIGTSTP
);
532 /* return to prompt mode */
533 pp
->mode
= SH_JMPERREXIT
;
539 /* child process, put to sleep */
540 sh_offstate(SH_STOPOK
);
541 sh_offstate(SH_MONITOR
);
542 shp
->sigflag
[SIGTSTP
] = 0;
544 killpg(job
.curpgid
,SIGTSTP
);
548 shp
->exitval
= (xno
&SH_EXITMASK
);
553 /* unlock output pool */
554 sh_offstate(SH_NOTRACK
);
555 if(!(pool
=sfpool(NIL(Sfio_t
*),shp
->outpool
,SF_WRITE
)))
556 pool
= shp
->outpool
; /* can't happen? */
559 if(shp
->lastsig
==SIGPIPE
)
568 #endif /* SHOPT_TYPEDEF*/
569 if(pp
->mode
== SH_JMPSCRIPT
&& !pp
->prev
)
572 siglongjmp(pp
->buff
,pp
->mode
);
575 static void array_notify(Namval_t
*np
, void *data
)
577 Namarr_t
*ap
= nv_arrayptr(np
);
580 (*ap
->fun
)(np
, 0, NV_AFREE
);
584 * This is the exit routine for the shell
587 void sh_done(void *ptr
, register int sig
)
589 Shell_t
*shp
= (Shell_t
*)ptr
;
591 register int savxit
= shp
->exitval
;
595 savxit
= SH_EXITSIG
|sig
;
597 (*shp
->userinit
)(shp
, -1);
598 if(t
=shp
->st
.trapcom
[0])
600 shp
->st
.trapcom
[0]=0; /*should free but not long */
601 shp
->oldexit
= savxit
;
603 savxit
= shp
->exitval
;
607 /* avoid recursive call for set -e */
608 sh_offstate(SH_ERREXIT
);
611 nv_scan(shp
->var_tree
,array_notify
,(void*)0,NV_ARRAY
,NV_ARRAY
);
615 #endif /* SHOPT_ACCT */
616 #if SHOPT_VSH || SHOPT_ESH
617 if(sh_isoption(SH_EMACS
)||sh_isoption(SH_VI
)||sh_isoption(SH_GMACS
))
621 if((sh_isoption(SH_INTERACTIVE
) && shp
->login_sh
) || (!sh_isoption(SH_INTERACTIVE
) && (sig
==SIGHUP
)))
622 job_walk(sfstderr
,job_terminate
,SIGHUP
,NIL(char**));
625 if(nv_search("VMTRACE", shp
->var_tree
,0))
626 strmatch((char*)0,(char*)0);
627 sfsync((Sfio_t
*)sfstdin
);
628 sfsync((Sfio_t
*)shp
->outpool
);
629 sfsync((Sfio_t
*)sfstdout
);
630 if(savxit
&SH_EXITSIG
)
631 sig
= savxit
&SH_EXITMASK
;
634 /* generate fault termination code */
641 if(sh_isoption(SH_NOEXEC
))
642 kiaclose((Lex_t
*)shp
->lex_context
);
643 #endif /* SHOPT_KIA */
644 exit(savxit
&SH_EXITMASK
);