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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 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 */ 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 */ 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 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 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