14887Schin /*********************************************************************** 24887Schin * * 34887Schin * This software is part of the ast package * 4*10898Sroland.mainz@nrubsig.org * Copyright (c) 1982-2009 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 } 101*10898Sroland.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; 144*10898Sroland.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; 200*10898Sroland.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; 217*10898Sroland.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 */ 221*10898Sroland.mainz@nrubsig.org #if defined(SIGRTMIN) && defined(SIGRTMAX) 222*10898Sroland.mainz@nrubsig.org if ((n = SIGRTMIN) > 0 && (sig = SIGRTMAX) > n && sig < SH_TRAP) 223*10898Sroland.mainz@nrubsig.org { 224*10898Sroland.mainz@nrubsig.org shp->sigruntime[SH_SIGRTMIN] = n; 225*10898Sroland.mainz@nrubsig.org shp->sigruntime[SH_SIGRTMAX] = sig; 226*10898Sroland.mainz@nrubsig.org } 227*10898Sroland.mainz@nrubsig.org #endif /* SIGRTMIN && SIGRTMAX */ 228*10898Sroland.mainz@nrubsig.org n = SIGTERM; 2294887Schin while(*tp->sh_name) 2304887Schin { 231*10898Sroland.mainz@nrubsig.org sig = (tp->sh_number&((1<<SH_SIGBITS)-1)); 232*10898Sroland.mainz@nrubsig.org if (!(sig-- & SH_TRAP)) 233*10898Sroland.mainz@nrubsig.org { 234*10898Sroland.mainz@nrubsig.org if ((tp->sh_number>>SH_SIGBITS) & SH_SIGRUNTIME) 235*10898Sroland.mainz@nrubsig.org sig = shp->sigruntime[sig]; 236*10898Sroland.mainz@nrubsig.org if(sig>n && sig<SH_TRAP) 237*10898Sroland.mainz@nrubsig.org n = sig; 238*10898Sroland.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); 248*10898Sroland.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; 298*10898Sroland.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 { 328*10898Sroland.mainz@nrubsig.org if(sig!=SIGCHLD) 329*10898Sroland.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 { 3654887Schin free(trap); 3664887Schin sh.st.trapcom[sig]=0; 3674887Schin } 3684887Schin sh.sigflag[sig] = flag; 3694887Schin } 3704887Schin 3714887Schin /* 3724887Schin * check for traps 3734887Schin */ 3744887Schin 3754887Schin void sh_chktrap(void) 3764887Schin { 3774887Schin register int sig=sh.st.trapmax; 3784887Schin register char *trap; 3798462SApril.Chin@Sun.COM if(!(sh.trapnote&~SH_SIGIGNORE)) 3804887Schin sig=0; 3814887Schin sh.trapnote &= ~SH_SIGTRAP; 3824887Schin /* execute errexit trap first */ 3834887Schin if(sh_isstate(SH_ERREXIT) && sh.exitval) 3844887Schin { 3854887Schin int sav_trapnote = sh.trapnote; 3864887Schin sh.trapnote &= ~SH_SIGSET; 3874887Schin if(sh.st.trap[SH_ERRTRAP]) 3888462SApril.Chin@Sun.COM { 3898462SApril.Chin@Sun.COM trap = sh.st.trap[SH_ERRTRAP]; 3908462SApril.Chin@Sun.COM sh.st.trap[SH_ERRTRAP] = 0; 3918462SApril.Chin@Sun.COM sh_trap(trap,0); 3928462SApril.Chin@Sun.COM sh.st.trap[SH_ERRTRAP] = trap; 3938462SApril.Chin@Sun.COM } 3944887Schin sh.trapnote = sav_trapnote; 3954887Schin if(sh_isoption(SH_ERREXIT)) 3964887Schin { 3974887Schin struct checkpt *pp = (struct checkpt*)sh.jmplist; 3984887Schin pp->mode = SH_JMPEXIT; 3994887Schin sh_exit(sh.exitval); 4004887Schin } 4014887Schin } 4024887Schin if(sh.sigflag[SIGALRM]&SH_SIGALRM) 4034887Schin sh_timetraps(); 404*10898Sroland.mainz@nrubsig.org #ifdef SHOPT_BGX 405*10898Sroland.mainz@nrubsig.org if((sh.sigflag[SIGCHLD]&SH_SIGTRAP) && sh.st.trapcom[SIGCHLD]) 406*10898Sroland.mainz@nrubsig.org job_chldtrap(&sh,sh.st.trapcom[SIGCHLD],1); 407*10898Sroland.mainz@nrubsig.org while(--sig>=0 && sig!=SIGCHLD) 408*10898Sroland.mainz@nrubsig.org #else 4094887Schin while(--sig>=0) 410*10898Sroland.mainz@nrubsig.org #endif /* SHOPT_BGX */ 4114887Schin { 4124887Schin if(sh.sigflag[sig]&SH_SIGTRAP) 4134887Schin { 4144887Schin sh.sigflag[sig] &= ~SH_SIGTRAP; 4154887Schin if(trap=sh.st.trapcom[sig]) 416*10898Sroland.mainz@nrubsig.org { 417*10898Sroland.mainz@nrubsig.org Sfio_t *fp; 418*10898Sroland.mainz@nrubsig.org if(sig==SIGPIPE && (fp=sfpool((Sfio_t*)0,sh.outpool,SF_WRITE)) && sferror(fp)) 419*10898Sroland.mainz@nrubsig.org sfclose(fp); 420*10898Sroland.mainz@nrubsig.org sh.oldexit = SH_EXITSIG|sig; 421*10898Sroland.mainz@nrubsig.org sh_trap(trap,0); 422*10898Sroland.mainz@nrubsig.org } 4234887Schin } 4244887Schin } 4254887Schin } 4264887Schin 4274887Schin 4284887Schin /* 4294887Schin * parse and execute the given trap string, stream or tree depending on mode 4304887Schin * mode==0 for string, mode==1 for stream, mode==2 for parse tree 4314887Schin */ 4324887Schin int sh_trap(const char *trap, int mode) 4334887Schin { 4348462SApril.Chin@Sun.COM Shell_t *shp = sh_getinterp(); 4358462SApril.Chin@Sun.COM int jmpval, savxit = shp->exitval; 4364887Schin int was_history = sh_isstate(SH_HISTORY); 4374887Schin int was_verbose = sh_isstate(SH_VERBOSE); 4384887Schin int staktop = staktell(); 4394887Schin char *savptr = stakfreeze(0); 4404887Schin struct checkpt buff; 4414887Schin Fcin_t savefc; 4424887Schin fcsave(&savefc); 4434887Schin sh_offstate(SH_HISTORY); 4444887Schin sh_offstate(SH_VERBOSE); 4458462SApril.Chin@Sun.COM shp->intrap++; 4464887Schin sh_pushcontext(&buff,SH_JMPTRAP); 4474887Schin jmpval = sigsetjmp(buff.buff,0); 4484887Schin if(jmpval == 0) 4494887Schin { 4504887Schin if(mode==2) 4514887Schin sh_exec((Shnode_t*)trap,sh_isstate(SH_ERREXIT)); 4524887Schin else 4534887Schin { 4544887Schin Sfio_t *sp; 4554887Schin if(mode) 4564887Schin sp = (Sfio_t*)trap; 4574887Schin else 4584887Schin sp = sfopen(NIL(Sfio_t*),trap,"s"); 4594887Schin sh_eval(sp,0); 4604887Schin } 4614887Schin } 4624887Schin else if(indone) 4634887Schin { 4644887Schin if(jmpval==SH_JMPSCRIPT) 4654887Schin indone=0; 4664887Schin else 4674887Schin { 4684887Schin if(jmpval==SH_JMPEXIT) 4698462SApril.Chin@Sun.COM savxit = shp->exitval; 4704887Schin jmpval=SH_JMPTRAP; 4714887Schin } 4724887Schin } 4734887Schin sh_popcontext(&buff); 4748462SApril.Chin@Sun.COM shp->intrap--; 4758462SApril.Chin@Sun.COM sfsync(shp->outpool); 4768462SApril.Chin@Sun.COM if(!shp->indebug && jmpval!=SH_JMPEXIT && jmpval!=SH_JMPFUN) 4778462SApril.Chin@Sun.COM shp->exitval=savxit; 4784887Schin stakset(savptr,staktop); 4794887Schin fcrestore(&savefc); 4804887Schin if(was_history) 4814887Schin sh_onstate(SH_HISTORY); 4824887Schin if(was_verbose) 4834887Schin sh_onstate(SH_VERBOSE); 4844887Schin exitset(); 485*10898Sroland.mainz@nrubsig.org if(jmpval>SH_JMPTRAP && (((struct checkpt*)shp->jmpbuffer)->prev || ((struct checkpt*)shp->jmpbuffer)->mode==SH_JMPSCRIPT)) 4868462SApril.Chin@Sun.COM siglongjmp(*shp->jmplist,jmpval); 4878462SApril.Chin@Sun.COM return(shp->exitval); 4884887Schin } 4894887Schin 4904887Schin /* 4914887Schin * exit the current scope and jump to an earlier one based on pp->mode 4924887Schin */ 4934887Schin void sh_exit(register int xno) 4944887Schin { 4958462SApril.Chin@Sun.COM Shell_t *shp = &sh; 4968462SApril.Chin@Sun.COM register struct checkpt *pp = (struct checkpt*)shp->jmplist; 4974887Schin register int sig=0; 4984887Schin register Sfio_t* pool; 4998462SApril.Chin@Sun.COM shp->exitval=xno; 5004887Schin if(xno==SH_EXITSIG) 5018462SApril.Chin@Sun.COM shp->exitval |= (sig=shp->lastsig); 5024887Schin #ifdef SIGTSTP 5038462SApril.Chin@Sun.COM if(shp->trapnote&SH_SIGTSTP) 5044887Schin { 5054887Schin /* ^Z detected by the shell */ 5068462SApril.Chin@Sun.COM shp->trapnote = 0; 5078462SApril.Chin@Sun.COM shp->sigflag[SIGTSTP] = 0; 5088462SApril.Chin@Sun.COM if(!shp->subshell && sh_isstate(SH_MONITOR) && !sh_isstate(SH_STOPOK)) 5094887Schin return; 5104887Schin if(sh_isstate(SH_TIMING)) 5114887Schin return; 5124887Schin /* Handles ^Z for shell builtins, subshells, and functs */ 5138462SApril.Chin@Sun.COM shp->lastsig = 0; 5144887Schin sh_onstate(SH_MONITOR); 5154887Schin sh_offstate(SH_STOPOK); 5168462SApril.Chin@Sun.COM shp->trapnote = 0; 5178462SApril.Chin@Sun.COM if(!shp->subshell && (sig=sh_fork(0,NIL(int*)))) 5184887Schin { 5194887Schin job.curpgid = 0; 5204887Schin job.parent = (pid_t)-1; 5214887Schin job_wait(sig); 5224887Schin job.parent = 0; 5238462SApril.Chin@Sun.COM shp->sigflag[SIGTSTP] = 0; 5244887Schin /* wait for child to stop */ 5258462SApril.Chin@Sun.COM shp->exitval = (SH_EXITSIG|SIGTSTP); 5264887Schin /* return to prompt mode */ 5274887Schin pp->mode = SH_JMPERREXIT; 5284887Schin } 5294887Schin else 5304887Schin { 5318462SApril.Chin@Sun.COM if(shp->subshell) 5324887Schin sh_subfork(); 5334887Schin /* child process, put to sleep */ 5344887Schin sh_offstate(SH_STOPOK); 5354887Schin sh_offstate(SH_MONITOR); 5368462SApril.Chin@Sun.COM shp->sigflag[SIGTSTP] = 0; 5374887Schin /* stop child job */ 5384887Schin killpg(job.curpgid,SIGTSTP); 5394887Schin /* child resumes */ 5404887Schin job_clear(); 5418462SApril.Chin@Sun.COM shp->forked = 1; 5428462SApril.Chin@Sun.COM shp->exitval = (xno&SH_EXITMASK); 5434887Schin return; 5444887Schin } 5454887Schin } 5464887Schin #endif /* SIGTSTP */ 5474887Schin /* unlock output pool */ 5484887Schin sh_offstate(SH_NOTRACK); 5498462SApril.Chin@Sun.COM if(!(pool=sfpool(NIL(Sfio_t*),shp->outpool,SF_WRITE))) 5508462SApril.Chin@Sun.COM pool = shp->outpool; /* can't happen? */ 5514887Schin sfclrlock(pool); 5524887Schin #ifdef SIGPIPE 5538462SApril.Chin@Sun.COM if(shp->lastsig==SIGPIPE) 5544887Schin sfpurge(pool); 5554887Schin #endif /* SIGPIPE */ 5564887Schin sfclrlock(sfstdin); 5574887Schin if(!pp) 5588462SApril.Chin@Sun.COM sh_done(shp,sig); 5598462SApril.Chin@Sun.COM shp->prefix = 0; 5608462SApril.Chin@Sun.COM #if SHOPT_TYPEDEF 5618462SApril.Chin@Sun.COM shp->mktype = 0; 5628462SApril.Chin@Sun.COM #endif /* SHOPT_TYPEDEF*/ 5634887Schin if(pp->mode == SH_JMPSCRIPT && !pp->prev) 5648462SApril.Chin@Sun.COM sh_done(shp,sig); 5658462SApril.Chin@Sun.COM if(pp->mode) 5668462SApril.Chin@Sun.COM siglongjmp(pp->buff,pp->mode); 5678462SApril.Chin@Sun.COM } 5688462SApril.Chin@Sun.COM 5698462SApril.Chin@Sun.COM static void array_notify(Namval_t *np, void *data) 5708462SApril.Chin@Sun.COM { 5718462SApril.Chin@Sun.COM Namarr_t *ap = nv_arrayptr(np); 5728462SApril.Chin@Sun.COM NOT_USED(data); 5738462SApril.Chin@Sun.COM if(ap && ap->fun) 5748462SApril.Chin@Sun.COM (*ap->fun)(np, 0, NV_AFREE); 5754887Schin } 5764887Schin 5774887Schin /* 5784887Schin * This is the exit routine for the shell 5794887Schin */ 5804887Schin 5818462SApril.Chin@Sun.COM void sh_done(void *ptr, register int sig) 5824887Schin { 5838462SApril.Chin@Sun.COM Shell_t *shp = (Shell_t*)ptr; 5844887Schin register char *t; 5858462SApril.Chin@Sun.COM register int savxit = shp->exitval; 5868462SApril.Chin@Sun.COM shp->trapnote = 0; 5874887Schin indone=1; 588*10898Sroland.mainz@nrubsig.org if(sig) 589*10898Sroland.mainz@nrubsig.org savxit = SH_EXITSIG|sig; 5908462SApril.Chin@Sun.COM if(shp->userinit) 5918462SApril.Chin@Sun.COM (*shp->userinit)(shp, -1); 5928462SApril.Chin@Sun.COM if(t=shp->st.trapcom[0]) 5934887Schin { 5948462SApril.Chin@Sun.COM shp->st.trapcom[0]=0; /*should free but not long */ 5958462SApril.Chin@Sun.COM shp->oldexit = savxit; 5964887Schin sh_trap(t,0); 5978462SApril.Chin@Sun.COM savxit = shp->exitval; 5984887Schin } 5994887Schin else 6004887Schin { 6014887Schin /* avoid recursive call for set -e */ 6024887Schin sh_offstate(SH_ERREXIT); 6034887Schin sh_chktrap(); 6044887Schin } 6058462SApril.Chin@Sun.COM nv_scan(shp->var_tree,array_notify,(void*)0,NV_ARRAY,NV_ARRAY); 6068462SApril.Chin@Sun.COM sh_freeup(shp); 6074887Schin #if SHOPT_ACCT 6084887Schin sh_accend(); 6094887Schin #endif /* SHOPT_ACCT */ 6104887Schin #if SHOPT_VSH || SHOPT_ESH 6114887Schin if(sh_isoption(SH_EMACS)||sh_isoption(SH_VI)||sh_isoption(SH_GMACS)) 6124887Schin tty_cooked(-1); 6134887Schin #endif 6144887Schin #ifdef JOBS 6158462SApril.Chin@Sun.COM if((sh_isoption(SH_INTERACTIVE) && shp->login_sh) || (!sh_isoption(SH_INTERACTIVE) && (sig==SIGHUP))) 6164887Schin job_walk(sfstderr,job_terminate,SIGHUP,NIL(char**)); 6174887Schin #endif /* JOBS */ 6188462SApril.Chin@Sun.COM job_close(shp); 6198462SApril.Chin@Sun.COM if(nv_search("VMTRACE", shp->var_tree,0)) 6204887Schin strmatch((char*)0,(char*)0); 6214887Schin sfsync((Sfio_t*)sfstdin); 6228462SApril.Chin@Sun.COM sfsync((Sfio_t*)shp->outpool); 6234887Schin sfsync((Sfio_t*)sfstdout); 624*10898Sroland.mainz@nrubsig.org if(savxit&SH_EXITSIG) 625*10898Sroland.mainz@nrubsig.org sig = savxit&SH_EXITMASK; 6264887Schin if(sig) 6274887Schin { 6284887Schin /* generate fault termination code */ 6294887Schin signal(sig,SIG_DFL); 6304887Schin sigrelease(sig); 6314887Schin kill(getpid(),sig); 6324887Schin pause(); 6334887Schin } 6344887Schin #if SHOPT_KIA 6354887Schin if(sh_isoption(SH_NOEXEC)) 6368462SApril.Chin@Sun.COM kiaclose((Lex_t*)shp->lex_context); 6374887Schin #endif /* SHOPT_KIA */ 6384887Schin exit(savxit&SH_EXITMASK); 6394887Schin } 6404887Schin 641