14887Schin /*********************************************************************** 24887Schin * * 34887Schin * This software is part of the ast package * 48462SApril.Chin@Sun.COM * Copyright (c) 1982-2008 AT&T Intellectual Property * 54887Schin * and is licensed under the * 64887Schin * Common Public License, Version 1.0 * 78462SApril.Chin@Sun.COM * by AT&T Intellectual Property * 84887Schin * * 94887Schin * A copy of the License is available at * 104887Schin * http://www.opensource.org/licenses/cpl1.0.txt * 114887Schin * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) * 124887Schin * * 134887Schin * Information and Software Systems Research * 144887Schin * AT&T Research * 154887Schin * Florham Park NJ * 164887Schin * * 174887Schin * David Korn <dgk@research.att.com> * 184887Schin * * 194887Schin ***********************************************************************/ 204887Schin #pragma prototyped 214887Schin /* 224887Schin * 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; 508462SApril.Chin@Sun.COM Namval_t *child; 518462SApril.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 { 608462SApril.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 */ 868462SApril.Chin@Sun.COM int sig; /* signal for $$ */ 878462SApril.Chin@Sun.COM pid_t bckpid; 888462SApril.Chin@Sun.COM pid_t cpid; 898462SApril.Chin@Sun.COM int coutpipe; 908462SApril.Chin@Sun.COM int cpipe; 918462SApril.Chin@Sun.COM int nofork; 92*8810SCasper.Dik@Sun.COM char subshare; 934887Schin } *subshell_data; 944887Schin 954887Schin static int subenv; 964887Schin 974887Schin /* 984887Schin * This routine will turn the sftmp() file into a real /tmp file or pipe 994887Schin */ 1008462SApril.Chin@Sun.COM void sh_subtmpfile(int pflag) 1014887Schin { 1028462SApril.Chin@Sun.COM Shell_t *shp = &sh; 1038462SApril.Chin@Sun.COM int fds[2]; 1048462SApril.Chin@Sun.COM Sfoff_t off; 1054887Schin if(sfset(sfstdout,0,0)&SF_STRING) 1064887Schin { 1074887Schin register int fd; 1088462SApril.Chin@Sun.COM register struct checkpt *pp = (struct checkpt*)shp->jmplist; 1094887Schin register struct subshell *sp = subshell_data->pipe; 1104887Schin /* save file descriptor 1 if open */ 1114887Schin if((sp->tmpfd = fd = fcntl(1,F_DUPFD,10)) >= 0) 1124887Schin { 1134887Schin fcntl(fd,F_SETFD,FD_CLOEXEC); 1148462SApril.Chin@Sun.COM shp->fdstatus[fd] = shp->fdstatus[1]|IOCLEX; 1154887Schin close(1); 1164887Schin } 1174887Schin else if(errno!=EBADF) 1184887Schin errormsg(SH_DICT,ERROR_system(1),e_toomany); 1198462SApril.Chin@Sun.COM if(!pflag) 1204887Schin { 1218462SApril.Chin@Sun.COM sfdisc(sfstdout,SF_POPDISC); 1228462SApril.Chin@Sun.COM if((fd=sffileno(sfstdout))>=0) 1234887Schin { 1248462SApril.Chin@Sun.COM sh.fdstatus[fd] = IOREAD|IOWRITE; 1258462SApril.Chin@Sun.COM sfsync(sfstdout); 1268462SApril.Chin@Sun.COM if(fd==1) 1278462SApril.Chin@Sun.COM fcntl(1,F_SETFD,0); 1288462SApril.Chin@Sun.COM else 1298462SApril.Chin@Sun.COM { 1308462SApril.Chin@Sun.COM sfsetfd(sfstdout,1); 1318462SApril.Chin@Sun.COM sh.fdstatus[1] = sh.fdstatus[fd]; 1328462SApril.Chin@Sun.COM sh.fdstatus[fd] = IOCLOSE; 1338462SApril.Chin@Sun.COM } 1348462SApril.Chin@Sun.COM goto skip; 1354887Schin } 1364887Schin } 1378462SApril.Chin@Sun.COM sh_pipe(fds); 1388462SApril.Chin@Sun.COM sp->pipefd = fds[0]; 1398462SApril.Chin@Sun.COM sh_fcntl(sp->pipefd,F_SETFD,FD_CLOEXEC); 1408462SApril.Chin@Sun.COM /* write the data to the pipe */ 1418462SApril.Chin@Sun.COM if(off = sftell(sfstdout)) 1428462SApril.Chin@Sun.COM { 1438462SApril.Chin@Sun.COM write(fds[1],sfsetbuf(sfstdout,(Void_t*)sfstdout,0),(size_t)off); 1448462SApril.Chin@Sun.COM sfpurge(sfstdout); 1458462SApril.Chin@Sun.COM } 1468462SApril.Chin@Sun.COM sfclose(sfstdout); 1478462SApril.Chin@Sun.COM if((sh_fcntl(fds[1],F_DUPFD, 1)) != 1) 1488462SApril.Chin@Sun.COM errormsg(SH_DICT,ERROR_system(1),e_file+4); 1498462SApril.Chin@Sun.COM sh_close(fds[1]); 1508462SApril.Chin@Sun.COM skip: 1518462SApril.Chin@Sun.COM sh_iostream(shp,1); 1524887Schin sfset(sfstdout,SF_SHARE|SF_PUBLIC,1); 1538462SApril.Chin@Sun.COM sfpool(sfstdout,shp->outpool,SF_WRITE); 1544887Schin if(pp && pp->olist && pp->olist->strm == sfstdout) 1554887Schin pp->olist->strm = 0; 1564887Schin } 1574887Schin } 1584887Schin 1594887Schin /* 1604887Schin * This routine creates a temp file if necessary and creates a subshell. 1614887Schin * The parent routine longjmps back to sh_subshell() 1624887Schin * The child continues possibly with its standard output replaced by temp file 1634887Schin */ 1644887Schin void sh_subfork(void) 1654887Schin { 1664887Schin register struct subshell *sp = subshell_data; 1678462SApril.Chin@Sun.COM Shell_t *shp = sp->shp; 1688462SApril.Chin@Sun.COM int curenv = shp->curenv; 1694887Schin pid_t pid; 1704887Schin /* see whether inside $(...) */ 1714887Schin if(sp->pipe) 1728462SApril.Chin@Sun.COM sh_subtmpfile(1); 1738462SApril.Chin@Sun.COM shp->curenv = 0; 1744887Schin if(pid = sh_fork(0,NIL(int*))) 1754887Schin { 1768462SApril.Chin@Sun.COM shp->curenv = curenv; 1774887Schin /* this is the parent part of the fork */ 1784887Schin if(sp->subpid==0) 1794887Schin sp->subpid = pid; 1808462SApril.Chin@Sun.COM siglongjmp(*shp->jmplist,SH_JMPSUB); 1814887Schin } 1824887Schin else 1834887Schin { 1844887Schin /* this is the child part of the fork */ 1854887Schin /* setting subpid to 1 causes subshell to exit when reached */ 1864887Schin sh_onstate(SH_FORKED); 1874887Schin sh_onstate(SH_NOLOG); 1884887Schin sh_offstate(SH_MONITOR); 1894887Schin subshell_data = 0; 1908462SApril.Chin@Sun.COM shp->subshell = 0; 1918462SApril.Chin@Sun.COM SH_SUBSHELLNOD->nvalue.s = 0; 1924887Schin sp->subpid=0; 1934887Schin } 1944887Schin } 1954887Schin 1968462SApril.Chin@Sun.COM int nv_subsaved(register Namval_t *np) 1978462SApril.Chin@Sun.COM { 1988462SApril.Chin@Sun.COM register struct subshell *sp; 1998462SApril.Chin@Sun.COM register struct Link *lp; 2008462SApril.Chin@Sun.COM for(sp = (struct subshell*)subshell_data; sp; sp=sp->prev) 2018462SApril.Chin@Sun.COM { 2028462SApril.Chin@Sun.COM for(lp=sp->svar; lp; lp = lp->next) 2038462SApril.Chin@Sun.COM { 2048462SApril.Chin@Sun.COM if(lp->node==np) 2058462SApril.Chin@Sun.COM return(1); 2068462SApril.Chin@Sun.COM } 2078462SApril.Chin@Sun.COM } 2088462SApril.Chin@Sun.COM return(0); 2098462SApril.Chin@Sun.COM } 2108462SApril.Chin@Sun.COM 2114887Schin /* 2124887Schin * This routine will make a copy of the given node in the 2134887Schin * layer created by the most recent subshell_fork if the 2144887Schin * node hasn't already been copied 2154887Schin */ 2164887Schin Namval_t *sh_assignok(register Namval_t *np,int add) 2174887Schin { 2188462SApril.Chin@Sun.COM register Namval_t *mp; 2198462SApril.Chin@Sun.COM register struct Link *lp; 2204887Schin register struct subshell *sp = (struct subshell*)subshell_data; 2218462SApril.Chin@Sun.COM struct Ufunction *rp; 2228462SApril.Chin@Sun.COM Shell_t *shp = sp->shp; 2238462SApril.Chin@Sun.COM Dt_t *dp; 2248462SApril.Chin@Sun.COM Namval_t *mpnext; 2258462SApril.Chin@Sun.COM Namarr_t *ap; 2268462SApril.Chin@Sun.COM int save; 2274887Schin /* don't bother with this */ 2284887Schin if(!sp->shpwd || (nv_isnull(np) && !add)) 2294887Schin return(np); 2304887Schin /* don't bother to save if in newer scope */ 2318462SApril.Chin@Sun.COM if(!(rp=shp->st.real_fun) || !(dp=rp->sdict)) 2328462SApril.Chin@Sun.COM dp = sp->var; 2338462SApril.Chin@Sun.COM if(np->nvenv && !nv_isattr(np,NV_MINIMAL|NV_EXPORT) && shp->last_root) 2348462SApril.Chin@Sun.COM dp = shp->last_root; 2358462SApril.Chin@Sun.COM if((mp=nv_search((char*)np,dp,HASH_BUCKET))!=np) 2368462SApril.Chin@Sun.COM { 2378462SApril.Chin@Sun.COM if(mp || !np->nvfun || np->nvfun->subshell>=sh.subshell) 2388462SApril.Chin@Sun.COM return(np); 2398462SApril.Chin@Sun.COM } 2408462SApril.Chin@Sun.COM if((ap=nv_arrayptr(np)) && (mp=nv_opensub(np))) 2418462SApril.Chin@Sun.COM { 2428462SApril.Chin@Sun.COM shp->last_root = ap->table; 2438462SApril.Chin@Sun.COM sh_assignok(mp,add); 2448462SApril.Chin@Sun.COM if(!add || array_assoc(ap)) 2458462SApril.Chin@Sun.COM return(np); 2468462SApril.Chin@Sun.COM } 2474887Schin for(lp=subshell_data->svar; lp; lp = lp->next) 2484887Schin { 2494887Schin if(lp->node==np) 2504887Schin return(np); 2514887Schin } 2528462SApril.Chin@Sun.COM /* first two pointers use linkage from np */ 2538462SApril.Chin@Sun.COM lp = (struct Link*)malloc(sizeof(*np)+2*sizeof(void*)); 2548462SApril.Chin@Sun.COM memset(lp,0, sizeof(*mp)+2*sizeof(void*)); 2554887Schin lp->node = np; 2568462SApril.Chin@Sun.COM if(!add && nv_isvtree(np)) 2578462SApril.Chin@Sun.COM { 2588462SApril.Chin@Sun.COM Namval_t fake; 2598462SApril.Chin@Sun.COM Dt_t *walk, *root=shp->var_tree; 2608462SApril.Chin@Sun.COM char *name = nv_name(np); 2618462SApril.Chin@Sun.COM int len = strlen(name); 2628462SApril.Chin@Sun.COM fake.nvname = name; 2638462SApril.Chin@Sun.COM mpnext = dtnext(root,&fake); 2648462SApril.Chin@Sun.COM dp = root->walk?root->walk:root; 2658462SApril.Chin@Sun.COM while(mp=mpnext) 2668462SApril.Chin@Sun.COM { 2678462SApril.Chin@Sun.COM walk = root->walk?root->walk:root; 2688462SApril.Chin@Sun.COM mpnext = dtnext(root,mp); 2698462SApril.Chin@Sun.COM if(memcmp(name,mp->nvname,len) || mp->nvname[len]!='.') 2708462SApril.Chin@Sun.COM break; 2718462SApril.Chin@Sun.COM nv_delete(mp,walk,NV_NOFREE); 2728462SApril.Chin@Sun.COM *((Namval_t**)mp) = lp->child; 2738462SApril.Chin@Sun.COM lp->child = mp; 2748462SApril.Chin@Sun.COM 2758462SApril.Chin@Sun.COM } 2768462SApril.Chin@Sun.COM } 2778462SApril.Chin@Sun.COM lp->dict = dp; 2788462SApril.Chin@Sun.COM mp = (Namval_t*)&lp->dict; 2794887Schin lp->next = subshell_data->svar; 2804887Schin subshell_data->svar = lp; 2818462SApril.Chin@Sun.COM save = shp->subshell; 2828462SApril.Chin@Sun.COM shp->subshell = 0; 2838462SApril.Chin@Sun.COM mp->nvname = np->nvname; 2848462SApril.Chin@Sun.COM nv_clone(np,mp,(add?(nv_isnull(np)?0:NV_NOFREE)|NV_ARRAY:NV_MOVE)); 2858462SApril.Chin@Sun.COM shp->subshell = save; 2864887Schin return(np); 2874887Schin } 2884887Schin 2894887Schin /* 2904887Schin * restore the variables 2914887Schin */ 2924887Schin static void nv_restore(struct subshell *sp) 2934887Schin { 2944887Schin register struct Link *lp, *lq; 2954887Schin register Namval_t *mp, *np; 2964887Schin const char *save = sp->shpwd; 2978462SApril.Chin@Sun.COM Namval_t *mpnext; 2984887Schin sp->shpwd = 0; /* make sure sh_assignok doesn't save with nv_unset() */ 2994887Schin for(lp=sp->svar; lp; lp=lq) 3004887Schin { 3018462SApril.Chin@Sun.COM np = (Namval_t*)&lp->dict; 3028462SApril.Chin@Sun.COM lq = lp->next; 3034887Schin mp = lp->node; 3048462SApril.Chin@Sun.COM if(!mp->nvname) 3058462SApril.Chin@Sun.COM continue; 3064887Schin if(nv_isarray(mp)) 3074887Schin nv_putsub(mp,NIL(char*),ARRAY_SCAN); 3084887Schin _nv_unset(mp,NV_RDONLY); 3098462SApril.Chin@Sun.COM if(nv_isarray(np)) 3108462SApril.Chin@Sun.COM { 3118462SApril.Chin@Sun.COM nv_clone(np,mp,NV_MOVE); 3128462SApril.Chin@Sun.COM goto skip; 3138462SApril.Chin@Sun.COM } 3144887Schin nv_setsize(mp,nv_size(np)); 3154887Schin if(!nv_isattr(np,NV_MINIMAL) || nv_isattr(np,NV_EXPORT)) 3164887Schin mp->nvenv = np->nvenv; 3174887Schin mp->nvfun = np->nvfun; 3184887Schin mp->nvflag = np->nvflag; 3198462SApril.Chin@Sun.COM if(nv_cover(mp)) 3204887Schin nv_putval(mp, np->nvalue.cp,0); 3214887Schin else 3224887Schin mp->nvalue.cp = np->nvalue.cp; 3234887Schin np->nvfun = 0; 3244887Schin if(nv_isattr(mp,NV_EXPORT)) 3254887Schin { 3264887Schin char *name = nv_name(mp); 3274887Schin sh_envput(sh.env,mp); 3284887Schin if(*name=='_' && strcmp(name,"_AST_FEATURES")==0) 3294887Schin astconf(NiL, NiL, NiL); 3304887Schin } 3314887Schin else if(nv_isattr(np,NV_EXPORT)) 3324887Schin env_delete(sh.env,nv_name(mp)); 3338462SApril.Chin@Sun.COM skip: 3348462SApril.Chin@Sun.COM for(mp=lp->child; mp; mp=mpnext) 3358462SApril.Chin@Sun.COM { 3368462SApril.Chin@Sun.COM mpnext = *((Namval_t**)mp); 3378462SApril.Chin@Sun.COM dtinsert(lp->dict,mp); 3388462SApril.Chin@Sun.COM } 3398462SApril.Chin@Sun.COM free((void*)lp); 3408462SApril.Chin@Sun.COM sp->svar = lq; 3414887Schin } 3424887Schin sp->shpwd=save; 3434887Schin } 3444887Schin 3454887Schin /* 3464887Schin * return pointer to alias tree 3474887Schin * create new one if in a subshell and one doesn't exist and create is non-zero 3484887Schin */ 3494887Schin Dt_t *sh_subaliastree(int create) 3504887Schin { 3514887Schin register struct subshell *sp = subshell_data; 3524887Schin if(!sp || sh.curenv==0) 3534887Schin return(sh.alias_tree); 3544887Schin if(!sp->salias && create) 3554887Schin { 3564887Schin sp->salias = dtopen(&_Nvdisc,Dtoset); 3574887Schin dtview(sp->salias,sh.alias_tree); 3584887Schin sh.alias_tree = sp->salias; 3594887Schin } 3604887Schin return(sp->salias); 3614887Schin } 3624887Schin 3634887Schin /* 3644887Schin * return pointer to function tree 3654887Schin * create new one if in a subshell and one doesn't exist and create is non-zero 3664887Schin */ 3674887Schin Dt_t *sh_subfuntree(int create) 3684887Schin { 3694887Schin register struct subshell *sp = subshell_data; 3704887Schin if(!sp || sh.curenv==0) 3714887Schin return(sh.fun_tree); 3724887Schin if(!sp->sfun && create) 3734887Schin { 3744887Schin sp->sfun = dtopen(&_Nvdisc,Dtoset); 3754887Schin dtview(sp->sfun,sh.fun_tree); 3764887Schin sh.fun_tree = sp->sfun; 3774887Schin } 3788462SApril.Chin@Sun.COM return(sh.fun_tree); 3794887Schin } 3804887Schin 3818462SApril.Chin@Sun.COM static void table_unset(register Dt_t *root,int fun) 3824887Schin { 3834887Schin register Namval_t *np,*nq; 3848462SApril.Chin@Sun.COM int flag; 3854887Schin for(np=(Namval_t*)dtfirst(root);np;np=nq) 3864887Schin { 3874887Schin nq = (Namval_t*)dtnext(root,np); 3888462SApril.Chin@Sun.COM flag=0; 3898462SApril.Chin@Sun.COM if(fun && np->nvalue.rp->fname && *np->nvalue.rp->fname=='/') 3908462SApril.Chin@Sun.COM { 3918462SApril.Chin@Sun.COM np->nvalue.rp->fdict = 0; 3928462SApril.Chin@Sun.COM flag = NV_NOFREE; 3938462SApril.Chin@Sun.COM } 3948462SApril.Chin@Sun.COM else 3958462SApril.Chin@Sun.COM _nv_unset(np,NV_RDONLY); 3968462SApril.Chin@Sun.COM nv_delete(np,root,flag|NV_FUNCTION); 3974887Schin } 3984887Schin } 3994887Schin 4004887Schin int sh_subsavefd(register int fd) 4014887Schin { 4024887Schin register struct subshell *sp = subshell_data; 4034887Schin register int old=0; 4044887Schin if(sp) 4054887Schin { 4064887Schin old = !(sp->fdsaved&(1<<(fd-1))); 4074887Schin sp->fdsaved |= (1<<(fd-1)); 4084887Schin } 4094887Schin return(old); 4104887Schin } 4114887Schin 4128462SApril.Chin@Sun.COM void sh_subjobcheck(pid_t pid) 4138462SApril.Chin@Sun.COM { 4148462SApril.Chin@Sun.COM register struct subshell *sp = subshell_data; 4158462SApril.Chin@Sun.COM while(sp) 4168462SApril.Chin@Sun.COM { 4178462SApril.Chin@Sun.COM if(sp->cpid==pid) 4188462SApril.Chin@Sun.COM { 4198462SApril.Chin@Sun.COM sh_close(sp->coutpipe); 4208462SApril.Chin@Sun.COM sh_close(sp->cpipe); 4218462SApril.Chin@Sun.COM sp->coutpipe = sp->cpipe = -1; 4228462SApril.Chin@Sun.COM return; 4238462SApril.Chin@Sun.COM } 4248462SApril.Chin@Sun.COM sp = sp->prev; 4258462SApril.Chin@Sun.COM } 4268462SApril.Chin@Sun.COM } 4278462SApril.Chin@Sun.COM 4284887Schin /* 4294887Schin * Run command tree <t> in a virtual sub-shell 4304887Schin * If comsub is not null, then output will be placed in temp file (or buffer) 4314887Schin * If comsub is not null, the return value will be a stream consisting of 4324887Schin * output of command <t>. Otherwise, NULL will be returned. 4334887Schin */ 4344887Schin 4354887Schin Sfio_t *sh_subshell(Shnode_t *t, int flags, int comsub) 4364887Schin { 4374887Schin Shell_t *shp = &sh; 4384887Schin struct subshell sub_data; 4394887Schin register struct subshell *sp = &sub_data; 4408462SApril.Chin@Sun.COM int jmpval,nsig=0; 4414887Schin int savecurenv = shp->curenv; 4428462SApril.Chin@Sun.COM int savejobpgid = job.curpgid; 4434887Schin int16_t subshell; 4444887Schin char *savsig; 4454887Schin Sfio_t *iop=0; 4464887Schin struct checkpt buff; 4474887Schin struct sh_scoped savst; 4484887Schin struct dolnod *argsav=0; 4494887Schin memset((char*)sp, 0, sizeof(*sp)); 4504887Schin sfsync(shp->outpool); 4518462SApril.Chin@Sun.COM argsav = sh_arguse(shp); 4524887Schin if(shp->curenv==0) 4534887Schin { 4544887Schin subshell_data=0; 4554887Schin subenv = 0; 4564887Schin } 4574887Schin shp->curenv = ++subenv; 4588462SApril.Chin@Sun.COM job.curpgid = 0; 4594887Schin savst = shp->st; 4604887Schin sh_pushcontext(&buff,SH_JMPSUB); 4614887Schin subshell = shp->subshell+1; 4628462SApril.Chin@Sun.COM SH_SUBSHELLNOD->nvalue.s = subshell; 4634887Schin shp->subshell = subshell; 4644887Schin sp->prev = subshell_data; 4658462SApril.Chin@Sun.COM sp->shp = shp; 4668462SApril.Chin@Sun.COM sp->sig = 0; 4674887Schin subshell_data = sp; 4684887Schin sp->errcontext = &buff.err; 4694887Schin sp->var = shp->var_tree; 4704887Schin sp->options = shp->options; 4714887Schin sp->jobs = job_subsave(); 4724887Schin /* make sure initialization has occurred */ 4734887Schin if(!shp->pathlist) 4744887Schin path_get("."); 4754887Schin sp->pathlist = path_dup((Pathcomp_t*)shp->pathlist); 4764887Schin if(!shp->pwd) 4774887Schin path_pwd(0); 4784887Schin sp->bckpid = shp->bckpid; 4798462SApril.Chin@Sun.COM if(comsub) 4808462SApril.Chin@Sun.COM sh_stats(STAT_COMSUB); 481*8810SCasper.Dik@Sun.COM sp->subshare = shp->subshare; 482*8810SCasper.Dik@Sun.COM shp->subshare = comsub==2 || (comsub==1 && sh_isoption(SH_SUBSHARE)); 483*8810SCasper.Dik@Sun.COM if(!comsub || !shp->subshare) 4844887Schin { 4854887Schin sp->shpwd = shp->pwd; 4864887Schin sp->pwd = (shp->pwd?strdup(shp->pwd):0); 4874887Schin sp->mask = shp->mask; 4888462SApril.Chin@Sun.COM sh_stats(STAT_SUBSHELL); 4894887Schin /* save trap table */ 4904887Schin shp->st.otrapcom = 0; 4914887Schin if((nsig=shp->st.trapmax*sizeof(char*))>0 || shp->st.trapcom[0]) 4924887Schin { 4934887Schin nsig += sizeof(char*); 4944887Schin memcpy(savsig=malloc(nsig),(char*)&shp->st.trapcom[0],nsig); 4954887Schin /* this nonsense needed for $(trap) */ 4964887Schin shp->st.otrapcom = (char**)savsig; 4974887Schin } 4988462SApril.Chin@Sun.COM sp->cpid = shp->cpid; 4998462SApril.Chin@Sun.COM sp->coutpipe = shp->coutpipe; 5008462SApril.Chin@Sun.COM sp->cpipe = shp->cpipe[1]; 5018462SApril.Chin@Sun.COM shp->coutpipe = shp->cpipe[1] = -1; 5028462SApril.Chin@Sun.COM shp->cpid = 0; 5034887Schin sh_sigreset(0); 5044887Schin } 5054887Schin jmpval = sigsetjmp(buff.buff,0); 5064887Schin if(jmpval==0) 5074887Schin { 5084887Schin if(comsub) 5094887Schin { 5104887Schin /* disable job control */ 5118462SApril.Chin@Sun.COM shp->spid = 0; 5124887Schin sp->jobcontrol = job.jobcontrol; 5134887Schin sp->monitor = (sh_isstate(SH_MONITOR)!=0); 5144887Schin job.jobcontrol=0; 5154887Schin sh_offstate(SH_MONITOR); 5164887Schin sp->pipe = sp; 5174887Schin /* save sfstdout and status */ 5184887Schin sp->saveout = sfswap(sfstdout,NIL(Sfio_t*)); 5194887Schin sp->fdstatus = shp->fdstatus[1]; 5204887Schin sp->tmpfd = -1; 5214887Schin sp->pipefd = -1; 5224887Schin /* use sftmp() file for standard output */ 5234887Schin if(!(iop = sftmp(PIPE_BUF))) 5244887Schin { 5254887Schin sfswap(sp->saveout,sfstdout); 5264887Schin errormsg(SH_DICT,ERROR_system(1),e_tmpcreate); 5274887Schin } 5284887Schin sfswap(iop,sfstdout); 5294887Schin sfset(sfstdout,SF_READ,0); 5304887Schin shp->fdstatus[1] = IOWRITE; 5318462SApril.Chin@Sun.COM if(!(sp->nofork = sh_state(SH_NOFORK))) 5328462SApril.Chin@Sun.COM sh_onstate(SH_NOFORK); 5338462SApril.Chin@Sun.COM flags |= sh_state(SH_NOFORK); 5344887Schin } 5354887Schin else if(sp->prev) 5364887Schin { 5374887Schin sp->pipe = sp->prev->pipe; 5384887Schin flags &= ~sh_state(SH_NOFORK); 5394887Schin } 5404887Schin sh_exec(t,flags); 5414887Schin } 5428462SApril.Chin@Sun.COM if(comsub!=2 && jmpval!=SH_JMPSUB && shp->st.trapcom[0] && shp->subshell) 5434887Schin { 5444887Schin /* trap on EXIT not handled by child */ 5454887Schin char *trap=shp->st.trapcom[0]; 5464887Schin shp->st.trapcom[0] = 0; /* prevent recursion */ 5474887Schin shp->oldexit = shp->exitval; 5484887Schin sh_trap(trap,0); 5494887Schin free(trap); 5504887Schin } 5514887Schin sh_popcontext(&buff); 5524887Schin if(shp->subshell==0) /* must be child process */ 5534887Schin { 5544887Schin subshell_data = sp->prev; 5554887Schin if(jmpval==SH_JMPSCRIPT) 5564887Schin siglongjmp(*shp->jmplist,jmpval); 5578462SApril.Chin@Sun.COM sh_done(shp,0); 5584887Schin } 5594887Schin if(comsub) 5604887Schin { 5614887Schin /* re-enable job control */ 5628462SApril.Chin@Sun.COM if(!sp->nofork) 5638462SApril.Chin@Sun.COM sh_offstate(SH_NOFORK); 5644887Schin job.jobcontrol = sp->jobcontrol; 5654887Schin if(sp->monitor) 5664887Schin sh_onstate(SH_MONITOR); 5674887Schin if(sp->pipefd>=0) 5684887Schin { 5694887Schin /* sftmp() file has been returned into pipe */ 5708462SApril.Chin@Sun.COM iop = sh_iostream(shp,sp->pipefd); 5714887Schin sfclose(sfstdout); 5724887Schin } 5734887Schin else 5744887Schin { 5754887Schin /* move tmp file to iop and restore sfstdout */ 5764887Schin iop = sfswap(sfstdout,NIL(Sfio_t*)); 5774887Schin if(!iop) 5784887Schin { 5794887Schin /* maybe locked try again */ 5804887Schin sfclrlock(sfstdout); 5814887Schin iop = sfswap(sfstdout,NIL(Sfio_t*)); 5824887Schin } 5834887Schin if(iop && sffileno(iop)==1) 5844887Schin { 5854887Schin int fd=sfsetfd(iop,3); 5864887Schin if(fd<0) 5874887Schin errormsg(SH_DICT,ERROR_system(1),e_toomany); 5884887Schin shp->sftable[fd] = iop; 5894887Schin fcntl(fd,F_SETFD,FD_CLOEXEC); 5904887Schin shp->fdstatus[fd] = (shp->fdstatus[1]|IOCLEX); 5914887Schin shp->fdstatus[1] = IOCLOSE; 5924887Schin } 5934887Schin sfset(iop,SF_READ,1); 5944887Schin } 5954887Schin sfswap(sp->saveout,sfstdout); 5964887Schin /* check if standard output was preserved */ 5974887Schin if(sp->tmpfd>=0) 5984887Schin { 5994887Schin close(1); 6004887Schin fcntl(sp->tmpfd,F_DUPFD,1); 6014887Schin sh_close(sp->tmpfd); 6024887Schin } 6034887Schin shp->fdstatus[1] = sp->fdstatus; 6044887Schin } 6054887Schin if(sp->subpid) 6068462SApril.Chin@Sun.COM { 6078462SApril.Chin@Sun.COM if(shp->exitval > SH_EXITSIG) 6088462SApril.Chin@Sun.COM sp->sig = (shp->exitval&SH_EXITMASK); 6098462SApril.Chin@Sun.COM shp->exitval = 0; 6108462SApril.Chin@Sun.COM if(comsub) 6118462SApril.Chin@Sun.COM shp->spid = sp->subpid; 6128462SApril.Chin@Sun.COM else 6138462SApril.Chin@Sun.COM job_wait(sp->subpid); 6148462SApril.Chin@Sun.COM } 6158462SApril.Chin@Sun.COM if(comsub && iop && sp->pipefd<0) 6164887Schin sfseek(iop,(off_t)0,SEEK_SET); 6174887Schin path_delete((Pathcomp_t*)shp->pathlist); 6184887Schin shp->pathlist = (void*)sp->pathlist; 6194887Schin job_subrestore(sp->jobs); 6204887Schin shp->jobenv = savecurenv; 6218462SApril.Chin@Sun.COM job.curpgid = savejobpgid; 6224887Schin shp->bckpid = sp->bckpid; 6234887Schin if(sp->shpwd) /* restore environment if saved */ 6244887Schin { 6258462SApril.Chin@Sun.COM int n; 6264887Schin shp->options = sp->options; 6274887Schin nv_restore(sp); 6284887Schin if(sp->salias) 6294887Schin { 6304887Schin shp->alias_tree = dtview(sp->salias,0); 6318462SApril.Chin@Sun.COM table_unset(sp->salias,0); 6324887Schin dtclose(sp->salias); 6334887Schin } 6344887Schin if(sp->sfun) 6354887Schin { 6364887Schin shp->fun_tree = dtview(sp->sfun,0); 6378462SApril.Chin@Sun.COM table_unset(sp->sfun,1); 6384887Schin dtclose(sp->sfun); 6394887Schin } 6408462SApril.Chin@Sun.COM n = shp->st.trapmax-savst.trapmax; 6414887Schin sh_sigreset(1); 6428462SApril.Chin@Sun.COM if(n>0) 6438462SApril.Chin@Sun.COM memset(&shp->st.trapcom[savst.trapmax],0,n*sizeof(char*)); 6444887Schin shp->st = savst; 6454887Schin shp->curenv = savecurenv; 6464887Schin if(nsig) 6474887Schin { 6484887Schin memcpy((char*)&shp->st.trapcom[0],savsig,nsig); 6494887Schin free((void*)savsig); 6504887Schin } 6514887Schin shp->options = sp->options; 6524887Schin if(!shp->pwd || strcmp(sp->pwd,shp->pwd)) 6534887Schin { 6544887Schin /* restore PWDNOD */ 6558462SApril.Chin@Sun.COM Namval_t *pwdnod = sh_scoped(shp,PWDNOD); 6564887Schin if(shp->pwd) 6574887Schin { 6584887Schin chdir(shp->pwd=sp->pwd); 6594887Schin path_newdir(shp->pathlist); 6604887Schin } 6614887Schin if(nv_isattr(pwdnod,NV_NOFREE)) 6624887Schin pwdnod->nvalue.cp = (const char*)sp->pwd; 6634887Schin } 6644887Schin else if(sp->shpwd != shp->pwd) 6654887Schin { 6664887Schin shp->pwd = sp->pwd; 6674887Schin if(PWDNOD->nvalue.cp==sp->shpwd) 6684887Schin PWDNOD->nvalue.cp = sp->pwd; 6694887Schin } 6704887Schin else 6714887Schin free((void*)sp->pwd); 6724887Schin if(sp->mask!=shp->mask) 6738462SApril.Chin@Sun.COM umask(shp->mask=sp->mask); 6748462SApril.Chin@Sun.COM if(shp->coutpipe>=0) 6758462SApril.Chin@Sun.COM { 6768462SApril.Chin@Sun.COM sh_close(shp->coutpipe); 6778462SApril.Chin@Sun.COM sh_close(shp->cpipe[1]); 6788462SApril.Chin@Sun.COM } 6798462SApril.Chin@Sun.COM shp->cpid = sp->cpid; 6808462SApril.Chin@Sun.COM shp->cpipe[1] = sp->cpipe; 6818462SApril.Chin@Sun.COM shp->coutpipe = sp->coutpipe; 6824887Schin } 683*8810SCasper.Dik@Sun.COM shp->subshare = sp->subshare; 6848462SApril.Chin@Sun.COM if(shp->subshell) 6858462SApril.Chin@Sun.COM SH_SUBSHELLNOD->nvalue.s = --shp->subshell; 6868462SApril.Chin@Sun.COM if(sp->sig) 6878462SApril.Chin@Sun.COM { 6888462SApril.Chin@Sun.COM if(sp->prev) 6898462SApril.Chin@Sun.COM sp->prev->sig = sp->sig; 6908462SApril.Chin@Sun.COM else 6918462SApril.Chin@Sun.COM { 6928462SApril.Chin@Sun.COM sh_fault(sp->sig); 6938462SApril.Chin@Sun.COM sh_chktrap(); 6948462SApril.Chin@Sun.COM } 6958462SApril.Chin@Sun.COM } 6968462SApril.Chin@Sun.COM subshell = shp->subshell; 6974887Schin subshell_data = sp->prev; 6988462SApril.Chin@Sun.COM sh_argfree(shp,argsav,0); 6994887Schin shp->trapnote = 0; 7004887Schin if(shp->topfd != buff.topfd) 7018462SApril.Chin@Sun.COM sh_iorestore(shp,buff.topfd|IOSUBSHELL,jmpval); 7024887Schin if(shp->exitval > SH_EXITSIG) 7034887Schin { 7044887Schin int sig = shp->exitval&SH_EXITMASK; 7054887Schin if(sig==SIGINT || sig== SIGQUIT) 7064887Schin sh_fault(sig); 7074887Schin } 7084887Schin return(iop); 7094887Schin } 710