14887Schin /*********************************************************************** 24887Schin * * 34887Schin * This software is part of the ast package * 4*12068SRoger.Faulkner@Oracle.COM * Copyright (c) 1982-2010 AT&T Intellectual Property * 54887Schin * and is licensed under the * 64887Schin * Common Public License, Version 1.0 * 78462SApril.Chin@Sun.COM * by AT&T Intellectual Property * 84887Schin * * 94887Schin * A copy of the License is available at * 104887Schin * http://www.opensource.org/licenses/cpl1.0.txt * 114887Schin * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) * 124887Schin * * 134887Schin * Information and Software Systems Research * 144887Schin * AT&T Research * 154887Schin * Florham Park NJ * 164887Schin * * 174887Schin * David Korn <dgk@research.att.com> * 184887Schin * * 194887Schin ***********************************************************************/ 204887Schin #pragma prototyped 214887Schin /* 224887Schin * Fault handling routines 234887Schin * 244887Schin * David Korn 254887Schin * AT&T Labs 264887Schin * 274887Schin */ 284887Schin 294887Schin #include "defs.h" 304887Schin #include <fcin.h> 314887Schin #include "io.h" 324887Schin #include "history.h" 338462SApril.Chin@Sun.COM #include "shlex.h" 344887Schin #include "variables.h" 354887Schin #include "jobs.h" 364887Schin #include "path.h" 378462SApril.Chin@Sun.COM #include "builtins.h" 384887Schin 394887Schin #define abortsig(sig) (sig==SIGABRT || sig==SIGBUS || sig==SIGILL || sig==SIGSEGV) 404887Schin 414887Schin static char indone; 424887Schin 434887Schin #if !_std_malloc 444887Schin # include <vmalloc.h> 454887Schin #endif 464887Schin #if defined(VMFL) && (VMALLOC_VERSION>=20031205L) 474887Schin /* 484887Schin * This exception handler is called after vmalloc() unlocks the region 494887Schin */ 504887Schin static int malloc_done(Vmalloc_t* vm, int type, Void_t* val, Vmdisc_t* dp) 514887Schin { 524887Schin dp->exceptf = 0; 534887Schin sh_exit(SH_EXITSIG); 544887Schin return(0); 554887Schin } 564887Schin #endif 574887Schin 584887Schin /* 594887Schin * Most signals caught or ignored by the shell come here 604887Schin */ 614887Schin void sh_fault(register int sig) 624887Schin { 638462SApril.Chin@Sun.COM register Shell_t *shp = sh_getinterp(); 648462SApril.Chin@Sun.COM register int flag=0; 658462SApril.Chin@Sun.COM register char *trap; 668462SApril.Chin@Sun.COM register struct checkpt *pp = (struct checkpt*)shp->jmplist; 674887Schin int action=0; 684887Schin /* reset handler */ 694887Schin if(!(sig&SH_TRAP)) 704887Schin signal(sig, sh_fault); 714887Schin sig &= ~SH_TRAP; 724887Schin #ifdef SIGWINCH 734887Schin if(sig==SIGWINCH) 744887Schin { 754887Schin int rows=0, cols=0; 764887Schin int32_t v; 774887Schin astwinsize(2,&rows,&cols); 784887Schin if(v = cols) 798462SApril.Chin@Sun.COM nv_putval(COLUMNS, (char*)&v, NV_INT32|NV_RDONLY); 804887Schin if(v = rows) 818462SApril.Chin@Sun.COM nv_putval(LINES, (char*)&v, NV_INT32|NV_RDONLY); 828462SApril.Chin@Sun.COM shp->winch++; 834887Schin } 844887Schin #endif /* SIGWINCH */ 858462SApril.Chin@Sun.COM if(shp->savesig) 864887Schin { 874887Schin /* critical region, save and process later */ 888462SApril.Chin@Sun.COM shp->savesig = sig; 898462SApril.Chin@Sun.COM return; 908462SApril.Chin@Sun.COM } 918462SApril.Chin@Sun.COM trap = shp->st.trapcom[sig]; 928462SApril.Chin@Sun.COM if(sig==SIGALRM && shp->bltinfun==b_sleep) 938462SApril.Chin@Sun.COM { 948462SApril.Chin@Sun.COM if(trap && *trap) 958462SApril.Chin@Sun.COM { 968462SApril.Chin@Sun.COM shp->trapnote |= SH_SIGTRAP; 978462SApril.Chin@Sun.COM shp->sigflag[sig] |= SH_SIGTRAP; 988462SApril.Chin@Sun.COM } 994887Schin return; 1004887Schin } 10110898Sroland.mainz@nrubsig.org if(shp->subshell && sig!=SIGINT && sig!=SIGQUIT && sig!=SIGWINCH && sig!=SIGCONT) 1028462SApril.Chin@Sun.COM { 1038462SApril.Chin@Sun.COM shp->exitval = SH_EXITSIG|sig; 1048462SApril.Chin@Sun.COM sh_subfork(); 1058462SApril.Chin@Sun.COM shp->exitval = 0; 1068462SApril.Chin@Sun.COM return; 1078462SApril.Chin@Sun.COM } 1084887Schin /* handle ignored signals */ 1098462SApril.Chin@Sun.COM if(trap && *trap==0) 1104887Schin return; 1118462SApril.Chin@Sun.COM flag = shp->sigflag[sig]&~SH_SIGOFF; 1124887Schin if(!trap) 1134887Schin { 1148462SApril.Chin@Sun.COM if(sig==SIGINT && (shp->trapnote&SH_SIGIGNORE)) 1158462SApril.Chin@Sun.COM return; 1164887Schin if(flag&SH_SIGIGNORE) 1174887Schin return; 1184887Schin if(flag&SH_SIGDONE) 1194887Schin { 1204887Schin void *ptr=0; 1218462SApril.Chin@Sun.COM if((flag&SH_SIGINTERACTIVE) && sh_isstate(SH_INTERACTIVE) && !sh_isstate(SH_FORKED) && ! shp->subshell) 1224887Schin { 1234887Schin /* check for TERM signal between fork/exec */ 1244887Schin if(sig==SIGTERM && job.in_critical) 1258462SApril.Chin@Sun.COM shp->trapnote |= SH_SIGTERM; 1264887Schin return; 1274887Schin } 1288462SApril.Chin@Sun.COM shp->lastsig = sig; 1294887Schin sigrelease(sig); 1304887Schin if(pp->mode < SH_JMPFUN) 1314887Schin pp->mode = SH_JMPFUN; 1324887Schin else 1334887Schin pp->mode = SH_JMPEXIT; 1344887Schin if(sig==SIGABRT || (abortsig(sig) && (ptr = malloc(1)))) 1354887Schin { 1364887Schin if(ptr) 1374887Schin free(ptr); 1388462SApril.Chin@Sun.COM if(!shp->subshell) 1398462SApril.Chin@Sun.COM sh_done(shp,sig); 1404887Schin sh_exit(SH_EXITSIG); 1414887Schin } 1424887Schin /* mark signal and continue */ 1438462SApril.Chin@Sun.COM shp->trapnote |= SH_SIGSET; 14410898Sroland.mainz@nrubsig.org if(sig <= shp->sigmax) 1458462SApril.Chin@Sun.COM shp->sigflag[sig] |= SH_SIGSET; 1464887Schin #if defined(VMFL) && (VMALLOC_VERSION>=20031205L) 1474887Schin if(abortsig(sig)) 1484887Schin { 1494887Schin /* abort inside malloc, process when malloc returns */ 1504887Schin /* VMFL defined when using vmalloc() */ 1514887Schin Vmdisc_t* dp = vmdisc(Vmregion,0); 1524887Schin if(dp) 1534887Schin dp->exceptf = malloc_done; 1544887Schin } 1554887Schin #endif 1564887Schin return; 1574887Schin } 1584887Schin } 1594887Schin errno = 0; 1604887Schin if(pp->mode==SH_JMPCMD) 1618462SApril.Chin@Sun.COM shp->lastsig = sig; 1624887Schin if(trap) 1634887Schin { 1644887Schin /* 1654887Schin * propogate signal to foreground group 1664887Schin */ 1674887Schin if(sig==SIGHUP && job.curpgid) 1684887Schin killpg(job.curpgid,SIGHUP); 1694887Schin flag = SH_SIGTRAP; 1704887Schin } 1714887Schin else 1724887Schin { 1738462SApril.Chin@Sun.COM shp->lastsig = sig; 1744887Schin flag = SH_SIGSET; 1754887Schin #ifdef SIGTSTP 1764887Schin if(sig==SIGTSTP) 1774887Schin { 1788462SApril.Chin@Sun.COM shp->trapnote |= SH_SIGTSTP; 1794887Schin if(pp->mode==SH_JMPCMD && sh_isstate(SH_STOPOK)) 1804887Schin { 1814887Schin sigrelease(sig); 1824887Schin sh_exit(SH_EXITSIG); 1834887Schin flag = 0; 1844887Schin } 1854887Schin } 1864887Schin #endif /* SIGTSTP */ 1874887Schin } 1884887Schin #ifdef ERROR_NOTIFY 1898462SApril.Chin@Sun.COM if((error_info.flags&ERROR_NOTIFY) && shp->bltinfun) 1908462SApril.Chin@Sun.COM action = (*shp->bltinfun)(-sig,(char**)0,(void*)0); 1914887Schin if(action>0) 1924887Schin return; 1938462SApril.Chin@Sun.COM #endif 1948462SApril.Chin@Sun.COM if(shp->bltinfun && shp->bltindata.notify) 1958462SApril.Chin@Sun.COM { 1968462SApril.Chin@Sun.COM shp->bltindata.sigset = 1; 1978462SApril.Chin@Sun.COM return; 1988462SApril.Chin@Sun.COM } 1998462SApril.Chin@Sun.COM shp->trapnote |= flag; 20010898Sroland.mainz@nrubsig.org if(sig <= shp->sigmax) 2018462SApril.Chin@Sun.COM shp->sigflag[sig] |= flag; 2024887Schin if(pp->mode==SH_JMPCMD && sh_isstate(SH_STOPOK)) 2034887Schin { 2044887Schin if(action<0) 2054887Schin return; 2064887Schin sigrelease(sig); 2074887Schin sh_exit(SH_EXITSIG); 2084887Schin } 2094887Schin } 2104887Schin 2114887Schin /* 2124887Schin * initialize signal handling 2134887Schin */ 2148462SApril.Chin@Sun.COM void sh_siginit(void *ptr) 2154887Schin { 2168462SApril.Chin@Sun.COM Shell_t *shp = (Shell_t*)ptr; 21710898Sroland.mainz@nrubsig.org register int sig, n; 2184887Schin register const struct shtable2 *tp = shtab_signals; 2194887Schin sig_begin(); 2204887Schin /* find the largest signal number in the table */ 22110898Sroland.mainz@nrubsig.org #if defined(SIGRTMIN) && defined(SIGRTMAX) 22210898Sroland.mainz@nrubsig.org if ((n = SIGRTMIN) > 0 && (sig = SIGRTMAX) > n && sig < SH_TRAP) 22310898Sroland.mainz@nrubsig.org { 22410898Sroland.mainz@nrubsig.org shp->sigruntime[SH_SIGRTMIN] = n; 22510898Sroland.mainz@nrubsig.org shp->sigruntime[SH_SIGRTMAX] = sig; 22610898Sroland.mainz@nrubsig.org } 22710898Sroland.mainz@nrubsig.org #endif /* SIGRTMIN && SIGRTMAX */ 22810898Sroland.mainz@nrubsig.org n = SIGTERM; 2294887Schin while(*tp->sh_name) 2304887Schin { 23110898Sroland.mainz@nrubsig.org sig = (tp->sh_number&((1<<SH_SIGBITS)-1)); 23210898Sroland.mainz@nrubsig.org if (!(sig-- & SH_TRAP)) 23310898Sroland.mainz@nrubsig.org { 23410898Sroland.mainz@nrubsig.org if ((tp->sh_number>>SH_SIGBITS) & SH_SIGRUNTIME) 23510898Sroland.mainz@nrubsig.org sig = shp->sigruntime[sig]; 23610898Sroland.mainz@nrubsig.org if(sig>n && sig<SH_TRAP) 23710898Sroland.mainz@nrubsig.org n = sig; 23810898Sroland.mainz@nrubsig.org } 2394887Schin tp++; 2404887Schin } 2418462SApril.Chin@Sun.COM shp->sigmax = n++; 2428462SApril.Chin@Sun.COM shp->st.trapcom = (char**)calloc(n,sizeof(char*)); 2438462SApril.Chin@Sun.COM shp->sigflag = (unsigned char*)calloc(n,1); 2448462SApril.Chin@Sun.COM shp->sigmsg = (char**)calloc(n,sizeof(char*)); 2454887Schin for(tp=shtab_signals; sig=tp->sh_number; tp++) 2464887Schin { 2474887Schin n = (sig>>SH_SIGBITS); 24810898Sroland.mainz@nrubsig.org if((sig &= ((1<<SH_SIGBITS)-1)) > (shp->sigmax+1)) 2494887Schin continue; 2504887Schin sig--; 2518462SApril.Chin@Sun.COM if(n&SH_SIGRUNTIME) 2528462SApril.Chin@Sun.COM sig = shp->sigruntime[sig]; 2534887Schin if(sig>=0) 2544887Schin { 2558462SApril.Chin@Sun.COM shp->sigflag[sig] = n; 2564887Schin if(*tp->sh_name) 2578462SApril.Chin@Sun.COM shp->sigmsg[sig] = (char*)tp->sh_value; 2584887Schin } 2594887Schin } 2604887Schin } 2614887Schin 2624887Schin /* 2634887Schin * Turn on trap handler for signal <sig> 2644887Schin */ 2654887Schin void sh_sigtrap(register int sig) 2664887Schin { 2674887Schin register int flag; 2684887Schin void (*fun)(int); 2694887Schin sh.st.otrapcom = 0; 2704887Schin if(sig==0) 2714887Schin sh_sigdone(); 2724887Schin else if(!((flag=sh.sigflag[sig])&(SH_SIGFAULT|SH_SIGOFF))) 2734887Schin { 2744887Schin /* don't set signal if already set or off by parent */ 2754887Schin if((fun=signal(sig,sh_fault))==SIG_IGN) 2764887Schin { 2774887Schin signal(sig,SIG_IGN); 2784887Schin flag |= SH_SIGOFF; 2794887Schin } 2804887Schin else 2814887Schin { 2824887Schin flag |= SH_SIGFAULT; 2834887Schin if(sig==SIGALRM && fun!=SIG_DFL && fun!=sh_fault) 2844887Schin signal(sig,fun); 2854887Schin } 2864887Schin flag &= ~(SH_SIGSET|SH_SIGTRAP); 2874887Schin sh.sigflag[sig] = flag; 2884887Schin } 2894887Schin } 2904887Schin 2914887Schin /* 2924887Schin * set signal handler so sh_done is called for all caught signals 2934887Schin */ 2944887Schin void sh_sigdone(void) 2954887Schin { 2964887Schin register int flag, sig = sh.sigmax; 2974887Schin sh.sigflag[0] |= SH_SIGFAULT; 29810898Sroland.mainz@nrubsig.org for(sig=sh.sigmax; sig>0; sig--) 2994887Schin { 3004887Schin flag = sh.sigflag[sig]; 3014887Schin if((flag&(SH_SIGDONE|SH_SIGIGNORE|SH_SIGINTERACTIVE)) && !(flag&(SH_SIGFAULT|SH_SIGOFF))) 3024887Schin sh_sigtrap(sig); 3034887Schin } 3044887Schin } 3054887Schin 3064887Schin /* 3074887Schin * Restore to default signals 3084887Schin * Free the trap strings if mode is non-zero 3094887Schin * If mode>1 then ignored traps cause signal to be ignored 3104887Schin */ 3114887Schin void sh_sigreset(register int mode) 3124887Schin { 3134887Schin register char *trap; 3144887Schin register int flag, sig=sh.st.trapmax; 3154887Schin while(sig-- > 0) 3164887Schin { 3174887Schin if(trap=sh.st.trapcom[sig]) 3184887Schin { 3194887Schin flag = sh.sigflag[sig]&~(SH_SIGTRAP|SH_SIGSET); 3204887Schin if(*trap) 3214887Schin { 3224887Schin if(mode) 3234887Schin free(trap); 3244887Schin sh.st.trapcom[sig] = 0; 3254887Schin } 3264887Schin else if(sig && mode>1) 3274887Schin { 32810898Sroland.mainz@nrubsig.org if(sig!=SIGCHLD) 32910898Sroland.mainz@nrubsig.org signal(sig,SIG_IGN); 3304887Schin flag &= ~SH_SIGFAULT; 3314887Schin flag |= SH_SIGOFF; 3324887Schin } 3334887Schin sh.sigflag[sig] = flag; 3344887Schin } 3354887Schin } 3368462SApril.Chin@Sun.COM for(sig=SH_DEBUGTRAP-1;sig>=0;sig--) 3374887Schin { 3384887Schin if(trap=sh.st.trap[sig]) 3394887Schin { 3404887Schin if(mode) 3414887Schin free(trap); 3424887Schin sh.st.trap[sig] = 0; 3434887Schin } 3444887Schin 3454887Schin } 3464887Schin sh.st.trapcom[0] = 0; 3474887Schin if(mode) 3484887Schin sh.st.trapmax = 0; 3494887Schin sh.trapnote=0; 3504887Schin } 3514887Schin 3524887Schin /* 3534887Schin * free up trap if set and restore signal handler if modified 3544887Schin */ 3554887Schin void sh_sigclear(register int sig) 3564887Schin { 3574887Schin register int flag = sh.sigflag[sig]; 3584887Schin register char *trap; 3594887Schin sh.st.otrapcom=0; 3604887Schin if(!(flag&SH_SIGFAULT)) 3614887Schin return; 3624887Schin flag &= ~(SH_SIGTRAP|SH_SIGSET); 3634887Schin if(trap=sh.st.trapcom[sig]) 3644887Schin { 365*12068SRoger.Faulkner@Oracle.COM if(!sh.subshell) 366*12068SRoger.Faulkner@Oracle.COM free(trap); 3674887Schin sh.st.trapcom[sig]=0; 3684887Schin } 3694887Schin sh.sigflag[sig] = flag; 3704887Schin } 3714887Schin 3724887Schin /* 3734887Schin * check for traps 3744887Schin */ 3754887Schin 3764887Schin void sh_chktrap(void) 3774887Schin { 3784887Schin register int sig=sh.st.trapmax; 3794887Schin register char *trap; 3808462SApril.Chin@Sun.COM if(!(sh.trapnote&~SH_SIGIGNORE)) 3814887Schin sig=0; 3824887Schin sh.trapnote &= ~SH_SIGTRAP; 3834887Schin /* execute errexit trap first */ 3844887Schin if(sh_isstate(SH_ERREXIT) && sh.exitval) 3854887Schin { 3864887Schin int sav_trapnote = sh.trapnote; 3874887Schin sh.trapnote &= ~SH_SIGSET; 3884887Schin if(sh.st.trap[SH_ERRTRAP]) 3898462SApril.Chin@Sun.COM { 3908462SApril.Chin@Sun.COM trap = sh.st.trap[SH_ERRTRAP]; 3918462SApril.Chin@Sun.COM sh.st.trap[SH_ERRTRAP] = 0; 3928462SApril.Chin@Sun.COM sh_trap(trap,0); 3938462SApril.Chin@Sun.COM sh.st.trap[SH_ERRTRAP] = trap; 3948462SApril.Chin@Sun.COM } 3954887Schin sh.trapnote = sav_trapnote; 3964887Schin if(sh_isoption(SH_ERREXIT)) 3974887Schin { 3984887Schin struct checkpt *pp = (struct checkpt*)sh.jmplist; 3994887Schin pp->mode = SH_JMPEXIT; 4004887Schin sh_exit(sh.exitval); 4014887Schin } 4024887Schin } 4034887Schin if(sh.sigflag[SIGALRM]&SH_SIGALRM) 4044887Schin sh_timetraps(); 40510898Sroland.mainz@nrubsig.org #ifdef SHOPT_BGX 40610898Sroland.mainz@nrubsig.org if((sh.sigflag[SIGCHLD]&SH_SIGTRAP) && sh.st.trapcom[SIGCHLD]) 40710898Sroland.mainz@nrubsig.org job_chldtrap(&sh,sh.st.trapcom[SIGCHLD],1); 408*12068SRoger.Faulkner@Oracle.COM #endif /* SHOPT_BGX */ 4094887Schin while(--sig>=0) 410*12068SRoger.Faulkner@Oracle.COM { 411*12068SRoger.Faulkner@Oracle.COM #ifdef SHOPT_BGX 412*12068SRoger.Faulkner@Oracle.COM if(sig==SIGCHLD) 413*12068SRoger.Faulkner@Oracle.COM continue; 41410898Sroland.mainz@nrubsig.org #endif /* SHOPT_BGX */ 4154887Schin if(sh.sigflag[sig]&SH_SIGTRAP) 4164887Schin { 4174887Schin sh.sigflag[sig] &= ~SH_SIGTRAP; 4184887Schin if(trap=sh.st.trapcom[sig]) 41910898Sroland.mainz@nrubsig.org { 42010898Sroland.mainz@nrubsig.org Sfio_t *fp; 42110898Sroland.mainz@nrubsig.org if(sig==SIGPIPE && (fp=sfpool((Sfio_t*)0,sh.outpool,SF_WRITE)) && sferror(fp)) 42210898Sroland.mainz@nrubsig.org sfclose(fp); 42310898Sroland.mainz@nrubsig.org sh.oldexit = SH_EXITSIG|sig; 42410898Sroland.mainz@nrubsig.org sh_trap(trap,0); 42510898Sroland.mainz@nrubsig.org } 4264887Schin } 4274887Schin } 4284887Schin } 4294887Schin 4304887Schin 4314887Schin /* 4324887Schin * parse and execute the given trap string, stream or tree depending on mode 4334887Schin * mode==0 for string, mode==1 for stream, mode==2 for parse tree 4344887Schin */ 4354887Schin int sh_trap(const char *trap, int mode) 4364887Schin { 4378462SApril.Chin@Sun.COM Shell_t *shp = sh_getinterp(); 4388462SApril.Chin@Sun.COM int jmpval, savxit = shp->exitval; 4394887Schin int was_history = sh_isstate(SH_HISTORY); 4404887Schin int was_verbose = sh_isstate(SH_VERBOSE); 4414887Schin int staktop = staktell(); 4424887Schin char *savptr = stakfreeze(0); 443*12068SRoger.Faulkner@Oracle.COM char ifstable[256]; 4444887Schin struct checkpt buff; 4454887Schin Fcin_t savefc; 4464887Schin fcsave(&savefc); 447*12068SRoger.Faulkner@Oracle.COM memcpy(ifstable,shp->ifstable,sizeof(ifstable)); 4484887Schin sh_offstate(SH_HISTORY); 4494887Schin sh_offstate(SH_VERBOSE); 4508462SApril.Chin@Sun.COM shp->intrap++; 4514887Schin sh_pushcontext(&buff,SH_JMPTRAP); 4524887Schin jmpval = sigsetjmp(buff.buff,0); 4534887Schin if(jmpval == 0) 4544887Schin { 4554887Schin if(mode==2) 4564887Schin sh_exec((Shnode_t*)trap,sh_isstate(SH_ERREXIT)); 4574887Schin else 4584887Schin { 4594887Schin Sfio_t *sp; 4604887Schin if(mode) 4614887Schin sp = (Sfio_t*)trap; 4624887Schin else 4634887Schin sp = sfopen(NIL(Sfio_t*),trap,"s"); 4644887Schin sh_eval(sp,0); 4654887Schin } 4664887Schin } 4674887Schin else if(indone) 4684887Schin { 4694887Schin if(jmpval==SH_JMPSCRIPT) 4704887Schin indone=0; 4714887Schin else 4724887Schin { 4734887Schin if(jmpval==SH_JMPEXIT) 4748462SApril.Chin@Sun.COM savxit = shp->exitval; 4754887Schin jmpval=SH_JMPTRAP; 4764887Schin } 4774887Schin } 4784887Schin sh_popcontext(&buff); 4798462SApril.Chin@Sun.COM shp->intrap--; 4808462SApril.Chin@Sun.COM sfsync(shp->outpool); 4818462SApril.Chin@Sun.COM if(!shp->indebug && jmpval!=SH_JMPEXIT && jmpval!=SH_JMPFUN) 4828462SApril.Chin@Sun.COM shp->exitval=savxit; 4834887Schin stakset(savptr,staktop); 4844887Schin fcrestore(&savefc); 485*12068SRoger.Faulkner@Oracle.COM memcpy(shp->ifstable,ifstable,sizeof(ifstable)); 4864887Schin if(was_history) 4874887Schin sh_onstate(SH_HISTORY); 4884887Schin if(was_verbose) 4894887Schin sh_onstate(SH_VERBOSE); 4904887Schin exitset(); 49110898Sroland.mainz@nrubsig.org if(jmpval>SH_JMPTRAP && (((struct checkpt*)shp->jmpbuffer)->prev || ((struct checkpt*)shp->jmpbuffer)->mode==SH_JMPSCRIPT)) 4928462SApril.Chin@Sun.COM siglongjmp(*shp->jmplist,jmpval); 4938462SApril.Chin@Sun.COM return(shp->exitval); 4944887Schin } 4954887Schin 4964887Schin /* 4974887Schin * exit the current scope and jump to an earlier one based on pp->mode 4984887Schin */ 4994887Schin void sh_exit(register int xno) 5004887Schin { 5018462SApril.Chin@Sun.COM Shell_t *shp = &sh; 5028462SApril.Chin@Sun.COM register struct checkpt *pp = (struct checkpt*)shp->jmplist; 5034887Schin register int sig=0; 5044887Schin register Sfio_t* pool; 5058462SApril.Chin@Sun.COM shp->exitval=xno; 5064887Schin if(xno==SH_EXITSIG) 5078462SApril.Chin@Sun.COM shp->exitval |= (sig=shp->lastsig); 5084887Schin #ifdef SIGTSTP 5098462SApril.Chin@Sun.COM if(shp->trapnote&SH_SIGTSTP) 5104887Schin { 5114887Schin /* ^Z detected by the shell */ 5128462SApril.Chin@Sun.COM shp->trapnote = 0; 5138462SApril.Chin@Sun.COM shp->sigflag[SIGTSTP] = 0; 5148462SApril.Chin@Sun.COM if(!shp->subshell && sh_isstate(SH_MONITOR) && !sh_isstate(SH_STOPOK)) 5154887Schin return; 5164887Schin if(sh_isstate(SH_TIMING)) 5174887Schin return; 5184887Schin /* Handles ^Z for shell builtins, subshells, and functs */ 5198462SApril.Chin@Sun.COM shp->lastsig = 0; 5204887Schin sh_onstate(SH_MONITOR); 5214887Schin sh_offstate(SH_STOPOK); 5228462SApril.Chin@Sun.COM shp->trapnote = 0; 5238462SApril.Chin@Sun.COM if(!shp->subshell && (sig=sh_fork(0,NIL(int*)))) 5244887Schin { 5254887Schin job.curpgid = 0; 5264887Schin job.parent = (pid_t)-1; 5274887Schin job_wait(sig); 5284887Schin job.parent = 0; 5298462SApril.Chin@Sun.COM shp->sigflag[SIGTSTP] = 0; 5304887Schin /* wait for child to stop */ 5318462SApril.Chin@Sun.COM shp->exitval = (SH_EXITSIG|SIGTSTP); 5324887Schin /* return to prompt mode */ 5334887Schin pp->mode = SH_JMPERREXIT; 5344887Schin } 5354887Schin else 5364887Schin { 5378462SApril.Chin@Sun.COM if(shp->subshell) 5384887Schin sh_subfork(); 5394887Schin /* child process, put to sleep */ 5404887Schin sh_offstate(SH_STOPOK); 5414887Schin sh_offstate(SH_MONITOR); 5428462SApril.Chin@Sun.COM shp->sigflag[SIGTSTP] = 0; 5434887Schin /* stop child job */ 5444887Schin killpg(job.curpgid,SIGTSTP); 5454887Schin /* child resumes */ 5464887Schin job_clear(); 5478462SApril.Chin@Sun.COM shp->forked = 1; 5488462SApril.Chin@Sun.COM shp->exitval = (xno&SH_EXITMASK); 5494887Schin return; 5504887Schin } 5514887Schin } 5524887Schin #endif /* SIGTSTP */ 5534887Schin /* unlock output pool */ 5544887Schin sh_offstate(SH_NOTRACK); 5558462SApril.Chin@Sun.COM if(!(pool=sfpool(NIL(Sfio_t*),shp->outpool,SF_WRITE))) 5568462SApril.Chin@Sun.COM pool = shp->outpool; /* can't happen? */ 5574887Schin sfclrlock(pool); 5584887Schin #ifdef SIGPIPE 5598462SApril.Chin@Sun.COM if(shp->lastsig==SIGPIPE) 5604887Schin sfpurge(pool); 5614887Schin #endif /* SIGPIPE */ 5624887Schin sfclrlock(sfstdin); 5634887Schin if(!pp) 5648462SApril.Chin@Sun.COM sh_done(shp,sig); 5658462SApril.Chin@Sun.COM shp->prefix = 0; 5668462SApril.Chin@Sun.COM #if SHOPT_TYPEDEF 5678462SApril.Chin@Sun.COM shp->mktype = 0; 5688462SApril.Chin@Sun.COM #endif /* SHOPT_TYPEDEF*/ 5694887Schin if(pp->mode == SH_JMPSCRIPT && !pp->prev) 5708462SApril.Chin@Sun.COM sh_done(shp,sig); 5718462SApril.Chin@Sun.COM if(pp->mode) 5728462SApril.Chin@Sun.COM siglongjmp(pp->buff,pp->mode); 5738462SApril.Chin@Sun.COM } 5748462SApril.Chin@Sun.COM 5758462SApril.Chin@Sun.COM static void array_notify(Namval_t *np, void *data) 5768462SApril.Chin@Sun.COM { 5778462SApril.Chin@Sun.COM Namarr_t *ap = nv_arrayptr(np); 5788462SApril.Chin@Sun.COM NOT_USED(data); 5798462SApril.Chin@Sun.COM if(ap && ap->fun) 5808462SApril.Chin@Sun.COM (*ap->fun)(np, 0, NV_AFREE); 5814887Schin } 5824887Schin 5834887Schin /* 5844887Schin * This is the exit routine for the shell 5854887Schin */ 5864887Schin 5878462SApril.Chin@Sun.COM void sh_done(void *ptr, register int sig) 5884887Schin { 5898462SApril.Chin@Sun.COM Shell_t *shp = (Shell_t*)ptr; 5904887Schin register char *t; 5918462SApril.Chin@Sun.COM register int savxit = shp->exitval; 5928462SApril.Chin@Sun.COM shp->trapnote = 0; 5934887Schin indone=1; 59410898Sroland.mainz@nrubsig.org if(sig) 59510898Sroland.mainz@nrubsig.org savxit = SH_EXITSIG|sig; 5968462SApril.Chin@Sun.COM if(shp->userinit) 5978462SApril.Chin@Sun.COM (*shp->userinit)(shp, -1); 5988462SApril.Chin@Sun.COM if(t=shp->st.trapcom[0]) 5994887Schin { 6008462SApril.Chin@Sun.COM shp->st.trapcom[0]=0; /*should free but not long */ 6018462SApril.Chin@Sun.COM shp->oldexit = savxit; 6024887Schin sh_trap(t,0); 6038462SApril.Chin@Sun.COM savxit = shp->exitval; 6044887Schin } 6054887Schin else 6064887Schin { 6074887Schin /* avoid recursive call for set -e */ 6084887Schin sh_offstate(SH_ERREXIT); 6094887Schin sh_chktrap(); 6104887Schin } 6118462SApril.Chin@Sun.COM nv_scan(shp->var_tree,array_notify,(void*)0,NV_ARRAY,NV_ARRAY); 6128462SApril.Chin@Sun.COM sh_freeup(shp); 6134887Schin #if SHOPT_ACCT 6144887Schin sh_accend(); 6154887Schin #endif /* SHOPT_ACCT */ 6164887Schin #if SHOPT_VSH || SHOPT_ESH 6174887Schin if(sh_isoption(SH_EMACS)||sh_isoption(SH_VI)||sh_isoption(SH_GMACS)) 6184887Schin tty_cooked(-1); 6194887Schin #endif 6204887Schin #ifdef JOBS 6218462SApril.Chin@Sun.COM if((sh_isoption(SH_INTERACTIVE) && shp->login_sh) || (!sh_isoption(SH_INTERACTIVE) && (sig==SIGHUP))) 6224887Schin job_walk(sfstderr,job_terminate,SIGHUP,NIL(char**)); 6234887Schin #endif /* JOBS */ 6248462SApril.Chin@Sun.COM job_close(shp); 6258462SApril.Chin@Sun.COM if(nv_search("VMTRACE", shp->var_tree,0)) 6264887Schin strmatch((char*)0,(char*)0); 6274887Schin sfsync((Sfio_t*)sfstdin); 6288462SApril.Chin@Sun.COM sfsync((Sfio_t*)shp->outpool); 6294887Schin sfsync((Sfio_t*)sfstdout); 63010898Sroland.mainz@nrubsig.org if(savxit&SH_EXITSIG) 63110898Sroland.mainz@nrubsig.org sig = savxit&SH_EXITMASK; 6324887Schin if(sig) 6334887Schin { 6344887Schin /* generate fault termination code */ 6354887Schin signal(sig,SIG_DFL); 6364887Schin sigrelease(sig); 6374887Schin kill(getpid(),sig); 6384887Schin pause(); 6394887Schin } 6404887Schin #if SHOPT_KIA 6414887Schin if(sh_isoption(SH_NOEXEC)) 6428462SApril.Chin@Sun.COM kiaclose((Lex_t*)shp->lex_context); 6434887Schin #endif /* SHOPT_KIA */ 6444887Schin exit(savxit&SH_EXITMASK); 6454887Schin } 6464887Schin 647