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