1 /***********************************************************************
2 * *
3 * This software is part of the ast package *
4 * Copyright (c) 1982-2012 AT&T Intellectual Property *
5 * and is licensed under the *
6 * Eclipse Public License, Version 1.0 *
7 * by AT&T Intellectual Property *
8 * *
9 * A copy of the License is available at *
10 * http://www.eclipse.org/org/documents/epl-v10.html *
11 * (with md5 checksum b35adb5213ca9657e911e9befb180842) *
12 * *
13 * Information and Software Systems Research *
14 * AT&T Research *
15 * Florham Park NJ *
16 * *
17 * David Korn <dgk@research.att.com> *
18 * *
19 ***********************************************************************/
20 #pragma prototyped
21 /*
22 * Fault handling routines
23 *
24 * David Korn
25 * AT&T Labs
26 *
27 */
28
29 #include "defs.h"
30 #include <fcin.h>
31 #include "io.h"
32 #include "history.h"
33 #include "shlex.h"
34 #include "variables.h"
35 #include "jobs.h"
36 #include "path.h"
37 #include "builtins.h"
38 #include "ulimit.h"
39
40 #define abortsig(sig) (sig==SIGABRT || sig==SIGBUS || sig==SIGILL || sig==SIGSEGV)
41
42 static char indone;
43 static int cursig = -1;
44
45 #if !_std_malloc
46 # include <vmalloc.h>
47 #endif
48 #if defined(VMFL) && (VMALLOC_VERSION>=20031205L)
49 /*
50 * This exception handler is called after vmalloc() unlocks the region
51 */
malloc_done(Vmalloc_t * vm,int type,Void_t * val,Vmdisc_t * dp)52 static int malloc_done(Vmalloc_t* vm, int type, Void_t* val, Vmdisc_t* dp)
53 {
54 dp->exceptf = 0;
55 sh_exit(SH_EXITSIG);
56 return(0);
57 }
58 #endif
59
60 /*
61 * Most signals caught or ignored by the shell come here
62 */
sh_fault(register int sig)63 void sh_fault(register int sig)
64 {
65 register Shell_t *shp = sh_getinterp();
66 register int flag=0;
67 register char *trap;
68 register struct checkpt *pp = (struct checkpt*)shp->jmplist;
69 int action=0;
70 /* reset handler */
71 if(!(sig&SH_TRAP))
72 signal(sig, sh_fault);
73 sig &= ~SH_TRAP;
74 #ifdef SIGWINCH
75 if(sig==SIGWINCH)
76 {
77 int rows=0, cols=0;
78 int32_t v;
79 astwinsize(2,&rows,&cols);
80 if(v = cols)
81 nv_putval(COLUMNS, (char*)&v, NV_INT32|NV_RDONLY);
82 if(v = rows)
83 nv_putval(LINES, (char*)&v, NV_INT32|NV_RDONLY);
84 shp->winch++;
85 }
86 #endif /* SIGWINCH */
87 trap = shp->st.trapcom[sig];
88 if(shp->savesig)
89 {
90 /* critical region, save and process later */
91 if(!(shp->sigflag[sig]&SH_SIGIGNORE))
92 shp->savesig = sig;
93 return;
94 }
95 if(sig==SIGALRM && shp->bltinfun==b_sleep)
96 {
97 if(trap && *trap)
98 {
99 shp->trapnote |= SH_SIGTRAP;
100 shp->sigflag[sig] |= SH_SIGTRAP;
101 }
102 return;
103 }
104 if(shp->subshell && trap && sig!=SIGINT && sig!=SIGQUIT && sig!=SIGWINCH && sig!=SIGCONT)
105 {
106 shp->exitval = SH_EXITSIG|sig;
107 sh_subfork();
108 shp->exitval = 0;
109 return;
110 }
111 /* handle ignored signals */
112 if(trap && *trap==0)
113 return;
114 flag = shp->sigflag[sig]&~SH_SIGOFF;
115 if(!trap)
116 {
117 if(sig==SIGINT && (shp->trapnote&SH_SIGIGNORE))
118 return;
119 if(flag&SH_SIGIGNORE)
120 {
121 if(shp->subshell)
122 shp->ignsig = sig;
123 sigrelease(sig);
124 return;
125 }
126 if(flag&SH_SIGDONE)
127 {
128 void *ptr=0;
129 if((flag&SH_SIGINTERACTIVE) && sh_isstate(SH_INTERACTIVE) && !sh_isstate(SH_FORKED) && ! shp->subshell)
130 {
131 /* check for TERM signal between fork/exec */
132 if(sig==SIGTERM && job.in_critical)
133 shp->trapnote |= SH_SIGTERM;
134 return;
135 }
136 shp->lastsig = sig;
137 sigrelease(sig);
138 if(pp->mode != SH_JMPSUB)
139 {
140 if(pp->mode < SH_JMPSUB)
141 pp->mode = shp->subshell?SH_JMPSUB:SH_JMPFUN;
142 else
143 pp->mode = SH_JMPEXIT;
144 }
145 if(shp->subshell)
146 sh_exit(SH_EXITSIG);
147 if(sig==SIGABRT || (abortsig(sig) && (ptr = malloc(1))))
148 {
149 if(ptr)
150 free(ptr);
151 sh_done(shp,sig);
152 }
153 /* mark signal and continue */
154 shp->trapnote |= SH_SIGSET;
155 if(sig <= shp->gd->sigmax)
156 shp->sigflag[sig] |= SH_SIGSET;
157 #if defined(VMFL) && (VMALLOC_VERSION>=20031205L)
158 if(abortsig(sig))
159 {
160 /* abort inside malloc, process when malloc returns */
161 /* VMFL defined when using vmalloc() */
162 Vmdisc_t* dp = vmdisc(Vmregion,0);
163 if(dp)
164 dp->exceptf = malloc_done;
165 }
166 #endif
167 return;
168 }
169 }
170 errno = 0;
171 if(pp->mode==SH_JMPCMD || (pp->mode==1 && shp->bltinfun) && !(flag&SH_SIGIGNORE))
172 shp->lastsig = sig;
173 if(trap)
174 {
175 /*
176 * propogate signal to foreground group
177 */
178 if(sig==SIGHUP && job.curpgid)
179 killpg(job.curpgid,SIGHUP);
180 flag = SH_SIGTRAP;
181 }
182 else
183 {
184 shp->lastsig = sig;
185 flag = SH_SIGSET;
186 #ifdef SIGTSTP
187 if(sig==SIGTSTP)
188 {
189 shp->trapnote |= SH_SIGTSTP;
190 if(pp->mode==SH_JMPCMD && sh_isstate(SH_STOPOK))
191 {
192 sigrelease(sig);
193 sh_exit(SH_EXITSIG);
194 return;
195 }
196 }
197 #endif /* SIGTSTP */
198 }
199 #ifdef ERROR_NOTIFY
200 if((error_info.flags&ERROR_NOTIFY) && shp->bltinfun)
201 action = (*shp->bltinfun)(-sig,(char**)0,(void*)0);
202 if(action>0)
203 return;
204 #endif
205 if(shp->bltinfun && shp->bltindata.notify)
206 {
207 shp->bltindata.sigset = 1;
208 return;
209 }
210 shp->trapnote |= flag;
211 if(sig <= shp->gd->sigmax)
212 shp->sigflag[sig] |= flag;
213 if(pp->mode==SH_JMPCMD && sh_isstate(SH_STOPOK))
214 {
215 if(action<0)
216 return;
217 sigrelease(sig);
218 sh_exit(SH_EXITSIG);
219 }
220 }
221
222 /*
223 * initialize signal handling
224 */
sh_siginit(void * ptr)225 void sh_siginit(void *ptr)
226 {
227 Shell_t *shp = (Shell_t*)ptr;
228 register int sig, n;
229 register const struct shtable2 *tp = shtab_signals;
230 sig_begin();
231 /* find the largest signal number in the table */
232 #if defined(SIGRTMIN) && defined(SIGRTMAX)
233 if ((n = SIGRTMIN) > 0 && (sig = SIGRTMAX) > n && sig < SH_TRAP)
234 {
235 shp->gd->sigruntime[SH_SIGRTMIN] = n;
236 shp->gd->sigruntime[SH_SIGRTMAX] = sig;
237 }
238 #endif /* SIGRTMIN && SIGRTMAX */
239 n = SIGTERM;
240 while(*tp->sh_name)
241 {
242 sig = (tp->sh_number&((1<<SH_SIGBITS)-1));
243 if (!(sig-- & SH_TRAP))
244 {
245 if ((tp->sh_number>>SH_SIGBITS) & SH_SIGRUNTIME)
246 sig = shp->gd->sigruntime[sig];
247 if(sig>n && sig<SH_TRAP)
248 n = sig;
249 }
250 tp++;
251 }
252 shp->gd->sigmax = n++;
253 shp->st.trapcom = (char**)calloc(n,sizeof(char*));
254 shp->sigflag = (unsigned char*)calloc(n,1);
255 shp->gd->sigmsg = (char**)calloc(n,sizeof(char*));
256 for(tp=shtab_signals; sig=tp->sh_number; tp++)
257 {
258 n = (sig>>SH_SIGBITS);
259 if((sig &= ((1<<SH_SIGBITS)-1)) > (shp->gd->sigmax+1))
260 continue;
261 sig--;
262 if(n&SH_SIGRUNTIME)
263 sig = shp->gd->sigruntime[sig];
264 if(sig>=0)
265 {
266 shp->sigflag[sig] = n;
267 if(*tp->sh_name)
268 shp->gd->sigmsg[sig] = (char*)tp->sh_value;
269 }
270 }
271 }
272
273 /*
274 * Turn on trap handler for signal <sig>
275 */
sh_sigtrap(register int sig)276 void sh_sigtrap(register int sig)
277 {
278 register int flag;
279 void (*fun)(int);
280 sh.st.otrapcom = 0;
281 if(sig==0)
282 sh_sigdone();
283 else if(!((flag=sh.sigflag[sig])&(SH_SIGFAULT|SH_SIGOFF)))
284 {
285 /* don't set signal if already set or off by parent */
286 if((fun=signal(sig,sh_fault))==SIG_IGN)
287 {
288 signal(sig,SIG_IGN);
289 flag |= SH_SIGOFF;
290 }
291 else
292 {
293 flag |= SH_SIGFAULT;
294 if(sig==SIGALRM && fun!=SIG_DFL && fun!=sh_fault)
295 signal(sig,fun);
296 }
297 flag &= ~(SH_SIGSET|SH_SIGTRAP);
298 sh.sigflag[sig] = flag;
299 }
300 }
301
302 /*
303 * set signal handler so sh_done is called for all caught signals
304 */
sh_sigdone(void)305 void sh_sigdone(void)
306 {
307 register int flag, sig = shgd->sigmax;
308 sh.sigflag[0] |= SH_SIGFAULT;
309 for(sig=shgd->sigmax; sig>0; sig--)
310 {
311 flag = sh.sigflag[sig];
312 if((flag&(SH_SIGDONE|SH_SIGIGNORE|SH_SIGINTERACTIVE)) && !(flag&(SH_SIGFAULT|SH_SIGOFF)))
313 sh_sigtrap(sig);
314 }
315 }
316
317 /*
318 * Restore to default signals
319 * Free the trap strings if mode is non-zero
320 * If mode>1 then ignored traps cause signal to be ignored
321 */
sh_sigreset(register int mode)322 void sh_sigreset(register int mode)
323 {
324 register char *trap;
325 register int flag, sig=sh.st.trapmax;
326 while(sig-- > 0)
327 {
328 if(trap=sh.st.trapcom[sig])
329 {
330 flag = sh.sigflag[sig]&~(SH_SIGTRAP|SH_SIGSET);
331 if(*trap)
332 {
333 if(mode)
334 free(trap);
335 sh.st.trapcom[sig] = 0;
336 }
337 else if(sig && mode>1)
338 {
339 if(sig!=SIGCHLD)
340 signal(sig,SIG_IGN);
341 flag &= ~SH_SIGFAULT;
342 flag |= SH_SIGOFF;
343 }
344 sh.sigflag[sig] = flag;
345 }
346 }
347 for(sig=SH_DEBUGTRAP-1;sig>=0;sig--)
348 {
349 if(trap=sh.st.trap[sig])
350 {
351 if(mode)
352 free(trap);
353 sh.st.trap[sig] = 0;
354 }
355
356 }
357 sh.st.trapcom[0] = 0;
358 if(mode)
359 sh.st.trapmax = 0;
360 sh.trapnote=0;
361 }
362
363 /*
364 * free up trap if set and restore signal handler if modified
365 */
sh_sigclear(register int sig)366 void sh_sigclear(register int sig)
367 {
368 register int flag = sh.sigflag[sig];
369 register char *trap;
370 sh.st.otrapcom=0;
371 if(!(flag&SH_SIGFAULT))
372 return;
373 flag &= ~(SH_SIGTRAP|SH_SIGSET);
374 if(trap=sh.st.trapcom[sig])
375 {
376 if(!sh.subshell)
377 free(trap);
378 sh.st.trapcom[sig]=0;
379 }
380 sh.sigflag[sig] = flag;
381 }
382
383 /*
384 * check for traps
385 */
386
sh_chktrap(Shell_t * shp)387 void sh_chktrap(Shell_t* shp)
388 {
389 register int sig=shp->st.trapmax;
390 register char *trap;
391 if(!(shp->trapnote&~SH_SIGIGNORE))
392 sig=0;
393 shp->trapnote &= ~SH_SIGTRAP;
394 /* execute errexit trap first */
395 if(sh_isstate(SH_ERREXIT) && shp->exitval)
396 {
397 int sav_trapnote = shp->trapnote;
398 shp->trapnote &= ~SH_SIGSET;
399 if(shp->st.trap[SH_ERRTRAP])
400 {
401 trap = shp->st.trap[SH_ERRTRAP];
402 shp->st.trap[SH_ERRTRAP] = 0;
403 sh_trap(trap,0);
404 shp->st.trap[SH_ERRTRAP] = trap;
405 }
406 shp->trapnote = sav_trapnote;
407 if(sh_isoption(SH_ERREXIT))
408 {
409 struct checkpt *pp = (struct checkpt*)shp->jmplist;
410 pp->mode = SH_JMPEXIT;
411 sh_exit(shp->exitval);
412 }
413 }
414 if(shp->sigflag[SIGALRM]&SH_SIGALRM)
415 sh_timetraps(shp);
416 #ifdef SHOPT_BGX
417 if((shp->sigflag[SIGCHLD]&SH_SIGTRAP) && shp->st.trapcom[SIGCHLD])
418 job_chldtrap(shp,shp->st.trapcom[SIGCHLD],1);
419 #endif /* SHOPT_BGX */
420 while(--sig>=0)
421 {
422 if(sig==cursig)
423 continue;
424 #ifdef SHOPT_BGX
425 if(sig==SIGCHLD)
426 continue;
427 #endif /* SHOPT_BGX */
428 if(shp->sigflag[sig]&SH_SIGTRAP)
429 {
430 shp->sigflag[sig] &= ~SH_SIGTRAP;
431 if(trap=shp->st.trapcom[sig])
432 {
433 cursig = sig;
434 sh_trap(trap,0);
435 cursig = -1;
436 }
437 }
438 }
439 }
440
441
442 /*
443 * parse and execute the given trap string, stream or tree depending on mode
444 * mode==0 for string, mode==1 for stream, mode==2 for parse tree
445 */
sh_trap(const char * trap,int mode)446 int sh_trap(const char *trap, int mode)
447 {
448 Shell_t *shp = sh_getinterp();
449 int jmpval, savxit = shp->exitval;
450 int was_history = sh_isstate(SH_HISTORY);
451 int was_verbose = sh_isstate(SH_VERBOSE);
452 int staktop = staktell();
453 char *savptr = stakfreeze(0);
454 char ifstable[256];
455 struct checkpt buff;
456 Fcin_t savefc;
457 fcsave(&savefc);
458 memcpy(ifstable,shp->ifstable,sizeof(ifstable));
459 sh_offstate(SH_HISTORY);
460 sh_offstate(SH_VERBOSE);
461 shp->intrap++;
462 sh_pushcontext(shp,&buff,SH_JMPTRAP);
463 jmpval = sigsetjmp(buff.buff,0);
464 if(jmpval == 0)
465 {
466 if(mode==2)
467 sh_exec((Shnode_t*)trap,sh_isstate(SH_ERREXIT));
468 else
469 {
470 Sfio_t *sp;
471 if(mode)
472 sp = (Sfio_t*)trap;
473 else
474 sp = sfopen(NIL(Sfio_t*),trap,"s");
475 sh_eval(sp,0);
476 }
477 }
478 else if(indone)
479 {
480 if(jmpval==SH_JMPSCRIPT)
481 indone=0;
482 else
483 {
484 if(jmpval==SH_JMPEXIT)
485 savxit = shp->exitval;
486 jmpval=SH_JMPTRAP;
487 }
488 }
489 sh_popcontext(shp,&buff);
490 shp->intrap--;
491 sfsync(shp->outpool);
492 if(!shp->indebug && jmpval!=SH_JMPEXIT && jmpval!=SH_JMPFUN)
493 shp->exitval=savxit;
494 stakset(savptr,staktop);
495 fcrestore(&savefc);
496 memcpy(shp->ifstable,ifstable,sizeof(ifstable));
497 if(was_history)
498 sh_onstate(SH_HISTORY);
499 if(was_verbose)
500 sh_onstate(SH_VERBOSE);
501 exitset();
502 if(jmpval>SH_JMPTRAP && (((struct checkpt*)shp->jmpbuffer)->prev || ((struct checkpt*)shp->jmpbuffer)->mode==SH_JMPSCRIPT))
503 siglongjmp(*shp->jmplist,jmpval);
504 return(shp->exitval);
505 }
506
507 /*
508 * exit the current scope and jump to an earlier one based on pp->mode
509 */
sh_exit(register int xno)510 void sh_exit(register int xno)
511 {
512 Shell_t *shp = sh_getinterp();
513 register struct checkpt *pp = (struct checkpt*)shp->jmplist;
514 register int sig=0;
515 register Sfio_t* pool;
516 shp->exitval=xno;
517 if(xno==SH_EXITSIG)
518 shp->exitval |= (sig=shp->lastsig);
519 if(pp && pp->mode>1)
520 cursig = -1;
521 #ifdef SIGTSTP
522 if(shp->trapnote&SH_SIGTSTP && job.jobcontrol)
523 {
524 /* ^Z detected by the shell */
525 shp->trapnote = 0;
526 shp->sigflag[SIGTSTP] = 0;
527 if(!shp->subshell && sh_isstate(SH_MONITOR) && !sh_isstate(SH_STOPOK))
528 return;
529 if(sh_isstate(SH_TIMING))
530 return;
531 /* Handles ^Z for shell builtins, subshells, and functs */
532 shp->lastsig = 0;
533 sh_onstate(SH_MONITOR);
534 sh_offstate(SH_STOPOK);
535 shp->trapnote = 0;
536 shp->forked = 1;
537 if(!shp->subshell && (sig=sh_fork(shp,0,NIL(int*))))
538 {
539 job.curpgid = 0;
540 job.parent = (pid_t)-1;
541 job_wait(sig);
542 shp->forked = 0;
543 job.parent = 0;
544 shp->sigflag[SIGTSTP] = 0;
545 /* wait for child to stop */
546 shp->exitval = (SH_EXITSIG|SIGTSTP);
547 /* return to prompt mode */
548 pp->mode = SH_JMPERREXIT;
549 }
550 else
551 {
552 if(shp->subshell)
553 sh_subfork();
554 /* child process, put to sleep */
555 sh_offstate(SH_STOPOK);
556 sh_offstate(SH_MONITOR);
557 shp->sigflag[SIGTSTP] = 0;
558 /* stop child job */
559 killpg(job.curpgid,SIGTSTP);
560 /* child resumes */
561 job_clear();
562 shp->exitval = (xno&SH_EXITMASK);
563 return;
564 }
565 }
566 #endif /* SIGTSTP */
567 /* unlock output pool */
568 sh_offstate(SH_NOTRACK);
569 if(!(pool=sfpool(NIL(Sfio_t*),shp->outpool,SF_WRITE)))
570 pool = shp->outpool; /* can't happen? */
571 sfclrlock(pool);
572 #ifdef SIGPIPE
573 if(shp->lastsig==SIGPIPE)
574 sfpurge(pool);
575 #endif /* SIGPIPE */
576 sfclrlock(sfstdin);
577 if(!pp)
578 sh_done(shp,sig);
579 shp->prefix = 0;
580 #if SHOPT_TYPEDEF
581 shp->mktype = 0;
582 #endif /* SHOPT_TYPEDEF*/
583 if(job.in_critical)
584 job_unlock();
585 if(pp->mode == SH_JMPSCRIPT && !pp->prev)
586 sh_done(shp,sig);
587 if(pp->mode)
588 siglongjmp(pp->buff,pp->mode);
589 }
590
array_notify(Namval_t * np,void * data)591 static void array_notify(Namval_t *np, void *data)
592 {
593 Namarr_t *ap = nv_arrayptr(np);
594 NOT_USED(data);
595 if(ap && ap->fun)
596 (*ap->fun)(np, 0, NV_AFREE);
597 }
598
599 /*
600 * This is the exit routine for the shell
601 */
602
sh_done(void * ptr,register int sig)603 void sh_done(void *ptr, register int sig)
604 {
605 Shell_t *shp = (Shell_t*)ptr;
606 register char *t;
607 register int savxit = shp->exitval;
608 shp->trapnote = 0;
609 indone=1;
610 if(sig)
611 savxit = SH_EXITSIG|sig;
612 if(shp->userinit)
613 (*shp->userinit)(shp, -1);
614 if(t=shp->st.trapcom[0])
615 {
616 shp->st.trapcom[0]=0; /*should free but not long */
617 shp->oldexit = savxit;
618 sh_trap(t,0);
619 savxit = shp->exitval;
620 }
621 else
622 {
623 /* avoid recursive call for set -e */
624 sh_offstate(SH_ERREXIT);
625 sh_chktrap(shp);
626 }
627 nv_scan(shp->var_tree,array_notify,(void*)0,NV_ARRAY,NV_ARRAY);
628 sh_freeup(shp);
629 #if SHOPT_ACCT
630 sh_accend();
631 #endif /* SHOPT_ACCT */
632 #if SHOPT_VSH || SHOPT_ESH
633 if(mbwide()||sh_isoption(SH_EMACS)||sh_isoption(SH_VI)||sh_isoption(SH_GMACS))
634 tty_cooked(-1);
635 #endif
636 #ifdef JOBS
637 if((sh_isoption(SH_INTERACTIVE) && shp->login_sh) || (!sh_isoption(SH_INTERACTIVE) && (sig==SIGHUP)))
638 job_walk(sfstderr, job_hup, SIGHUP, NIL(char**));
639 #endif /* JOBS */
640 job_close(shp);
641 if(nv_search("VMTRACE", shp->var_tree,0))
642 strmatch((char*)0,(char*)0);
643 sfsync((Sfio_t*)sfstdin);
644 sfsync((Sfio_t*)shp->outpool);
645 sfsync((Sfio_t*)sfstdout);
646 if(savxit&SH_EXITSIG)
647 sig = savxit&SH_EXITMASK;
648 if(sig)
649 {
650 /* generate fault termination code */
651 if(RLIMIT_CORE!=RLIMIT_UNKNOWN)
652 {
653 #ifdef _lib_getrlimit
654 struct rlimit rlp;
655 getrlimit(RLIMIT_CORE,&rlp);
656 rlp.rlim_cur = 0;
657 setrlimit(RLIMIT_CORE,&rlp);
658 #else
659 vlimit(RLIMIT_CORE,0);
660 #endif
661 }
662 signal(sig,SIG_DFL);
663 sigrelease(sig);
664 kill(getpid(),sig);
665 pause();
666 }
667 #if SHOPT_KIA
668 if(sh_isoption(SH_NOEXEC))
669 kiaclose((Lex_t*)shp->lex_context);
670 #endif /* SHOPT_KIA */
671 exit(savxit&SH_EXITMASK);
672 }
673
674