14887Schin /*********************************************************************** 24887Schin * * 34887Schin * This software is part of the ast package * 4*10898Sroland.mainz@nrubsig.org * Copyright (c) 1982-2009 AT&T Intellectual Property * 54887Schin * and is licensed under the * 64887Schin * Common Public License, Version 1.0 * 78462SApril.Chin@Sun.COM * by AT&T Intellectual Property * 84887Schin * * 94887Schin * A copy of the License is available at * 104887Schin * http://www.opensource.org/licenses/cpl1.0.txt * 114887Schin * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) * 124887Schin * * 134887Schin * Information and Software Systems Research * 144887Schin * AT&T Research * 154887Schin * Florham Park NJ * 164887Schin * * 174887Schin * David Korn <dgk@research.att.com> * 184887Schin * * 194887Schin ***********************************************************************/ 204887Schin #pragma prototyped 214887Schin /* 224887Schin * 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; 928810SCasper.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; 105*10898Sroland.mainz@nrubsig.org register struct checkpt *pp = (struct checkpt*)shp->jmplist; 106*10898Sroland.mainz@nrubsig.org register struct subshell *sp = subshell_data->pipe; 1074887Schin if(sfset(sfstdout,0,0)&SF_STRING) 1084887Schin { 1094887Schin register int fd; 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); 116*10898Sroland.mainz@nrubsig.org shp->fdstatus[1] = IOCLOSE; 1174887Schin } 1184887Schin else if(errno!=EBADF) 119*10898Sroland.mainz@nrubsig.org { 120*10898Sroland.mainz@nrubsig.org ((struct checkpt*)shp->jmplist)->mode = SH_JMPERREXIT; 121*10898Sroland.mainz@nrubsig.org shp->toomany = 1; 1224887Schin errormsg(SH_DICT,ERROR_system(1),e_toomany); 123*10898Sroland.mainz@nrubsig.org } 124*10898Sroland.mainz@nrubsig.org if(shp->subshare || !pflag) 1254887Schin { 1268462SApril.Chin@Sun.COM sfdisc(sfstdout,SF_POPDISC); 1278462SApril.Chin@Sun.COM if((fd=sffileno(sfstdout))>=0) 1284887Schin { 129*10898Sroland.mainz@nrubsig.org shp->fdstatus[fd] = IOREAD|IOWRITE; 1308462SApril.Chin@Sun.COM sfsync(sfstdout); 1318462SApril.Chin@Sun.COM if(fd==1) 1328462SApril.Chin@Sun.COM fcntl(1,F_SETFD,0); 1338462SApril.Chin@Sun.COM else 1348462SApril.Chin@Sun.COM { 1358462SApril.Chin@Sun.COM sfsetfd(sfstdout,1); 136*10898Sroland.mainz@nrubsig.org shp->fdstatus[1] = shp->fdstatus[fd]; 137*10898Sroland.mainz@nrubsig.org shp->fdstatus[fd] = IOCLOSE; 1388462SApril.Chin@Sun.COM } 1398462SApril.Chin@Sun.COM goto skip; 1404887Schin } 1414887Schin } 142*10898Sroland.mainz@nrubsig.org } 143*10898Sroland.mainz@nrubsig.org if(sp && (shp->fdstatus[1]==IOCLOSE || (!shp->subshare && !(shp->fdstatus[1]&IONOSEEK)))) 144*10898Sroland.mainz@nrubsig.org { 145*10898Sroland.mainz@nrubsig.org struct stat statb,statx; 146*10898Sroland.mainz@nrubsig.org int fd; 1478462SApril.Chin@Sun.COM sh_pipe(fds); 1488462SApril.Chin@Sun.COM sp->pipefd = fds[0]; 1498462SApril.Chin@Sun.COM sh_fcntl(sp->pipefd,F_SETFD,FD_CLOEXEC); 1508462SApril.Chin@Sun.COM /* write the data to the pipe */ 1518462SApril.Chin@Sun.COM if(off = sftell(sfstdout)) 1528462SApril.Chin@Sun.COM { 1538462SApril.Chin@Sun.COM write(fds[1],sfsetbuf(sfstdout,(Void_t*)sfstdout,0),(size_t)off); 1548462SApril.Chin@Sun.COM sfpurge(sfstdout); 1558462SApril.Chin@Sun.COM } 156*10898Sroland.mainz@nrubsig.org if((sfset(sfstdout,0,0)&SF_STRING) || fstat(1,&statb)<0) 157*10898Sroland.mainz@nrubsig.org statb.st_ino = 0; 1588462SApril.Chin@Sun.COM sfclose(sfstdout); 1598462SApril.Chin@Sun.COM if((sh_fcntl(fds[1],F_DUPFD, 1)) != 1) 160*10898Sroland.mainz@nrubsig.org errormsg(SH_DICT,ERROR_system(1),e_redirect); 1618462SApril.Chin@Sun.COM sh_close(fds[1]); 162*10898Sroland.mainz@nrubsig.org if(statb.st_ino) for(fd=0; fd < 10; fd++) 163*10898Sroland.mainz@nrubsig.org { 164*10898Sroland.mainz@nrubsig.org if(fd==1 || ((shp->fdstatus[fd]&(IONOSEEK|IOSEEK|IOWRITE))!=(IOSEEK|IOWRITE)) || fstat(fd,&statx)<0) 165*10898Sroland.mainz@nrubsig.org continue; 166*10898Sroland.mainz@nrubsig.org if(statb.st_ino==statx.st_ino && statb.st_dev==statx.st_dev) 167*10898Sroland.mainz@nrubsig.org { 168*10898Sroland.mainz@nrubsig.org sh_close(fd); 169*10898Sroland.mainz@nrubsig.org fcntl(1,F_DUPFD, fd); 170*10898Sroland.mainz@nrubsig.org } 171*10898Sroland.mainz@nrubsig.org } 1728462SApril.Chin@Sun.COM skip: 1738462SApril.Chin@Sun.COM sh_iostream(shp,1); 1744887Schin sfset(sfstdout,SF_SHARE|SF_PUBLIC,1); 1758462SApril.Chin@Sun.COM sfpool(sfstdout,shp->outpool,SF_WRITE); 1764887Schin if(pp && pp->olist && pp->olist->strm == sfstdout) 1774887Schin pp->olist->strm = 0; 1784887Schin } 1794887Schin } 1804887Schin 181*10898Sroland.mainz@nrubsig.org 1824887Schin /* 1834887Schin * This routine creates a temp file if necessary and creates a subshell. 1844887Schin * The parent routine longjmps back to sh_subshell() 1854887Schin * The child continues possibly with its standard output replaced by temp file 1864887Schin */ 1874887Schin void sh_subfork(void) 1884887Schin { 1894887Schin register struct subshell *sp = subshell_data; 1908462SApril.Chin@Sun.COM Shell_t *shp = sp->shp; 1918462SApril.Chin@Sun.COM int curenv = shp->curenv; 1924887Schin pid_t pid; 193*10898Sroland.mainz@nrubsig.org char *trap = shp->st.trapcom[0]; 194*10898Sroland.mainz@nrubsig.org if(trap) 195*10898Sroland.mainz@nrubsig.org trap = strdup(trap); 1964887Schin /* see whether inside $(...) */ 1974887Schin if(sp->pipe) 1988462SApril.Chin@Sun.COM sh_subtmpfile(1); 1998462SApril.Chin@Sun.COM shp->curenv = 0; 200*10898Sroland.mainz@nrubsig.org if(pid = sh_fork(FSHOWME,NIL(int*))) 2014887Schin { 2028462SApril.Chin@Sun.COM shp->curenv = curenv; 2034887Schin /* this is the parent part of the fork */ 2044887Schin if(sp->subpid==0) 2054887Schin sp->subpid = pid; 206*10898Sroland.mainz@nrubsig.org if(trap) 207*10898Sroland.mainz@nrubsig.org free((void*)trap); 2088462SApril.Chin@Sun.COM siglongjmp(*shp->jmplist,SH_JMPSUB); 2094887Schin } 2104887Schin else 2114887Schin { 2124887Schin /* this is the child part of the fork */ 2134887Schin /* setting subpid to 1 causes subshell to exit when reached */ 2144887Schin sh_onstate(SH_FORKED); 2154887Schin sh_onstate(SH_NOLOG); 2164887Schin sh_offstate(SH_MONITOR); 2174887Schin subshell_data = 0; 2188462SApril.Chin@Sun.COM shp->subshell = 0; 2198462SApril.Chin@Sun.COM SH_SUBSHELLNOD->nvalue.s = 0; 2204887Schin sp->subpid=0; 221*10898Sroland.mainz@nrubsig.org shp->st.trapcom[0] = trap; 2224887Schin } 2234887Schin } 2244887Schin 2258462SApril.Chin@Sun.COM int nv_subsaved(register Namval_t *np) 2268462SApril.Chin@Sun.COM { 2278462SApril.Chin@Sun.COM register struct subshell *sp; 2288462SApril.Chin@Sun.COM register struct Link *lp; 2298462SApril.Chin@Sun.COM for(sp = (struct subshell*)subshell_data; sp; sp=sp->prev) 2308462SApril.Chin@Sun.COM { 2318462SApril.Chin@Sun.COM for(lp=sp->svar; lp; lp = lp->next) 2328462SApril.Chin@Sun.COM { 2338462SApril.Chin@Sun.COM if(lp->node==np) 2348462SApril.Chin@Sun.COM return(1); 2358462SApril.Chin@Sun.COM } 2368462SApril.Chin@Sun.COM } 2378462SApril.Chin@Sun.COM return(0); 2388462SApril.Chin@Sun.COM } 2398462SApril.Chin@Sun.COM 2404887Schin /* 2414887Schin * This routine will make a copy of the given node in the 2424887Schin * layer created by the most recent subshell_fork if the 2434887Schin * node hasn't already been copied 2444887Schin */ 2454887Schin Namval_t *sh_assignok(register Namval_t *np,int add) 2464887Schin { 2478462SApril.Chin@Sun.COM register Namval_t *mp; 2488462SApril.Chin@Sun.COM register struct Link *lp; 2494887Schin register struct subshell *sp = (struct subshell*)subshell_data; 2508462SApril.Chin@Sun.COM struct Ufunction *rp; 2518462SApril.Chin@Sun.COM Shell_t *shp = sp->shp; 2528462SApril.Chin@Sun.COM Dt_t *dp; 2538462SApril.Chin@Sun.COM Namval_t *mpnext; 2548462SApril.Chin@Sun.COM Namarr_t *ap; 2558462SApril.Chin@Sun.COM int save; 2564887Schin /* don't bother with this */ 257*10898Sroland.mainz@nrubsig.org if(!sp->shpwd || (nv_isnull(np) && !add) || np==SH_LEVELNOD) 2584887Schin return(np); 2594887Schin /* don't bother to save if in newer scope */ 2608462SApril.Chin@Sun.COM if(!(rp=shp->st.real_fun) || !(dp=rp->sdict)) 2618462SApril.Chin@Sun.COM dp = sp->var; 2628462SApril.Chin@Sun.COM if(np->nvenv && !nv_isattr(np,NV_MINIMAL|NV_EXPORT) && shp->last_root) 2638462SApril.Chin@Sun.COM dp = shp->last_root; 2648462SApril.Chin@Sun.COM if((mp=nv_search((char*)np,dp,HASH_BUCKET))!=np) 2658462SApril.Chin@Sun.COM { 2668462SApril.Chin@Sun.COM if(mp || !np->nvfun || np->nvfun->subshell>=sh.subshell) 2678462SApril.Chin@Sun.COM return(np); 2688462SApril.Chin@Sun.COM } 2698462SApril.Chin@Sun.COM if((ap=nv_arrayptr(np)) && (mp=nv_opensub(np))) 2708462SApril.Chin@Sun.COM { 2718462SApril.Chin@Sun.COM shp->last_root = ap->table; 2728462SApril.Chin@Sun.COM sh_assignok(mp,add); 2738462SApril.Chin@Sun.COM if(!add || array_assoc(ap)) 2748462SApril.Chin@Sun.COM return(np); 2758462SApril.Chin@Sun.COM } 2764887Schin for(lp=subshell_data->svar; lp; lp = lp->next) 2774887Schin { 2784887Schin if(lp->node==np) 2794887Schin return(np); 2804887Schin } 2818462SApril.Chin@Sun.COM /* first two pointers use linkage from np */ 2828462SApril.Chin@Sun.COM lp = (struct Link*)malloc(sizeof(*np)+2*sizeof(void*)); 2838462SApril.Chin@Sun.COM memset(lp,0, sizeof(*mp)+2*sizeof(void*)); 2844887Schin lp->node = np; 2858462SApril.Chin@Sun.COM if(!add && nv_isvtree(np)) 2868462SApril.Chin@Sun.COM { 2878462SApril.Chin@Sun.COM Namval_t fake; 2888462SApril.Chin@Sun.COM Dt_t *walk, *root=shp->var_tree; 2898462SApril.Chin@Sun.COM char *name = nv_name(np); 2908462SApril.Chin@Sun.COM int len = strlen(name); 2918462SApril.Chin@Sun.COM fake.nvname = name; 2928462SApril.Chin@Sun.COM mpnext = dtnext(root,&fake); 2938462SApril.Chin@Sun.COM dp = root->walk?root->walk:root; 2948462SApril.Chin@Sun.COM while(mp=mpnext) 2958462SApril.Chin@Sun.COM { 2968462SApril.Chin@Sun.COM walk = root->walk?root->walk:root; 2978462SApril.Chin@Sun.COM mpnext = dtnext(root,mp); 2988462SApril.Chin@Sun.COM if(memcmp(name,mp->nvname,len) || mp->nvname[len]!='.') 2998462SApril.Chin@Sun.COM break; 3008462SApril.Chin@Sun.COM nv_delete(mp,walk,NV_NOFREE); 3018462SApril.Chin@Sun.COM *((Namval_t**)mp) = lp->child; 3028462SApril.Chin@Sun.COM lp->child = mp; 3038462SApril.Chin@Sun.COM 3048462SApril.Chin@Sun.COM } 3058462SApril.Chin@Sun.COM } 3068462SApril.Chin@Sun.COM lp->dict = dp; 3078462SApril.Chin@Sun.COM mp = (Namval_t*)&lp->dict; 3084887Schin lp->next = subshell_data->svar; 3094887Schin subshell_data->svar = lp; 3108462SApril.Chin@Sun.COM save = shp->subshell; 3118462SApril.Chin@Sun.COM shp->subshell = 0; 3128462SApril.Chin@Sun.COM mp->nvname = np->nvname; 3138462SApril.Chin@Sun.COM nv_clone(np,mp,(add?(nv_isnull(np)?0:NV_NOFREE)|NV_ARRAY:NV_MOVE)); 3148462SApril.Chin@Sun.COM shp->subshell = save; 3154887Schin return(np); 3164887Schin } 3174887Schin 3184887Schin /* 3194887Schin * restore the variables 3204887Schin */ 3214887Schin static void nv_restore(struct subshell *sp) 3224887Schin { 3234887Schin register struct Link *lp, *lq; 3244887Schin register Namval_t *mp, *np; 3254887Schin const char *save = sp->shpwd; 3268462SApril.Chin@Sun.COM Namval_t *mpnext; 3274887Schin sp->shpwd = 0; /* make sure sh_assignok doesn't save with nv_unset() */ 3284887Schin for(lp=sp->svar; lp; lp=lq) 3294887Schin { 3308462SApril.Chin@Sun.COM np = (Namval_t*)&lp->dict; 3318462SApril.Chin@Sun.COM lq = lp->next; 3324887Schin mp = lp->node; 3338462SApril.Chin@Sun.COM if(!mp->nvname) 3348462SApril.Chin@Sun.COM continue; 3354887Schin if(nv_isarray(mp)) 3364887Schin nv_putsub(mp,NIL(char*),ARRAY_SCAN); 337*10898Sroland.mainz@nrubsig.org _nv_unset(mp,NV_RDONLY|NV_CLONE); 3388462SApril.Chin@Sun.COM if(nv_isarray(np)) 3398462SApril.Chin@Sun.COM { 3408462SApril.Chin@Sun.COM nv_clone(np,mp,NV_MOVE); 3418462SApril.Chin@Sun.COM goto skip; 3428462SApril.Chin@Sun.COM } 3434887Schin nv_setsize(mp,nv_size(np)); 3444887Schin if(!nv_isattr(np,NV_MINIMAL) || nv_isattr(np,NV_EXPORT)) 3454887Schin mp->nvenv = np->nvenv; 3464887Schin mp->nvfun = np->nvfun; 3474887Schin mp->nvflag = np->nvflag; 3488462SApril.Chin@Sun.COM if(nv_cover(mp)) 349*10898Sroland.mainz@nrubsig.org { 350*10898Sroland.mainz@nrubsig.org nv_putval(mp, nv_getval(np),np->nvflag|NV_NOFREE); 351*10898Sroland.mainz@nrubsig.org if(!nv_isattr(np,NV_NOFREE)) 352*10898Sroland.mainz@nrubsig.org nv_offattr(mp,NV_NOFREE); 353*10898Sroland.mainz@nrubsig.org } 3544887Schin else 3554887Schin mp->nvalue.cp = np->nvalue.cp; 3564887Schin np->nvfun = 0; 3574887Schin if(nv_isattr(mp,NV_EXPORT)) 3584887Schin { 3594887Schin char *name = nv_name(mp); 3604887Schin sh_envput(sh.env,mp); 3614887Schin if(*name=='_' && strcmp(name,"_AST_FEATURES")==0) 3624887Schin astconf(NiL, NiL, NiL); 3634887Schin } 3644887Schin else if(nv_isattr(np,NV_EXPORT)) 3654887Schin env_delete(sh.env,nv_name(mp)); 3668462SApril.Chin@Sun.COM skip: 3678462SApril.Chin@Sun.COM for(mp=lp->child; mp; mp=mpnext) 3688462SApril.Chin@Sun.COM { 3698462SApril.Chin@Sun.COM mpnext = *((Namval_t**)mp); 3708462SApril.Chin@Sun.COM dtinsert(lp->dict,mp); 3718462SApril.Chin@Sun.COM } 3728462SApril.Chin@Sun.COM free((void*)lp); 3738462SApril.Chin@Sun.COM sp->svar = lq; 3744887Schin } 3754887Schin sp->shpwd=save; 3764887Schin } 3774887Schin 3784887Schin /* 3794887Schin * return pointer to alias tree 3804887Schin * create new one if in a subshell and one doesn't exist and create is non-zero 3814887Schin */ 3824887Schin Dt_t *sh_subaliastree(int create) 3834887Schin { 3844887Schin register struct subshell *sp = subshell_data; 3854887Schin if(!sp || sh.curenv==0) 3864887Schin return(sh.alias_tree); 3874887Schin if(!sp->salias && create) 3884887Schin { 3894887Schin sp->salias = dtopen(&_Nvdisc,Dtoset); 3904887Schin dtview(sp->salias,sh.alias_tree); 3914887Schin sh.alias_tree = sp->salias; 3924887Schin } 3934887Schin return(sp->salias); 3944887Schin } 3954887Schin 3964887Schin /* 3974887Schin * return pointer to function tree 3984887Schin * create new one if in a subshell and one doesn't exist and create is non-zero 3994887Schin */ 4004887Schin Dt_t *sh_subfuntree(int create) 4014887Schin { 4024887Schin register struct subshell *sp = subshell_data; 4034887Schin if(!sp || sh.curenv==0) 4044887Schin return(sh.fun_tree); 4054887Schin if(!sp->sfun && create) 4064887Schin { 4074887Schin sp->sfun = dtopen(&_Nvdisc,Dtoset); 4084887Schin dtview(sp->sfun,sh.fun_tree); 4094887Schin sh.fun_tree = sp->sfun; 4104887Schin } 4118462SApril.Chin@Sun.COM return(sh.fun_tree); 4124887Schin } 4134887Schin 4148462SApril.Chin@Sun.COM static void table_unset(register Dt_t *root,int fun) 4154887Schin { 4164887Schin register Namval_t *np,*nq; 4178462SApril.Chin@Sun.COM int flag; 4184887Schin for(np=(Namval_t*)dtfirst(root);np;np=nq) 4194887Schin { 4204887Schin nq = (Namval_t*)dtnext(root,np); 4218462SApril.Chin@Sun.COM flag=0; 422*10898Sroland.mainz@nrubsig.org if(fun && np->nvalue.rp && np->nvalue.rp->fname && *np->nvalue.rp->fname=='/') 4238462SApril.Chin@Sun.COM { 4248462SApril.Chin@Sun.COM np->nvalue.rp->fdict = 0; 4258462SApril.Chin@Sun.COM flag = NV_NOFREE; 4268462SApril.Chin@Sun.COM } 4278462SApril.Chin@Sun.COM else 4288462SApril.Chin@Sun.COM _nv_unset(np,NV_RDONLY); 4298462SApril.Chin@Sun.COM nv_delete(np,root,flag|NV_FUNCTION); 4304887Schin } 4314887Schin } 4324887Schin 4334887Schin int sh_subsavefd(register int fd) 4344887Schin { 4354887Schin register struct subshell *sp = subshell_data; 4364887Schin register int old=0; 4374887Schin if(sp) 4384887Schin { 4394887Schin old = !(sp->fdsaved&(1<<(fd-1))); 4404887Schin sp->fdsaved |= (1<<(fd-1)); 4414887Schin } 4424887Schin return(old); 4434887Schin } 4444887Schin 4458462SApril.Chin@Sun.COM void sh_subjobcheck(pid_t pid) 4468462SApril.Chin@Sun.COM { 4478462SApril.Chin@Sun.COM register struct subshell *sp = subshell_data; 4488462SApril.Chin@Sun.COM while(sp) 4498462SApril.Chin@Sun.COM { 4508462SApril.Chin@Sun.COM if(sp->cpid==pid) 4518462SApril.Chin@Sun.COM { 4528462SApril.Chin@Sun.COM sh_close(sp->coutpipe); 4538462SApril.Chin@Sun.COM sh_close(sp->cpipe); 4548462SApril.Chin@Sun.COM sp->coutpipe = sp->cpipe = -1; 4558462SApril.Chin@Sun.COM return; 4568462SApril.Chin@Sun.COM } 4578462SApril.Chin@Sun.COM sp = sp->prev; 4588462SApril.Chin@Sun.COM } 4598462SApril.Chin@Sun.COM } 4608462SApril.Chin@Sun.COM 4614887Schin /* 4624887Schin * Run command tree <t> in a virtual sub-shell 4634887Schin * If comsub is not null, then output will be placed in temp file (or buffer) 4644887Schin * If comsub is not null, the return value will be a stream consisting of 4654887Schin * output of command <t>. Otherwise, NULL will be returned. 4664887Schin */ 4674887Schin 4684887Schin Sfio_t *sh_subshell(Shnode_t *t, int flags, int comsub) 4694887Schin { 4704887Schin Shell_t *shp = &sh; 4714887Schin struct subshell sub_data; 4724887Schin register struct subshell *sp = &sub_data; 473*10898Sroland.mainz@nrubsig.org int jmpval,nsig=0,duped=0; 4744887Schin int savecurenv = shp->curenv; 4758462SApril.Chin@Sun.COM int savejobpgid = job.curpgid; 4764887Schin int16_t subshell; 4774887Schin char *savsig; 4784887Schin Sfio_t *iop=0; 4794887Schin struct checkpt buff; 4804887Schin struct sh_scoped savst; 4814887Schin struct dolnod *argsav=0; 4824887Schin memset((char*)sp, 0, sizeof(*sp)); 4834887Schin sfsync(shp->outpool); 4848462SApril.Chin@Sun.COM argsav = sh_arguse(shp); 4854887Schin if(shp->curenv==0) 4864887Schin { 4874887Schin subshell_data=0; 4884887Schin subenv = 0; 4894887Schin } 4904887Schin shp->curenv = ++subenv; 4918462SApril.Chin@Sun.COM job.curpgid = 0; 4924887Schin savst = shp->st; 4934887Schin sh_pushcontext(&buff,SH_JMPSUB); 4944887Schin subshell = shp->subshell+1; 4958462SApril.Chin@Sun.COM SH_SUBSHELLNOD->nvalue.s = subshell; 4964887Schin shp->subshell = subshell; 4974887Schin sp->prev = subshell_data; 4988462SApril.Chin@Sun.COM sp->shp = shp; 4998462SApril.Chin@Sun.COM sp->sig = 0; 5004887Schin subshell_data = sp; 5014887Schin sp->errcontext = &buff.err; 5024887Schin sp->var = shp->var_tree; 5034887Schin sp->options = shp->options; 5044887Schin sp->jobs = job_subsave(); 5054887Schin /* make sure initialization has occurred */ 5064887Schin if(!shp->pathlist) 5074887Schin path_get("."); 5084887Schin sp->pathlist = path_dup((Pathcomp_t*)shp->pathlist); 5094887Schin if(!shp->pwd) 5104887Schin path_pwd(0); 5114887Schin sp->bckpid = shp->bckpid; 5128462SApril.Chin@Sun.COM if(comsub) 5138462SApril.Chin@Sun.COM sh_stats(STAT_COMSUB); 5148810SCasper.Dik@Sun.COM sp->subshare = shp->subshare; 5158810SCasper.Dik@Sun.COM shp->subshare = comsub==2 || (comsub==1 && sh_isoption(SH_SUBSHARE)); 5168810SCasper.Dik@Sun.COM if(!comsub || !shp->subshare) 5174887Schin { 5184887Schin sp->shpwd = shp->pwd; 5194887Schin sp->pwd = (shp->pwd?strdup(shp->pwd):0); 5204887Schin sp->mask = shp->mask; 5218462SApril.Chin@Sun.COM sh_stats(STAT_SUBSHELL); 5224887Schin /* save trap table */ 5234887Schin shp->st.otrapcom = 0; 5244887Schin if((nsig=shp->st.trapmax*sizeof(char*))>0 || shp->st.trapcom[0]) 5254887Schin { 5264887Schin nsig += sizeof(char*); 5274887Schin memcpy(savsig=malloc(nsig),(char*)&shp->st.trapcom[0],nsig); 5284887Schin /* this nonsense needed for $(trap) */ 5294887Schin shp->st.otrapcom = (char**)savsig; 5304887Schin } 5318462SApril.Chin@Sun.COM sp->cpid = shp->cpid; 5328462SApril.Chin@Sun.COM sp->coutpipe = shp->coutpipe; 5338462SApril.Chin@Sun.COM sp->cpipe = shp->cpipe[1]; 5348462SApril.Chin@Sun.COM shp->cpid = 0; 5354887Schin sh_sigreset(0); 5364887Schin } 5374887Schin jmpval = sigsetjmp(buff.buff,0); 5384887Schin if(jmpval==0) 5394887Schin { 5404887Schin if(comsub) 5414887Schin { 5424887Schin /* disable job control */ 5438462SApril.Chin@Sun.COM shp->spid = 0; 5444887Schin sp->jobcontrol = job.jobcontrol; 5454887Schin sp->monitor = (sh_isstate(SH_MONITOR)!=0); 5464887Schin job.jobcontrol=0; 5474887Schin sh_offstate(SH_MONITOR); 5484887Schin sp->pipe = sp; 5494887Schin /* save sfstdout and status */ 5504887Schin sp->saveout = sfswap(sfstdout,NIL(Sfio_t*)); 5514887Schin sp->fdstatus = shp->fdstatus[1]; 5524887Schin sp->tmpfd = -1; 5534887Schin sp->pipefd = -1; 5544887Schin /* use sftmp() file for standard output */ 5554887Schin if(!(iop = sftmp(PIPE_BUF))) 5564887Schin { 5574887Schin sfswap(sp->saveout,sfstdout); 5584887Schin errormsg(SH_DICT,ERROR_system(1),e_tmpcreate); 5594887Schin } 5604887Schin sfswap(iop,sfstdout); 5614887Schin sfset(sfstdout,SF_READ,0); 5624887Schin shp->fdstatus[1] = IOWRITE; 5638462SApril.Chin@Sun.COM if(!(sp->nofork = sh_state(SH_NOFORK))) 5648462SApril.Chin@Sun.COM sh_onstate(SH_NOFORK); 5658462SApril.Chin@Sun.COM flags |= sh_state(SH_NOFORK); 5664887Schin } 5674887Schin else if(sp->prev) 5684887Schin { 5694887Schin sp->pipe = sp->prev->pipe; 5704887Schin flags &= ~sh_state(SH_NOFORK); 5714887Schin } 5724887Schin sh_exec(t,flags); 5734887Schin } 5748462SApril.Chin@Sun.COM if(comsub!=2 && jmpval!=SH_JMPSUB && shp->st.trapcom[0] && shp->subshell) 5754887Schin { 5764887Schin /* trap on EXIT not handled by child */ 5774887Schin char *trap=shp->st.trapcom[0]; 5784887Schin shp->st.trapcom[0] = 0; /* prevent recursion */ 5794887Schin shp->oldexit = shp->exitval; 5804887Schin sh_trap(trap,0); 5814887Schin free(trap); 5824887Schin } 5834887Schin sh_popcontext(&buff); 5844887Schin if(shp->subshell==0) /* must be child process */ 5854887Schin { 5864887Schin subshell_data = sp->prev; 5874887Schin if(jmpval==SH_JMPSCRIPT) 5884887Schin siglongjmp(*shp->jmplist,jmpval); 589*10898Sroland.mainz@nrubsig.org shp->exitval &= SH_EXITMASK; 5908462SApril.Chin@Sun.COM sh_done(shp,0); 5914887Schin } 5924887Schin if(comsub) 5934887Schin { 5944887Schin /* re-enable job control */ 5958462SApril.Chin@Sun.COM if(!sp->nofork) 5968462SApril.Chin@Sun.COM sh_offstate(SH_NOFORK); 5974887Schin job.jobcontrol = sp->jobcontrol; 5984887Schin if(sp->monitor) 5994887Schin sh_onstate(SH_MONITOR); 6004887Schin if(sp->pipefd>=0) 6014887Schin { 6024887Schin /* sftmp() file has been returned into pipe */ 6038462SApril.Chin@Sun.COM iop = sh_iostream(shp,sp->pipefd); 6044887Schin sfclose(sfstdout); 6054887Schin } 6064887Schin else 6074887Schin { 6084887Schin /* move tmp file to iop and restore sfstdout */ 6094887Schin iop = sfswap(sfstdout,NIL(Sfio_t*)); 6104887Schin if(!iop) 6114887Schin { 6124887Schin /* maybe locked try again */ 6134887Schin sfclrlock(sfstdout); 6144887Schin iop = sfswap(sfstdout,NIL(Sfio_t*)); 6154887Schin } 6164887Schin if(iop && sffileno(iop)==1) 6174887Schin { 6184887Schin int fd=sfsetfd(iop,3); 6194887Schin if(fd<0) 620*10898Sroland.mainz@nrubsig.org { 621*10898Sroland.mainz@nrubsig.org shp->toomany = 1; 622*10898Sroland.mainz@nrubsig.org ((struct checkpt*)shp->jmplist)->mode = SH_JMPERREXIT; 6234887Schin errormsg(SH_DICT,ERROR_system(1),e_toomany); 624*10898Sroland.mainz@nrubsig.org } 6254887Schin shp->sftable[fd] = iop; 6264887Schin fcntl(fd,F_SETFD,FD_CLOEXEC); 6274887Schin shp->fdstatus[fd] = (shp->fdstatus[1]|IOCLEX); 6284887Schin shp->fdstatus[1] = IOCLOSE; 6294887Schin } 6304887Schin sfset(iop,SF_READ,1); 6314887Schin } 6324887Schin sfswap(sp->saveout,sfstdout); 6334887Schin /* check if standard output was preserved */ 6344887Schin if(sp->tmpfd>=0) 6354887Schin { 6364887Schin close(1); 637*10898Sroland.mainz@nrubsig.org if (fcntl(sp->tmpfd,F_DUPFD,1) != 1) 638*10898Sroland.mainz@nrubsig.org duped++; 6394887Schin sh_close(sp->tmpfd); 6404887Schin } 6414887Schin shp->fdstatus[1] = sp->fdstatus; 6424887Schin } 6434887Schin if(sp->subpid) 6448462SApril.Chin@Sun.COM { 6458462SApril.Chin@Sun.COM if(shp->exitval > SH_EXITSIG) 6468462SApril.Chin@Sun.COM sp->sig = (shp->exitval&SH_EXITMASK); 6478462SApril.Chin@Sun.COM shp->exitval = 0; 6488462SApril.Chin@Sun.COM if(comsub) 6498462SApril.Chin@Sun.COM shp->spid = sp->subpid; 6508462SApril.Chin@Sun.COM } 6518462SApril.Chin@Sun.COM if(comsub && iop && sp->pipefd<0) 6524887Schin sfseek(iop,(off_t)0,SEEK_SET); 6534887Schin path_delete((Pathcomp_t*)shp->pathlist); 6544887Schin shp->pathlist = (void*)sp->pathlist; 6554887Schin job_subrestore(sp->jobs); 6564887Schin shp->jobenv = savecurenv; 6578462SApril.Chin@Sun.COM job.curpgid = savejobpgid; 6584887Schin shp->bckpid = sp->bckpid; 6594887Schin if(sp->shpwd) /* restore environment if saved */ 6604887Schin { 6618462SApril.Chin@Sun.COM int n; 6624887Schin shp->options = sp->options; 6634887Schin nv_restore(sp); 6644887Schin if(sp->salias) 6654887Schin { 6664887Schin shp->alias_tree = dtview(sp->salias,0); 6678462SApril.Chin@Sun.COM table_unset(sp->salias,0); 6684887Schin dtclose(sp->salias); 6694887Schin } 6704887Schin if(sp->sfun) 6714887Schin { 6724887Schin shp->fun_tree = dtview(sp->sfun,0); 6738462SApril.Chin@Sun.COM table_unset(sp->sfun,1); 6744887Schin dtclose(sp->sfun); 6754887Schin } 6768462SApril.Chin@Sun.COM n = shp->st.trapmax-savst.trapmax; 6774887Schin sh_sigreset(1); 6788462SApril.Chin@Sun.COM if(n>0) 6798462SApril.Chin@Sun.COM memset(&shp->st.trapcom[savst.trapmax],0,n*sizeof(char*)); 6804887Schin shp->st = savst; 6814887Schin shp->curenv = savecurenv; 6824887Schin if(nsig) 6834887Schin { 6844887Schin memcpy((char*)&shp->st.trapcom[0],savsig,nsig); 6854887Schin free((void*)savsig); 6864887Schin } 6874887Schin shp->options = sp->options; 6884887Schin if(!shp->pwd || strcmp(sp->pwd,shp->pwd)) 6894887Schin { 6904887Schin /* restore PWDNOD */ 6918462SApril.Chin@Sun.COM Namval_t *pwdnod = sh_scoped(shp,PWDNOD); 6924887Schin if(shp->pwd) 6934887Schin { 6944887Schin chdir(shp->pwd=sp->pwd); 6954887Schin path_newdir(shp->pathlist); 6964887Schin } 6974887Schin if(nv_isattr(pwdnod,NV_NOFREE)) 6984887Schin pwdnod->nvalue.cp = (const char*)sp->pwd; 6994887Schin } 7004887Schin else if(sp->shpwd != shp->pwd) 7014887Schin { 7024887Schin shp->pwd = sp->pwd; 7034887Schin if(PWDNOD->nvalue.cp==sp->shpwd) 7044887Schin PWDNOD->nvalue.cp = sp->pwd; 7054887Schin } 7064887Schin else 7074887Schin free((void*)sp->pwd); 7084887Schin if(sp->mask!=shp->mask) 7098462SApril.Chin@Sun.COM umask(shp->mask=sp->mask); 710*10898Sroland.mainz@nrubsig.org if(shp->coutpipe!=sp->coutpipe) 7118462SApril.Chin@Sun.COM { 7128462SApril.Chin@Sun.COM sh_close(shp->coutpipe); 7138462SApril.Chin@Sun.COM sh_close(shp->cpipe[1]); 7148462SApril.Chin@Sun.COM } 7158462SApril.Chin@Sun.COM shp->cpid = sp->cpid; 7168462SApril.Chin@Sun.COM shp->cpipe[1] = sp->cpipe; 7178462SApril.Chin@Sun.COM shp->coutpipe = sp->coutpipe; 7184887Schin } 7198810SCasper.Dik@Sun.COM shp->subshare = sp->subshare; 7208462SApril.Chin@Sun.COM if(shp->subshell) 7218462SApril.Chin@Sun.COM SH_SUBSHELLNOD->nvalue.s = --shp->subshell; 722*10898Sroland.mainz@nrubsig.org subshell = shp->subshell; 723*10898Sroland.mainz@nrubsig.org subshell_data = sp->prev; 724*10898Sroland.mainz@nrubsig.org sh_argfree(shp,argsav,0); 725*10898Sroland.mainz@nrubsig.org if(shp->topfd != buff.topfd) 726*10898Sroland.mainz@nrubsig.org sh_iorestore(shp,buff.topfd|IOSUBSHELL,jmpval); 7278462SApril.Chin@Sun.COM if(sp->sig) 7288462SApril.Chin@Sun.COM { 7298462SApril.Chin@Sun.COM if(sp->prev) 7308462SApril.Chin@Sun.COM sp->prev->sig = sp->sig; 7318462SApril.Chin@Sun.COM else 7328462SApril.Chin@Sun.COM { 7338462SApril.Chin@Sun.COM sh_fault(sp->sig); 7348462SApril.Chin@Sun.COM sh_chktrap(); 7358462SApril.Chin@Sun.COM } 7368462SApril.Chin@Sun.COM } 737*10898Sroland.mainz@nrubsig.org sh_sigcheck(); 7384887Schin shp->trapnote = 0; 739*10898Sroland.mainz@nrubsig.org if(sp->subpid && !comsub) 740*10898Sroland.mainz@nrubsig.org job_wait(sp->subpid); 7414887Schin if(shp->exitval > SH_EXITSIG) 7424887Schin { 7434887Schin int sig = shp->exitval&SH_EXITMASK; 7444887Schin if(sig==SIGINT || sig== SIGQUIT) 7454887Schin sh_fault(sig); 7464887Schin } 747*10898Sroland.mainz@nrubsig.org if(duped) 748*10898Sroland.mainz@nrubsig.org { 749*10898Sroland.mainz@nrubsig.org ((struct checkpt*)shp->jmplist)->mode = SH_JMPERREXIT; 750*10898Sroland.mainz@nrubsig.org shp->toomany = 1; 751*10898Sroland.mainz@nrubsig.org errormsg(SH_DICT,ERROR_system(1),e_redirect); 752*10898Sroland.mainz@nrubsig.org } 753*10898Sroland.mainz@nrubsig.org if(jmpval && shp->toomany) 754*10898Sroland.mainz@nrubsig.org siglongjmp(*shp->jmplist,jmpval); 7554887Schin return(iop); 7564887Schin } 757