14887Schin /*********************************************************************** 24887Schin * * 34887Schin * This software is part of the ast package * 4*8462SApril.Chin@Sun.COM * Copyright (c) 1982-2008 AT&T Intellectual Property * 54887Schin * and is licensed under the * 64887Schin * Common Public License, Version 1.0 * 7*8462SApril.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 * UNIX shell parse tree executer 234887Schin * 244887Schin * David Korn 254887Schin * AT&T Labs 264887Schin * 274887Schin */ 284887Schin 294887Schin #include "defs.h" 304887Schin #include <fcin.h> 314887Schin #include "variables.h" 324887Schin #include "path.h" 334887Schin #include "name.h" 344887Schin #include "io.h" 354887Schin #include "shnodes.h" 364887Schin #include "jobs.h" 374887Schin #include "test.h" 384887Schin #include "builtins.h" 394887Schin #include "FEATURE/time" 404887Schin #include "FEATURE/externs" 414887Schin #include "FEATURE/locale" 424887Schin #include "streval.h" 434887Schin 444887Schin #if !_std_malloc 454887Schin # include <vmalloc.h> 464887Schin #endif 474887Schin 48*8462SApril.Chin@Sun.COM #if _lib_vfork 49*8462SApril.Chin@Sun.COM # include <ast_vfork.h> 50*8462SApril.Chin@Sun.COM #else 51*8462SApril.Chin@Sun.COM # define vfork() fork() 52*8462SApril.Chin@Sun.COM #endif 53*8462SApril.Chin@Sun.COM 544887Schin #define SH_NTFORK SH_TIMING 554887Schin 564887Schin #if _lib_nice 574887Schin extern int nice(int); 584887Schin #endif /* _lib_nice */ 594887Schin #if !_lib_spawnveg 604887Schin # define spawnveg(a,b,c,d) spawnve(a,b,c) 614887Schin #endif /* !_lib_spawnveg */ 624887Schin #if SHOPT_SPAWN 63*8462SApril.Chin@Sun.COM static pid_t sh_ntfork(Shell_t*,const Shnode_t*,char*[],int*,int); 644887Schin #endif /* SHOPT_SPAWN */ 654887Schin 66*8462SApril.Chin@Sun.COM static void sh_funct(Shell_t *,Namval_t*, int, char*[], struct argnod*,int); 674887Schin static int trim_eq(const char*, const char*); 68*8462SApril.Chin@Sun.COM static void coproc_init(Shell_t*, int pipes[]); 694887Schin 704887Schin static void *timeout; 714887Schin static char pipejob; 724887Schin 734887Schin struct funenv 744887Schin { 754887Schin Namval_t *node; 764887Schin struct argnod *env; 774887Schin }; 784887Schin 794887Schin /* ======== command execution ========*/ 804887Schin 814887Schin /* 824887Schin * print time <t> in h:m:s format with precision <p> 834887Schin */ 844887Schin static void l_time(Sfio_t *outfile,register clock_t t,int p) 854887Schin { 864887Schin register int min, sec, frac; 874887Schin register int hr; 884887Schin if(p) 894887Schin { 904887Schin frac = t%sh.lim.clk_tck; 914887Schin frac = (frac*100)/sh.lim.clk_tck; 924887Schin } 934887Schin t /= sh.lim.clk_tck; 944887Schin sec = t%60; 954887Schin t /= 60; 964887Schin min = t%60; 974887Schin if(hr=t/60) 984887Schin sfprintf(outfile,"%dh",hr); 994887Schin if(p) 1004887Schin sfprintf(outfile,"%dm%d%c%0*ds",min,sec,GETDECIMAL(0),p,frac); 1014887Schin else 1024887Schin sfprintf(outfile,"%dm%ds",min,sec); 1034887Schin } 1044887Schin 105*8462SApril.Chin@Sun.COM static int p_time(Shell_t *shp, Sfio_t *out, const char *format, clock_t *tm) 1064887Schin { 107*8462SApril.Chin@Sun.COM int c,p,l,n,offset = staktell(); 108*8462SApril.Chin@Sun.COM const char *first; 109*8462SApril.Chin@Sun.COM double d; 110*8462SApril.Chin@Sun.COM Stk_t *stkp = shp->stk; 1114887Schin for(first=format ; c= *format; format++) 1124887Schin { 1134887Schin if(c!='%') 1144887Schin continue; 115*8462SApril.Chin@Sun.COM sfwrite(stkp, first, format-first); 1164887Schin n = l = 0; 1174887Schin p = 3; 1184887Schin if((c= *++format) == '%') 1194887Schin { 1204887Schin first = format; 1214887Schin continue; 1224887Schin } 1234887Schin if(c>='0' && c <='9') 1244887Schin { 1254887Schin p = (c>'3')?3:(c-'0'); 1264887Schin c = *++format; 1274887Schin } 1284887Schin else if(c=='P') 1294887Schin { 1304887Schin if(d=tm[0]) 1314887Schin d = 100.*(((double)(tm[1]+tm[2]))/d); 1324887Schin p = 2; 1334887Schin goto skip; 1344887Schin } 1354887Schin if(c=='l') 1364887Schin { 1374887Schin l = 1; 1384887Schin c = *++format; 1394887Schin } 1404887Schin if(c=='U') 1414887Schin n = 1; 1424887Schin else if(c=='S') 1434887Schin n = 2; 1444887Schin else if(c!='R') 1454887Schin { 146*8462SApril.Chin@Sun.COM stkseek(stkp,offset); 1474887Schin errormsg(SH_DICT,ERROR_exit(0),e_badtformat,c); 1484887Schin return(0); 1494887Schin } 1504887Schin d = (double)tm[n]/sh.lim.clk_tck; 1514887Schin skip: 1524887Schin if(l) 153*8462SApril.Chin@Sun.COM l_time(stkp, tm[n], p); 1544887Schin else 155*8462SApril.Chin@Sun.COM sfprintf(stkp,"%.*f",p, d); 1564887Schin first = format+1; 1574887Schin } 1584887Schin if(format>first) 159*8462SApril.Chin@Sun.COM sfwrite(stkp,first, format-first); 160*8462SApril.Chin@Sun.COM sfputc(stkp,'\n'); 161*8462SApril.Chin@Sun.COM n = stktell(stkp)-offset; 162*8462SApril.Chin@Sun.COM sfwrite(out,stkptr(stkp,offset),n); 163*8462SApril.Chin@Sun.COM stkseek(stkp,offset); 1644887Schin return(n); 1654887Schin } 1664887Schin 1674887Schin #if SHOPT_OPTIMIZE 1684887Schin /* 1694887Schin * clear argument pointers that point into the stack 1704887Schin */ 1714887Schin static int p_arg(struct argnod*,int); 1724887Schin static int p_switch(struct regnod*); 1734887Schin static int p_comarg(register struct comnod *com) 1744887Schin { 1754887Schin Namval_t *np=com->comnamp; 1764887Schin int n = p_arg(com->comset,ARG_ASSIGN); 1774887Schin if(com->comarg && (com->comtyp&COMSCAN)) 1784887Schin n+= p_arg(com->comarg,0); 1794887Schin if(com->comstate && np) 1804887Schin { 1814887Schin /* call builtin to cleanup state */ 182*8462SApril.Chin@Sun.COM Shbltin_t *bp = &sh.bltindata; 183*8462SApril.Chin@Sun.COM void *save_ptr = bp->ptr; 184*8462SApril.Chin@Sun.COM void *save_data = bp->data; 185*8462SApril.Chin@Sun.COM bp->bnode = np; 186*8462SApril.Chin@Sun.COM bp->vnode = com->comnamq; 187*8462SApril.Chin@Sun.COM bp->ptr = nv_context(np); 188*8462SApril.Chin@Sun.COM bp->data = com->comstate; 189*8462SApril.Chin@Sun.COM bp->flags = SH_END_OPTIM; 190*8462SApril.Chin@Sun.COM (*funptr(np))(0,(char**)0, bp); 191*8462SApril.Chin@Sun.COM bp->ptr = save_ptr; 192*8462SApril.Chin@Sun.COM bp->data = save_data; 1934887Schin } 1944887Schin com->comstate = 0; 1954887Schin if(com->comarg && !np) 1964887Schin n++; 1974887Schin return(n); 1984887Schin } 1994887Schin 2004887Schin extern void sh_optclear(Shell_t*, void*); 2014887Schin 2024887Schin static int sh_tclear(register Shnode_t *t) 2034887Schin { 2044887Schin int n=0; 2054887Schin if(!t) 2064887Schin return(0); 2074887Schin switch(t->tre.tretyp&COMMSK) 2084887Schin { 2094887Schin case TTIME: 2104887Schin case TPAR: 2114887Schin return(sh_tclear(t->par.partre)); 2124887Schin case TCOM: 2134887Schin return(p_comarg((struct comnod*)t)); 2144887Schin case TSETIO: 2154887Schin case TFORK: 2164887Schin return(sh_tclear(t->fork.forktre)); 2174887Schin case TIF: 2184887Schin n=sh_tclear(t->if_.iftre); 2194887Schin n+=sh_tclear(t->if_.thtre); 2204887Schin n+=sh_tclear(t->if_.eltre); 2214887Schin return(n); 2224887Schin case TWH: 2234887Schin if(t->wh.whinc) 2244887Schin n=sh_tclear((Shnode_t*)(t->wh.whinc)); 2254887Schin n+=sh_tclear(t->wh.whtre); 2264887Schin n+=sh_tclear(t->wh.dotre); 2274887Schin return(n); 2284887Schin case TLST: 2294887Schin case TAND: 2304887Schin case TORF: 2314887Schin case TFIL: 2324887Schin n=sh_tclear(t->lst.lstlef); 2334887Schin return(n+sh_tclear(t->lst.lstrit)); 2344887Schin case TARITH: 2354887Schin return(p_arg(t->ar.arexpr,ARG_ARITH)); 2364887Schin case TFOR: 2374887Schin n=sh_tclear(t->for_.fortre); 2384887Schin return(n+sh_tclear((Shnode_t*)t->for_.forlst)); 2394887Schin case TSW: 2404887Schin n=p_arg(t->sw.swarg,0); 2414887Schin return(n+p_switch(t->sw.swlst)); 2424887Schin case TFUN: 2434887Schin n=sh_tclear(t->funct.functtre); 2444887Schin return(n+sh_tclear((Shnode_t*)t->funct.functargs)); 2454887Schin case TTST: 2464887Schin if((t->tre.tretyp&TPAREN)==TPAREN) 2474887Schin return(sh_tclear(t->lst.lstlef)); 2484887Schin else 2494887Schin { 2504887Schin n=p_arg(&(t->lst.lstlef->arg),0); 2514887Schin if(t->tre.tretyp&TBINARY) 2524887Schin n+=p_arg(&(t->lst.lstrit->arg),0); 2534887Schin } 2544887Schin } 2554887Schin return(n); 2564887Schin } 2574887Schin 2584887Schin static int p_arg(register struct argnod *arg,int flag) 2594887Schin { 2604887Schin while(arg) 2614887Schin { 2624887Schin if(strlen(arg->argval) || (arg->argflag==ARG_RAW)) 2634887Schin arg->argchn.ap = 0; 2644887Schin else if(flag==0) 2654887Schin sh_tclear((Shnode_t*)arg->argchn.ap); 2664887Schin else 2674887Schin sh_tclear(((struct fornod*)arg->argchn.ap)->fortre); 2684887Schin arg = arg->argnxt.ap; 2694887Schin } 2704887Schin return(0); 2714887Schin } 2724887Schin 2734887Schin static int p_switch(register struct regnod *reg) 2744887Schin { 2754887Schin int n=0; 2764887Schin while(reg) 2774887Schin { 2784887Schin n+=p_arg(reg->regptr,0); 2794887Schin n+=sh_tclear(reg->regcom); 2804887Schin reg = reg->regnxt; 2814887Schin } 2824887Schin return(n); 2834887Schin } 2844887Schin # define OPTIMIZE_FLAG (ARG_OPTIMIZE) 2854887Schin # define OPTIMIZE (flags&OPTIMIZE_FLAG) 2864887Schin #else 2874887Schin # define OPTIMIZE_FLAG (0) 2884887Schin # define OPTIMIZE (0) 2894887Schin # define sh_tclear(x) 2904887Schin #endif /* SHOPT_OPTIMIZE */ 2914887Schin 2924887Schin static void out_pattern(Sfio_t *iop, register const char *cp, int n) 2934887Schin { 2944887Schin register int c; 2954887Schin do 2964887Schin { 2974887Schin switch(c= *cp) 2984887Schin { 2994887Schin case 0: 3004887Schin if(n<0) 3014887Schin return; 3024887Schin c = n; 3034887Schin break; 3044887Schin case '\n': 3054887Schin sfputr(iop,"$'\\n",'\''); 3064887Schin continue; 3074887Schin case '\\': 3084887Schin if (!(c = *++cp)) 3094887Schin c = '\\'; 3104887Schin /*FALLTHROUGH*/ 3114887Schin case ' ': 3124887Schin case '<': case '>': case ';': 3134887Schin case '$': case '`': case '\t': 3144887Schin sfputc(iop,'\\'); 3154887Schin break; 3164887Schin } 3174887Schin sfputc(iop,c); 3184887Schin } 3194887Schin while(*cp++); 3204887Schin } 3214887Schin 3224887Schin static void out_string(Sfio_t *iop, register const char *cp, int c, int quoted) 3234887Schin { 3244887Schin if(quoted) 3254887Schin { 326*8462SApril.Chin@Sun.COM int n = stktell(stkstd); 3274887Schin cp = sh_fmtq(cp); 3284887Schin if(iop==stkstd && cp==stkptr(stkstd,n)) 3294887Schin { 3304887Schin *stkptr(stkstd,stktell(stkstd)-1) = c; 3314887Schin return; 3324887Schin } 3334887Schin } 3344887Schin sfputr(iop,cp,c); 3354887Schin } 3364887Schin 3374887Schin struct Level 3384887Schin { 3394887Schin Namfun_t hdr; 3404887Schin short maxlevel; 3414887Schin }; 3424887Schin 3434887Schin /* 3444887Schin * this is for a debugger but it hasn't been tested yet 3454887Schin * if a debug script sets .sh.level it should set up the scope 3464887Schin * as if you were executing in that level 3474887Schin */ 3484887Schin static void put_level(Namval_t* np,const char *val,int flags,Namfun_t *fp) 3494887Schin { 3504887Schin Shscope_t *sp; 3514887Schin struct Level *lp = (struct Level*)fp; 3524887Schin int16_t level, oldlevel = (int16_t)nv_getnum(np); 3534887Schin nv_putv(np,val,flags,fp); 354*8462SApril.Chin@Sun.COM if(!val) 355*8462SApril.Chin@Sun.COM return; 3564887Schin level = nv_getnum(np); 3574887Schin if(level<0 || level > lp->maxlevel) 3584887Schin { 359*8462SApril.Chin@Sun.COM nv_putv(np, (char*)&oldlevel, NV_INT16, fp); 3604887Schin /* perhaps this should be an error */ 3614887Schin return; 3624887Schin } 3634887Schin if(level==oldlevel) 3644887Schin return; 3654887Schin if(sp = sh_getscope(level,SEEK_SET)) 3664887Schin { 367*8462SApril.Chin@Sun.COM sh_setscope(sp); 368*8462SApril.Chin@Sun.COM error_info.id = sp->cmdname; 369*8462SApril.Chin@Sun.COM 3704887Schin } 3714887Schin } 3724887Schin 373*8462SApril.Chin@Sun.COM static const Namdisc_t level_disc = { sizeof(struct Level), put_level }; 374*8462SApril.Chin@Sun.COM 375*8462SApril.Chin@Sun.COM static struct Level *init_level(int level) 376*8462SApril.Chin@Sun.COM { 377*8462SApril.Chin@Sun.COM struct Level *lp = newof(NiL,struct Level,1,0); 378*8462SApril.Chin@Sun.COM lp->maxlevel = level; 379*8462SApril.Chin@Sun.COM _nv_unset(SH_LEVELNOD,0); 380*8462SApril.Chin@Sun.COM nv_onattr(SH_LEVELNOD,NV_INT16|NV_NOFREE); 381*8462SApril.Chin@Sun.COM nv_putval(SH_LEVELNOD,(char*)&lp->maxlevel,NV_INT16); 382*8462SApril.Chin@Sun.COM lp->hdr.disc = &level_disc; 383*8462SApril.Chin@Sun.COM nv_disc(SH_LEVELNOD,&lp->hdr,NV_FIRST); 384*8462SApril.Chin@Sun.COM return(lp); 385*8462SApril.Chin@Sun.COM } 3864887Schin 3874887Schin /* 3884887Schin * write the current common on the stack and make it available as .sh.command 3894887Schin */ 390*8462SApril.Chin@Sun.COM int sh_debug(Shell_t *shp, const char *trap, const char *name, const char *subscript, char *const argv[], int flags) 3914887Schin { 392*8462SApril.Chin@Sun.COM Stk_t *stkp=shp->stk; 3934887Schin struct sh_scoped savst; 3944887Schin Namval_t *np = SH_COMMANDNOD; 395*8462SApril.Chin@Sun.COM char *sav = stkptr(stkp,0); 396*8462SApril.Chin@Sun.COM int n=4, offset=stktell(stkp); 3974887Schin const char *cp = "+=( "; 3984887Schin Sfio_t *iop = stkstd; 399*8462SApril.Chin@Sun.COM short level; 400*8462SApril.Chin@Sun.COM if(shp->indebug) 401*8462SApril.Chin@Sun.COM return(0); 402*8462SApril.Chin@Sun.COM shp->indebug = 1; 4034887Schin if(name) 4044887Schin { 4054887Schin sfputr(iop,name,-1); 4064887Schin if(subscript) 4074887Schin { 4084887Schin sfputc(iop,'['); 4094887Schin out_string(iop,subscript,']',1); 4104887Schin } 4114887Schin if(!(flags&ARG_APPEND)) 4124887Schin cp+=1, n-=1; 4134887Schin if(!(flags&ARG_ASSIGN)) 4144887Schin n -= 2; 4154887Schin sfwrite(iop,cp,n); 4164887Schin } 4174887Schin if(!(flags&ARG_RAW)) 4184887Schin out_string(iop, *argv++,' ', 0); 4194887Schin n = (flags&ARG_ARITH); 4204887Schin while(cp = *argv++) 4214887Schin { 4224887Schin if((flags&ARG_EXP) && argv[1]==0) 4234887Schin out_pattern(iop, cp,' '); 4244887Schin else 4254887Schin out_string(iop, cp,' ',n?0: (flags&(ARG_RAW|ARG_NOGLOB))||*argv); 4264887Schin } 4274887Schin if(flags&ARG_ASSIGN) 4284887Schin sfputc(iop,')'); 4294887Schin else if(iop==stkstd) 430*8462SApril.Chin@Sun.COM *stkptr(stkp,stktell(stkp)-1) = 0; 431*8462SApril.Chin@Sun.COM np->nvalue.cp = stkfreeze(stkp,1); 4324887Schin /* now setup .sh.level variable */ 433*8462SApril.Chin@Sun.COM shp->st.lineno = error_info.line; 434*8462SApril.Chin@Sun.COM level = shp->fn_depth+shp->dot_depth; 435*8462SApril.Chin@Sun.COM if(!SH_LEVELNOD->nvfun || !SH_LEVELNOD->nvfun->disc || nv_isattr(SH_LEVELNOD,NV_INT16|NV_NOFREE)!=(NV_INT16|NV_NOFREE)) 436*8462SApril.Chin@Sun.COM init_level(level); 437*8462SApril.Chin@Sun.COM else 438*8462SApril.Chin@Sun.COM nv_putval(SH_LEVELNOD,(char*)&level,NV_INT16); 439*8462SApril.Chin@Sun.COM savst = shp->st; 440*8462SApril.Chin@Sun.COM shp->st.trap[SH_DEBUGTRAP] = 0; 4414887Schin n = sh_trap(trap,0); 4424887Schin np->nvalue.cp = 0; 443*8462SApril.Chin@Sun.COM shp->indebug = 0; 444*8462SApril.Chin@Sun.COM if(shp->st.cmdname) 445*8462SApril.Chin@Sun.COM error_info.id = shp->st.cmdname; 446*8462SApril.Chin@Sun.COM nv_putval(SH_PATHNAMENOD,shp->st.filename,NV_NOFREE); 447*8462SApril.Chin@Sun.COM nv_putval(SH_FUNNAMENOD,shp->st.funname,NV_NOFREE); 448*8462SApril.Chin@Sun.COM shp->st = savst; 449*8462SApril.Chin@Sun.COM if(sav != stkptr(stkp,0)) 450*8462SApril.Chin@Sun.COM stkset(stkp,sav,0); 4514887Schin else 452*8462SApril.Chin@Sun.COM stkseek(stkp,offset); 4534887Schin return(n); 4544887Schin } 4554887Schin 4564887Schin /* 4574887Schin * Given stream <iop> compile and execute 4584887Schin */ 4594887Schin int sh_eval(register Sfio_t *iop, int mode) 4604887Schin { 4614887Schin register Shnode_t *t; 4624887Schin Shell_t *shp = sh_getinterp(); 4634887Schin struct slnod *saveslp = shp->st.staklist; 4644887Schin int jmpval; 4654887Schin struct checkpt *pp = (struct checkpt*)shp->jmplist; 4664887Schin struct checkpt buff; 4674887Schin static Sfio_t *io_save; 468*8462SApril.Chin@Sun.COM volatile int traceon=0, lineno=0; 4694887Schin io_save = iop; /* preserve correct value across longjmp */ 470*8462SApril.Chin@Sun.COM #define SH_TOPFUN 0x8000 /* this is a temporary tksh hack */ 471*8462SApril.Chin@Sun.COM if (mode & SH_TOPFUN) 472*8462SApril.Chin@Sun.COM { 473*8462SApril.Chin@Sun.COM mode ^= SH_TOPFUN; 474*8462SApril.Chin@Sun.COM shp->fn_reset = 1; 475*8462SApril.Chin@Sun.COM } 4764887Schin sh_pushcontext(&buff,SH_JMPEVAL); 4774887Schin buff.olist = pp->olist; 4784887Schin jmpval = sigsetjmp(buff.buff,0); 4794887Schin if(jmpval==0) 4804887Schin { 481*8462SApril.Chin@Sun.COM if(mode&SH_READEVAL) 482*8462SApril.Chin@Sun.COM { 483*8462SApril.Chin@Sun.COM lineno = shp->inlineno; 484*8462SApril.Chin@Sun.COM if(traceon=sh_isoption(SH_XTRACE)) 485*8462SApril.Chin@Sun.COM sh_offoption(SH_XTRACE); 486*8462SApril.Chin@Sun.COM } 487*8462SApril.Chin@Sun.COM t = (Shnode_t*)sh_parse(shp,iop,(mode&SH_READEVAL)?0:SH_NL); 488*8462SApril.Chin@Sun.COM if(mode&SH_READEVAL) 489*8462SApril.Chin@Sun.COM mode &= SH_READEVAL; 490*8462SApril.Chin@Sun.COM else 491*8462SApril.Chin@Sun.COM sfclose(iop); 4924887Schin io_save = 0; 4934887Schin if(!sh_isoption(SH_VERBOSE)) 4944887Schin sh_offstate(SH_VERBOSE); 4954887Schin if(mode && shp->hist_ptr) 4964887Schin { 4974887Schin hist_flush(shp->hist_ptr); 4984887Schin mode = sh_state(SH_INTERACTIVE); 4994887Schin } 5004887Schin sh_exec(t,sh_isstate(SH_ERREXIT)|mode); 5014887Schin } 5024887Schin sh_popcontext(&buff); 503*8462SApril.Chin@Sun.COM if(traceon) 504*8462SApril.Chin@Sun.COM sh_onoption(SH_XTRACE); 505*8462SApril.Chin@Sun.COM if(lineno) 506*8462SApril.Chin@Sun.COM shp->inlineno = lineno; 5074887Schin if(io_save) 5084887Schin sfclose(io_save); 509*8462SApril.Chin@Sun.COM sh_freeup(shp); 5104887Schin shp->st.staklist = saveslp; 511*8462SApril.Chin@Sun.COM shp->fn_reset = 0; 5124887Schin if(jmpval>SH_JMPEVAL) 5134887Schin siglongjmp(*shp->jmplist,jmpval); 514*8462SApril.Chin@Sun.COM return(shp->exitval); 5154887Schin } 5164887Schin 5174887Schin #if SHOPT_FASTPIPE 518*8462SApril.Chin@Sun.COM static int pipe_exec(Shell_t* shp,int pv[], Shnode_t *t, int errorflg) 5194887Schin { 5204887Schin struct checkpt buff; 5214887Schin register Shnode_t *tchild = t->fork.forktre; 5224887Schin Namval_t *np; 523*8462SApril.Chin@Sun.COM int jmpval; 524*8462SApril.Chin@Sun.COM volatile Sfio_t *iop; 525*8462SApril.Chin@Sun.COM volatile int r; 5264887Schin if((tchild->tre.tretyp&COMMSK)!=TCOM || !(np=(Namval_t*)(tchild->com.comnamp))) 5274887Schin { 5284887Schin sh_pipe(pv); 5294887Schin return(sh_exec(t,errorflg)); 5304887Schin } 531*8462SApril.Chin@Sun.COM pv[0] = shp->lim.open_max; 532*8462SApril.Chin@Sun.COM shp->fdstatus[pv[0]] = IOREAD|IODUP|IOSEEK; 533*8462SApril.Chin@Sun.COM pv[1] = shp->lim.open_max+1; 534*8462SApril.Chin@Sun.COM shp->fdstatus[pv[1]] = IOWRITE|IOSEEK; 5354887Schin iop = sftmp(IOBSIZE+1); 536*8462SApril.Chin@Sun.COM shp->sftable[shp->lim.open_max+1] = iop; 5374887Schin sh_pushcontext(&buff,SH_JMPIO); 5384887Schin if(t->tre.tretyp&FPIN) 539*8462SApril.Chin@Sun.COM sh_iosave(shp,0,shp->topfd,(char*)0); 540*8462SApril.Chin@Sun.COM sh_iosave(shp,1,shp->topfd,(char*)0); 5414887Schin jmpval = sigsetjmp(buff.buff,0); 5424887Schin if(jmpval==0) 5434887Schin { 5444887Schin if(t->tre.tretyp&FPIN) 545*8462SApril.Chin@Sun.COM sh_iorenumber(shp,shp->inpipe[0],0); 546*8462SApril.Chin@Sun.COM sh_iorenumber(shp,shp->lim.open_max+1,1); 5474887Schin r = sh_exec(tchild,errorflg); 5484887Schin if(sffileno(sfstdout)>=0) 5494887Schin pv[0] = sfsetfd(sfstdout,10); 5504887Schin iop = sfswap(sfstdout,0); 5514887Schin } 5524887Schin sh_popcontext(&buff); 553*8462SApril.Chin@Sun.COM shp->sftable[pv[0]] = iop; 554*8462SApril.Chin@Sun.COM shp->fdstatus[pv[0]] = IOREAD|IODUP|IOSEEK; 5554887Schin sfset(iop,SF_WRITE,0); 5564887Schin sfseek(iop,0L,SEEK_SET); 557*8462SApril.Chin@Sun.COM sh_iorestore(shp,buff.topfd,jmpval); 5584887Schin if(jmpval>SH_JMPIO) 559*8462SApril.Chin@Sun.COM siglongjmp(*shp->jmplist,jmpval); 5604887Schin return(r); 5614887Schin } 5624887Schin #endif /* SHOPT_FASTPIPE */ 5634887Schin 5644887Schin /* 5654887Schin * returns 1 when option -<c> is specified 5664887Schin */ 5674887Schin static int checkopt(char *argv[], int c) 5684887Schin { 5694887Schin char *cp; 5704887Schin while(cp = *++argv) 5714887Schin { 5724887Schin if(*cp=='+') 5734887Schin continue; 5744887Schin if(*cp!='-' || cp[1]=='-') 5754887Schin break; 576*8462SApril.Chin@Sun.COM if(strchr(++cp,c)) 5774887Schin return(1); 578*8462SApril.Chin@Sun.COM if(*cp=='h' && cp[1]==0 && *++argv==0) 579*8462SApril.Chin@Sun.COM break; 5804887Schin } 5814887Schin return(0); 5824887Schin } 5834887Schin 5844887Schin static void free_list(struct openlist *olist) 5854887Schin { 5864887Schin struct openlist *item,*next; 5874887Schin for(item=olist;item;item=next) 5884887Schin { 5894887Schin next = item->next; 5904887Schin free((void*)item); 5914887Schin } 5924887Schin } 5934887Schin 594*8462SApril.Chin@Sun.COM /* 595*8462SApril.Chin@Sun.COM * set ${.sh.name} and ${.sh.subscript} 596*8462SApril.Chin@Sun.COM * set _ to reference for ${.sh.name}[$.sh.subscript] 597*8462SApril.Chin@Sun.COM */ 598*8462SApril.Chin@Sun.COM static int set_instance(Namval_t *nq, Namval_t *node, struct Namref *nr) 599*8462SApril.Chin@Sun.COM { 600*8462SApril.Chin@Sun.COM char *cp = nv_name(nq); 601*8462SApril.Chin@Sun.COM Namarr_t *ap; 602*8462SApril.Chin@Sun.COM memset(nr,0,sizeof(*nr)); 603*8462SApril.Chin@Sun.COM nr->np = nq; 604*8462SApril.Chin@Sun.COM nr->root = sh.var_tree; 605*8462SApril.Chin@Sun.COM nr->table = sh.last_table; 606*8462SApril.Chin@Sun.COM if(sh.var_tree!=sh.var_base && !nv_open(cp,nr->root,NV_VARNAME|NV_NOREF|NV_NOSCOPE|NV_NOADD|NV_NOFAIL)) 607*8462SApril.Chin@Sun.COM nr->root = sh.var_base; 608*8462SApril.Chin@Sun.COM nv_putval(SH_NAMENOD, cp, NV_NOFREE); 609*8462SApril.Chin@Sun.COM memcpy(node,L_ARGNOD,sizeof(*node)); 610*8462SApril.Chin@Sun.COM L_ARGNOD->nvalue.nrp = nr; 611*8462SApril.Chin@Sun.COM L_ARGNOD->nvflag = NV_REF|NV_NOFREE; 612*8462SApril.Chin@Sun.COM L_ARGNOD->nvfun = 0; 613*8462SApril.Chin@Sun.COM L_ARGNOD->nvenv = 0; 614*8462SApril.Chin@Sun.COM if((ap=nv_arrayptr(nq)) && (cp = nv_getsub(nq)) && (cp = strdup(cp))) 615*8462SApril.Chin@Sun.COM { 616*8462SApril.Chin@Sun.COM nv_putval(SH_SUBSCRNOD,nr->sub=cp,NV_NOFREE); 617*8462SApril.Chin@Sun.COM return(ap->nelem&ARRAY_SCAN); 618*8462SApril.Chin@Sun.COM } 619*8462SApril.Chin@Sun.COM return(0); 620*8462SApril.Chin@Sun.COM } 621*8462SApril.Chin@Sun.COM 622*8462SApril.Chin@Sun.COM static void unset_instance(Namval_t *nq, Namval_t *node, struct Namref *nr,long mode) 623*8462SApril.Chin@Sun.COM { 624*8462SApril.Chin@Sun.COM L_ARGNOD->nvalue.nrp = node->nvalue.nrp; 625*8462SApril.Chin@Sun.COM L_ARGNOD->nvflag = node->nvflag; 626*8462SApril.Chin@Sun.COM L_ARGNOD->nvfun = node->nvfun; 627*8462SApril.Chin@Sun.COM if(nr->sub) 628*8462SApril.Chin@Sun.COM { 629*8462SApril.Chin@Sun.COM nv_putsub(nq, nr->sub, mode); 630*8462SApril.Chin@Sun.COM free((void*)nr->sub); 631*8462SApril.Chin@Sun.COM } 632*8462SApril.Chin@Sun.COM nv_unset(SH_NAMENOD); 633*8462SApril.Chin@Sun.COM nv_unset(SH_SUBSCRNOD); 634*8462SApril.Chin@Sun.COM } 6354887Schin 6364887Schin int sh_exec(register const Shnode_t *t, int flags) 6374887Schin { 638*8462SApril.Chin@Sun.COM register Shell_t *shp = &sh; 639*8462SApril.Chin@Sun.COM Stk_t *stkp = shp->stk; 6404887Schin sh_sigcheck(); 641*8462SApril.Chin@Sun.COM if(t && !shp->st.execbrk && !sh_isoption(SH_NOEXEC)) 6424887Schin { 6434887Schin register int type = flags; 6444887Schin register char *com0 = 0; 6454887Schin int errorflg = (type&sh_state(SH_ERREXIT))|OPTIMIZE; 6464887Schin int execflg = (type&sh_state(SH_NOFORK)); 6474887Schin int mainloop = (type&sh_state(SH_INTERACTIVE)); 648*8462SApril.Chin@Sun.COM #if SHOPT_AMP || SHOPT_SPAWN 6494887Schin int ntflag = (type&sh_state(SH_NTFORK)); 6504887Schin #endif 651*8462SApril.Chin@Sun.COM int topfd = shp->topfd; 652*8462SApril.Chin@Sun.COM char *sav=stkptr(stkp,0); 653*8462SApril.Chin@Sun.COM char *cp=0, **com=0, *comn; 6544887Schin int argn; 6554887Schin int skipexitset = 0; 6564887Schin int was_interactive = 0; 6574887Schin int was_errexit = sh_isstate(SH_ERREXIT); 6584887Schin int was_monitor = sh_isstate(SH_MONITOR); 6594887Schin int echeck = 0; 6604887Schin if(flags&sh_state(SH_INTERACTIVE)) 6614887Schin { 6624887Schin pipejob = 0; 6634887Schin job.curpgid = 0; 6644887Schin flags &= ~sh_state(SH_INTERACTIVE); 6654887Schin } 6664887Schin sh_offstate(SH_ERREXIT); 6674887Schin sh_offstate(SH_DEFPATH); 6684887Schin if(was_errexit&flags) 6694887Schin sh_onstate(SH_ERREXIT); 6704887Schin if(was_monitor&flags) 6714887Schin sh_onstate(SH_MONITOR); 6724887Schin type = t->tre.tretyp; 673*8462SApril.Chin@Sun.COM if(!shp->intrap) 674*8462SApril.Chin@Sun.COM shp->oldexit=shp->exitval; 675*8462SApril.Chin@Sun.COM shp->exitval=0; 676*8462SApril.Chin@Sun.COM shp->lastsig = 0; 677*8462SApril.Chin@Sun.COM shp->lastpath = 0; 6784887Schin switch(type&COMMSK) 6794887Schin { 6804887Schin case TCOM: 6814887Schin { 6824887Schin register struct argnod *argp; 6834887Schin char *trap; 6844887Schin Namval_t *np, *nq, *last_table; 6854887Schin struct ionod *io; 686*8462SApril.Chin@Sun.COM int command=0, flgs=NV_ASSIGN; 687*8462SApril.Chin@Sun.COM shp->bltindata.invariant = type>>(COMBITS+2); 688*8462SApril.Chin@Sun.COM type &= (COMMSK|COMSCAN); 689*8462SApril.Chin@Sun.COM sh_stats(STAT_SCMDS); 690*8462SApril.Chin@Sun.COM error_info.line = t->com.comline-shp->st.firstline; 691*8462SApril.Chin@Sun.COM com = sh_argbuild(shp,&argn,&(t->com),OPTIMIZE); 6924887Schin echeck = 1; 6934887Schin if(t->tre.tretyp&COMSCAN) 6944887Schin { 6954887Schin argp = t->com.comarg; 6964887Schin if(argp && *com && !(argp->argflag&ARG_RAW)) 6974887Schin sh_sigcheck(); 6984887Schin } 6994887Schin np = (Namval_t*)(t->com.comnamp); 7004887Schin nq = (Namval_t*)(t->com.comnamq); 7014887Schin com0 = com[0]; 702*8462SApril.Chin@Sun.COM shp->xargexit = 0; 7034887Schin while(np==SYSCOMMAND) 7044887Schin { 705*8462SApril.Chin@Sun.COM register int n = b_command(0,com,&shp->bltindata); 7064887Schin if(n==0) 7074887Schin break; 7084887Schin command += n; 7094887Schin np = 0; 7104887Schin if(!(com0= *(com+=n))) 7114887Schin break; 712*8462SApril.Chin@Sun.COM np = nv_bfsearch(com0, shp->bltin_tree, &nq, &cp); 7134887Schin } 714*8462SApril.Chin@Sun.COM if(shp->xargexit) 7154887Schin { 716*8462SApril.Chin@Sun.COM shp->xargmin -= command; 717*8462SApril.Chin@Sun.COM shp->xargmax -= command; 7184887Schin } 7194887Schin else 720*8462SApril.Chin@Sun.COM shp->xargmin = 0; 7214887Schin argn -= command; 7224887Schin if(!command && np && is_abuiltin(np)) 723*8462SApril.Chin@Sun.COM np = dtsearch(shp->fun_tree,np); 724*8462SApril.Chin@Sun.COM if(com0) 7254887Schin { 726*8462SApril.Chin@Sun.COM if(!np && !strchr(com0,'/')) 7274887Schin { 728*8462SApril.Chin@Sun.COM Dt_t *root = command?shp->bltin_tree:shp->fun_tree; 729*8462SApril.Chin@Sun.COM np = nv_bfsearch(com0, root, &nq, &cp); 730*8462SApril.Chin@Sun.COM #if SHOPT_NAMESPACE 731*8462SApril.Chin@Sun.COM if(shp->namespace && !nq && !cp) 732*8462SApril.Chin@Sun.COM { 733*8462SApril.Chin@Sun.COM int offset = stktell(stkp); 734*8462SApril.Chin@Sun.COM sfputr(stkp,nv_name(shp->namespace),-1); 735*8462SApril.Chin@Sun.COM sfputc(stkp,'.'); 736*8462SApril.Chin@Sun.COM sfputr(stkp,com0,0); 737*8462SApril.Chin@Sun.COM stkseek(stkp,offset); 738*8462SApril.Chin@Sun.COM np = nv_bfsearch(stkptr(stkp,offset), root, &nq, &cp); 739*8462SApril.Chin@Sun.COM } 740*8462SApril.Chin@Sun.COM #endif /* SHOPT_NAMESPACE */ 7414887Schin } 742*8462SApril.Chin@Sun.COM comn = com[argn-1]; 7434887Schin } 7444887Schin io = t->tre.treio; 745*8462SApril.Chin@Sun.COM if(shp->envlist = argp = t->com.comset) 7464887Schin { 747*8462SApril.Chin@Sun.COM if(argn==0 || (np && nv_isattr(np,BLT_SPC))) 7484887Schin { 749*8462SApril.Chin@Sun.COM if(argn) 750*8462SApril.Chin@Sun.COM { 751*8462SApril.Chin@Sun.COM if(checkopt(com,'A')) 752*8462SApril.Chin@Sun.COM flgs |= NV_ARRAY; 753*8462SApril.Chin@Sun.COM else if(checkopt(com,'a')) 754*8462SApril.Chin@Sun.COM flgs |= NV_IARRAY; 755*8462SApril.Chin@Sun.COM } 7564887Schin #if SHOPT_BASH 7574887Schin if(np==SYSLOCAL) 7584887Schin { 7594887Schin if(!nv_getval(SH_FUNNAMENOD)) 7604887Schin errormsg(SH_DICT,ERROR_exit(1),"%s: can only be used in a function",com0); 761*8462SApril.Chin@Sun.COM if(!shp->st.var_local) 7624887Schin { 763*8462SApril.Chin@Sun.COM sh_scope(shp,(struct argnod*)0,0); 764*8462SApril.Chin@Sun.COM shp->st.var_local = shp->var_tree; 7654887Schin } 7664887Schin 7674887Schin } 7684887Schin if(np==SYSTYPESET || np==SYSLOCAL) 7694887Schin #else 770*8462SApril.Chin@Sun.COM if(np==SYSTYPESET || (np && np->nvalue.bfp==SYSTYPESET->nvalue.bfp)) 7714887Schin #endif 7724887Schin { 773*8462SApril.Chin@Sun.COM if(np!=SYSTYPESET) 774*8462SApril.Chin@Sun.COM shp->typeinit = np; 775*8462SApril.Chin@Sun.COM if(checkopt(com,'C')) 776*8462SApril.Chin@Sun.COM flgs |= NV_COMVAR; 777*8462SApril.Chin@Sun.COM if(checkopt(com,'S')) 778*8462SApril.Chin@Sun.COM flgs |= NV_STATIC; 7794887Schin if(checkopt(com,'n')) 7804887Schin flgs |= NV_NOREF; 7814887Schin #if SHOPT_TYPEDEF 782*8462SApril.Chin@Sun.COM else if(argn>=3 && checkopt(com,'T')) 7834887Schin { 784*8462SApril.Chin@Sun.COM shp->prefix = NV_CLASS; 7854887Schin flgs |= NV_TYPE; 7864887Schin 7874887Schin } 7884887Schin #endif /* SHOPT_TYPEDEF */ 789*8462SApril.Chin@Sun.COM if((shp->fn_depth && !shp->prefix) || np==SYSLOCAL) 7904887Schin flgs |= NV_NOSCOPE; 7914887Schin } 7924887Schin else if(np==SYSEXPORT) 7934887Schin flgs |= NV_EXPORT; 794*8462SApril.Chin@Sun.COM if(flgs&(NV_EXPORT|NV_NOREF)) 795*8462SApril.Chin@Sun.COM flgs |= NV_IDENT; 796*8462SApril.Chin@Sun.COM else 797*8462SApril.Chin@Sun.COM flgs |= NV_VARNAME; 7984887Schin #if 0 7994887Schin if(OPTIMIZE) 8004887Schin flgs |= NV_TAGGED; 8014887Schin #endif 8024887Schin nv_setlist(argp,flgs); 803*8462SApril.Chin@Sun.COM if(np==shp->typeinit) 804*8462SApril.Chin@Sun.COM shp->typeinit = 0; 805*8462SApril.Chin@Sun.COM shp->envlist = argp; 8064887Schin argp = NULL; 8074887Schin } 8084887Schin } 809*8462SApril.Chin@Sun.COM last_table = shp->last_table; 810*8462SApril.Chin@Sun.COM shp->last_table = 0; 8114887Schin if((io||argn)) 8124887Schin { 813*8462SApril.Chin@Sun.COM Shbltin_t *bp=0; 8144887Schin static char *argv[1]; 815*8462SApril.Chin@Sun.COM int tflags = 1; 816*8462SApril.Chin@Sun.COM if(np && nv_isattr(np,BLT_DCL)) 817*8462SApril.Chin@Sun.COM tflags |= 2; 8184887Schin if(argn==0) 8194887Schin { 8204887Schin /* fake 'true' built-in */ 8214887Schin np = SYSTRUE; 8224887Schin *argv = nv_name(np); 8234887Schin com = argv; 8244887Schin } 8254887Schin /* set +x doesn't echo */ 8264887Schin else if((np!=SYSSET) && sh_isoption(SH_XTRACE)) 827*8462SApril.Chin@Sun.COM sh_trace(com-command,tflags); 8284887Schin else if((t->tre.tretyp&FSHOWME) && sh_isoption(SH_SHOWME)) 8294887Schin { 8304887Schin int ison = sh_isoption(SH_XTRACE); 8314887Schin if(!ison) 8324887Schin sh_onoption(SH_XTRACE); 833*8462SApril.Chin@Sun.COM sh_trace(com-command,tflags); 8344887Schin if(io) 835*8462SApril.Chin@Sun.COM sh_redirect(shp,io,SH_SHOWME); 8364887Schin if(!ison) 8374887Schin sh_offoption(SH_XTRACE); 8384887Schin break; 8394887Schin } 840*8462SApril.Chin@Sun.COM if(trap=shp->st.trap[SH_DEBUGTRAP]) 841*8462SApril.Chin@Sun.COM { 842*8462SApril.Chin@Sun.COM int n = sh_debug(shp,trap,(char*)0,(char*)0, com, ARG_RAW); 843*8462SApril.Chin@Sun.COM if(n==255 && shp->fn_depth+shp->dot_depth) 844*8462SApril.Chin@Sun.COM { 845*8462SApril.Chin@Sun.COM np = SYSRETURN; 846*8462SApril.Chin@Sun.COM argn = 1; 847*8462SApril.Chin@Sun.COM com[0] = np->nvname; 848*8462SApril.Chin@Sun.COM com[1] = 0; 849*8462SApril.Chin@Sun.COM io = 0; 850*8462SApril.Chin@Sun.COM argp = 0; 851*8462SApril.Chin@Sun.COM } 852*8462SApril.Chin@Sun.COM else if(n==2) 853*8462SApril.Chin@Sun.COM break; 854*8462SApril.Chin@Sun.COM } 8554887Schin if(io) 856*8462SApril.Chin@Sun.COM sfsync(shp->outpool); 857*8462SApril.Chin@Sun.COM shp->lastpath = 0; 8584887Schin if(!np && !strchr(com0,'/')) 8594887Schin { 860*8462SApril.Chin@Sun.COM if(path_search(com0,NIL(Pathcomp_t**),1)) 861*8462SApril.Chin@Sun.COM { 862*8462SApril.Chin@Sun.COM error_info.line = t->com.comline-shp->st.firstline; 863*8462SApril.Chin@Sun.COM if((np=nv_search(com0,shp->fun_tree,0)) && !np->nvalue.ip) 864*8462SApril.Chin@Sun.COM { 865*8462SApril.Chin@Sun.COM Namval_t *mp=nv_search(com0,shp->bltin_tree,0); 866*8462SApril.Chin@Sun.COM if(mp) 867*8462SApril.Chin@Sun.COM np = mp; 868*8462SApril.Chin@Sun.COM } 869*8462SApril.Chin@Sun.COM } 8704887Schin else 8714887Schin { 872*8462SApril.Chin@Sun.COM if((np=nv_search(com0,shp->track_tree,0)) && !nv_isattr(np,NV_NOALIAS) && np->nvalue.cp) 873*8462SApril.Chin@Sun.COM np=nv_search(nv_getval(np),shp->bltin_tree,0); 8744887Schin else 8754887Schin np = 0; 8764887Schin } 8774887Schin } 8784887Schin /* check for builtins */ 8794887Schin if(np && is_abuiltin(np)) 8804887Schin { 881*8462SApril.Chin@Sun.COM volatile int scope=0, share=0; 882*8462SApril.Chin@Sun.COM volatile void *save_ptr; 883*8462SApril.Chin@Sun.COM volatile void *save_data; 884*8462SApril.Chin@Sun.COM int jmpval, save_prompt; 8854887Schin struct checkpt buff; 8864887Schin unsigned long was_vi=0, was_emacs=0, was_gmacs=0; 8874887Schin struct stat statb; 888*8462SApril.Chin@Sun.COM bp = &shp->bltindata; 889*8462SApril.Chin@Sun.COM save_ptr = bp->ptr; 890*8462SApril.Chin@Sun.COM save_data = bp->data; 891*8462SApril.Chin@Sun.COM memset(&statb, 0, sizeof(struct stat)); 8924887Schin if(strchr(nv_name(np),'/')) 8934887Schin { 8944887Schin /* 8954887Schin * disable editors for built-in 8964887Schin * versions of commands on PATH 8974887Schin */ 8984887Schin was_vi = sh_isoption(SH_VI); 8994887Schin was_emacs = sh_isoption(SH_EMACS); 9004887Schin was_gmacs = sh_isoption(SH_GMACS); 9014887Schin sh_offoption(SH_VI); 9024887Schin sh_offoption(SH_EMACS); 9034887Schin sh_offoption(SH_GMACS); 9044887Schin } 9054887Schin sh_pushcontext(&buff,SH_JMPCMD); 9064887Schin jmpval = sigsetjmp(buff.buff,1); 9074887Schin if(jmpval == 0) 9084887Schin { 9094887Schin if(!(nv_isattr(np,BLT_ENV))) 9104887Schin error_info.flags |= ERROR_SILENT; 9114887Schin errorpush(&buff.err,0); 9124887Schin if(io) 9134887Schin { 9144887Schin struct openlist *item; 9154887Schin if(np==SYSLOGIN) 9164887Schin type=1; 9174887Schin else if(np==SYSEXEC) 9184887Schin type=1+!com[1]; 9194887Schin else 920*8462SApril.Chin@Sun.COM type = (execflg && !shp->subshell && !shp->st.trapcom[0]); 921*8462SApril.Chin@Sun.COM sh_redirect(shp,io,type); 9224887Schin for(item=buff.olist;item;item=item->next) 9234887Schin item->strm=0; 9244887Schin } 9254887Schin if(!(nv_isattr(np,BLT_ENV))) 9264887Schin { 927*8462SApril.Chin@Sun.COM if(bp->nosfio) 928*8462SApril.Chin@Sun.COM { 929*8462SApril.Chin@Sun.COM if(!shp->pwd) 930*8462SApril.Chin@Sun.COM path_pwd(0); 931*8462SApril.Chin@Sun.COM if(shp->pwd) 932*8462SApril.Chin@Sun.COM stat(".",&statb); 933*8462SApril.Chin@Sun.COM } 934*8462SApril.Chin@Sun.COM sfsync(NULL); 9354887Schin share = sfset(sfstdin,SF_SHARE,0); 9364887Schin sh_onstate(SH_STOPOK); 9374887Schin sfpool(sfstderr,NIL(Sfio_t*),SF_WRITE); 9384887Schin sfset(sfstderr,SF_LINE,1); 939*8462SApril.Chin@Sun.COM save_prompt = shp->nextprompt; 940*8462SApril.Chin@Sun.COM shp->nextprompt = 0; 9414887Schin } 9424887Schin if(argp) 9434887Schin { 9444887Schin scope++; 945*8462SApril.Chin@Sun.COM sh_scope(shp,argp,0); 9464887Schin } 9474887Schin opt_info.index = opt_info.offset = 0; 9484887Schin opt_info.disc = 0; 9494887Schin error_info.id = *com; 950*8462SApril.Chin@Sun.COM if(argn) 951*8462SApril.Chin@Sun.COM shp->exitval = 0; 952*8462SApril.Chin@Sun.COM shp->bltinfun = funptr(np); 953*8462SApril.Chin@Sun.COM bp->bnode = np; 954*8462SApril.Chin@Sun.COM bp->vnode = nq; 955*8462SApril.Chin@Sun.COM bp->ptr = nv_context(np); 956*8462SApril.Chin@Sun.COM bp->data = t->com.comstate; 957*8462SApril.Chin@Sun.COM bp->sigset = 0; 958*8462SApril.Chin@Sun.COM bp->notify = 0; 959*8462SApril.Chin@Sun.COM bp->flags = (OPTIMIZE!=0); 960*8462SApril.Chin@Sun.COM if(shp->subshell && nv_isattr(np,BLT_NOSFIO)) 961*8462SApril.Chin@Sun.COM sh_subtmpfile(0); 962*8462SApril.Chin@Sun.COM if(execflg && !shp->subshell && 963*8462SApril.Chin@Sun.COM !shp->st.trapcom[0] && !shp->st.trap[SH_ERRTRAP] && shp->fn_depth==0 && !nv_isattr(np,BLT_ENV)) 9644887Schin { 9654887Schin /* do close-on-exec */ 9664887Schin int fd; 967*8462SApril.Chin@Sun.COM for(fd=0; fd < shp->lim.open_max; fd++) 968*8462SApril.Chin@Sun.COM if((shp->fdstatus[fd]&IOCLEX)&&fd!=shp->infd) 9694887Schin sh_close(fd); 9704887Schin } 971*8462SApril.Chin@Sun.COM if(argn) 972*8462SApril.Chin@Sun.COM shp->exitval = (*shp->bltinfun)(argn,com,(void*)bp); 9734887Schin if(error_info.flags&ERROR_INTERACTIVE) 9744887Schin tty_check(ERRIO); 975*8462SApril.Chin@Sun.COM ((Shnode_t*)t)->com.comstate = shp->bltindata.data; 976*8462SApril.Chin@Sun.COM bp->data = (void*)save_data; 977*8462SApril.Chin@Sun.COM if(!nv_isattr(np,BLT_EXIT) && shp->exitval!=SH_RUNPROG) 978*8462SApril.Chin@Sun.COM shp->exitval &= SH_EXITMASK; 9794887Schin } 9804887Schin else 9814887Schin { 9824887Schin struct openlist *item; 9834887Schin for(item=buff.olist;item;item=item->next) 9844887Schin { 9854887Schin if(item->strm) 9864887Schin { 9874887Schin sfclrlock(item->strm); 988*8462SApril.Chin@Sun.COM if(shp->hist_ptr && item->strm == shp->hist_ptr->histfp) 989*8462SApril.Chin@Sun.COM hist_close(shp->hist_ptr); 9904887Schin else 9914887Schin sfclose(item->strm); 9924887Schin } 9934887Schin } 994*8462SApril.Chin@Sun.COM if(shp->bltinfun && (error_info.flags&ERROR_NOTIFY)) 995*8462SApril.Chin@Sun.COM (*shp->bltinfun)(-2,com,(void*)bp); 9964887Schin /* failure on special built-ins fatal */ 9974887Schin if(jmpval<=SH_JMPCMD && (!nv_isattr(np,BLT_SPC) || command)) 9984887Schin jmpval=0; 9994887Schin } 1000*8462SApril.Chin@Sun.COM if(bp && bp->ptr!= nv_context(np)) 1001*8462SApril.Chin@Sun.COM np->nvfun = (Namfun_t*)bp->ptr; 10024887Schin if(!(nv_isattr(np,BLT_ENV))) 10034887Schin { 1004*8462SApril.Chin@Sun.COM if(bp->nosfio && shp->pwd) 10054887Schin { 10064887Schin struct stat stata; 10074887Schin stat(".",&stata); 10084887Schin /* restore directory changed */ 10094887Schin if(statb.st_ino!=stata.st_ino || statb.st_dev!=stata.st_dev) 1010*8462SApril.Chin@Sun.COM chdir(shp->pwd); 10114887Schin } 10124887Schin sh_offstate(SH_STOPOK); 10134887Schin if(share&SF_SHARE) 10144887Schin sfset(sfstdin,SF_PUBLIC|SF_SHARE,1); 10154887Schin sfset(sfstderr,SF_LINE,0); 1016*8462SApril.Chin@Sun.COM sfpool(sfstderr,shp->outpool,SF_WRITE); 10174887Schin sfpool(sfstdin,NIL(Sfio_t*),SF_WRITE); 1018*8462SApril.Chin@Sun.COM shp->nextprompt = save_prompt; 10194887Schin } 10204887Schin sh_popcontext(&buff); 10214887Schin errorpop(&buff.err); 10224887Schin error_info.flags &= ~ERROR_SILENT; 1023*8462SApril.Chin@Sun.COM shp->bltinfun = 0; 10244887Schin if(buff.olist) 10254887Schin free_list(buff.olist); 10264887Schin if(was_vi) 10274887Schin sh_onoption(SH_VI); 10284887Schin else if(was_emacs) 10294887Schin sh_onoption(SH_EMACS); 10304887Schin else if(was_gmacs) 10314887Schin sh_onoption(SH_GMACS); 10324887Schin if(scope) 1033*8462SApril.Chin@Sun.COM sh_unscope(shp); 1034*8462SApril.Chin@Sun.COM bp->ptr = (void*)save_ptr; 1035*8462SApril.Chin@Sun.COM bp->data = (void*)save_data; 10364887Schin /* don't restore for subshell exec */ 1037*8462SApril.Chin@Sun.COM if((shp->topfd>topfd) && !(shp->subshell && np==SYSEXEC)) 1038*8462SApril.Chin@Sun.COM sh_iorestore(shp,topfd,jmpval); 10394887Schin if(jmpval) 1040*8462SApril.Chin@Sun.COM siglongjmp(*shp->jmplist,jmpval); 1041*8462SApril.Chin@Sun.COM #if 0 1042*8462SApril.Chin@Sun.COM if(flgs&NV_STATIC) 1043*8462SApril.Chin@Sun.COM ((Shnode_t*)t)->com.comset = 0; 1044*8462SApril.Chin@Sun.COM #endif 1045*8462SApril.Chin@Sun.COM if(shp->exitval >=0) 10464887Schin goto setexit; 10474887Schin np = 0; 10484887Schin type=0; 10494887Schin } 10504887Schin /* check for functions */ 10514887Schin if(!command && np && nv_isattr(np,NV_FUNCTION)) 10524887Schin { 1053*8462SApril.Chin@Sun.COM volatile int indx; 1054*8462SApril.Chin@Sun.COM int jmpval=0; 10554887Schin struct checkpt buff; 10564887Schin Namval_t node; 1057*8462SApril.Chin@Sun.COM struct Namref nr; 1058*8462SApril.Chin@Sun.COM long mode; 10594887Schin register struct slnod *slp; 10604887Schin if(!np->nvalue.ip) 10614887Schin { 1062*8462SApril.Chin@Sun.COM indx = path_search(com0,NIL(Pathcomp_t**),0); 10634887Schin if(indx==1) 1064*8462SApril.Chin@Sun.COM np = nv_search(com0,shp->fun_tree,HASH_NOSCOPE); 1065*8462SApril.Chin@Sun.COM 10664887Schin if(!np->nvalue.ip) 10674887Schin { 10684887Schin if(indx==1) 10694887Schin { 10704887Schin errormsg(SH_DICT,ERROR_exit(0),e_defined,com0); 1071*8462SApril.Chin@Sun.COM shp->exitval = ERROR_NOEXEC; 10724887Schin } 10734887Schin else 10744887Schin { 10754887Schin errormsg(SH_DICT,ERROR_exit(0),e_found,"function"); 1076*8462SApril.Chin@Sun.COM shp->exitval = ERROR_NOENT; 10774887Schin } 10784887Schin goto setexit; 10794887Schin } 10804887Schin } 10814887Schin /* increase refcnt for unset */ 10824887Schin slp = (struct slnod*)np->nvenv; 10834887Schin sh_funstaks(slp->slchild,1); 10844887Schin staklink(slp->slptr); 10854887Schin if(nq) 10864887Schin { 1087*8462SApril.Chin@Sun.COM shp->last_table = last_table; 1088*8462SApril.Chin@Sun.COM mode = set_instance(nq,&node,&nr); 10894887Schin } 10904887Schin if(io) 10914887Schin { 1092*8462SApril.Chin@Sun.COM indx = shp->topfd; 10934887Schin sh_pushcontext(&buff,SH_JMPCMD); 10944887Schin jmpval = sigsetjmp(buff.buff,0); 10954887Schin } 10964887Schin if(jmpval == 0) 10974887Schin { 10984887Schin if(io) 1099*8462SApril.Chin@Sun.COM indx = sh_redirect(shp,io,execflg); 1100*8462SApril.Chin@Sun.COM sh_funct(shp,np,argn,com,t->com.comset,(flags&~OPTIMIZE_FLAG)); 11014887Schin } 11024887Schin if(io) 11034887Schin { 11044887Schin if(buff.olist) 11054887Schin free_list(buff.olist); 11064887Schin sh_popcontext(&buff); 1107*8462SApril.Chin@Sun.COM sh_iorestore(shp,indx,jmpval); 11084887Schin } 11094887Schin if(nq) 1110*8462SApril.Chin@Sun.COM unset_instance(nq,&node,&nr,mode); 11114887Schin sh_funstaks(slp->slchild,-1); 11124887Schin stakdelete(slp->slptr); 11134887Schin if(jmpval > SH_JMPFUN) 1114*8462SApril.Chin@Sun.COM siglongjmp(*shp->jmplist,jmpval); 11154887Schin goto setexit; 11164887Schin } 11174887Schin } 11184887Schin else if(!io) 11194887Schin { 11204887Schin setexit: 11214887Schin exitset(); 11224887Schin break; 11234887Schin } 11244887Schin } 11254887Schin case TFORK: 11264887Schin { 11274887Schin register pid_t parent; 11284887Schin int no_fork,jobid; 11294887Schin int pipes[2]; 11304887Schin no_fork = (execflg && !(type&(FAMP|FPOU)) && 1131*8462SApril.Chin@Sun.COM #if SHOPT_AMP || SHOPT_SPAWN 1132*8462SApril.Chin@Sun.COM !ntflag && 1133*8462SApril.Chin@Sun.COM #endif 1134*8462SApril.Chin@Sun.COM !shp->subshell && !shp->st.trapcom[0] && 1135*8462SApril.Chin@Sun.COM !shp->st.trap[SH_ERRTRAP] && shp->fn_depth==0 && 1136*8462SApril.Chin@Sun.COM !(pipejob && sh_isoption(SH_PIPEFAIL))); 1137*8462SApril.Chin@Sun.COM if(shp->subshell) 1138*8462SApril.Chin@Sun.COM sh_subtmpfile(1); 1139*8462SApril.Chin@Sun.COM if(sh_isstate(SH_PROFILE) || shp->dot_depth) 11404887Schin { 11414887Schin /* disable foreground job monitor */ 11424887Schin if(!(type&FAMP)) 11434887Schin sh_offstate(SH_MONITOR); 11444887Schin #if SHOPT_DEVFD 11454887Schin else if(!(type&FINT)) 11464887Schin sh_offstate(SH_MONITOR); 11474887Schin #endif /* SHOPT_DEVFD */ 11484887Schin } 11494887Schin if(no_fork) 11504887Schin job.parent=parent=0; 11514887Schin else 11524887Schin { 11534887Schin if(type&FCOOP) 1154*8462SApril.Chin@Sun.COM coproc_init(shp,pipes); 11554887Schin nv_getval(RANDNOD); 11564887Schin #if SHOPT_AMP 11574887Schin if((type&(FAMP|FINT)) == (FAMP|FINT)) 1158*8462SApril.Chin@Sun.COM parent = sh_ntfork(shp,t,com,&jobid,ntflag); 11594887Schin else 11604887Schin parent = sh_fork(type,&jobid); 11614887Schin if(parent<0) 11624887Schin break; 11634887Schin #else 11644887Schin #if SHOPT_SPAWN 11654887Schin # ifdef _lib_fork 11664887Schin if(com) 1167*8462SApril.Chin@Sun.COM parent = sh_ntfork(shp,t,com,&jobid,ntflag); 11684887Schin else 11694887Schin parent = sh_fork(type,&jobid); 11704887Schin # else 1171*8462SApril.Chin@Sun.COM if((parent = sh_ntfork(shp,t,com,&jobid,ntflag))<=0) 11724887Schin break; 11734887Schin # endif /* _lib_fork */ 11744887Schin if(parent<0) 11754887Schin break; 11764887Schin #else 11774887Schin parent = sh_fork(type,&jobid); 11784887Schin #endif /* SHOPT_SPAWN */ 11794887Schin #endif 11804887Schin } 11814887Schin if(job.parent=parent) 11824887Schin /* This is the parent branch of fork 11834887Schin * It may or may not wait for the child 11844887Schin */ 11854887Schin { 11864887Schin if(type&FPCL) 1187*8462SApril.Chin@Sun.COM sh_close(shp->inpipe[0]); 11884887Schin if(type&(FCOOP|FAMP)) 1189*8462SApril.Chin@Sun.COM shp->bckpid = parent; 1190*8462SApril.Chin@Sun.COM else if(!(type&(FAMP|FPOU))) 11914887Schin { 1192*8462SApril.Chin@Sun.COM if(shp->topfd > topfd) 1193*8462SApril.Chin@Sun.COM sh_iorestore(shp,topfd,0); 1194*8462SApril.Chin@Sun.COM if(!sh_isoption(SH_MONITOR)) 1195*8462SApril.Chin@Sun.COM { 1196*8462SApril.Chin@Sun.COM if(!(shp->sigflag[SIGINT]&(SH_SIGFAULT|SH_SIGOFF))) 1197*8462SApril.Chin@Sun.COM sh_sigtrap(SIGINT); 1198*8462SApril.Chin@Sun.COM shp->trapnote |= SH_SIGIGNORE; 1199*8462SApril.Chin@Sun.COM } 1200*8462SApril.Chin@Sun.COM if(execflg && shp->subshell) 1201*8462SApril.Chin@Sun.COM { 1202*8462SApril.Chin@Sun.COM shp->spid = parent; 1203*8462SApril.Chin@Sun.COM job.pwlist->p_env--; 1204*8462SApril.Chin@Sun.COM } 1205*8462SApril.Chin@Sun.COM else 1206*8462SApril.Chin@Sun.COM job_wait(parent); 1207*8462SApril.Chin@Sun.COM if(!sh_isoption(SH_MONITOR)) 1208*8462SApril.Chin@Sun.COM { 1209*8462SApril.Chin@Sun.COM shp->trapnote &= ~SH_SIGIGNORE; 1210*8462SApril.Chin@Sun.COM if(shp->exitval == (SH_EXITSIG|SIGINT)) 1211*8462SApril.Chin@Sun.COM sh_fault(SIGINT); 1212*8462SApril.Chin@Sun.COM } 12134887Schin } 12144887Schin if(type&FAMP) 12154887Schin { 12164887Schin if(sh_isstate(SH_PROFILE) || sh_isstate(SH_INTERACTIVE)) 12174887Schin { 12184887Schin /* print job number */ 12194887Schin #ifdef JOBS 12204887Schin sfprintf(sfstderr,"[%d]\t%d\n",jobid,parent); 12214887Schin #else 12224887Schin sfprintf(sfstderr,"%d\n",parent); 12234887Schin #endif /* JOBS */ 12244887Schin } 12254887Schin } 12264887Schin break; 12274887Schin } 12284887Schin else 12294887Schin /* 12304887Schin * this is the FORKED branch (child) of execute 12314887Schin */ 12324887Schin { 1233*8462SApril.Chin@Sun.COM volatile int jmpval; 12344887Schin struct checkpt buff; 12354887Schin if(no_fork) 12364887Schin sh_sigreset(2); 12374887Schin sh_pushcontext(&buff,SH_JMPEXIT); 12384887Schin jmpval = sigsetjmp(buff.buff,0); 12394887Schin if(jmpval) 12404887Schin goto done; 12414887Schin if((type&FINT) && !sh_isstate(SH_MONITOR)) 12424887Schin { 12434887Schin /* default std input for & */ 12444887Schin signal(SIGINT,SIG_IGN); 12454887Schin signal(SIGQUIT,SIG_IGN); 1246*8462SApril.Chin@Sun.COM if(!shp->st.ioset) 12474887Schin { 12484887Schin if(sh_close(0)>=0) 12494887Schin sh_chkopen(e_devnull); 12504887Schin } 12514887Schin } 12524887Schin sh_offstate(SH_MONITOR); 12534887Schin /* pipe in or out */ 12544887Schin #ifdef _lib_nice 12554887Schin if((type&FAMP) && sh_isoption(SH_BGNICE)) 12564887Schin nice(4); 12574887Schin #endif /* _lib_nice */ 12584887Schin if(type&FPIN) 12594887Schin { 1260*8462SApril.Chin@Sun.COM sh_iorenumber(shp,shp->inpipe[0],0); 12614887Schin if(!(type&FPOU) || (type&FCOOP)) 1262*8462SApril.Chin@Sun.COM sh_close(shp->inpipe[1]); 12634887Schin } 12644887Schin if(type&FPOU) 12654887Schin { 1266*8462SApril.Chin@Sun.COM sh_iorenumber(shp,shp->outpipe[1],1); 1267*8462SApril.Chin@Sun.COM sh_pclose(shp->outpipe); 12684887Schin } 12694887Schin if((type&COMMSK)!=TCOM) 1270*8462SApril.Chin@Sun.COM error_info.line = t->fork.forkline-shp->st.firstline; 1271*8462SApril.Chin@Sun.COM if(shp->topfd) 1272*8462SApril.Chin@Sun.COM sh_iounsave(shp); 1273*8462SApril.Chin@Sun.COM topfd = shp->topfd; 1274*8462SApril.Chin@Sun.COM sh_redirect(shp,t->tre.treio,1); 1275*8462SApril.Chin@Sun.COM if(shp->topfd > topfd) 1276*8462SApril.Chin@Sun.COM { 1277*8462SApril.Chin@Sun.COM while((parent = vfork()) < 0) 1278*8462SApril.Chin@Sun.COM _sh_fork(parent, 0, (int*)0); 1279*8462SApril.Chin@Sun.COM if(parent) 1280*8462SApril.Chin@Sun.COM { 1281*8462SApril.Chin@Sun.COM job_clear(); 1282*8462SApril.Chin@Sun.COM job_post(parent,0); 1283*8462SApril.Chin@Sun.COM job_wait(parent); 1284*8462SApril.Chin@Sun.COM sh_iorestore(shp,topfd,SH_JMPCMD); 1285*8462SApril.Chin@Sun.COM sh_done(shp,(shp->exitval&SH_EXITSIG)?(shp->exitval&SH_EXITMASK):0); 1286*8462SApril.Chin@Sun.COM 1287*8462SApril.Chin@Sun.COM } 1288*8462SApril.Chin@Sun.COM } 12894887Schin if((type&COMMSK)!=TCOM) 12904887Schin { 12914887Schin /* don't clear job table for out 12924887Schin pipes so that jobs comand can 12934887Schin be used in a pipeline 12944887Schin */ 12954887Schin if(!no_fork && !(type&FPOU)) 12964887Schin job_clear(); 12974887Schin sh_exec(t->fork.forktre,flags|sh_state(SH_NOFORK)); 12984887Schin } 12994887Schin else if(com0) 13004887Schin { 13014887Schin sh_offoption(SH_ERREXIT); 1302*8462SApril.Chin@Sun.COM sh_freeup(shp); 13034887Schin path_exec(com0,com,t->com.comset); 13044887Schin } 13054887Schin done: 13064887Schin sh_popcontext(&buff); 13074887Schin if(jmpval>SH_JMPEXIT) 1308*8462SApril.Chin@Sun.COM siglongjmp(*shp->jmplist,jmpval); 1309*8462SApril.Chin@Sun.COM sh_done(shp,0); 13104887Schin } 13114887Schin } 13124887Schin 13134887Schin case TSETIO: 13144887Schin { 13154887Schin /* 13164887Schin * don't create a new process, just 13174887Schin * save and restore io-streams 13184887Schin */ 13194887Schin pid_t pid; 13204887Schin int jmpval, waitall; 13214887Schin struct checkpt buff; 1322*8462SApril.Chin@Sun.COM if(shp->subshell) 13234887Schin execflg = 0; 13244887Schin sh_pushcontext(&buff,SH_JMPIO); 13254887Schin if(type&FPIN) 13264887Schin { 13274887Schin was_interactive = sh_isstate(SH_INTERACTIVE); 13284887Schin sh_offstate(SH_INTERACTIVE); 13294887Schin if(!execflg) 1330*8462SApril.Chin@Sun.COM sh_iosave(shp,0,shp->topfd,(char*)0); 1331*8462SApril.Chin@Sun.COM sh_iorenumber(shp,shp->inpipe[0],0); 13324887Schin /* 13334887Schin * if read end of pipe is a simple command 13344887Schin * treat as non-sharable to improve performance 13354887Schin */ 13364887Schin if((t->fork.forktre->tre.tretyp&COMMSK)==TCOM) 13374887Schin sfset(sfstdin,SF_PUBLIC|SF_SHARE,0); 13384887Schin waitall = job.waitall; 13394887Schin job.waitall = 0; 13404887Schin pid = job.parent; 13414887Schin } 13424887Schin else 1343*8462SApril.Chin@Sun.COM error_info.line = t->fork.forkline-shp->st.firstline; 13444887Schin jmpval = sigsetjmp(buff.buff,0); 13454887Schin if(jmpval==0) 13464887Schin { 1347*8462SApril.Chin@Sun.COM sh_redirect(shp,t->fork.forkio,execflg); 13484887Schin (t->fork.forktre)->tre.tretyp |= t->tre.tretyp&FSHOWME; 13494887Schin sh_exec(t->fork.forktre,flags); 13504887Schin } 1351*8462SApril.Chin@Sun.COM else 1352*8462SApril.Chin@Sun.COM sfsync(shp->outpool); 13534887Schin sh_popcontext(&buff); 1354*8462SApril.Chin@Sun.COM sh_iorestore(shp,buff.topfd,jmpval); 13554887Schin if(buff.olist) 13564887Schin free_list(buff.olist); 13574887Schin if(type&FPIN) 13584887Schin { 13594887Schin job.waitall = waitall; 1360*8462SApril.Chin@Sun.COM type = shp->exitval; 13614887Schin if(!(type&SH_EXITSIG)) 13624887Schin { 13634887Schin /* wait for remainder of pipline */ 13644887Schin job_wait(waitall?pid:0); 13654887Schin if(type || !sh_isoption(SH_PIPEFAIL)) 1366*8462SApril.Chin@Sun.COM shp->exitval = type; 13674887Schin } 1368*8462SApril.Chin@Sun.COM shp->st.ioset = 0; 13694887Schin } 13704887Schin if(jmpval>SH_JMPIO) 1371*8462SApril.Chin@Sun.COM siglongjmp(*shp->jmplist,jmpval); 13724887Schin break; 13734887Schin } 13744887Schin 13754887Schin case TPAR: 13764887Schin echeck = 1; 13774887Schin flags &= ~OPTIMIZE_FLAG; 1378*8462SApril.Chin@Sun.COM if(!shp->subshell && !shp->st.trapcom[0] && !shp->st.trap[SH_ERRTRAP] && (flags&sh_state(SH_NOFORK))) 13794887Schin { 13804887Schin int jmpval; 13814887Schin struct checkpt buff; 13824887Schin sh_pushcontext(&buff,SH_JMPEXIT); 13834887Schin jmpval = sigsetjmp(buff.buff,0); 13844887Schin if(jmpval==0) 13854887Schin sh_exec(t->par.partre,flags); 13864887Schin sh_popcontext(&buff); 13874887Schin if(jmpval > SH_JMPEXIT) 1388*8462SApril.Chin@Sun.COM siglongjmp(*shp->jmplist,jmpval); 1389*8462SApril.Chin@Sun.COM sh_done(shp,0); 13904887Schin } 13914887Schin else 13924887Schin sh_subshell(t->par.partre,flags,0); 13934887Schin break; 13944887Schin 13954887Schin case TFIL: 13964887Schin { 13974887Schin /* 13984887Schin * This code sets up a pipe. 13994887Schin * All elements of the pipe are started by the parent. 14004887Schin * The last element executes in current environment 14014887Schin */ 14024887Schin int pvo[2]; /* old pipe for multi-stage */ 14034887Schin int pvn[2]; /* current set up pipe */ 14044887Schin int savepipe = pipejob; 14054887Schin int showme = t->tre.tretyp&FSHOWME; 14064887Schin pid_t savepgid = job.curpgid; 1407*8462SApril.Chin@Sun.COM job.curpgid = 0; 1408*8462SApril.Chin@Sun.COM if(shp->subshell) 1409*8462SApril.Chin@Sun.COM sh_subtmpfile(1); 1410*8462SApril.Chin@Sun.COM shp->inpipe = pvo; 1411*8462SApril.Chin@Sun.COM shp->outpipe = pvn; 14124887Schin pvo[1] = -1; 14134887Schin if(sh_isoption(SH_PIPEFAIL)) 14144887Schin job.waitall = 1; 14154887Schin else 14164887Schin job.waitall |= !pipejob && sh_isstate(SH_MONITOR); 14174887Schin do 14184887Schin { 14194887Schin #if SHOPT_FASTPIPE 1420*8462SApril.Chin@Sun.COM type = pipe_exec(shp,pvn,t->lst.lstlef, errorflg); 14214887Schin #else 14224887Schin /* create the pipe */ 14234887Schin sh_pipe(pvn); 14244887Schin /* execute out part of pipe no wait */ 14254887Schin (t->lst.lstlef)->tre.tretyp |= showme; 14264887Schin type = sh_exec(t->lst.lstlef, errorflg); 14274887Schin #endif /* SHOPT_FASTPIPE */ 14284887Schin pipejob=1; 14294887Schin /* save the pipe stream-ids */ 14304887Schin pvo[0] = pvn[0]; 14314887Schin /* close out-part of pipe */ 14324887Schin sh_close(pvn[1]); 14334887Schin /* pipeline all in one process group */ 14344887Schin t = t->lst.lstrit; 14354887Schin } 14364887Schin /* repeat until end of pipeline */ 14374887Schin while(!type && t->tre.tretyp==TFIL); 1438*8462SApril.Chin@Sun.COM shp->inpipe = pvn; 1439*8462SApril.Chin@Sun.COM shp->outpipe = 0; 14404887Schin if(type == 0) 14414887Schin { 14424887Schin /* 14434887Schin * execute last element of pipeline 14444887Schin * in the current process 14454887Schin */ 14464887Schin ((Shnode_t*)t)->tre.tretyp |= showme; 14474887Schin sh_exec(t,flags); 14484887Schin } 14494887Schin else 14504887Schin /* execution failure, close pipe */ 14514887Schin sh_pclose(pvn); 14524887Schin pipejob = savepipe; 14534887Schin #ifdef SIGTSTP 14544887Schin if(!pipejob && sh_isstate(SH_MONITOR)) 1455*8462SApril.Chin@Sun.COM tcsetpgrp(JOBTTY,shp->pid); 14564887Schin #endif /*SIGTSTP */ 14574887Schin job.curpgid = savepgid; 14584887Schin break; 14594887Schin } 14604887Schin 14614887Schin case TLST: 14624887Schin { 14634887Schin /* a list of commands are executed here */ 14644887Schin do 14654887Schin { 14664887Schin sh_exec(t->lst.lstlef,errorflg|OPTIMIZE); 14674887Schin t = t->lst.lstrit; 14684887Schin } 14694887Schin while(t->tre.tretyp == TLST); 14704887Schin sh_exec(t,flags); 14714887Schin break; 14724887Schin } 14734887Schin 14744887Schin case TAND: 14754887Schin if(type&TTEST) 14764887Schin skipexitset++; 14774887Schin if(sh_exec(t->lst.lstlef,OPTIMIZE)==0) 14784887Schin sh_exec(t->lst.lstrit,flags); 14794887Schin break; 14804887Schin 14814887Schin case TORF: 14824887Schin if(type&TTEST) 14834887Schin skipexitset++; 14844887Schin if(sh_exec(t->lst.lstlef,OPTIMIZE)!=0) 14854887Schin sh_exec(t->lst.lstrit,flags); 14864887Schin break; 14874887Schin 14884887Schin case TFOR: /* for and select */ 14894887Schin { 14904887Schin register char **args; 14914887Schin register int nargs; 14924887Schin register Namval_t *np; 14934887Schin int flag = errorflg|OPTIMIZE_FLAG; 14944887Schin struct dolnod *argsav=0; 14954887Schin struct comnod *tp; 14964887Schin char *cp, *trap, *nullptr = 0; 14974887Schin int nameref, refresh=1; 1498*8462SApril.Chin@Sun.COM char *av[5]; 14994887Schin #if SHOPT_OPTIMIZE 1500*8462SApril.Chin@Sun.COM int jmpval = ((struct checkpt*)shp->jmplist)->mode; 15014887Schin struct checkpt buff; 1502*8462SApril.Chin@Sun.COM void *optlist = shp->optlist; 1503*8462SApril.Chin@Sun.COM shp->optlist = 0; 15044887Schin sh_tclear(t->for_.fortre); 15054887Schin sh_pushcontext(&buff,jmpval); 15064887Schin jmpval = sigsetjmp(buff.buff,0); 15074887Schin if(jmpval) 15084887Schin goto endfor; 15094887Schin #endif /* SHOPT_OPTIMIZE */ 1510*8462SApril.Chin@Sun.COM error_info.line = t->for_.forline-shp->st.firstline; 15114887Schin if(!(tp=t->for_.forlst)) 15124887Schin { 1513*8462SApril.Chin@Sun.COM args=shp->st.dolv+1; 1514*8462SApril.Chin@Sun.COM nargs = shp->st.dolc; 1515*8462SApril.Chin@Sun.COM argsav=sh_arguse(shp); 15164887Schin } 15174887Schin else 15184887Schin { 1519*8462SApril.Chin@Sun.COM args=sh_argbuild(shp,&argn,tp,0); 15204887Schin nargs = argn; 15214887Schin } 1522*8462SApril.Chin@Sun.COM np = nv_open(t->for_.fornam, shp->var_tree,NV_NOASSIGN|NV_NOARRAY|NV_VARNAME|NV_NOREF); 15234887Schin nameref = nv_isref(np)!=0; 1524*8462SApril.Chin@Sun.COM shp->st.loopcnt++; 15254887Schin cp = *args; 1526*8462SApril.Chin@Sun.COM while(cp && shp->st.execbrk==0) 15274887Schin { 15284887Schin if(t->tre.tretyp&COMSCAN) 15294887Schin { 15304887Schin char *val; 15314887Schin int save_prompt; 15324887Schin /* reuse register */ 15334887Schin if(refresh) 15344887Schin { 15354887Schin sh_menu(sfstderr,nargs,args); 15364887Schin refresh = 0; 15374887Schin } 1538*8462SApril.Chin@Sun.COM save_prompt = shp->nextprompt; 1539*8462SApril.Chin@Sun.COM shp->nextprompt = 3; 1540*8462SApril.Chin@Sun.COM shp->timeout = 0; 1541*8462SApril.Chin@Sun.COM shp->exitval=sh_readline(shp,&nullptr,0,1,1000*shp->st.tmout); 1542*8462SApril.Chin@Sun.COM shp->nextprompt = save_prompt; 1543*8462SApril.Chin@Sun.COM if(shp->exitval||sfeof(sfstdin)||sferror(sfstdin)) 15444887Schin { 1545*8462SApril.Chin@Sun.COM shp->exitval = 1; 15464887Schin break; 15474887Schin } 1548*8462SApril.Chin@Sun.COM if(!(val=nv_getval(sh_scoped(shp,REPLYNOD)))) 15494887Schin continue; 15504887Schin else 15514887Schin { 15524887Schin if(*(cp=val) == 0) 15534887Schin { 15544887Schin refresh++; 15554887Schin goto check; 15564887Schin } 15574887Schin while(type = *cp++) 15584887Schin if(type < '0' && type > '9') 15594887Schin break; 15604887Schin if(type!=0) 15614887Schin type = nargs; 15624887Schin else 15634887Schin type = (int)strtol(val, (char**)0, 10)-1; 15644887Schin if(type<0 || type >= nargs) 15654887Schin cp = ""; 15664887Schin else 15674887Schin cp = args[type]; 15684887Schin } 15694887Schin } 15704887Schin if(nameref) 15714887Schin nv_offattr(np,NV_REF); 15724887Schin else if(nv_isattr(np, NV_ARRAY)) 15734887Schin nv_putsub(np,NIL(char*),0L); 15744887Schin nv_putval(np,cp,0); 15754887Schin if(nameref) 15764887Schin nv_setref(np,(Dt_t*)0,NV_VARNAME); 1577*8462SApril.Chin@Sun.COM if(trap=shp->st.trap[SH_DEBUGTRAP]) 15784887Schin { 15794887Schin av[0] = (t->tre.tretyp&COMSCAN)?"select":"for"; 15804887Schin av[1] = t->for_.fornam; 1581*8462SApril.Chin@Sun.COM av[2] = "in"; 15824887Schin av[3] = cp; 1583*8462SApril.Chin@Sun.COM av[4] = 0; 1584*8462SApril.Chin@Sun.COM sh_debug(shp,trap,(char*)0,(char*)0,av,0); 15854887Schin } 15864887Schin sh_exec(t->for_.fortre,flag); 15874887Schin flag &= ~OPTIMIZE_FLAG; 15884887Schin if(t->tre.tretyp&COMSCAN) 15894887Schin { 1590*8462SApril.Chin@Sun.COM if((cp=nv_getval(sh_scoped(shp,REPLYNOD))) && *cp==0) 15914887Schin refresh++; 15924887Schin } 15934887Schin else 15944887Schin cp = *++args; 15954887Schin check: 1596*8462SApril.Chin@Sun.COM if(shp->st.breakcnt<0) 1597*8462SApril.Chin@Sun.COM shp->st.execbrk = (++shp->st.breakcnt !=0); 15984887Schin } 15994887Schin #if SHOPT_OPTIMIZE 16004887Schin endfor: 16014887Schin sh_popcontext(&buff); 16024887Schin sh_tclear(t->for_.fortre); 1603*8462SApril.Chin@Sun.COM sh_optclear(shp,optlist); 16044887Schin if(jmpval) 1605*8462SApril.Chin@Sun.COM siglongjmp(*shp->jmplist,jmpval); 16064887Schin #endif /*SHOPT_OPTIMIZE */ 1607*8462SApril.Chin@Sun.COM if(shp->st.breakcnt>0) 1608*8462SApril.Chin@Sun.COM shp->st.execbrk = (--shp->st.breakcnt !=0); 1609*8462SApril.Chin@Sun.COM shp->st.loopcnt--; 1610*8462SApril.Chin@Sun.COM sh_argfree(shp,argsav,0); 16114887Schin nv_close(np); 16124887Schin break; 16134887Schin } 16144887Schin 16154887Schin case TWH: /* while and until */ 16164887Schin { 1617*8462SApril.Chin@Sun.COM volatile int r=0; 16184887Schin int first = OPTIMIZE_FLAG; 16194887Schin Shnode_t *tt = t->wh.whtre; 16204887Schin #if SHOPT_FILESCAN 16214887Schin Sfio_t *iop=0; 16224887Schin int savein,fd; 16234887Schin #endif /*SHOPT_FILESCAN*/ 16244887Schin #if SHOPT_OPTIMIZE 1625*8462SApril.Chin@Sun.COM int jmpval = ((struct checkpt*)shp->jmplist)->mode; 16264887Schin struct checkpt buff; 1627*8462SApril.Chin@Sun.COM void *optlist = shp->optlist; 1628*8462SApril.Chin@Sun.COM shp->optlist = 0; 16294887Schin sh_tclear(t->wh.whtre); 16304887Schin sh_tclear(t->wh.dotre); 16314887Schin sh_pushcontext(&buff,jmpval); 16324887Schin jmpval = sigsetjmp(buff.buff,0); 16334887Schin if(jmpval) 16344887Schin goto endwhile; 16354887Schin #endif /* SHOPT_OPTIMIZE */ 16364887Schin #if SHOPT_FILESCAN 16374887Schin if(type==TWH && tt->tre.tretyp==TCOM && !tt->com.comarg && tt->com.comio) 16384887Schin { 1639*8462SApril.Chin@Sun.COM fd = sh_redirect(shp,tt->com.comio,3); 16404887Schin savein = dup(0); 16414887Schin if(fd==0) 16424887Schin fd = savein; 16434887Schin iop = sfnew(NULL,NULL,SF_UNBOUND,fd,SF_READ); 16444887Schin close(0); 16454887Schin open("/dev/null",O_RDONLY); 1646*8462SApril.Chin@Sun.COM shp->offsets[0] = -1; 1647*8462SApril.Chin@Sun.COM shp->offsets[1] = 0; 16484887Schin if(tt->com.comset) 16494887Schin nv_setlist(tt->com.comset,NV_IDENT|NV_ASSIGN); 16504887Schin } 16514887Schin #endif /*SHOPT_FILESCAN */ 1652*8462SApril.Chin@Sun.COM shp->st.loopcnt++; 1653*8462SApril.Chin@Sun.COM while(shp->st.execbrk==0) 16544887Schin { 16554887Schin #if SHOPT_FILESCAN 16564887Schin if(iop) 16574887Schin { 1658*8462SApril.Chin@Sun.COM if(!(shp->cur_line=sfgetr(iop,'\n',SF_STRING))) 16594887Schin break; 16604887Schin } 16614887Schin else 16624887Schin #endif /*SHOPT_FILESCAN */ 16634887Schin if((sh_exec(tt,first)==0)!=(type==TWH)) 16644887Schin break; 16654887Schin r = sh_exec(t->wh.dotre,first|errorflg); 1666*8462SApril.Chin@Sun.COM if(shp->st.breakcnt<0) 1667*8462SApril.Chin@Sun.COM shp->st.execbrk = (++shp->st.breakcnt !=0); 16684887Schin /* This is for the arithmetic for */ 1669*8462SApril.Chin@Sun.COM if(shp->st.execbrk==0 && t->wh.whinc) 16704887Schin sh_exec((Shnode_t*)t->wh.whinc,first); 16714887Schin first = 0; 16724887Schin errorflg &= ~OPTIMIZE_FLAG; 16734887Schin #if SHOPT_FILESCAN 1674*8462SApril.Chin@Sun.COM shp->offsets[0] = -1; 1675*8462SApril.Chin@Sun.COM shp->offsets[1] = 0; 16764887Schin #endif /*SHOPT_FILESCAN */ 16774887Schin } 16784887Schin #if SHOPT_OPTIMIZE 16794887Schin endwhile: 16804887Schin sh_popcontext(&buff); 16814887Schin sh_tclear(t->wh.whtre); 16824887Schin sh_tclear(t->wh.dotre); 1683*8462SApril.Chin@Sun.COM sh_optclear(shp,optlist); 16844887Schin if(jmpval) 1685*8462SApril.Chin@Sun.COM siglongjmp(*shp->jmplist,jmpval); 16864887Schin #endif /*SHOPT_OPTIMIZE */ 1687*8462SApril.Chin@Sun.COM if(shp->st.breakcnt>0) 1688*8462SApril.Chin@Sun.COM shp->st.execbrk = (--shp->st.breakcnt !=0); 1689*8462SApril.Chin@Sun.COM shp->st.loopcnt--; 1690*8462SApril.Chin@Sun.COM shp->exitval= r; 16914887Schin #if SHOPT_FILESCAN 16924887Schin if(iop) 16934887Schin { 16944887Schin sfclose(iop); 16954887Schin close(0); 16964887Schin dup(savein); 1697*8462SApril.Chin@Sun.COM shp->cur_line = 0; 16984887Schin } 16994887Schin #endif /*SHOPT_FILESCAN */ 17004887Schin break; 17014887Schin } 17024887Schin case TARITH: /* (( expression )) */ 17034887Schin { 17044887Schin register char *trap; 1705*8462SApril.Chin@Sun.COM char *arg[4]; 1706*8462SApril.Chin@Sun.COM error_info.line = t->ar.arline-shp->st.firstline; 1707*8462SApril.Chin@Sun.COM arg[0] = "(("; 17084887Schin if(!(t->ar.arexpr->argflag&ARG_RAW)) 1709*8462SApril.Chin@Sun.COM arg[1] = sh_macpat(shp,t->ar.arexpr,OPTIMIZE|ARG_ARITH); 17104887Schin else 17114887Schin arg[1] = t->ar.arexpr->argval; 1712*8462SApril.Chin@Sun.COM arg[2] = "))"; 1713*8462SApril.Chin@Sun.COM arg[3] = 0; 1714*8462SApril.Chin@Sun.COM if(trap=shp->st.trap[SH_DEBUGTRAP]) 1715*8462SApril.Chin@Sun.COM sh_debug(shp,trap,(char*)0, (char*)0, arg, ARG_ARITH); 17164887Schin if(sh_isoption(SH_XTRACE)) 17174887Schin { 17184887Schin sh_trace(NIL(char**),0); 17194887Schin sfprintf(sfstderr,"((%s))\n",arg[1]); 17204887Schin } 17214887Schin if(t->ar.arcomp) 1722*8462SApril.Chin@Sun.COM shp->exitval = !arith_exec((Arith_t*)t->ar.arcomp); 17234887Schin else 1724*8462SApril.Chin@Sun.COM shp->exitval = !sh_arith(arg[1]); 17254887Schin break; 17264887Schin } 17274887Schin 17284887Schin case TIF: 17294887Schin if(sh_exec(t->if_.iftre,OPTIMIZE)==0) 17304887Schin sh_exec(t->if_.thtre,flags); 17314887Schin else if(t->if_.eltre) 17324887Schin sh_exec(t->if_.eltre, flags); 17334887Schin else 1734*8462SApril.Chin@Sun.COM shp->exitval=0; /* force zero exit for if-then-fi */ 17354887Schin break; 17364887Schin 17374887Schin case TSW: 17384887Schin { 17394887Schin Shnode_t *tt = (Shnode_t*)t; 1740*8462SApril.Chin@Sun.COM char *trap, *r = sh_macpat(shp,tt->sw.swarg,OPTIMIZE); 1741*8462SApril.Chin@Sun.COM error_info.line = t->sw.swline-shp->st.firstline; 17424887Schin t= (Shnode_t*)(tt->sw.swlst); 1743*8462SApril.Chin@Sun.COM if(trap=shp->st.trap[SH_DEBUGTRAP]) 17444887Schin { 1745*8462SApril.Chin@Sun.COM char *av[4]; 1746*8462SApril.Chin@Sun.COM av[0] = "case"; 17474887Schin av[1] = r; 1748*8462SApril.Chin@Sun.COM av[2] = "in"; 1749*8462SApril.Chin@Sun.COM av[3] = 0; 1750*8462SApril.Chin@Sun.COM sh_debug(shp,trap, (char*)0, (char*)0, av, 0); 17514887Schin } 17524887Schin while(t) 17534887Schin { 17544887Schin register struct argnod *rex=(struct argnod*)t->reg.regptr; 17554887Schin while(rex) 17564887Schin { 17574887Schin register char *s; 17584887Schin if(rex->argflag&ARG_MAC) 17594887Schin { 1760*8462SApril.Chin@Sun.COM s = sh_macpat(shp,rex,OPTIMIZE|ARG_EXP); 17614887Schin while(*s=='\\' && s[1]==0) 17624887Schin s+=2; 17634887Schin } 17644887Schin else 17654887Schin s = rex->argval; 17664887Schin type = (rex->argflag&ARG_RAW); 17674887Schin if((type && strcmp(r,s)==0) || 17684887Schin (!type && (strmatch(r,s) 17694887Schin || trim_eq(r,s)))) 17704887Schin { 17714887Schin do sh_exec(t->reg.regcom,(t->reg.regflag?0:flags)); 17724887Schin while(t->reg.regflag && 17734887Schin (t=(Shnode_t*)t->reg.regnxt)); 17744887Schin t=0; 17754887Schin break; 17764887Schin } 17774887Schin else 17784887Schin rex=rex->argnxt.ap; 17794887Schin } 17804887Schin if(t) 17814887Schin t=(Shnode_t*)t->reg.regnxt; 17824887Schin } 17834887Schin break; 17844887Schin } 17854887Schin 17864887Schin case TTIME: 17874887Schin { 17884887Schin /* time the command */ 17894887Schin struct tms before,after; 17904887Schin const char *format = e_timeformat; 17914887Schin clock_t at, tm[3]; 17924887Schin #ifdef timeofday 17934887Schin struct timeval tb,ta; 17944887Schin #else 17954887Schin clock_t bt; 17964887Schin #endif /* timeofday */ 17974887Schin if(type!=TTIME) 17984887Schin { 17994887Schin sh_exec(t->par.partre,OPTIMIZE); 1800*8462SApril.Chin@Sun.COM shp->exitval = !shp->exitval; 18014887Schin break; 18024887Schin } 18034887Schin if(t->par.partre) 18044887Schin { 18054887Schin long timer_on; 18064887Schin timer_on = sh_isstate(SH_TIMING); 18074887Schin #ifdef timeofday 18084887Schin timeofday(&tb); 18094887Schin times(&before); 18104887Schin #else 18114887Schin bt = times(&before); 18124887Schin #endif /* timeofday */ 18134887Schin job.waitall = 1; 18144887Schin sh_onstate(SH_TIMING); 18154887Schin sh_exec(t->par.partre,OPTIMIZE); 18164887Schin if(!timer_on) 18174887Schin sh_offstate(SH_TIMING); 18184887Schin job.waitall = 0; 18194887Schin } 18204887Schin else 18214887Schin { 18224887Schin #ifndef timeofday 18234887Schin bt = 0; 18244887Schin #endif /* timeofday */ 18254887Schin before.tms_utime = before.tms_cutime = 0; 18264887Schin before.tms_stime = before.tms_cstime = 0; 18274887Schin } 18284887Schin #ifdef timeofday 18294887Schin times(&after); 18304887Schin timeofday(&ta); 1831*8462SApril.Chin@Sun.COM at = shp->lim.clk_tck*(ta.tv_sec-tb.tv_sec); 1832*8462SApril.Chin@Sun.COM at += ((shp->lim.clk_tck*(((1000000L/2)/shp->lim.clk_tck)+(ta.tv_usec-tb.tv_usec)))/1000000L); 18334887Schin #else 18344887Schin at = times(&after) - bt; 18354887Schin #endif /* timeofday */ 18364887Schin tm[0] = at; 18374887Schin if(t->par.partre) 18384887Schin { 1839*8462SApril.Chin@Sun.COM Namval_t *np = nv_open("TIMEFORMAT",shp->var_tree,NV_NOADD); 18404887Schin if(np) 18414887Schin { 18424887Schin format = nv_getval(np); 18434887Schin nv_close(np); 18444887Schin } 18454887Schin if(!format) 18464887Schin format = e_timeformat; 18474887Schin } 18484887Schin else 18494887Schin format = strchr(format+1,'\n')+1; 18504887Schin tm[1] = after.tms_utime - before.tms_utime; 18514887Schin tm[1] += after.tms_cutime - before.tms_cutime; 18524887Schin tm[2] = after.tms_stime - before.tms_stime; 18534887Schin tm[2] += after.tms_cstime - before.tms_cstime; 18544887Schin if(format && *format) 1855*8462SApril.Chin@Sun.COM p_time(shp,sfstderr,sh_translate(format),tm); 18564887Schin break; 18574887Schin } 18584887Schin case TFUN: 18594887Schin { 18604887Schin register Namval_t *np; 18614887Schin register struct slnod *slp; 18624887Schin register char *fname = ((struct functnod*)t)->functnam; 18634887Schin register char *cp = strrchr(fname,'.'); 18644887Schin register Namval_t *npv=0; 18654887Schin #if SHOPT_NAMESPACE 18664887Schin if(t->tre.tretyp==TNSPACE) 18674887Schin { 18684887Schin Dt_t *root,*oldroot, *top=0; 1869*8462SApril.Chin@Sun.COM Namval_t *oldnspace = shp->namespace; 1870*8462SApril.Chin@Sun.COM int offset = stktell(stkp); 1871*8462SApril.Chin@Sun.COM long optindex = shp->st.optindex; 18724887Schin if(cp) 18734887Schin errormsg(SH_DICT,ERROR_exit(1),e_ident,fname); 1874*8462SApril.Chin@Sun.COM sfputc(stkp,'.'); 1875*8462SApril.Chin@Sun.COM sfputr(stkp,fname,0); 1876*8462SApril.Chin@Sun.COM np = nv_open(stkptr(stkp,offset),shp->var_base,NV_NOASSIGN|NV_NOARRAY|NV_VARNAME); 1877*8462SApril.Chin@Sun.COM offset = stktell(stkp); 1878*8462SApril.Chin@Sun.COM shp->namespace = np; 18794887Schin if(!(root=nv_dict(np))) 18804887Schin { 18814887Schin root = dtopen(&_Nvdisc,Dtoset); 18824887Schin nv_putval(np,(char*)root,NV_TABLE|NV_NOFREE); 1883*8462SApril.Chin@Sun.COM shp->st.optindex = 1; 18844887Schin } 1885*8462SApril.Chin@Sun.COM if(oldnspace && dtvnext(dtvnext(shp->var_tree))) 1886*8462SApril.Chin@Sun.COM top = dtview(shp->var_tree,0); 1887*8462SApril.Chin@Sun.COM else if(dtvnext(shp->var_tree)) 1888*8462SApril.Chin@Sun.COM top = dtview(shp->var_tree,0); 1889*8462SApril.Chin@Sun.COM oldroot = shp->var_tree; 1890*8462SApril.Chin@Sun.COM dtview(root,shp->var_base); 1891*8462SApril.Chin@Sun.COM shp->var_tree = root; 18924887Schin if(top) 1893*8462SApril.Chin@Sun.COM dtview(shp->var_tree,top); 18944887Schin sh_exec(t->for_.fortre,flags); 1895*8462SApril.Chin@Sun.COM if(dtvnext(shp->var_tree)) 1896*8462SApril.Chin@Sun.COM top = dtview(shp->var_tree,0); 1897*8462SApril.Chin@Sun.COM shp->var_tree = oldroot; 18984887Schin if(top) 1899*8462SApril.Chin@Sun.COM dtview(top,shp->var_tree); 1900*8462SApril.Chin@Sun.COM shp->namespace = oldnspace; 1901*8462SApril.Chin@Sun.COM shp->st.optindex = optindex; 19024887Schin break; 19034887Schin } 19044887Schin #endif /* SHOPT_NAMESPACE */ 19054887Schin /* look for discipline functions */ 1906*8462SApril.Chin@Sun.COM error_info.line = t->funct.functline-shp->st.firstline; 19074887Schin /* Function names cannot be special builtin */ 1908*8462SApril.Chin@Sun.COM if(cp || shp->prefix) 19094887Schin { 1910*8462SApril.Chin@Sun.COM int offset = stktell(stkp); 1911*8462SApril.Chin@Sun.COM if(shp->prefix) 19124887Schin { 1913*8462SApril.Chin@Sun.COM cp = shp->prefix; 1914*8462SApril.Chin@Sun.COM shp->prefix = 0; 1915*8462SApril.Chin@Sun.COM npv = nv_open(cp,shp->var_tree,NV_NOASSIGN|NV_NOARRAY|NV_VARNAME); 1916*8462SApril.Chin@Sun.COM shp->prefix = cp; 19174887Schin cp = fname; 19184887Schin } 19194887Schin else 19204887Schin { 1921*8462SApril.Chin@Sun.COM sfwrite(stkp,fname,cp++-fname); 1922*8462SApril.Chin@Sun.COM sfputc(stkp,0); 1923*8462SApril.Chin@Sun.COM npv = nv_open(stkptr(stkp,offset),shp->var_tree,NV_NOASSIGN|NV_NOARRAY|NV_VARNAME); 19244887Schin } 1925*8462SApril.Chin@Sun.COM offset = stktell(stkp); 1926*8462SApril.Chin@Sun.COM sfprintf(stkp,"%s.%s%c",nv_name(npv),cp,0); 1927*8462SApril.Chin@Sun.COM fname = stkptr(stkp,offset); 19284887Schin } 1929*8462SApril.Chin@Sun.COM else if((np=nv_search(fname,shp->bltin_tree,0)) && nv_isattr(np,BLT_SPC)) 19304887Schin errormsg(SH_DICT,ERROR_exit(1),e_badfun,fname); 19314887Schin #if SHOPT_NAMESPACE 1932*8462SApril.Chin@Sun.COM else if(shp->namespace) 19334887Schin { 1934*8462SApril.Chin@Sun.COM int offset = stktell(stkp); 1935*8462SApril.Chin@Sun.COM sfputr(stkp,nv_name(shp->namespace),-1); 1936*8462SApril.Chin@Sun.COM sfputc(stkp,'.'); 1937*8462SApril.Chin@Sun.COM sfputr(stkp,fname,0); 1938*8462SApril.Chin@Sun.COM fname = stkptr(stkp,offset); 19394887Schin } 19404887Schin #endif /* SHOPT_NAMESPACE */ 19414887Schin np = nv_open(fname,sh_subfuntree(1),NV_NOASSIGN|NV_NOARRAY|NV_VARNAME|NV_NOSCOPE); 19424887Schin if(npv) 19434887Schin { 1944*8462SApril.Chin@Sun.COM Namval_t *tp = npv; 1945*8462SApril.Chin@Sun.COM if(!shp->mktype) 1946*8462SApril.Chin@Sun.COM { 1947*8462SApril.Chin@Sun.COM if(shp->typeinit) 1948*8462SApril.Chin@Sun.COM { 1949*8462SApril.Chin@Sun.COM if(tp=nv_open(shp->typeinit->nvname,shp->typedict,NV_IDENT|NV_NOFAIL)) 1950*8462SApril.Chin@Sun.COM nv_close(npv); 1951*8462SApril.Chin@Sun.COM else 1952*8462SApril.Chin@Sun.COM tp = npv; 1953*8462SApril.Chin@Sun.COM } 1954*8462SApril.Chin@Sun.COM cp = nv_setdisc(tp,cp,np,(Namfun_t*)tp); 1955*8462SApril.Chin@Sun.COM } 1956*8462SApril.Chin@Sun.COM nv_close(tp); 19574887Schin if(!cp) 19584887Schin errormsg(SH_DICT,ERROR_exit(1),e_baddisc,fname); 19594887Schin } 19604887Schin if(np->nvalue.rp) 19614887Schin { 19624887Schin slp = (struct slnod*)np->nvenv; 19634887Schin sh_funstaks(slp->slchild,-1); 19644887Schin stakdelete(slp->slptr); 1965*8462SApril.Chin@Sun.COM if(shp->funload) 1966*8462SApril.Chin@Sun.COM { 1967*8462SApril.Chin@Sun.COM free((void*)np->nvalue.rp); 1968*8462SApril.Chin@Sun.COM np->nvalue.rp = 0; 1969*8462SApril.Chin@Sun.COM } 1970*8462SApril.Chin@Sun.COM 19714887Schin } 1972*8462SApril.Chin@Sun.COM if(!np->nvalue.rp) 1973*8462SApril.Chin@Sun.COM { 1974*8462SApril.Chin@Sun.COM np->nvalue.rp = new_of(struct Ufunction,shp->funload?sizeof(Dtlink_t):0); 1975*8462SApril.Chin@Sun.COM memset((void*)np->nvalue.rp,0,sizeof(struct Ufunction)); 1976*8462SApril.Chin@Sun.COM } 19774887Schin if(t->funct.functstak) 19784887Schin { 1979*8462SApril.Chin@Sun.COM static Dtdisc_t _Rpdisc = 1980*8462SApril.Chin@Sun.COM { 1981*8462SApril.Chin@Sun.COM offsetof(struct Ufunction,fname), -1, sizeof(struct Ufunction) 1982*8462SApril.Chin@Sun.COM }; 19834887Schin struct functnod *fp; 19844887Schin slp = t->funct.functstak; 19854887Schin sh_funstaks(slp->slchild,1); 19864887Schin staklink(slp->slptr); 19874887Schin np->nvenv = (char*)slp; 19884887Schin nv_funtree(np) = (int*)(t->funct.functtre); 19894887Schin np->nvalue.rp->hoffset = t->funct.functloc; 19904887Schin np->nvalue.rp->lineno = t->funct.functline; 1991*8462SApril.Chin@Sun.COM np->nvalue.rp->nspace = shp->namespace; 19924887Schin np->nvalue.rp->fname = 0; 1993*8462SApril.Chin@Sun.COM np->nvalue.rp->fdict = shp->fun_tree; 19944887Schin fp = (struct functnod*)(slp+1); 19954887Schin if(fp->functtyp==(TFUN|FAMP)) 19964887Schin np->nvalue.rp->fname = fp->functnam; 19974887Schin nv_setsize(np,fp->functline); 19984887Schin nv_offattr(np,NV_FPOSIX); 1999*8462SApril.Chin@Sun.COM if(shp->funload) 2000*8462SApril.Chin@Sun.COM { 2001*8462SApril.Chin@Sun.COM struct Ufunction *rp = np->nvalue.rp; 2002*8462SApril.Chin@Sun.COM rp->np = np; 2003*8462SApril.Chin@Sun.COM if(!shp->fpathdict) 2004*8462SApril.Chin@Sun.COM shp->fpathdict = dtopen(&_Rpdisc,Dtbag); 2005*8462SApril.Chin@Sun.COM if(shp->fpathdict) 2006*8462SApril.Chin@Sun.COM dtinsert(shp->fpathdict,rp); 2007*8462SApril.Chin@Sun.COM } 20084887Schin } 20094887Schin else 20104887Schin nv_unset(np); 20114887Schin if(type&FPOSIX) 20124887Schin nv_onattr(np,NV_FUNCTION|NV_FPOSIX); 20134887Schin else 20144887Schin nv_onattr(np,NV_FUNCTION); 20154887Schin if(type&FPIN) 20164887Schin nv_onattr(np,NV_FTMP); 2017*8462SApril.Chin@Sun.COM if(type&FOPTGET) 2018*8462SApril.Chin@Sun.COM nv_onattr(np,NV_OPTGET); 20194887Schin break; 20204887Schin } 20214887Schin 20224887Schin /* new test compound command */ 20234887Schin case TTST: 20244887Schin { 20254887Schin register int n; 20264887Schin register char *left; 20274887Schin int negate = (type&TNEGATE)!=0; 20284887Schin if(type&TTEST) 20294887Schin skipexitset++; 2030*8462SApril.Chin@Sun.COM error_info.line = t->tst.tstline-shp->st.firstline; 20314887Schin echeck = 1; 20324887Schin if((type&TPAREN)==TPAREN) 20334887Schin { 20344887Schin sh_exec(t->lst.lstlef,OPTIMIZE); 2035*8462SApril.Chin@Sun.COM n = !shp->exitval; 20364887Schin } 20374887Schin else 20384887Schin { 20394887Schin register int traceon=0; 20404887Schin register char *right; 20414887Schin register char *trap; 20424887Schin char *argv[6]; 20434887Schin n = type>>TSHIFT; 2044*8462SApril.Chin@Sun.COM left = sh_macpat(shp,&(t->lst.lstlef->arg),OPTIMIZE); 20454887Schin if(type&TBINARY) 2046*8462SApril.Chin@Sun.COM right = sh_macpat(shp,&(t->lst.lstrit->arg),((n==TEST_PEQ||n==TEST_PNE)?ARG_EXP:0)|OPTIMIZE); 2047*8462SApril.Chin@Sun.COM if(trap=shp->st.trap[SH_DEBUGTRAP]) 20484887Schin argv[0] = (type&TNEGATE)?((char*)e_tstbegin):"[["; 20494887Schin if(sh_isoption(SH_XTRACE)) 20504887Schin { 20514887Schin traceon = sh_trace(NIL(char**),0); 20524887Schin sfwrite(sfstderr,e_tstbegin,(type&TNEGATE?5:3)); 20534887Schin } 20544887Schin if(type&TUNARY) 20554887Schin { 20564887Schin if(traceon) 20574887Schin sfprintf(sfstderr,"-%c %s",n,sh_fmtq(left)); 20584887Schin if(trap) 20594887Schin { 20604887Schin char unop[3]; 20614887Schin unop[0] = '-'; 20624887Schin unop[1] = n; 20634887Schin unop[2] = 0; 20644887Schin argv[1] = unop; 20654887Schin argv[2] = left; 20664887Schin argv[3] = "]]"; 20674887Schin argv[4] = 0; 2068*8462SApril.Chin@Sun.COM sh_debug(shp,trap,(char*)0,(char*)0,argv, 0); 20694887Schin } 20704887Schin n = test_unop(n,left); 20714887Schin } 20724887Schin else if(type&TBINARY) 20734887Schin { 20744887Schin char *op; 20754887Schin int pattern = 0; 20764887Schin if(trap || traceon) 20774887Schin op = (char*)(shtab_testops+(n&037)-1)->sh_name; 20784887Schin type >>= TSHIFT; 20794887Schin if(type==TEST_PEQ || type==TEST_PNE) 20804887Schin pattern=ARG_EXP; 20814887Schin if(trap) 20824887Schin { 20834887Schin argv[1] = left; 20844887Schin argv[2] = op; 20854887Schin argv[3] = right; 20864887Schin argv[4] = "]]"; 20874887Schin argv[5] = 0; 2088*8462SApril.Chin@Sun.COM sh_debug(shp,trap,(char*)0,(char*)0,argv, pattern); 20894887Schin } 20904887Schin n = test_binop(n,left,right); 20914887Schin if(traceon) 20924887Schin { 20934887Schin sfprintf(sfstderr,"%s %s ",sh_fmtq(left),op); 20944887Schin if(pattern) 20954887Schin out_pattern(sfstderr,right,-1); 20964887Schin else 20974887Schin sfputr(sfstderr,sh_fmtq(right),-1); 20984887Schin } 20994887Schin } 21004887Schin if(traceon) 21014887Schin sfwrite(sfstderr,e_tstend,4); 21024887Schin } 2103*8462SApril.Chin@Sun.COM shp->exitval = ((!n)^negate); 21044887Schin if(!skipexitset) 21054887Schin exitset(); 21064887Schin break; 21074887Schin } 21084887Schin } 2109*8462SApril.Chin@Sun.COM if(shp->trapnote || (shp->exitval && sh_isstate(SH_ERREXIT)) && 21104887Schin t && echeck) 21114887Schin sh_chktrap(); 21124887Schin /* set $_ */ 21134887Schin if(mainloop && com0) 21144887Schin { 21154887Schin /* store last argument here if it fits */ 21164887Schin static char lastarg[32]; 21174887Schin if(sh_isstate(SH_FORKED)) 2118*8462SApril.Chin@Sun.COM sh_done(shp,0); 2119*8462SApril.Chin@Sun.COM if(shp->lastarg!= lastarg && shp->lastarg) 2120*8462SApril.Chin@Sun.COM free(shp->lastarg); 2121*8462SApril.Chin@Sun.COM if(strlen(comn) < sizeof(lastarg)) 21224887Schin { 21234887Schin nv_onattr(L_ARGNOD,NV_NOFREE); 2124*8462SApril.Chin@Sun.COM shp->lastarg = strcpy(lastarg,comn); 21254887Schin } 21264887Schin else 21274887Schin { 21284887Schin nv_offattr(L_ARGNOD,NV_NOFREE); 2129*8462SApril.Chin@Sun.COM shp->lastarg = strdup(comn); 21304887Schin } 21314887Schin } 21324887Schin if(!skipexitset) 21334887Schin exitset(); 21344887Schin if(!(OPTIMIZE)) 21354887Schin { 2136*8462SApril.Chin@Sun.COM if(sav != stkptr(stkp,0)) 2137*8462SApril.Chin@Sun.COM stkset(stkp,sav,0); 2138*8462SApril.Chin@Sun.COM else if(stktell(stkp)) 2139*8462SApril.Chin@Sun.COM stkseek(stkp,0); 21404887Schin } 2141*8462SApril.Chin@Sun.COM if(shp->trapnote&SH_SIGSET) 2142*8462SApril.Chin@Sun.COM sh_exit(SH_EXITSIG|shp->lastsig); 21434887Schin if(was_interactive) 21444887Schin sh_onstate(SH_INTERACTIVE); 21454887Schin if(was_monitor && sh_isoption(SH_MONITOR)) 21464887Schin sh_onstate(SH_MONITOR); 21474887Schin if(was_errexit) 21484887Schin sh_onstate(SH_ERREXIT); 21494887Schin } 2150*8462SApril.Chin@Sun.COM return(shp->exitval); 2151*8462SApril.Chin@Sun.COM } 2152*8462SApril.Chin@Sun.COM 2153*8462SApril.Chin@Sun.COM int sh_run(int argn, char *argv[]) 2154*8462SApril.Chin@Sun.COM { 2155*8462SApril.Chin@Sun.COM register struct dolnod *dp; 2156*8462SApril.Chin@Sun.COM register struct comnod *t = (struct comnod*)stakalloc(sizeof(struct comnod)); 2157*8462SApril.Chin@Sun.COM int savtop = staktell(); 2158*8462SApril.Chin@Sun.COM char *savptr = stakfreeze(0); 2159*8462SApril.Chin@Sun.COM Opt_t *op, *np = optctx(0, 0); 2160*8462SApril.Chin@Sun.COM Shbltin_t bltindata; 2161*8462SApril.Chin@Sun.COM bltindata = sh.bltindata; 2162*8462SApril.Chin@Sun.COM op = optctx(np, 0); 2163*8462SApril.Chin@Sun.COM memset(t, 0, sizeof(struct comnod)); 2164*8462SApril.Chin@Sun.COM dp = (struct dolnod*)stakalloc((unsigned)sizeof(struct dolnod) + ARG_SPARE*sizeof(char*) + argn*sizeof(char*)); 2165*8462SApril.Chin@Sun.COM dp->dolnum = argn; 2166*8462SApril.Chin@Sun.COM dp->dolbot = ARG_SPARE; 2167*8462SApril.Chin@Sun.COM memcpy(dp->dolval+ARG_SPARE, argv, (argn+1)*sizeof(char*)); 2168*8462SApril.Chin@Sun.COM t->comarg = (struct argnod*)dp; 2169*8462SApril.Chin@Sun.COM if(!strchr(argv[0],'/')) 2170*8462SApril.Chin@Sun.COM t->comnamp = (void*)nv_bfsearch(argv[0],sh.fun_tree,(Namval_t**)&t->comnamq,(char**)0); 2171*8462SApril.Chin@Sun.COM argn=sh_exec((Shnode_t*)t,sh_isstate(SH_ERREXIT)); 2172*8462SApril.Chin@Sun.COM optctx(op,np); 2173*8462SApril.Chin@Sun.COM sh.bltindata = bltindata; 2174*8462SApril.Chin@Sun.COM if(savptr!=stakptr(0)) 2175*8462SApril.Chin@Sun.COM stakset(savptr,savtop); 2176*8462SApril.Chin@Sun.COM else 2177*8462SApril.Chin@Sun.COM stakseek(savtop); 2178*8462SApril.Chin@Sun.COM return(argn); 21794887Schin } 21804887Schin 21814887Schin /* 21824887Schin * test for equality with second argument trimmed 21834887Schin * returns 1 if r == trim(s) otherwise 0 21844887Schin */ 21854887Schin 21864887Schin static int trim_eq(register const char *r,register const char *s) 21874887Schin { 21884887Schin register char c; 21894887Schin while(c = *s++) 21904887Schin { 21914887Schin if(c=='\\') 21924887Schin c = *s++; 21934887Schin if(c && c != *r++) 21944887Schin return(0); 21954887Schin } 21964887Schin return(*r==0); 21974887Schin } 21984887Schin 21994887Schin /* 22004887Schin * print out the command line if set -x is on 22014887Schin */ 22024887Schin 22034887Schin int sh_trace(register char *argv[], register int nl) 22044887Schin { 2205*8462SApril.Chin@Sun.COM Shell_t *shp = &sh; 22064887Schin register char *cp; 22074887Schin register int bracket = 0; 2208*8462SApril.Chin@Sun.COM int decl = (nl&2); 2209*8462SApril.Chin@Sun.COM nl &= ~2; 22104887Schin if(sh_isoption(SH_XTRACE)) 22114887Schin { 22124887Schin /* make this trace atomic */ 22134887Schin sfset(sfstderr,SF_SHARE|SF_PUBLIC,0); 2214*8462SApril.Chin@Sun.COM if(!(cp=nv_getval(sh_scoped(shp,PS4NOD)))) 22154887Schin cp = "+ "; 22164887Schin else 22174887Schin { 22184887Schin sh_offoption(SH_XTRACE); 2219*8462SApril.Chin@Sun.COM cp = sh_mactry(shp,cp); 22204887Schin sh_onoption(SH_XTRACE); 22214887Schin } 22224887Schin if(*cp) 22234887Schin sfputr(sfstderr,cp,-1); 22244887Schin if(argv) 22254887Schin { 22264887Schin char *argv0 = *argv; 22274887Schin nl = (nl?'\n':-1); 22284887Schin /* don't quote [ and [[ */ 22294887Schin if(*(cp=argv[0])=='[' && (!cp[1] || !cp[2]&&cp[1]=='[')) 22304887Schin { 22314887Schin sfputr(sfstderr,cp,*++argv?' ':nl); 22324887Schin bracket = 1; 22334887Schin } 22344887Schin while(cp = *argv++) 22354887Schin { 22364887Schin if(bracket==0 || *argv || *cp!=']') 22374887Schin cp = sh_fmtq(cp); 2238*8462SApril.Chin@Sun.COM if(decl && shp->prefix && cp!=argv0 && *cp!='-') 22394887Schin { 22404887Schin if(*cp=='.' && cp[1]==0) 2241*8462SApril.Chin@Sun.COM cp = shp->prefix; 22424887Schin else 2243*8462SApril.Chin@Sun.COM sfputr(sfstderr,shp->prefix,'.'); 22444887Schin } 22454887Schin sfputr(sfstderr,cp,*argv?' ':nl); 22464887Schin } 22474887Schin sfset(sfstderr,SF_SHARE|SF_PUBLIC,1); 22484887Schin } 22494887Schin return(1); 22504887Schin } 22514887Schin return(0); 22524887Schin } 22534887Schin 22544887Schin /* 22554887Schin * This routine creates a subshell by calling fork() or vfork() 22564887Schin * If ((flags&COMASK)==TCOM), then vfork() is permitted 22574887Schin * If fork fails, the shell sleeps for exponentially longer periods 22584887Schin * and tries again until a limit is reached. 22594887Schin * SH_FORKLIM is the max period between forks - power of 2 usually. 22604887Schin * Currently shell tries after 2,4,8,16, and 32 seconds and then quits 22614887Schin * Failures cause the routine to error exit. 22624887Schin * Parent links to here-documents are removed by the child 22634887Schin * Traps are reset by the child 22644887Schin * The process-id of the child is returned to the parent, 0 to the child. 22654887Schin */ 22664887Schin 22674887Schin static void timed_out(void *handle) 22684887Schin { 22694887Schin NOT_USED(handle); 22704887Schin timeout = 0; 22714887Schin } 22724887Schin 22734887Schin 22744887Schin /* 22754887Schin * called by parent and child after fork by sh_fork() 22764887Schin */ 22774887Schin pid_t _sh_fork(register pid_t parent,int flags,int *jobid) 22784887Schin { 22794887Schin static long forkcnt = 1000L; 2280*8462SApril.Chin@Sun.COM Shell_t *shp = &sh; 22814887Schin pid_t curpgid = job.curpgid; 22824887Schin pid_t postid = (flags&FAMP)?0:curpgid; 2283*8462SApril.Chin@Sun.COM int sig,nochild; 22844887Schin if(parent<0) 22854887Schin { 2286*8462SApril.Chin@Sun.COM sh_sigcheck(); 22874887Schin if((forkcnt *= 2) > 1000L*SH_FORKLIM) 22884887Schin { 22894887Schin forkcnt=1000L; 22904887Schin errormsg(SH_DICT,ERROR_system(ERROR_NOEXEC),e_nofork); 22914887Schin } 22924887Schin timeout = (void*)sh_timeradd(forkcnt, 0, timed_out, NIL(void*)); 2293*8462SApril.Chin@Sun.COM nochild = job_wait((pid_t)1); 22944887Schin if(timeout) 22954887Schin { 2296*8462SApril.Chin@Sun.COM if(nochild) 2297*8462SApril.Chin@Sun.COM pause(); 2298*8462SApril.Chin@Sun.COM else if(forkcnt>1000L) 2299*8462SApril.Chin@Sun.COM forkcnt /= 2; 23004887Schin timerdel(timeout); 2301*8462SApril.Chin@Sun.COM timeout = 0; 23024887Schin } 23034887Schin return(-1); 23044887Schin } 2305*8462SApril.Chin@Sun.COM forkcnt = 1000L; 23064887Schin if(parent) 23074887Schin { 2308*8462SApril.Chin@Sun.COM int myjob,waitall=job.waitall; 2309*8462SApril.Chin@Sun.COM shp->nforks++; 23104887Schin if(job.toclear) 23114887Schin job_clear(); 2312*8462SApril.Chin@Sun.COM job.waitall = waitall; 23134887Schin #ifdef JOBS 23144887Schin /* first process defines process group */ 23154887Schin if(sh_isstate(SH_MONITOR)) 23164887Schin { 23174887Schin /* 23184887Schin * errno==EPERM means that an earlier processes 23194887Schin * completed. Make parent the job group id. 23204887Schin */ 23214887Schin if(postid==0) 23224887Schin job.curpgid = parent; 23234887Schin if(job.jobcontrol || (flags&FAMP)) 23244887Schin { 23254887Schin if(setpgid(parent,job.curpgid)<0 && errno==EPERM) 23264887Schin setpgid(parent,parent); 23274887Schin } 23284887Schin } 23294887Schin #endif /* JOBS */ 23304887Schin if(!sh_isstate(SH_MONITOR) && job.waitall && postid==0) 23314887Schin job.curpgid = parent; 23324887Schin if(flags&FCOOP) 2333*8462SApril.Chin@Sun.COM shp->cpid = parent; 23344887Schin myjob = job_post(parent,postid); 23354887Schin if(flags&FAMP) 23364887Schin job.curpgid = curpgid; 23374887Schin if(jobid) 23384887Schin *jobid = myjob; 23394887Schin return(parent); 23404887Schin } 23414887Schin #if !_std_malloc 23424887Schin vmtrace(-1); 23434887Schin #endif 23444887Schin /* This is the child process */ 2345*8462SApril.Chin@Sun.COM if(shp->trapnote&SH_SIGTERM) 23464887Schin sh_exit(SH_EXITSIG|SIGTERM); 2347*8462SApril.Chin@Sun.COM shp->nforks=0; 23484887Schin timerdel(NIL(void*)); 23494887Schin #ifdef JOBS 23504887Schin if(!job.jobcontrol && !(flags&FAMP)) 23514887Schin sh_offstate(SH_MONITOR); 23524887Schin if(sh_isstate(SH_MONITOR)) 23534887Schin { 23544887Schin parent = getpid(); 23554887Schin if(postid==0) 23564887Schin job.curpgid = parent; 23574887Schin while(setpgid(0,job.curpgid)<0 && job.curpgid!=parent) 23584887Schin job.curpgid = parent; 23594887Schin # ifdef SIGTSTP 23604887Schin if(job.curpgid==parent && !(flags&FAMP)) 23614887Schin tcsetpgrp(job.fd,job.curpgid); 23624887Schin # endif /* SIGTSTP */ 23634887Schin } 23644887Schin # ifdef SIGTSTP 23654887Schin if(job.jobcontrol) 23664887Schin { 23674887Schin signal(SIGTTIN,SIG_DFL); 23684887Schin signal(SIGTTOU,SIG_DFL); 23694887Schin signal(SIGTSTP,SIG_DFL); 23704887Schin } 23714887Schin # endif /* SIGTSTP */ 23724887Schin job.jobcontrol = 0; 23734887Schin #endif /* JOBS */ 23744887Schin job.toclear = 1; 2375*8462SApril.Chin@Sun.COM shp->login_sh = 0; 23764887Schin sh_offoption(SH_LOGIN_SHELL); 23774887Schin sh_onstate(SH_FORKED); 23784887Schin sh_onstate(SH_NOLOG); 2379*8462SApril.Chin@Sun.COM if (shp->fn_reset) 2380*8462SApril.Chin@Sun.COM shp->fn_depth = shp->fn_reset = 0; 23814887Schin #if SHOPT_ACCT 23824887Schin sh_accsusp(); 23834887Schin #endif /* SHOPT_ACCT */ 23844887Schin /* Reset remaining signals to parent */ 23854887Schin /* except for those `lost' by trap */ 23864887Schin sh_sigreset(2); 2387*8462SApril.Chin@Sun.COM shp->subshell = 0; 2388*8462SApril.Chin@Sun.COM if((flags&FAMP) && shp->coutpipe>1) 2389*8462SApril.Chin@Sun.COM sh_close(shp->coutpipe); 2390*8462SApril.Chin@Sun.COM sig = shp->savesig; 2391*8462SApril.Chin@Sun.COM shp->savesig = 0; 23924887Schin if(sig>0) 23934887Schin sh_fault(sig); 23944887Schin sh_sigcheck(); 23954887Schin return(0); 23964887Schin } 23974887Schin 23984887Schin pid_t sh_fork(int flags, int *jobid) 23994887Schin { 24004887Schin register pid_t parent; 24014887Schin register int sig; 24024887Schin #if SHOPT_FASTPIPE 24034887Schin if(sffileno(sfstdin)<0) 24044887Schin { 24054887Schin off_t current = sfseek(sfstdin,(off_t)0,SEEK_CUR); 24064887Schin sfseek(sfstdin,(off_t)0,SEEK_END); 24074887Schin sfdisc(sfstdin,SF_POPDISC); 24084887Schin fcntl(sffileno(sfstdin),F_SETFD,0); 24094887Schin sh_iostream(0); 24104887Schin sfseek(sfstdin,current,SEEK_SET); 24114887Schin } 24124887Schin #endif /* SHOPT_FASTPIPE */ 24134887Schin if(!sh.pathlist) 24144887Schin path_get(""); 24154887Schin sfsync(NIL(Sfio_t*)); 24164887Schin sh.trapnote &= ~SH_SIGTERM; 24174887Schin job_fork(-1); 24184887Schin sh.savesig = -1; 24194887Schin while(_sh_fork(parent=fork(),flags,jobid) < 0); 2420*8462SApril.Chin@Sun.COM sh_stats(STAT_FORKS); 24214887Schin sig = sh.savesig; 24224887Schin sh.savesig = 0; 24234887Schin if(sig>0) 24244887Schin sh_fault(sig); 24254887Schin job_fork(parent); 24264887Schin return(parent); 24274887Schin } 24284887Schin 24294887Schin /* 24304887Schin * add exports from previous scope to the new scope 24314887Schin */ 24324887Schin static void local_exports(register Namval_t *np, void *data) 24334887Schin { 24344887Schin register Namval_t *mp; 24354887Schin register char *cp; 24364887Schin if(nv_isarray(np)) 24374887Schin nv_putsub(np,NIL(char*),0); 24384887Schin if((cp = nv_getval(np)) && (mp = nv_search(nv_name(np), sh.var_tree, NV_ADD|HASH_NOSCOPE)) && nv_isnull(mp)) 24394887Schin nv_putval(mp, cp, 0); 24404887Schin } 24414887Schin 24424887Schin /* 24434887Schin * This routine is used to execute the given function <fun> in a new scope 24444887Schin * If <fun> is NULL, then arg points to a structure containing a pointer 24454887Schin * to a function that will be executed in the current environment. 24464887Schin */ 24474887Schin int sh_funscope(int argn, char *argv[],int(*fun)(void*),void *arg,int execflg) 24484887Schin { 2449*8462SApril.Chin@Sun.COM register char *trap; 2450*8462SApril.Chin@Sun.COM register int nsig; 2451*8462SApril.Chin@Sun.COM register Shell_t *shp = &sh; 2452*8462SApril.Chin@Sun.COM struct dolnod *argsav=0,*saveargfor; 2453*8462SApril.Chin@Sun.COM struct sh_scoped savst, *prevscope = shp->st.self; 2454*8462SApril.Chin@Sun.COM struct argnod *envlist=0; 2455*8462SApril.Chin@Sun.COM int jmpval; 2456*8462SApril.Chin@Sun.COM volatile int r = 0; 2457*8462SApril.Chin@Sun.COM char *savstak; 2458*8462SApril.Chin@Sun.COM struct funenv *fp; 2459*8462SApril.Chin@Sun.COM struct checkpt buff; 2460*8462SApril.Chin@Sun.COM Namval_t *nspace = shp->namespace; 2461*8462SApril.Chin@Sun.COM if(shp->fn_depth==0) 2462*8462SApril.Chin@Sun.COM shp->glob_options = shp->options; 2463*8462SApril.Chin@Sun.COM else 2464*8462SApril.Chin@Sun.COM shp->options = shp->glob_options; 2465*8462SApril.Chin@Sun.COM #if 0 2466*8462SApril.Chin@Sun.COM shp->st.lineno = error_info.line; 2467*8462SApril.Chin@Sun.COM #endif 2468*8462SApril.Chin@Sun.COM *prevscope = shp->st; 24694887Schin sh_offoption(SH_ERREXIT); 2470*8462SApril.Chin@Sun.COM shp->st.prevst = prevscope; 2471*8462SApril.Chin@Sun.COM shp->st.self = &savst; 2472*8462SApril.Chin@Sun.COM shp->topscope = (Shscope_t*)shp->st.self; 2473*8462SApril.Chin@Sun.COM shp->st.opterror = shp->st.optchar = 0; 2474*8462SApril.Chin@Sun.COM shp->st.optindex = 1; 2475*8462SApril.Chin@Sun.COM shp->st.loopcnt = 0; 24764887Schin if(!fun) 24774887Schin { 24784887Schin fp = (struct funenv*)arg; 2479*8462SApril.Chin@Sun.COM shp->st.real_fun = (fp->node)->nvalue.rp; 24804887Schin envlist = fp->env; 24814887Schin } 2482*8462SApril.Chin@Sun.COM prevscope->save_tree = shp->var_tree; 2483*8462SApril.Chin@Sun.COM sh_scope(shp,envlist,1); 2484*8462SApril.Chin@Sun.COM if(dtvnext(prevscope->save_tree)!= (shp->namespace?shp->var_base:0)) 24854887Schin { 24864887Schin /* eliminate parent scope */ 24874887Schin nv_scan(prevscope->save_tree, local_exports,(void*)0, NV_EXPORT, NV_EXPORT|NV_NOSCOPE); 24884887Schin } 2489*8462SApril.Chin@Sun.COM shp->st.save_tree = shp->var_tree; 24904887Schin if(!fun) 24914887Schin { 24924887Schin Namval_t *np; 24934887Schin if(nv_isattr(fp->node,NV_TAGGED)) 24944887Schin sh_onoption(SH_XTRACE); 24954887Schin else 24964887Schin sh_offoption(SH_XTRACE); 24974887Schin #if SHOPT_NAMESPACE 2498*8462SApril.Chin@Sun.COM if((np=(fp->node)->nvalue.rp->nspace) && np!=shp->namespace) 24994887Schin { 2500*8462SApril.Chin@Sun.COM Dt_t *dt = shp->var_tree; 25014887Schin dtview(dt,0); 25024887Schin dtview(dt,nv_dict(np)); 2503*8462SApril.Chin@Sun.COM shp->var_tree = nv_dict(np); 2504*8462SApril.Chin@Sun.COM shp->namespace = np; 25054887Schin } 25064887Schin #endif /* SHOPT_NAMESPACE */ 25074887Schin } 2508*8462SApril.Chin@Sun.COM shp->st.cmdname = argv[0]; 25094887Schin /* save trap table */ 2510*8462SApril.Chin@Sun.COM if((nsig=shp->st.trapmax*sizeof(char*))>0 || shp->st.trapcom[0]) 25114887Schin { 25124887Schin nsig += sizeof(char*); 2513*8462SApril.Chin@Sun.COM memcpy(savstak=stakalloc(nsig),(char*)&shp->st.trapcom[0],nsig); 25144887Schin } 25154887Schin sh_sigreset(0); 2516*8462SApril.Chin@Sun.COM argsav = sh_argnew(shp,argv,&saveargfor); 25174887Schin sh_pushcontext(&buff,SH_JMPFUN); 25184887Schin errorpush(&buff.err,0); 25194887Schin error_info.id = argv[0]; 2520*8462SApril.Chin@Sun.COM shp->st.var_local = shp->var_tree; 25214887Schin jmpval = sigsetjmp(buff.buff,0); 25224887Schin if(!fun) 25234887Schin { 2524*8462SApril.Chin@Sun.COM shp->st.filename = fp->node->nvalue.rp->fname; 2525*8462SApril.Chin@Sun.COM shp->st.funname = nv_name(fp->node); 2526*8462SApril.Chin@Sun.COM nv_putval(SH_PATHNAMENOD,shp->st.filename,NV_NOFREE); 2527*8462SApril.Chin@Sun.COM nv_putval(SH_FUNNAMENOD,shp->st.funname,NV_NOFREE); 25284887Schin } 25294887Schin if(jmpval == 0) 25304887Schin { 2531*8462SApril.Chin@Sun.COM if(shp->fn_depth++ > MAXDEPTH) 2532*8462SApril.Chin@Sun.COM siglongjmp(*shp->jmplist,SH_JMPERRFN); 25334887Schin else if(fun) 25344887Schin r= (*fun)(arg); 25354887Schin else 25364887Schin { 25374887Schin sh_exec((Shnode_t*)(nv_funtree((fp->node))),execflg|SH_ERREXIT); 2538*8462SApril.Chin@Sun.COM r = shp->exitval; 25394887Schin } 25404887Schin } 2541*8462SApril.Chin@Sun.COM if(--shp->fn_depth==1 && jmpval==SH_JMPERRFN) 25424887Schin errormsg(SH_DICT,ERROR_exit(1),e_toodeep,argv[0]); 25434887Schin sh_popcontext(&buff); 2544*8462SApril.Chin@Sun.COM if (shp->st.self != &savst) 2545*8462SApril.Chin@Sun.COM shp->var_tree = (Dt_t*)savst.save_tree; 2546*8462SApril.Chin@Sun.COM sh_unscope(shp); 2547*8462SApril.Chin@Sun.COM shp->namespace = nspace; 2548*8462SApril.Chin@Sun.COM shp->var_tree = (Dt_t*)prevscope->save_tree; 2549*8462SApril.Chin@Sun.COM if(shp->topscope != (Shscope_t*)shp->st.self) 2550*8462SApril.Chin@Sun.COM sh_setscope(shp->topscope); 2551*8462SApril.Chin@Sun.COM sh_argreset(shp,argsav,saveargfor); 2552*8462SApril.Chin@Sun.COM trap = shp->st.trapcom[0]; 2553*8462SApril.Chin@Sun.COM shp->st.trapcom[0] = 0; 25544887Schin sh_sigreset(1); 2555*8462SApril.Chin@Sun.COM if (shp->st.self != &savst) 2556*8462SApril.Chin@Sun.COM *shp->st.self = shp->st; 2557*8462SApril.Chin@Sun.COM shp->st = *prevscope; 2558*8462SApril.Chin@Sun.COM shp->topscope = (Shscope_t*)prevscope; 2559*8462SApril.Chin@Sun.COM nv_getval(sh_scoped(shp,IFSNOD)); 25604887Schin if(nsig) 2561*8462SApril.Chin@Sun.COM memcpy((char*)&shp->st.trapcom[0],savstak,nsig); 2562*8462SApril.Chin@Sun.COM shp->trapnote=0; 25634887Schin if(nsig) 25644887Schin stakset(savstak,0); 2565*8462SApril.Chin@Sun.COM shp->options = shp->glob_options; 25664887Schin if(trap) 25674887Schin { 25684887Schin sh_trap(trap,0); 25694887Schin free(trap); 25704887Schin } 2571*8462SApril.Chin@Sun.COM if(shp->exitval > SH_EXITSIG) 2572*8462SApril.Chin@Sun.COM sh_fault(shp->exitval&SH_EXITMASK); 25734887Schin if(jmpval > SH_JMPFUN) 25744887Schin { 25754887Schin sh_chktrap(); 2576*8462SApril.Chin@Sun.COM siglongjmp(*shp->jmplist,jmpval); 25774887Schin } 25784887Schin return(r); 25794887Schin } 25804887Schin 2581*8462SApril.Chin@Sun.COM static void sh_funct(Shell_t *shp,Namval_t *np,int argn, char *argv[],struct argnod *envlist,int execflg) 25824887Schin { 25834887Schin struct funenv fun; 25844887Schin char *fname = nv_getval(SH_FUNNAMENOD); 2585*8462SApril.Chin@Sun.COM struct Level *lp =(struct Level*)(SH_LEVELNOD->nvfun); 2586*8462SApril.Chin@Sun.COM int level; 2587*8462SApril.Chin@Sun.COM sh_stats(STAT_FUNCT); 2588*8462SApril.Chin@Sun.COM if(!lp->hdr.disc) 2589*8462SApril.Chin@Sun.COM lp = init_level(0); 2590*8462SApril.Chin@Sun.COM if((struct sh_scoped*)shp->topscope != shp->st.self) 2591*8462SApril.Chin@Sun.COM sh_setscope(shp->topscope); 2592*8462SApril.Chin@Sun.COM level = lp->maxlevel = shp->dot_depth + shp->fn_depth+1; 2593*8462SApril.Chin@Sun.COM SH_LEVELNOD->nvalue.s = lp->maxlevel; 2594*8462SApril.Chin@Sun.COM shp->st.lineno = error_info.line; 25954887Schin if(nv_isattr(np,NV_FPOSIX)) 25964887Schin { 25974887Schin char *save; 2598*8462SApril.Chin@Sun.COM int loopcnt = shp->st.loopcnt; 2599*8462SApril.Chin@Sun.COM shp->posix_fun = np; 2600*8462SApril.Chin@Sun.COM save = argv[-1]; 2601*8462SApril.Chin@Sun.COM argv[-1] = 0; 2602*8462SApril.Chin@Sun.COM shp->st.funname = nv_name(np); 2603*8462SApril.Chin@Sun.COM nv_putval(SH_FUNNAMENOD, nv_name(np),NV_NOFREE); 26044887Schin opt_info.index = opt_info.offset = 0; 26054887Schin error_info.errors = 0; 2606*8462SApril.Chin@Sun.COM shp->st.loopcnt = 0; 2607*8462SApril.Chin@Sun.COM b_dot_cmd(argn+1,argv-1,&shp->bltindata); 2608*8462SApril.Chin@Sun.COM shp->st.loopcnt = loopcnt; 26094887Schin argv[-1] = save; 26104887Schin } 26114887Schin else 26124887Schin { 26134887Schin fun.env = envlist; 26144887Schin fun.node = np; 26154887Schin sh_funscope(argn,argv,0,&fun,execflg); 26164887Schin } 2617*8462SApril.Chin@Sun.COM if(level-- != nv_getnum(SH_LEVELNOD)) 2618*8462SApril.Chin@Sun.COM { 2619*8462SApril.Chin@Sun.COM Shscope_t *sp = sh_getscope(0,SEEK_END); 2620*8462SApril.Chin@Sun.COM sh_setscope(sp); 2621*8462SApril.Chin@Sun.COM } 2622*8462SApril.Chin@Sun.COM lp->maxlevel = level; 2623*8462SApril.Chin@Sun.COM SH_LEVELNOD->nvalue.s = lp->maxlevel; 2624*8462SApril.Chin@Sun.COM #if 0 2625*8462SApril.Chin@Sun.COM nv_putval(SH_FUNNAMENOD,shp->st.funname,NV_NOFREE); 2626*8462SApril.Chin@Sun.COM #else 26274887Schin nv_putval(SH_FUNNAMENOD,fname,NV_NOFREE); 2628*8462SApril.Chin@Sun.COM #endif 2629*8462SApril.Chin@Sun.COM nv_putval(SH_PATHNAMENOD,shp->st.filename,NV_NOFREE); 26304887Schin } 26314887Schin 26324887Schin /* 26334887Schin * external interface to execute a function without arguments 26344887Schin * <np> is the function node 26354887Schin * If <nq> is not-null, then sh.name and sh.subscript will be set 26364887Schin */ 26374887Schin int sh_fun(Namval_t *np, Namval_t *nq, char *argv[]) 26384887Schin { 2639*8462SApril.Chin@Sun.COM Shell_t *shp = &sh; 26404887Schin register int offset; 26414887Schin register char *base; 26424887Schin Namval_t node; 2643*8462SApril.Chin@Sun.COM struct Namref nr; 2644*8462SApril.Chin@Sun.COM long mode; 2645*8462SApril.Chin@Sun.COM char *prefix = shp->prefix; 26464887Schin int n=0; 26474887Schin char *av[2]; 26484887Schin Fcin_t save; 26494887Schin fcsave(&save); 26504887Schin if((offset=staktell())>0) 26514887Schin base=stakfreeze(0); 2652*8462SApril.Chin@Sun.COM shp->prefix = 0; 26534887Schin if(!argv) 26544887Schin { 26554887Schin argv = av; 26564887Schin argv[1]=0; 26574887Schin } 26584887Schin argv[0] = nv_name(np); 26594887Schin while(argv[n]) 26604887Schin n++; 26614887Schin if(nq) 2662*8462SApril.Chin@Sun.COM mode = set_instance(nq,&node, &nr); 26634887Schin if(is_abuiltin(np)) 26644887Schin { 26654887Schin int jmpval; 26664887Schin struct checkpt buff; 2667*8462SApril.Chin@Sun.COM Shbltin_t *bp = &sh.bltindata; 26684887Schin sh_pushcontext(&buff,SH_JMPCMD); 26694887Schin jmpval = sigsetjmp(buff.buff,1); 26704887Schin if(jmpval == 0) 26714887Schin { 2672*8462SApril.Chin@Sun.COM bp->bnode = np; 2673*8462SApril.Chin@Sun.COM bp->ptr = nv_context(np); 26744887Schin errorpush(&buff.err,0); 26754887Schin error_info.id = argv[0]; 26764887Schin opt_info.index = opt_info.offset = 0; 26774887Schin opt_info.disc = 0; 26784887Schin sh.exitval = 0; 2679*8462SApril.Chin@Sun.COM sh.exitval = (*funptr(np))(n,argv,(void*)bp); 26804887Schin } 26814887Schin sh_popcontext(&buff); 26824887Schin if(jmpval>SH_JMPCMD) 26834887Schin siglongjmp(*sh.jmplist,jmpval); 26844887Schin } 26854887Schin else 2686*8462SApril.Chin@Sun.COM sh_funct(shp,np,n,argv,(struct argnod*)0,sh_isstate(SH_ERREXIT)); 26874887Schin if(nq) 2688*8462SApril.Chin@Sun.COM unset_instance(nq, &node, &nr, mode); 26894887Schin fcrestore(&save); 26904887Schin if(offset>0) 26914887Schin stakset(base,offset); 2692*8462SApril.Chin@Sun.COM shp->prefix = prefix; 26934887Schin return(sh.exitval); 26944887Schin } 26954887Schin 26964887Schin /* 26974887Schin * This dummy routine is called by built-ins that do recursion 26984887Schin * on the file system (chmod, chgrp, chown). It causes 26994887Schin * the shell to invoke the non-builtin version in this case 27004887Schin */ 27014887Schin int cmdrecurse(int argc, char* argv[], int ac, char* av[]) 27024887Schin { 27034887Schin NOT_USED(argc); 27044887Schin NOT_USED(argv[0]); 27054887Schin NOT_USED(ac); 27064887Schin NOT_USED(av[0]); 27074887Schin return(SH_RUNPROG); 27084887Schin } 27094887Schin 27104887Schin /* 27114887Schin * set up pipe for cooperating process 27124887Schin */ 2713*8462SApril.Chin@Sun.COM static void coproc_init(Shell_t *shp, int pipes[]) 27144887Schin { 27154887Schin int outfd; 2716*8462SApril.Chin@Sun.COM if(shp->coutpipe>=0 && shp->cpid) 27174887Schin errormsg(SH_DICT,ERROR_exit(1),e_pexists); 2718*8462SApril.Chin@Sun.COM shp->cpid = 0; 2719*8462SApril.Chin@Sun.COM if(shp->cpipe[0]<=0 || shp->cpipe[1]<=0) 27204887Schin { 27214887Schin /* first co-process */ 2722*8462SApril.Chin@Sun.COM sh_pclose(shp->cpipe); 2723*8462SApril.Chin@Sun.COM sh_pipe(shp->cpipe); 2724*8462SApril.Chin@Sun.COM if((outfd=shp->cpipe[1]) < 10) 27254887Schin { 2726*8462SApril.Chin@Sun.COM int fd=fcntl(shp->cpipe[1],F_DUPFD,10); 27274887Schin if(fd>=10) 27284887Schin { 2729*8462SApril.Chin@Sun.COM shp->fdstatus[fd] = (shp->fdstatus[outfd]&~IOCLEX); 27304887Schin close(outfd); 2731*8462SApril.Chin@Sun.COM shp->fdstatus[outfd] = IOCLOSE; 2732*8462SApril.Chin@Sun.COM shp->cpipe[1] = fd; 27334887Schin } 27344887Schin } 2735*8462SApril.Chin@Sun.COM if(fcntl(*shp->cpipe,F_SETFD,FD_CLOEXEC)>=0) 2736*8462SApril.Chin@Sun.COM shp->fdstatus[shp->cpipe[0]] |= IOCLEX; 2737*8462SApril.Chin@Sun.COM shp->fdptrs[shp->cpipe[0]] = shp->cpipe; 27384887Schin 2739*8462SApril.Chin@Sun.COM if(fcntl(shp->cpipe[1],F_SETFD,FD_CLOEXEC) >=0) 2740*8462SApril.Chin@Sun.COM shp->fdstatus[shp->cpipe[1]] |= IOCLEX; 27414887Schin } 2742*8462SApril.Chin@Sun.COM shp->outpipe = shp->cpipe; 2743*8462SApril.Chin@Sun.COM sh_pipe(shp->inpipe=pipes); 2744*8462SApril.Chin@Sun.COM shp->coutpipe = shp->inpipe[1]; 2745*8462SApril.Chin@Sun.COM shp->fdptrs[shp->coutpipe] = &shp->coutpipe; 2746*8462SApril.Chin@Sun.COM if(fcntl(shp->outpipe[0],F_SETFD,FD_CLOEXEC)>=0) 2747*8462SApril.Chin@Sun.COM shp->fdstatus[shp->outpipe[0]] |= IOCLEX; 27484887Schin } 27494887Schin 27504887Schin #if SHOPT_SPAWN 27514887Schin 27524887Schin 27534887Schin #if SHOPT_AMP || !defined(_lib_fork) 27544887Schin /* 27554887Schin * print out function definition 27564887Schin */ 27574887Schin static void print_fun(register Namval_t* np, void *data) 27584887Schin { 27594887Schin register char *format; 27604887Schin NOT_USED(data); 27614887Schin if(!is_afunction(np) || !np->nvalue.ip) 27624887Schin return; 27634887Schin if(nv_isattr(np,NV_FPOSIX)) 27644887Schin format="%s()\n{ "; 27654887Schin else 27664887Schin format="function %s\n{ "; 27674887Schin sfprintf(sfstdout,format,nv_name(np)); 27684887Schin sh_deparse(sfstdout,(Shnode_t*)(nv_funtree(np)),0); 27694887Schin sfwrite(sfstdout,"}\n",2); 27704887Schin } 27714887Schin 27724887Schin /* 27734887Schin * create a shell script consisting of t->fork.forktre and execute it 27744887Schin */ 27754887Schin static int run_subshell(const Shnode_t *t,pid_t grp) 27764887Schin { 2777*8462SApril.Chin@Sun.COM static const char prolog[] = "(print $(typeset +A);set; typeset -p; print .sh.dollar=$$;set +o)"; 27784887Schin register int i, fd, trace = sh_isoption(SH_XTRACE); 27794887Schin int pin,pout; 27804887Schin pid_t pid; 27814887Schin char *arglist[2], *envlist[2], devfd[12], *cp; 27824887Schin Sfio_t *sp = sftmp(0); 27834887Schin envlist[0] = "_=" SH_ID; 27844887Schin envlist[1] = 0; 27854887Schin arglist[0] = error_info.id?error_info.id:sh.shname; 27864887Schin if(*arglist[0]=='-') 27874887Schin arglist[0]++; 27884887Schin arglist[1] = devfd; 27894887Schin strncpy(devfd,e_devfdNN,sizeof(devfd)); 27904887Schin arglist[2] = 0; 27914887Schin sfstack(sfstdout,sp); 27924887Schin if(trace) 27934887Schin sh_offoption(SH_XTRACE); 27944887Schin sfwrite(sfstdout,"typeset -A -- ",14); 27954887Schin sh_trap(prolog,0); 27964887Schin nv_scan(sh.fun_tree, print_fun, (void*)0,0, 0); 27974887Schin if(sh.st.dolc>0) 27984887Schin { 27994887Schin /* pass the positional parameters */ 28004887Schin char **argv = sh.st.dolv+1; 28014887Schin sfwrite(sfstdout,"set --",6); 28024887Schin while(*argv) 28034887Schin sfprintf(sfstdout," %s",sh_fmtq(*argv++)); 28044887Schin sfputc(sfstdout,'\n'); 28054887Schin } 28064887Schin pin = (sh.inpipe?sh.inpipe[1]:0); 28074887Schin pout = (sh.outpipe?sh.outpipe[0]:0); 28084887Schin for(i=3; i < 10; i++) 28094887Schin { 28104887Schin if(sh.fdstatus[i]&IOCLEX && i!=pin && i!=pout) 28114887Schin { 28124887Schin sfprintf(sfstdout,"exec %d<&%d\n",i,i); 28134887Schin fcntl(i,F_SETFD,0); 28144887Schin } 28154887Schin } 28164887Schin sfprintf(sfstdout,"LINENO=%d\n",t->fork.forkline); 28174887Schin if(trace) 28184887Schin { 28194887Schin sfwrite(sfstdout,"set -x\n",7); 28204887Schin sh_onoption(SH_XTRACE); 28214887Schin } 28224887Schin sfstack(sfstdout,NIL(Sfio_t*)); 28234887Schin sh_deparse(sp,t->fork.forktre,0); 28244887Schin sfseek(sp,(Sfoff_t)0,SEEK_SET); 28254887Schin fd = sh_dup(sffileno(sp)); 28264887Schin cp = devfd+8; 28274887Schin if(fd>9) 28284887Schin *cp++ = '0' + (fd/10); 28294887Schin *cp++ = '0' + fd%10; 28304887Schin *cp = 0; 28314887Schin sfclose(sp); 28324887Schin sfsync(NIL(Sfio_t*)); 28334887Schin if(!sh.shpath) 28344887Schin sh.shpath = pathshell(); 28354887Schin pid = spawnveg(sh.shpath,arglist,envlist,grp); 28364887Schin close(fd); 28374887Schin for(i=3; i < 10; i++) 28384887Schin { 28394887Schin if(sh.fdstatus[i]&IOCLEX && i!=pin && i!=pout) 28404887Schin fcntl(i,F_SETFD,FD_CLOEXEC); 28414887Schin } 28424887Schin if(pid <=0) 28434887Schin errormsg(SH_DICT,ERROR_system(ERROR_NOEXEC),e_exec,arglist[0]); 28444887Schin return(pid); 28454887Schin } 28464887Schin #endif /* !_lib_fork */ 28474887Schin 28484887Schin static void sigreset(int mode) 28494887Schin { 28504887Schin register char *trap; 28514887Schin register int sig=sh.st.trapmax; 28524887Schin while(sig-- > 0) 28534887Schin { 28544887Schin if((trap=sh.st.trapcom[sig]) && *trap==0) 28554887Schin signal(sig,mode?sh_fault:SIG_IGN); 28564887Schin } 28574887Schin } 28584887Schin 28594887Schin /* 28604887Schin * A combined fork/exec for systems with slow or non-existent fork() 28614887Schin */ 2862*8462SApril.Chin@Sun.COM static pid_t sh_ntfork(Shell_t *shp,const Shnode_t *t,char *argv[],int *jobid,int flag) 28634887Schin { 28644887Schin static pid_t spawnpid; 28654887Schin static int savetype; 28664887Schin static int savejobid; 2867*8462SApril.Chin@Sun.COM struct checkpt buff; 2868*8462SApril.Chin@Sun.COM int otype=0, jmpval; 2869*8462SApril.Chin@Sun.COM volatile int jobwasset=0, scope=0, sigwasset=0; 2870*8462SApril.Chin@Sun.COM char **arge, *path; 2871*8462SApril.Chin@Sun.COM volatile pid_t grp = 0; 2872*8462SApril.Chin@Sun.COM Pathcomp_t *pp; 28734887Schin if(flag) 28744887Schin { 28754887Schin otype = savetype; 28764887Schin savetype=0; 28774887Schin } 28784887Schin # if SHOPT_AMP || !defined(_lib_fork) 28794887Schin if(!argv) 28804887Schin { 28814887Schin register Shnode_t *tchild = t->fork.forktre; 28824887Schin int optimize=0; 28834887Schin otype = t->tre.tretyp; 28844887Schin savetype = otype; 28854887Schin spawnpid = 0; 28864887Schin # ifndef _lib_fork 28874887Schin if((tchild->tre.tretyp&COMMSK)==TCOM) 28884887Schin { 28894887Schin Namval_t *np = (Namval_t*)(tchild->com.comnamp); 28904887Schin if(np) 28914887Schin { 28924887Schin path = nv_name(np); 28934887Schin if(!nv_isattr(np,BLT_ENV)) 28944887Schin np=0; 28954887Schin else if(strcmp(path,"echo")==0 || memcmp(path,"print",5)==0) 28964887Schin np=0; 28974887Schin } 28984887Schin else if(!tchild->com.comarg) 28994887Schin optimize=1; 29004887Schin else if(tchild->com.comtyp&COMSCAN) 29014887Schin { 29024887Schin if(tchild->com.comarg->argflag&ARG_RAW) 29034887Schin path = tchild->com.comarg->argval; 29044887Schin else 29054887Schin path = 0; 29064887Schin } 29074887Schin else 29084887Schin path = ((struct dolnod*)tchild->com.comarg)->dolval[ARG_SPARE]; 29094887Schin if(!np && path && !nv_search(path,shp->fun_tree,0)) 29104887Schin optimize=1; 29114887Schin } 29124887Schin # endif 29134887Schin sh_pushcontext(&buff,SH_JMPIO); 29144887Schin jmpval = sigsetjmp(buff.buff,0); 29154887Schin { 29164887Schin if((otype&FINT) && !sh_isstate(SH_MONITOR)) 29174887Schin { 29184887Schin signal(SIGQUIT,SIG_IGN); 29194887Schin signal(SIGINT,SIG_IGN); 29204887Schin if(!shp->st.ioset) 29214887Schin { 2922*8462SApril.Chin@Sun.COM sh_iosave(shp,0,buff.topfd,(char*)0); 2923*8462SApril.Chin@Sun.COM sh_iorenumber(shp,sh_chkopen(e_devnull),0); 29244887Schin } 29254887Schin } 29264887Schin if(otype&FPIN) 29274887Schin { 29284887Schin int fd = shp->inpipe[1]; 2929*8462SApril.Chin@Sun.COM sh_iosave(shp,0,buff.topfd,(char*)0); 2930*8462SApril.Chin@Sun.COM sh_iorenumber(shp,shp->inpipe[0],0); 29314887Schin if(fd>=0 && (!(otype&FPOU) || (otype&FCOOP)) && fcntl(fd,F_SETFD,FD_CLOEXEC)>=0) 29324887Schin shp->fdstatus[fd] |= IOCLEX; 29334887Schin } 29344887Schin if(otype&FPOU) 29354887Schin { 2936*8462SApril.Chin@Sun.COM sh_iosave(shp,1,buff.topfd,(char*)0); 2937*8462SApril.Chin@Sun.COM sh_iorenumber(shp,sh_dup(shp->outpipe[1]),1); 29384887Schin if(fcntl(shp->outpipe[0],F_SETFD,FD_CLOEXEC)>=0) 29394887Schin shp->fdstatus[shp->outpipe[0]] |= IOCLEX; 29404887Schin } 29414887Schin 29424887Schin if(t->fork.forkio) 2943*8462SApril.Chin@Sun.COM sh_redirect(shp,t->fork.forkio,0); 29444887Schin if(optimize==0) 29454887Schin { 29464887Schin #ifdef SIGTSTP 29474887Schin if(job.jobcontrol) 29484887Schin { 29494887Schin signal(SIGTTIN,SIG_DFL); 29504887Schin signal(SIGTTOU,SIG_DFL); 29514887Schin } 29524887Schin #endif /* SIGTSTP */ 29534887Schin #ifdef JOBS 29544887Schin if(sh_isstate(SH_MONITOR) && (job.jobcontrol || (otype&FAMP))) 29554887Schin { 29564887Schin if((otype&FAMP) || job.curpgid==0) 29574887Schin grp = 1; 29584887Schin else 29594887Schin grp = job.curpgid; 29604887Schin } 29614887Schin #endif /* JOBS */ 29624887Schin spawnpid = run_subshell(t,grp); 29634887Schin } 29644887Schin else 29654887Schin { 29664887Schin sh_exec(tchild,SH_NTFORK); 29674887Schin if(jobid) 29684887Schin *jobid = savejobid; 29694887Schin } 29704887Schin } 29714887Schin sh_popcontext(&buff); 29724887Schin if((otype&FINT) && !sh_isstate(SH_MONITOR)) 29734887Schin { 29744887Schin signal(SIGQUIT,sh_fault); 29754887Schin signal(SIGINT,sh_fault); 29764887Schin } 29774887Schin if((otype&FPIN) && (!(otype&FPOU) || (otype&FCOOP)) && fcntl(shp->inpipe[1],F_SETFD,FD_CLOEXEC)>=0) 29784887Schin shp->fdstatus[shp->inpipe[1]] &= ~IOCLEX; 29794887Schin if(t->fork.forkio || otype) 2980*8462SApril.Chin@Sun.COM sh_iorestore(shp,buff.topfd,jmpval); 29814887Schin if(optimize==0) 29824887Schin { 29834887Schin #ifdef SIGTSTP 29844887Schin if(job.jobcontrol) 29854887Schin { 29864887Schin signal(SIGTTIN,SIG_IGN); 29874887Schin signal(SIGTTOU,SIG_IGN); 29884887Schin } 29894887Schin #endif /* SIGTSTP */ 29904887Schin if(spawnpid>0) 29914887Schin _sh_fork(spawnpid,otype,jobid); 29924887Schin if(grp>0 && !(otype&FAMP)) 29934887Schin { 29944887Schin while(tcsetpgrp(job.fd,job.curpgid)<0 && job.curpgid!=spawnpid) 29954887Schin job.curpgid = spawnpid; 29964887Schin } 29974887Schin } 29984887Schin savetype=0; 29994887Schin if(jmpval>SH_JMPIO) 30004887Schin siglongjmp(*shp->jmplist,jmpval); 30014887Schin if(spawnpid<0 && (otype&FCOOP)) 30024887Schin { 30034887Schin sh_close(shp->coutpipe); 30044887Schin sh_close(shp->cpipe[1]); 30054887Schin shp->cpipe[1] = -1; 30064887Schin shp->coutpipe = -1; 30074887Schin } 30084887Schin shp->exitval = 0; 30094887Schin return(spawnpid); 30104887Schin } 30114887Schin # endif /* !_lib_fork */ 30124887Schin sh_pushcontext(&buff,SH_JMPCMD); 30134887Schin errorpush(&buff.err,ERROR_SILENT); 30144887Schin jmpval = sigsetjmp(buff.buff,0); 30154887Schin if(jmpval == 0) 30164887Schin { 30174887Schin if((otype&FINT) && !sh_isstate(SH_MONITOR)) 30184887Schin { 30194887Schin signal(SIGQUIT,SIG_IGN); 30204887Schin signal(SIGINT,SIG_IGN); 30214887Schin } 30224887Schin spawnpid = -1; 30234887Schin if(t->com.comio) 3024*8462SApril.Chin@Sun.COM sh_redirect(shp,t->com.comio,0); 30254887Schin error_info.id = *argv; 30264887Schin if(t->com.comset) 30274887Schin { 30284887Schin scope++; 3029*8462SApril.Chin@Sun.COM sh_scope(shp,t->com.comset,0); 30304887Schin } 30314887Schin if(!strchr(path=argv[0],'/')) 30324887Schin { 30334887Schin Namval_t *np; 30344887Schin if((np=nv_search(path,shp->track_tree,0)) && !nv_isattr(np,NV_NOALIAS) && np->nvalue.cp) 30354887Schin path = nv_getval(np); 30364887Schin else if(path_absolute(path,NIL(Pathcomp_t*))) 30374887Schin { 3038*8462SApril.Chin@Sun.COM path = stkptr(shp->stk,PATH_OFFSET); 3039*8462SApril.Chin@Sun.COM stkfreeze(shp->stk,0); 3040*8462SApril.Chin@Sun.COM } 3041*8462SApril.Chin@Sun.COM else 3042*8462SApril.Chin@Sun.COM { 3043*8462SApril.Chin@Sun.COM pp=path_get(path); 3044*8462SApril.Chin@Sun.COM while(pp) 30454887Schin { 3046*8462SApril.Chin@Sun.COM if(pp->len==1 && *pp->name=='.') 3047*8462SApril.Chin@Sun.COM break; 3048*8462SApril.Chin@Sun.COM pp = pp->next; 30494887Schin } 3050*8462SApril.Chin@Sun.COM if(!pp) 3051*8462SApril.Chin@Sun.COM path = 0; 30524887Schin } 3053*8462SApril.Chin@Sun.COM } 3054*8462SApril.Chin@Sun.COM else if(sh_isoption(SH_RESTRICTED)) 3055*8462SApril.Chin@Sun.COM errormsg(SH_DICT,ERROR_exit(1),e_restricted,path); 3056*8462SApril.Chin@Sun.COM if(!path) 3057*8462SApril.Chin@Sun.COM { 3058*8462SApril.Chin@Sun.COM spawnpid = -1; 3059*8462SApril.Chin@Sun.COM goto fail; 3060*8462SApril.Chin@Sun.COM } 3061*8462SApril.Chin@Sun.COM arge = sh_envgen(); 3062*8462SApril.Chin@Sun.COM shp->exitval = 0; 30634887Schin #ifdef SIGTSTP 30644887Schin if(job.jobcontrol) 30654887Schin { 30664887Schin signal(SIGTTIN,SIG_DFL); 30674887Schin signal(SIGTTOU,SIG_DFL); 30684887Schin jobwasset++; 30694887Schin } 30704887Schin #endif /* SIGTSTP */ 30714887Schin #ifdef JOBS 30724887Schin if(sh_isstate(SH_MONITOR) && (job.jobcontrol || (otype&FAMP))) 30734887Schin { 30744887Schin if((otype&FAMP) || job.curpgid==0) 30754887Schin grp = 1; 30764887Schin else 30774887Schin grp = job.curpgid; 30784887Schin } 30794887Schin #endif /* JOBS */ 30804887Schin 30814887Schin sfsync(NIL(Sfio_t*)); 30824887Schin sigreset(0); /* set signals to ignore */ 30834887Schin sigwasset++; 30844887Schin /* find first path that has a library component */ 30854887Schin for(pp=path_get(argv[0]); pp && !pp->lib ; pp=pp->next); 30864887Schin spawnpid = path_spawn(path,argv,arge,pp,(grp<<1)|1); 30874887Schin if(spawnpid < 0 && errno==ENOEXEC) 30884887Schin { 30894887Schin char *devfd; 30904887Schin int fd = open(path,O_RDONLY); 30914887Schin argv[-1] = argv[0]; 30924887Schin argv[0] = path; 30934887Schin if(fd>=0) 30944887Schin { 30954887Schin struct stat statb; 30964887Schin sfprintf(sh.strbuf,"/dev/fd/%d",fd); 30974887Schin if(stat(devfd=sfstruse(sh.strbuf),&statb)>=0) 30984887Schin argv[0] = devfd; 30994887Schin } 31004887Schin if(!shp->shpath) 31014887Schin shp->shpath = pathshell(); 31024887Schin spawnpid = path_spawn(shp->shpath,&argv[-1],arge,pp,(grp<<1)|1); 31034887Schin if(fd>=0) 31044887Schin close(fd); 31054887Schin argv[0] = argv[-1]; 31064887Schin } 31074887Schin fail: 31084887Schin if(spawnpid < 0) switch(errno=shp->path_err) 31094887Schin { 31104887Schin case ENOENT: 31114887Schin errormsg(SH_DICT,ERROR_system(ERROR_NOENT),e_found+4); 31124887Schin default: 31134887Schin errormsg(SH_DICT,ERROR_system(ERROR_NOEXEC),e_exec+4); 31144887Schin } 31154887Schin } 31164887Schin else 31174887Schin exitset(); 31184887Schin sh_popcontext(&buff); 31194887Schin if(buff.olist) 31204887Schin free_list(buff.olist); 31214887Schin #ifdef SIGTSTP 31224887Schin if(jobwasset) 31234887Schin { 31244887Schin signal(SIGTTIN,SIG_IGN); 31254887Schin signal(SIGTTOU,SIG_IGN); 31264887Schin } 31274887Schin #endif /* SIGTSTP */ 31284887Schin if(sigwasset) 31294887Schin sigreset(1); /* restore ignored signals */ 31304887Schin if(scope) 31314887Schin { 3132*8462SApril.Chin@Sun.COM sh_unscope(shp); 31334887Schin if(jmpval==SH_JMPSCRIPT) 31344887Schin nv_setlist(t->com.comset,NV_EXPORT|NV_IDENT|NV_ASSIGN); 31354887Schin } 31364887Schin if(t->com.comio) 3137*8462SApril.Chin@Sun.COM sh_iorestore(shp,buff.topfd,jmpval); 31384887Schin if(jmpval>SH_JMPCMD) 31394887Schin siglongjmp(*shp->jmplist,jmpval); 31404887Schin if(spawnpid>0) 31414887Schin { 31424887Schin _sh_fork(spawnpid,otype,jobid); 31434887Schin #ifdef JOBS 31444887Schin if(grp==1) 31454887Schin job.curpgid = spawnpid; 31464887Schin # ifdef SIGTSTP 31474887Schin if(grp>0 && !(otype&FAMP)) 31484887Schin { 31494887Schin while(tcsetpgrp(job.fd,job.curpgid)<0 && job.curpgid!=spawnpid) 31504887Schin job.curpgid = spawnpid; 31514887Schin } 31524887Schin # endif /* SIGTSTP */ 31534887Schin #endif /* JOBS */ 31544887Schin savejobid = *jobid; 31554887Schin if(otype) 31564887Schin return(0); 31574887Schin } 31584887Schin return(spawnpid); 31594887Schin } 31604887Schin 31614887Schin # ifdef _was_lib_fork 31624887Schin # define _lib_fork 1 31634887Schin # endif 31644887Schin # ifndef _lib_fork 31654887Schin pid_t fork(void) 31664887Schin { 31674887Schin errormsg(SH_DICT,ERROR_exit(3),e_notimp,"fork"); 31684887Schin return(-1); 31694887Schin } 31704887Schin # endif /* _lib_fork */ 31714887Schin #endif /* SHOPT_SPAWN */ 3172