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 * Create and manage subshells avoiding forks when possible 234887Schin * 244887Schin * David Korn 254887Schin * AT&T Labs 264887Schin * 274887Schin */ 284887Schin 294887Schin #include "defs.h" 304887Schin #include <ls.h> 314887Schin #include "io.h" 324887Schin #include "fault.h" 334887Schin #include "shnodes.h" 344887Schin #include "shlex.h" 354887Schin #include "jobs.h" 364887Schin #include "variables.h" 374887Schin #include "path.h" 384887Schin 394887Schin #ifndef PIPE_BUF 404887Schin # define PIPE_BUF 512 414887Schin #endif 424887Schin 434887Schin /* 444887Schin * Note that the following structure must be the same 454887Schin * size as the Dtlink_t structure 464887Schin */ 474887Schin struct Link 484887Schin { 494887Schin struct Link *next; 50*8462SApril.Chin@Sun.COM Namval_t *child; 51*8462SApril.Chin@Sun.COM Dt_t *dict; 524887Schin Namval_t *node; 534887Schin }; 544887Schin 554887Schin /* 564887Schin * The following structure is used for command substitution and (...) 574887Schin */ 584887Schin static struct subshell 594887Schin { 60*8462SApril.Chin@Sun.COM Shell_t *shp; /* shell interpreter */ 614887Schin struct subshell *prev; /* previous subshell data */ 624887Schin struct subshell *pipe; /* subshell where output goes to pipe on fork */ 634887Schin Dt_t *var; /* variable table at time of subshell */ 644887Schin struct Link *svar; /* save shell variable table */ 654887Schin Dt_t *sfun; /* function scope for subshell */ 664887Schin Dt_t *salias;/* alias scope for subshell */ 674887Schin Pathcomp_t *pathlist; /* for PATH variable */ 684887Schin #if (ERROR_VERSION >= 20030214L) 694887Schin struct Error_context_s *errcontext; 704887Schin #else 714887Schin struct errorcontext *errcontext; 724887Schin #endif 734887Schin Shopt_t options;/* save shell options */ 744887Schin pid_t subpid; /* child process id */ 754887Schin Sfio_t* saveout;/*saved standard output */ 764887Schin char *pwd; /* present working directory */ 774887Schin const char *shpwd; /* saved pointer to sh.pwd */ 784887Schin void *jobs; /* save job info */ 794887Schin mode_t mask; /* saved umask */ 804887Schin short tmpfd; /* saved tmp file descriptor */ 814887Schin short pipefd; /* read fd if pipe is created */ 824887Schin char jobcontrol; 834887Schin char monitor; 844887Schin unsigned char fdstatus; 854887Schin int fdsaved; /* bit make for saved files */ 86*8462SApril.Chin@Sun.COM int sig; /* signal for $$ */ 87*8462SApril.Chin@Sun.COM pid_t bckpid; 88*8462SApril.Chin@Sun.COM pid_t cpid; 89*8462SApril.Chin@Sun.COM int coutpipe; 90*8462SApril.Chin@Sun.COM int cpipe; 91*8462SApril.Chin@Sun.COM int nofork; 924887Schin } *subshell_data; 934887Schin 944887Schin static int subenv; 954887Schin 964887Schin /* 974887Schin * This routine will turn the sftmp() file into a real /tmp file or pipe 984887Schin */ 99*8462SApril.Chin@Sun.COM void sh_subtmpfile(int pflag) 1004887Schin { 101*8462SApril.Chin@Sun.COM Shell_t *shp = &sh; 102*8462SApril.Chin@Sun.COM int fds[2]; 103*8462SApril.Chin@Sun.COM Sfoff_t off; 1044887Schin if(sfset(sfstdout,0,0)&SF_STRING) 1054887Schin { 1064887Schin register int fd; 107*8462SApril.Chin@Sun.COM register struct checkpt *pp = (struct checkpt*)shp->jmplist; 1084887Schin register struct subshell *sp = subshell_data->pipe; 1094887Schin /* save file descriptor 1 if open */ 1104887Schin if((sp->tmpfd = fd = fcntl(1,F_DUPFD,10)) >= 0) 1114887Schin { 1124887Schin fcntl(fd,F_SETFD,FD_CLOEXEC); 113*8462SApril.Chin@Sun.COM shp->fdstatus[fd] = shp->fdstatus[1]|IOCLEX; 1144887Schin close(1); 1154887Schin } 1164887Schin else if(errno!=EBADF) 1174887Schin errormsg(SH_DICT,ERROR_system(1),e_toomany); 118*8462SApril.Chin@Sun.COM if(!pflag) 1194887Schin { 120*8462SApril.Chin@Sun.COM sfdisc(sfstdout,SF_POPDISC); 121*8462SApril.Chin@Sun.COM if((fd=sffileno(sfstdout))>=0) 1224887Schin { 123*8462SApril.Chin@Sun.COM sh.fdstatus[fd] = IOREAD|IOWRITE; 124*8462SApril.Chin@Sun.COM sfsync(sfstdout); 125*8462SApril.Chin@Sun.COM if(fd==1) 126*8462SApril.Chin@Sun.COM fcntl(1,F_SETFD,0); 127*8462SApril.Chin@Sun.COM else 128*8462SApril.Chin@Sun.COM { 129*8462SApril.Chin@Sun.COM sfsetfd(sfstdout,1); 130*8462SApril.Chin@Sun.COM sh.fdstatus[1] = sh.fdstatus[fd]; 131*8462SApril.Chin@Sun.COM sh.fdstatus[fd] = IOCLOSE; 132*8462SApril.Chin@Sun.COM } 133*8462SApril.Chin@Sun.COM goto skip; 1344887Schin } 1354887Schin } 136*8462SApril.Chin@Sun.COM sh_pipe(fds); 137*8462SApril.Chin@Sun.COM sp->pipefd = fds[0]; 138*8462SApril.Chin@Sun.COM sh_fcntl(sp->pipefd,F_SETFD,FD_CLOEXEC); 139*8462SApril.Chin@Sun.COM /* write the data to the pipe */ 140*8462SApril.Chin@Sun.COM if(off = sftell(sfstdout)) 141*8462SApril.Chin@Sun.COM { 142*8462SApril.Chin@Sun.COM write(fds[1],sfsetbuf(sfstdout,(Void_t*)sfstdout,0),(size_t)off); 143*8462SApril.Chin@Sun.COM sfpurge(sfstdout); 144*8462SApril.Chin@Sun.COM } 145*8462SApril.Chin@Sun.COM sfclose(sfstdout); 146*8462SApril.Chin@Sun.COM if((sh_fcntl(fds[1],F_DUPFD, 1)) != 1) 147*8462SApril.Chin@Sun.COM errormsg(SH_DICT,ERROR_system(1),e_file+4); 148*8462SApril.Chin@Sun.COM sh_close(fds[1]); 149*8462SApril.Chin@Sun.COM skip: 150*8462SApril.Chin@Sun.COM sh_iostream(shp,1); 1514887Schin sfset(sfstdout,SF_SHARE|SF_PUBLIC,1); 152*8462SApril.Chin@Sun.COM sfpool(sfstdout,shp->outpool,SF_WRITE); 1534887Schin if(pp && pp->olist && pp->olist->strm == sfstdout) 1544887Schin pp->olist->strm = 0; 1554887Schin } 1564887Schin } 1574887Schin 1584887Schin /* 1594887Schin * This routine creates a temp file if necessary and creates a subshell. 1604887Schin * The parent routine longjmps back to sh_subshell() 1614887Schin * The child continues possibly with its standard output replaced by temp file 1624887Schin */ 1634887Schin void sh_subfork(void) 1644887Schin { 1654887Schin register struct subshell *sp = subshell_data; 166*8462SApril.Chin@Sun.COM Shell_t *shp = sp->shp; 167*8462SApril.Chin@Sun.COM int curenv = shp->curenv; 1684887Schin pid_t pid; 1694887Schin /* see whether inside $(...) */ 1704887Schin if(sp->pipe) 171*8462SApril.Chin@Sun.COM sh_subtmpfile(1); 172*8462SApril.Chin@Sun.COM shp->curenv = 0; 1734887Schin if(pid = sh_fork(0,NIL(int*))) 1744887Schin { 175*8462SApril.Chin@Sun.COM shp->curenv = curenv; 1764887Schin /* this is the parent part of the fork */ 1774887Schin if(sp->subpid==0) 1784887Schin sp->subpid = pid; 179*8462SApril.Chin@Sun.COM siglongjmp(*shp->jmplist,SH_JMPSUB); 1804887Schin } 1814887Schin else 1824887Schin { 1834887Schin /* this is the child part of the fork */ 1844887Schin /* setting subpid to 1 causes subshell to exit when reached */ 1854887Schin sh_onstate(SH_FORKED); 1864887Schin sh_onstate(SH_NOLOG); 1874887Schin sh_offstate(SH_MONITOR); 1884887Schin subshell_data = 0; 189*8462SApril.Chin@Sun.COM shp->subshell = 0; 190*8462SApril.Chin@Sun.COM SH_SUBSHELLNOD->nvalue.s = 0; 1914887Schin sp->subpid=0; 1924887Schin } 1934887Schin } 1944887Schin 195*8462SApril.Chin@Sun.COM int nv_subsaved(register Namval_t *np) 196*8462SApril.Chin@Sun.COM { 197*8462SApril.Chin@Sun.COM register struct subshell *sp; 198*8462SApril.Chin@Sun.COM register struct Link *lp; 199*8462SApril.Chin@Sun.COM for(sp = (struct subshell*)subshell_data; sp; sp=sp->prev) 200*8462SApril.Chin@Sun.COM { 201*8462SApril.Chin@Sun.COM for(lp=sp->svar; lp; lp = lp->next) 202*8462SApril.Chin@Sun.COM { 203*8462SApril.Chin@Sun.COM if(lp->node==np) 204*8462SApril.Chin@Sun.COM return(1); 205*8462SApril.Chin@Sun.COM } 206*8462SApril.Chin@Sun.COM } 207*8462SApril.Chin@Sun.COM return(0); 208*8462SApril.Chin@Sun.COM } 209*8462SApril.Chin@Sun.COM 2104887Schin /* 2114887Schin * This routine will make a copy of the given node in the 2124887Schin * layer created by the most recent subshell_fork if the 2134887Schin * node hasn't already been copied 2144887Schin */ 2154887Schin Namval_t *sh_assignok(register Namval_t *np,int add) 2164887Schin { 217*8462SApril.Chin@Sun.COM register Namval_t *mp; 218*8462SApril.Chin@Sun.COM register struct Link *lp; 2194887Schin register struct subshell *sp = (struct subshell*)subshell_data; 220*8462SApril.Chin@Sun.COM struct Ufunction *rp; 221*8462SApril.Chin@Sun.COM Shell_t *shp = sp->shp; 222*8462SApril.Chin@Sun.COM Dt_t *dp; 223*8462SApril.Chin@Sun.COM Namval_t *mpnext; 224*8462SApril.Chin@Sun.COM Namarr_t *ap; 225*8462SApril.Chin@Sun.COM int save; 2264887Schin /* don't bother with this */ 2274887Schin if(!sp->shpwd || (nv_isnull(np) && !add)) 2284887Schin return(np); 2294887Schin /* don't bother to save if in newer scope */ 230*8462SApril.Chin@Sun.COM if(!(rp=shp->st.real_fun) || !(dp=rp->sdict)) 231*8462SApril.Chin@Sun.COM dp = sp->var; 232*8462SApril.Chin@Sun.COM if(np->nvenv && !nv_isattr(np,NV_MINIMAL|NV_EXPORT) && shp->last_root) 233*8462SApril.Chin@Sun.COM dp = shp->last_root; 234*8462SApril.Chin@Sun.COM if((mp=nv_search((char*)np,dp,HASH_BUCKET))!=np) 235*8462SApril.Chin@Sun.COM { 236*8462SApril.Chin@Sun.COM if(mp || !np->nvfun || np->nvfun->subshell>=sh.subshell) 237*8462SApril.Chin@Sun.COM return(np); 238*8462SApril.Chin@Sun.COM } 239*8462SApril.Chin@Sun.COM if((ap=nv_arrayptr(np)) && (mp=nv_opensub(np))) 240*8462SApril.Chin@Sun.COM { 241*8462SApril.Chin@Sun.COM shp->last_root = ap->table; 242*8462SApril.Chin@Sun.COM sh_assignok(mp,add); 243*8462SApril.Chin@Sun.COM if(!add || array_assoc(ap)) 244*8462SApril.Chin@Sun.COM return(np); 245*8462SApril.Chin@Sun.COM } 2464887Schin for(lp=subshell_data->svar; lp; lp = lp->next) 2474887Schin { 2484887Schin if(lp->node==np) 2494887Schin return(np); 2504887Schin } 251*8462SApril.Chin@Sun.COM /* first two pointers use linkage from np */ 252*8462SApril.Chin@Sun.COM lp = (struct Link*)malloc(sizeof(*np)+2*sizeof(void*)); 253*8462SApril.Chin@Sun.COM memset(lp,0, sizeof(*mp)+2*sizeof(void*)); 2544887Schin lp->node = np; 255*8462SApril.Chin@Sun.COM if(!add && nv_isvtree(np)) 256*8462SApril.Chin@Sun.COM { 257*8462SApril.Chin@Sun.COM Namval_t fake; 258*8462SApril.Chin@Sun.COM Dt_t *walk, *root=shp->var_tree; 259*8462SApril.Chin@Sun.COM char *name = nv_name(np); 260*8462SApril.Chin@Sun.COM int len = strlen(name); 261*8462SApril.Chin@Sun.COM fake.nvname = name; 262*8462SApril.Chin@Sun.COM mpnext = dtnext(root,&fake); 263*8462SApril.Chin@Sun.COM dp = root->walk?root->walk:root; 264*8462SApril.Chin@Sun.COM while(mp=mpnext) 265*8462SApril.Chin@Sun.COM { 266*8462SApril.Chin@Sun.COM walk = root->walk?root->walk:root; 267*8462SApril.Chin@Sun.COM mpnext = dtnext(root,mp); 268*8462SApril.Chin@Sun.COM if(memcmp(name,mp->nvname,len) || mp->nvname[len]!='.') 269*8462SApril.Chin@Sun.COM break; 270*8462SApril.Chin@Sun.COM nv_delete(mp,walk,NV_NOFREE); 271*8462SApril.Chin@Sun.COM *((Namval_t**)mp) = lp->child; 272*8462SApril.Chin@Sun.COM lp->child = mp; 273*8462SApril.Chin@Sun.COM 274*8462SApril.Chin@Sun.COM } 275*8462SApril.Chin@Sun.COM } 276*8462SApril.Chin@Sun.COM lp->dict = dp; 277*8462SApril.Chin@Sun.COM mp = (Namval_t*)&lp->dict; 2784887Schin lp->next = subshell_data->svar; 2794887Schin subshell_data->svar = lp; 280*8462SApril.Chin@Sun.COM save = shp->subshell; 281*8462SApril.Chin@Sun.COM shp->subshell = 0; 282*8462SApril.Chin@Sun.COM mp->nvname = np->nvname; 283*8462SApril.Chin@Sun.COM nv_clone(np,mp,(add?(nv_isnull(np)?0:NV_NOFREE)|NV_ARRAY:NV_MOVE)); 284*8462SApril.Chin@Sun.COM shp->subshell = save; 2854887Schin return(np); 2864887Schin } 2874887Schin 2884887Schin /* 2894887Schin * restore the variables 2904887Schin */ 2914887Schin static void nv_restore(struct subshell *sp) 2924887Schin { 2934887Schin register struct Link *lp, *lq; 2944887Schin register Namval_t *mp, *np; 2954887Schin const char *save = sp->shpwd; 296*8462SApril.Chin@Sun.COM Namval_t *mpnext; 2974887Schin sp->shpwd = 0; /* make sure sh_assignok doesn't save with nv_unset() */ 2984887Schin for(lp=sp->svar; lp; lp=lq) 2994887Schin { 300*8462SApril.Chin@Sun.COM np = (Namval_t*)&lp->dict; 301*8462SApril.Chin@Sun.COM lq = lp->next; 3024887Schin mp = lp->node; 303*8462SApril.Chin@Sun.COM if(!mp->nvname) 304*8462SApril.Chin@Sun.COM continue; 3054887Schin if(nv_isarray(mp)) 3064887Schin nv_putsub(mp,NIL(char*),ARRAY_SCAN); 3074887Schin _nv_unset(mp,NV_RDONLY); 308*8462SApril.Chin@Sun.COM if(nv_isarray(np)) 309*8462SApril.Chin@Sun.COM { 310*8462SApril.Chin@Sun.COM nv_clone(np,mp,NV_MOVE); 311*8462SApril.Chin@Sun.COM goto skip; 312*8462SApril.Chin@Sun.COM } 3134887Schin nv_setsize(mp,nv_size(np)); 3144887Schin if(!nv_isattr(np,NV_MINIMAL) || nv_isattr(np,NV_EXPORT)) 3154887Schin mp->nvenv = np->nvenv; 3164887Schin mp->nvfun = np->nvfun; 3174887Schin mp->nvflag = np->nvflag; 318*8462SApril.Chin@Sun.COM if(nv_cover(mp)) 3194887Schin nv_putval(mp, np->nvalue.cp,0); 3204887Schin else 3214887Schin mp->nvalue.cp = np->nvalue.cp; 3224887Schin np->nvfun = 0; 3234887Schin if(nv_isattr(mp,NV_EXPORT)) 3244887Schin { 3254887Schin char *name = nv_name(mp); 3264887Schin sh_envput(sh.env,mp); 3274887Schin if(*name=='_' && strcmp(name,"_AST_FEATURES")==0) 3284887Schin astconf(NiL, NiL, NiL); 3294887Schin } 3304887Schin else if(nv_isattr(np,NV_EXPORT)) 3314887Schin env_delete(sh.env,nv_name(mp)); 332*8462SApril.Chin@Sun.COM skip: 333*8462SApril.Chin@Sun.COM for(mp=lp->child; mp; mp=mpnext) 334*8462SApril.Chin@Sun.COM { 335*8462SApril.Chin@Sun.COM mpnext = *((Namval_t**)mp); 336*8462SApril.Chin@Sun.COM dtinsert(lp->dict,mp); 337*8462SApril.Chin@Sun.COM } 338*8462SApril.Chin@Sun.COM free((void*)lp); 339*8462SApril.Chin@Sun.COM sp->svar = lq; 3404887Schin } 3414887Schin sp->shpwd=save; 3424887Schin } 3434887Schin 3444887Schin /* 3454887Schin * return pointer to alias tree 3464887Schin * create new one if in a subshell and one doesn't exist and create is non-zero 3474887Schin */ 3484887Schin Dt_t *sh_subaliastree(int create) 3494887Schin { 3504887Schin register struct subshell *sp = subshell_data; 3514887Schin if(!sp || sh.curenv==0) 3524887Schin return(sh.alias_tree); 3534887Schin if(!sp->salias && create) 3544887Schin { 3554887Schin sp->salias = dtopen(&_Nvdisc,Dtoset); 3564887Schin dtview(sp->salias,sh.alias_tree); 3574887Schin sh.alias_tree = sp->salias; 3584887Schin } 3594887Schin return(sp->salias); 3604887Schin } 3614887Schin 3624887Schin /* 3634887Schin * return pointer to function tree 3644887Schin * create new one if in a subshell and one doesn't exist and create is non-zero 3654887Schin */ 3664887Schin Dt_t *sh_subfuntree(int create) 3674887Schin { 3684887Schin register struct subshell *sp = subshell_data; 3694887Schin if(!sp || sh.curenv==0) 3704887Schin return(sh.fun_tree); 3714887Schin if(!sp->sfun && create) 3724887Schin { 3734887Schin sp->sfun = dtopen(&_Nvdisc,Dtoset); 3744887Schin dtview(sp->sfun,sh.fun_tree); 3754887Schin sh.fun_tree = sp->sfun; 3764887Schin } 377*8462SApril.Chin@Sun.COM return(sh.fun_tree); 3784887Schin } 3794887Schin 380*8462SApril.Chin@Sun.COM static void table_unset(register Dt_t *root,int fun) 3814887Schin { 3824887Schin register Namval_t *np,*nq; 383*8462SApril.Chin@Sun.COM int flag; 3844887Schin for(np=(Namval_t*)dtfirst(root);np;np=nq) 3854887Schin { 3864887Schin nq = (Namval_t*)dtnext(root,np); 387*8462SApril.Chin@Sun.COM flag=0; 388*8462SApril.Chin@Sun.COM if(fun && np->nvalue.rp->fname && *np->nvalue.rp->fname=='/') 389*8462SApril.Chin@Sun.COM { 390*8462SApril.Chin@Sun.COM np->nvalue.rp->fdict = 0; 391*8462SApril.Chin@Sun.COM flag = NV_NOFREE; 392*8462SApril.Chin@Sun.COM } 393*8462SApril.Chin@Sun.COM else 394*8462SApril.Chin@Sun.COM _nv_unset(np,NV_RDONLY); 395*8462SApril.Chin@Sun.COM nv_delete(np,root,flag|NV_FUNCTION); 3964887Schin } 3974887Schin } 3984887Schin 3994887Schin int sh_subsavefd(register int fd) 4004887Schin { 4014887Schin register struct subshell *sp = subshell_data; 4024887Schin register int old=0; 4034887Schin if(sp) 4044887Schin { 4054887Schin old = !(sp->fdsaved&(1<<(fd-1))); 4064887Schin sp->fdsaved |= (1<<(fd-1)); 4074887Schin } 4084887Schin return(old); 4094887Schin } 4104887Schin 411*8462SApril.Chin@Sun.COM void sh_subjobcheck(pid_t pid) 412*8462SApril.Chin@Sun.COM { 413*8462SApril.Chin@Sun.COM register struct subshell *sp = subshell_data; 414*8462SApril.Chin@Sun.COM while(sp) 415*8462SApril.Chin@Sun.COM { 416*8462SApril.Chin@Sun.COM if(sp->cpid==pid) 417*8462SApril.Chin@Sun.COM { 418*8462SApril.Chin@Sun.COM sh_close(sp->coutpipe); 419*8462SApril.Chin@Sun.COM sh_close(sp->cpipe); 420*8462SApril.Chin@Sun.COM sp->coutpipe = sp->cpipe = -1; 421*8462SApril.Chin@Sun.COM return; 422*8462SApril.Chin@Sun.COM } 423*8462SApril.Chin@Sun.COM sp = sp->prev; 424*8462SApril.Chin@Sun.COM } 425*8462SApril.Chin@Sun.COM } 426*8462SApril.Chin@Sun.COM 4274887Schin /* 4284887Schin * Run command tree <t> in a virtual sub-shell 4294887Schin * If comsub is not null, then output will be placed in temp file (or buffer) 4304887Schin * If comsub is not null, the return value will be a stream consisting of 4314887Schin * output of command <t>. Otherwise, NULL will be returned. 4324887Schin */ 4334887Schin 4344887Schin Sfio_t *sh_subshell(Shnode_t *t, int flags, int comsub) 4354887Schin { 4364887Schin Shell_t *shp = &sh; 4374887Schin struct subshell sub_data; 4384887Schin register struct subshell *sp = &sub_data; 439*8462SApril.Chin@Sun.COM int jmpval,nsig=0; 4404887Schin int savecurenv = shp->curenv; 441*8462SApril.Chin@Sun.COM int savejobpgid = job.curpgid; 4424887Schin int16_t subshell; 4434887Schin char *savsig; 4444887Schin Sfio_t *iop=0; 4454887Schin struct checkpt buff; 4464887Schin struct sh_scoped savst; 4474887Schin struct dolnod *argsav=0; 4484887Schin memset((char*)sp, 0, sizeof(*sp)); 4494887Schin sfsync(shp->outpool); 450*8462SApril.Chin@Sun.COM argsav = sh_arguse(shp); 4514887Schin if(shp->curenv==0) 4524887Schin { 4534887Schin subshell_data=0; 4544887Schin subenv = 0; 4554887Schin } 4564887Schin shp->curenv = ++subenv; 457*8462SApril.Chin@Sun.COM job.curpgid = 0; 4584887Schin savst = shp->st; 4594887Schin sh_pushcontext(&buff,SH_JMPSUB); 4604887Schin subshell = shp->subshell+1; 461*8462SApril.Chin@Sun.COM SH_SUBSHELLNOD->nvalue.s = subshell; 4624887Schin shp->subshell = subshell; 4634887Schin sp->prev = subshell_data; 464*8462SApril.Chin@Sun.COM sp->shp = shp; 465*8462SApril.Chin@Sun.COM sp->sig = 0; 4664887Schin subshell_data = sp; 4674887Schin sp->errcontext = &buff.err; 4684887Schin sp->var = shp->var_tree; 4694887Schin sp->options = shp->options; 4704887Schin sp->jobs = job_subsave(); 4714887Schin /* make sure initialization has occurred */ 4724887Schin if(!shp->pathlist) 4734887Schin path_get("."); 4744887Schin sp->pathlist = path_dup((Pathcomp_t*)shp->pathlist); 4754887Schin if(!shp->pwd) 4764887Schin path_pwd(0); 4774887Schin sp->bckpid = shp->bckpid; 478*8462SApril.Chin@Sun.COM if(comsub) 479*8462SApril.Chin@Sun.COM sh_stats(STAT_COMSUB); 480*8462SApril.Chin@Sun.COM if(!comsub || (comsub==1 && !sh_isoption(SH_SUBSHARE))) 4814887Schin { 4824887Schin sp->shpwd = shp->pwd; 4834887Schin sp->pwd = (shp->pwd?strdup(shp->pwd):0); 4844887Schin sp->mask = shp->mask; 485*8462SApril.Chin@Sun.COM sh_stats(STAT_SUBSHELL); 4864887Schin /* save trap table */ 4874887Schin shp->st.otrapcom = 0; 4884887Schin if((nsig=shp->st.trapmax*sizeof(char*))>0 || shp->st.trapcom[0]) 4894887Schin { 4904887Schin nsig += sizeof(char*); 4914887Schin memcpy(savsig=malloc(nsig),(char*)&shp->st.trapcom[0],nsig); 4924887Schin /* this nonsense needed for $(trap) */ 4934887Schin shp->st.otrapcom = (char**)savsig; 4944887Schin } 495*8462SApril.Chin@Sun.COM sp->cpid = shp->cpid; 496*8462SApril.Chin@Sun.COM sp->coutpipe = shp->coutpipe; 497*8462SApril.Chin@Sun.COM sp->cpipe = shp->cpipe[1]; 498*8462SApril.Chin@Sun.COM shp->coutpipe = shp->cpipe[1] = -1; 499*8462SApril.Chin@Sun.COM shp->cpid = 0; 5004887Schin sh_sigreset(0); 5014887Schin } 5024887Schin jmpval = sigsetjmp(buff.buff,0); 5034887Schin if(jmpval==0) 5044887Schin { 5054887Schin if(comsub) 5064887Schin { 5074887Schin /* disable job control */ 508*8462SApril.Chin@Sun.COM shp->spid = 0; 5094887Schin sp->jobcontrol = job.jobcontrol; 5104887Schin sp->monitor = (sh_isstate(SH_MONITOR)!=0); 5114887Schin job.jobcontrol=0; 5124887Schin sh_offstate(SH_MONITOR); 5134887Schin sp->pipe = sp; 5144887Schin /* save sfstdout and status */ 5154887Schin sp->saveout = sfswap(sfstdout,NIL(Sfio_t*)); 5164887Schin sp->fdstatus = shp->fdstatus[1]; 5174887Schin sp->tmpfd = -1; 5184887Schin sp->pipefd = -1; 5194887Schin /* use sftmp() file for standard output */ 5204887Schin if(!(iop = sftmp(PIPE_BUF))) 5214887Schin { 5224887Schin sfswap(sp->saveout,sfstdout); 5234887Schin errormsg(SH_DICT,ERROR_system(1),e_tmpcreate); 5244887Schin } 5254887Schin sfswap(iop,sfstdout); 5264887Schin sfset(sfstdout,SF_READ,0); 5274887Schin shp->fdstatus[1] = IOWRITE; 528*8462SApril.Chin@Sun.COM if(!(sp->nofork = sh_state(SH_NOFORK))) 529*8462SApril.Chin@Sun.COM sh_onstate(SH_NOFORK); 530*8462SApril.Chin@Sun.COM flags |= sh_state(SH_NOFORK); 5314887Schin } 5324887Schin else if(sp->prev) 5334887Schin { 5344887Schin sp->pipe = sp->prev->pipe; 5354887Schin flags &= ~sh_state(SH_NOFORK); 5364887Schin } 5374887Schin sh_exec(t,flags); 5384887Schin } 539*8462SApril.Chin@Sun.COM if(comsub!=2 && jmpval!=SH_JMPSUB && shp->st.trapcom[0] && shp->subshell) 5404887Schin { 5414887Schin /* trap on EXIT not handled by child */ 5424887Schin char *trap=shp->st.trapcom[0]; 5434887Schin shp->st.trapcom[0] = 0; /* prevent recursion */ 5444887Schin shp->oldexit = shp->exitval; 5454887Schin sh_trap(trap,0); 5464887Schin free(trap); 5474887Schin } 5484887Schin sh_popcontext(&buff); 5494887Schin if(shp->subshell==0) /* must be child process */ 5504887Schin { 5514887Schin subshell_data = sp->prev; 5524887Schin if(jmpval==SH_JMPSCRIPT) 5534887Schin siglongjmp(*shp->jmplist,jmpval); 554*8462SApril.Chin@Sun.COM sh_done(shp,0); 5554887Schin } 5564887Schin if(comsub) 5574887Schin { 5584887Schin /* re-enable job control */ 559*8462SApril.Chin@Sun.COM if(!sp->nofork) 560*8462SApril.Chin@Sun.COM sh_offstate(SH_NOFORK); 5614887Schin job.jobcontrol = sp->jobcontrol; 5624887Schin if(sp->monitor) 5634887Schin sh_onstate(SH_MONITOR); 5644887Schin if(sp->pipefd>=0) 5654887Schin { 5664887Schin /* sftmp() file has been returned into pipe */ 567*8462SApril.Chin@Sun.COM iop = sh_iostream(shp,sp->pipefd); 5684887Schin sfclose(sfstdout); 5694887Schin } 5704887Schin else 5714887Schin { 5724887Schin /* move tmp file to iop and restore sfstdout */ 5734887Schin iop = sfswap(sfstdout,NIL(Sfio_t*)); 5744887Schin if(!iop) 5754887Schin { 5764887Schin /* maybe locked try again */ 5774887Schin sfclrlock(sfstdout); 5784887Schin iop = sfswap(sfstdout,NIL(Sfio_t*)); 5794887Schin } 5804887Schin if(iop && sffileno(iop)==1) 5814887Schin { 5824887Schin int fd=sfsetfd(iop,3); 5834887Schin if(fd<0) 5844887Schin errormsg(SH_DICT,ERROR_system(1),e_toomany); 5854887Schin shp->sftable[fd] = iop; 5864887Schin fcntl(fd,F_SETFD,FD_CLOEXEC); 5874887Schin shp->fdstatus[fd] = (shp->fdstatus[1]|IOCLEX); 5884887Schin shp->fdstatus[1] = IOCLOSE; 5894887Schin } 5904887Schin sfset(iop,SF_READ,1); 5914887Schin } 5924887Schin sfswap(sp->saveout,sfstdout); 5934887Schin /* check if standard output was preserved */ 5944887Schin if(sp->tmpfd>=0) 5954887Schin { 5964887Schin close(1); 5974887Schin fcntl(sp->tmpfd,F_DUPFD,1); 5984887Schin sh_close(sp->tmpfd); 5994887Schin } 6004887Schin shp->fdstatus[1] = sp->fdstatus; 6014887Schin } 6024887Schin if(sp->subpid) 603*8462SApril.Chin@Sun.COM { 604*8462SApril.Chin@Sun.COM if(shp->exitval > SH_EXITSIG) 605*8462SApril.Chin@Sun.COM sp->sig = (shp->exitval&SH_EXITMASK); 606*8462SApril.Chin@Sun.COM shp->exitval = 0; 607*8462SApril.Chin@Sun.COM if(comsub) 608*8462SApril.Chin@Sun.COM shp->spid = sp->subpid; 609*8462SApril.Chin@Sun.COM else 610*8462SApril.Chin@Sun.COM job_wait(sp->subpid); 611*8462SApril.Chin@Sun.COM } 612*8462SApril.Chin@Sun.COM if(comsub && iop && sp->pipefd<0) 6134887Schin sfseek(iop,(off_t)0,SEEK_SET); 6144887Schin path_delete((Pathcomp_t*)shp->pathlist); 6154887Schin shp->pathlist = (void*)sp->pathlist; 6164887Schin job_subrestore(sp->jobs); 6174887Schin shp->jobenv = savecurenv; 618*8462SApril.Chin@Sun.COM job.curpgid = savejobpgid; 6194887Schin shp->bckpid = sp->bckpid; 6204887Schin if(sp->shpwd) /* restore environment if saved */ 6214887Schin { 622*8462SApril.Chin@Sun.COM int n; 6234887Schin shp->options = sp->options; 6244887Schin nv_restore(sp); 6254887Schin if(sp->salias) 6264887Schin { 6274887Schin shp->alias_tree = dtview(sp->salias,0); 628*8462SApril.Chin@Sun.COM table_unset(sp->salias,0); 6294887Schin dtclose(sp->salias); 6304887Schin } 6314887Schin if(sp->sfun) 6324887Schin { 6334887Schin shp->fun_tree = dtview(sp->sfun,0); 634*8462SApril.Chin@Sun.COM table_unset(sp->sfun,1); 6354887Schin dtclose(sp->sfun); 6364887Schin } 637*8462SApril.Chin@Sun.COM n = shp->st.trapmax-savst.trapmax; 6384887Schin sh_sigreset(1); 639*8462SApril.Chin@Sun.COM if(n>0) 640*8462SApril.Chin@Sun.COM memset(&shp->st.trapcom[savst.trapmax],0,n*sizeof(char*)); 6414887Schin shp->st = savst; 6424887Schin shp->curenv = savecurenv; 6434887Schin if(nsig) 6444887Schin { 6454887Schin memcpy((char*)&shp->st.trapcom[0],savsig,nsig); 6464887Schin free((void*)savsig); 6474887Schin } 6484887Schin shp->options = sp->options; 6494887Schin if(!shp->pwd || strcmp(sp->pwd,shp->pwd)) 6504887Schin { 6514887Schin /* restore PWDNOD */ 652*8462SApril.Chin@Sun.COM Namval_t *pwdnod = sh_scoped(shp,PWDNOD); 6534887Schin if(shp->pwd) 6544887Schin { 6554887Schin chdir(shp->pwd=sp->pwd); 6564887Schin path_newdir(shp->pathlist); 6574887Schin } 6584887Schin if(nv_isattr(pwdnod,NV_NOFREE)) 6594887Schin pwdnod->nvalue.cp = (const char*)sp->pwd; 6604887Schin } 6614887Schin else if(sp->shpwd != shp->pwd) 6624887Schin { 6634887Schin shp->pwd = sp->pwd; 6644887Schin if(PWDNOD->nvalue.cp==sp->shpwd) 6654887Schin PWDNOD->nvalue.cp = sp->pwd; 6664887Schin } 6674887Schin else 6684887Schin free((void*)sp->pwd); 6694887Schin if(sp->mask!=shp->mask) 670*8462SApril.Chin@Sun.COM umask(shp->mask=sp->mask); 671*8462SApril.Chin@Sun.COM if(shp->coutpipe>=0) 672*8462SApril.Chin@Sun.COM { 673*8462SApril.Chin@Sun.COM sh_close(shp->coutpipe); 674*8462SApril.Chin@Sun.COM sh_close(shp->cpipe[1]); 675*8462SApril.Chin@Sun.COM } 676*8462SApril.Chin@Sun.COM shp->cpid = sp->cpid; 677*8462SApril.Chin@Sun.COM shp->cpipe[1] = sp->cpipe; 678*8462SApril.Chin@Sun.COM shp->coutpipe = sp->coutpipe; 6794887Schin } 680*8462SApril.Chin@Sun.COM if(shp->subshell) 681*8462SApril.Chin@Sun.COM SH_SUBSHELLNOD->nvalue.s = --shp->subshell; 682*8462SApril.Chin@Sun.COM if(sp->sig) 683*8462SApril.Chin@Sun.COM { 684*8462SApril.Chin@Sun.COM if(sp->prev) 685*8462SApril.Chin@Sun.COM sp->prev->sig = sp->sig; 686*8462SApril.Chin@Sun.COM else 687*8462SApril.Chin@Sun.COM { 688*8462SApril.Chin@Sun.COM sh_fault(sp->sig); 689*8462SApril.Chin@Sun.COM sh_chktrap(); 690*8462SApril.Chin@Sun.COM } 691*8462SApril.Chin@Sun.COM } 692*8462SApril.Chin@Sun.COM subshell = shp->subshell; 6934887Schin subshell_data = sp->prev; 694*8462SApril.Chin@Sun.COM sh_argfree(shp,argsav,0); 6954887Schin shp->trapnote = 0; 6964887Schin if(shp->topfd != buff.topfd) 697*8462SApril.Chin@Sun.COM sh_iorestore(shp,buff.topfd|IOSUBSHELL,jmpval); 6984887Schin if(shp->exitval > SH_EXITSIG) 6994887Schin { 7004887Schin int sig = shp->exitval&SH_EXITMASK; 7014887Schin if(sig==SIGINT || sig== SIGQUIT) 7024887Schin sh_fault(sig); 7034887Schin } 7044887Schin return(iop); 7054887Schin } 706