14887Schin /*********************************************************************** 24887Schin * * 34887Schin * This software is part of the ast package * 4*12068SRoger.Faulkner@Oracle.COM * Copyright (c) 1982-2010 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; 10510898Sroland.mainz@nrubsig.org register struct checkpt *pp = (struct checkpt*)shp->jmplist; 10610898Sroland.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); 11610898Sroland.mainz@nrubsig.org shp->fdstatus[1] = IOCLOSE; 1174887Schin } 1184887Schin else if(errno!=EBADF) 11910898Sroland.mainz@nrubsig.org { 12010898Sroland.mainz@nrubsig.org ((struct checkpt*)shp->jmplist)->mode = SH_JMPERREXIT; 12110898Sroland.mainz@nrubsig.org shp->toomany = 1; 1224887Schin errormsg(SH_DICT,ERROR_system(1),e_toomany); 12310898Sroland.mainz@nrubsig.org } 12410898Sroland.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 { 12910898Sroland.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); 13610898Sroland.mainz@nrubsig.org shp->fdstatus[1] = shp->fdstatus[fd]; 13710898Sroland.mainz@nrubsig.org shp->fdstatus[fd] = IOCLOSE; 1388462SApril.Chin@Sun.COM } 1398462SApril.Chin@Sun.COM goto skip; 1404887Schin } 1414887Schin } 14210898Sroland.mainz@nrubsig.org } 14310898Sroland.mainz@nrubsig.org if(sp && (shp->fdstatus[1]==IOCLOSE || (!shp->subshare && !(shp->fdstatus[1]&IONOSEEK)))) 14410898Sroland.mainz@nrubsig.org { 14510898Sroland.mainz@nrubsig.org struct stat statb,statx; 14610898Sroland.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 } 15610898Sroland.mainz@nrubsig.org if((sfset(sfstdout,0,0)&SF_STRING) || fstat(1,&statb)<0) 15710898Sroland.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) 16010898Sroland.mainz@nrubsig.org errormsg(SH_DICT,ERROR_system(1),e_redirect); 1618462SApril.Chin@Sun.COM sh_close(fds[1]); 16210898Sroland.mainz@nrubsig.org if(statb.st_ino) for(fd=0; fd < 10; fd++) 16310898Sroland.mainz@nrubsig.org { 16410898Sroland.mainz@nrubsig.org if(fd==1 || ((shp->fdstatus[fd]&(IONOSEEK|IOSEEK|IOWRITE))!=(IOSEEK|IOWRITE)) || fstat(fd,&statx)<0) 16510898Sroland.mainz@nrubsig.org continue; 16610898Sroland.mainz@nrubsig.org if(statb.st_ino==statx.st_ino && statb.st_dev==statx.st_dev) 16710898Sroland.mainz@nrubsig.org { 16810898Sroland.mainz@nrubsig.org sh_close(fd); 16910898Sroland.mainz@nrubsig.org fcntl(1,F_DUPFD, fd); 17010898Sroland.mainz@nrubsig.org } 17110898Sroland.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 18110898Sroland.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; 19310898Sroland.mainz@nrubsig.org char *trap = shp->st.trapcom[0]; 19410898Sroland.mainz@nrubsig.org if(trap) 19510898Sroland.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; 20010898Sroland.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; 20610898Sroland.mainz@nrubsig.org if(trap) 20710898Sroland.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); 216*12068SRoger.Faulkner@Oracle.COM sh_offoption(SH_MONITOR); 2174887Schin sh_offstate(SH_MONITOR); 2184887Schin subshell_data = 0; 2198462SApril.Chin@Sun.COM shp->subshell = 0; 2208462SApril.Chin@Sun.COM SH_SUBSHELLNOD->nvalue.s = 0; 2214887Schin sp->subpid=0; 22210898Sroland.mainz@nrubsig.org shp->st.trapcom[0] = trap; 2234887Schin } 2244887Schin } 2254887Schin 2268462SApril.Chin@Sun.COM int nv_subsaved(register Namval_t *np) 2278462SApril.Chin@Sun.COM { 2288462SApril.Chin@Sun.COM register struct subshell *sp; 2298462SApril.Chin@Sun.COM register struct Link *lp; 2308462SApril.Chin@Sun.COM for(sp = (struct subshell*)subshell_data; sp; sp=sp->prev) 2318462SApril.Chin@Sun.COM { 2328462SApril.Chin@Sun.COM for(lp=sp->svar; lp; lp = lp->next) 2338462SApril.Chin@Sun.COM { 2348462SApril.Chin@Sun.COM if(lp->node==np) 2358462SApril.Chin@Sun.COM return(1); 2368462SApril.Chin@Sun.COM } 2378462SApril.Chin@Sun.COM } 2388462SApril.Chin@Sun.COM return(0); 2398462SApril.Chin@Sun.COM } 2408462SApril.Chin@Sun.COM 2414887Schin /* 2424887Schin * This routine will make a copy of the given node in the 2434887Schin * layer created by the most recent subshell_fork if the 2444887Schin * node hasn't already been copied 2454887Schin */ 2464887Schin Namval_t *sh_assignok(register Namval_t *np,int add) 2474887Schin { 2488462SApril.Chin@Sun.COM register Namval_t *mp; 2498462SApril.Chin@Sun.COM register struct Link *lp; 2504887Schin register struct subshell *sp = (struct subshell*)subshell_data; 2518462SApril.Chin@Sun.COM struct Ufunction *rp; 2528462SApril.Chin@Sun.COM Shell_t *shp = sp->shp; 2538462SApril.Chin@Sun.COM Dt_t *dp; 2548462SApril.Chin@Sun.COM Namval_t *mpnext; 2558462SApril.Chin@Sun.COM Namarr_t *ap; 2568462SApril.Chin@Sun.COM int save; 2574887Schin /* don't bother with this */ 25810898Sroland.mainz@nrubsig.org if(!sp->shpwd || (nv_isnull(np) && !add) || np==SH_LEVELNOD) 2594887Schin return(np); 2604887Schin /* don't bother to save if in newer scope */ 2618462SApril.Chin@Sun.COM if(!(rp=shp->st.real_fun) || !(dp=rp->sdict)) 2628462SApril.Chin@Sun.COM dp = sp->var; 2638462SApril.Chin@Sun.COM if(np->nvenv && !nv_isattr(np,NV_MINIMAL|NV_EXPORT) && shp->last_root) 2648462SApril.Chin@Sun.COM dp = shp->last_root; 2658462SApril.Chin@Sun.COM if((mp=nv_search((char*)np,dp,HASH_BUCKET))!=np) 2668462SApril.Chin@Sun.COM { 2678462SApril.Chin@Sun.COM if(mp || !np->nvfun || np->nvfun->subshell>=sh.subshell) 2688462SApril.Chin@Sun.COM return(np); 2698462SApril.Chin@Sun.COM } 2708462SApril.Chin@Sun.COM if((ap=nv_arrayptr(np)) && (mp=nv_opensub(np))) 2718462SApril.Chin@Sun.COM { 2728462SApril.Chin@Sun.COM shp->last_root = ap->table; 2738462SApril.Chin@Sun.COM sh_assignok(mp,add); 2748462SApril.Chin@Sun.COM if(!add || array_assoc(ap)) 2758462SApril.Chin@Sun.COM return(np); 2768462SApril.Chin@Sun.COM } 2774887Schin for(lp=subshell_data->svar; lp; lp = lp->next) 2784887Schin { 2794887Schin if(lp->node==np) 2804887Schin return(np); 2814887Schin } 2828462SApril.Chin@Sun.COM /* first two pointers use linkage from np */ 2838462SApril.Chin@Sun.COM lp = (struct Link*)malloc(sizeof(*np)+2*sizeof(void*)); 2848462SApril.Chin@Sun.COM memset(lp,0, sizeof(*mp)+2*sizeof(void*)); 2854887Schin lp->node = np; 2868462SApril.Chin@Sun.COM if(!add && nv_isvtree(np)) 2878462SApril.Chin@Sun.COM { 2888462SApril.Chin@Sun.COM Namval_t fake; 2898462SApril.Chin@Sun.COM Dt_t *walk, *root=shp->var_tree; 2908462SApril.Chin@Sun.COM char *name = nv_name(np); 2918462SApril.Chin@Sun.COM int len = strlen(name); 2928462SApril.Chin@Sun.COM fake.nvname = name; 2938462SApril.Chin@Sun.COM mpnext = dtnext(root,&fake); 2948462SApril.Chin@Sun.COM dp = root->walk?root->walk:root; 2958462SApril.Chin@Sun.COM while(mp=mpnext) 2968462SApril.Chin@Sun.COM { 2978462SApril.Chin@Sun.COM walk = root->walk?root->walk:root; 2988462SApril.Chin@Sun.COM mpnext = dtnext(root,mp); 2998462SApril.Chin@Sun.COM if(memcmp(name,mp->nvname,len) || mp->nvname[len]!='.') 3008462SApril.Chin@Sun.COM break; 3018462SApril.Chin@Sun.COM nv_delete(mp,walk,NV_NOFREE); 3028462SApril.Chin@Sun.COM *((Namval_t**)mp) = lp->child; 3038462SApril.Chin@Sun.COM lp->child = mp; 3048462SApril.Chin@Sun.COM 3058462SApril.Chin@Sun.COM } 3068462SApril.Chin@Sun.COM } 3078462SApril.Chin@Sun.COM lp->dict = dp; 3088462SApril.Chin@Sun.COM mp = (Namval_t*)&lp->dict; 3094887Schin lp->next = subshell_data->svar; 3104887Schin subshell_data->svar = lp; 3118462SApril.Chin@Sun.COM save = shp->subshell; 3128462SApril.Chin@Sun.COM shp->subshell = 0; 3138462SApril.Chin@Sun.COM mp->nvname = np->nvname; 3148462SApril.Chin@Sun.COM nv_clone(np,mp,(add?(nv_isnull(np)?0:NV_NOFREE)|NV_ARRAY:NV_MOVE)); 3158462SApril.Chin@Sun.COM shp->subshell = save; 3164887Schin return(np); 3174887Schin } 3184887Schin 3194887Schin /* 3204887Schin * restore the variables 3214887Schin */ 3224887Schin static void nv_restore(struct subshell *sp) 3234887Schin { 3244887Schin register struct Link *lp, *lq; 3254887Schin register Namval_t *mp, *np; 3264887Schin const char *save = sp->shpwd; 3278462SApril.Chin@Sun.COM Namval_t *mpnext; 3284887Schin sp->shpwd = 0; /* make sure sh_assignok doesn't save with nv_unset() */ 3294887Schin for(lp=sp->svar; lp; lp=lq) 3304887Schin { 3318462SApril.Chin@Sun.COM np = (Namval_t*)&lp->dict; 3328462SApril.Chin@Sun.COM lq = lp->next; 3334887Schin mp = lp->node; 3348462SApril.Chin@Sun.COM if(!mp->nvname) 3358462SApril.Chin@Sun.COM continue; 3364887Schin if(nv_isarray(mp)) 3374887Schin nv_putsub(mp,NIL(char*),ARRAY_SCAN); 33810898Sroland.mainz@nrubsig.org _nv_unset(mp,NV_RDONLY|NV_CLONE); 3398462SApril.Chin@Sun.COM if(nv_isarray(np)) 3408462SApril.Chin@Sun.COM { 3418462SApril.Chin@Sun.COM nv_clone(np,mp,NV_MOVE); 3428462SApril.Chin@Sun.COM goto skip; 3438462SApril.Chin@Sun.COM } 3444887Schin nv_setsize(mp,nv_size(np)); 3454887Schin if(!nv_isattr(np,NV_MINIMAL) || nv_isattr(np,NV_EXPORT)) 3464887Schin mp->nvenv = np->nvenv; 3474887Schin mp->nvfun = np->nvfun; 3484887Schin mp->nvflag = np->nvflag; 3498462SApril.Chin@Sun.COM if(nv_cover(mp)) 35010898Sroland.mainz@nrubsig.org { 35110898Sroland.mainz@nrubsig.org nv_putval(mp, nv_getval(np),np->nvflag|NV_NOFREE); 35210898Sroland.mainz@nrubsig.org if(!nv_isattr(np,NV_NOFREE)) 35310898Sroland.mainz@nrubsig.org nv_offattr(mp,NV_NOFREE); 35410898Sroland.mainz@nrubsig.org } 3554887Schin else 3564887Schin mp->nvalue.cp = np->nvalue.cp; 3574887Schin np->nvfun = 0; 3584887Schin if(nv_isattr(mp,NV_EXPORT)) 3594887Schin { 3604887Schin char *name = nv_name(mp); 3614887Schin sh_envput(sh.env,mp); 3624887Schin if(*name=='_' && strcmp(name,"_AST_FEATURES")==0) 3634887Schin astconf(NiL, NiL, NiL); 3644887Schin } 3654887Schin else if(nv_isattr(np,NV_EXPORT)) 3664887Schin env_delete(sh.env,nv_name(mp)); 3678462SApril.Chin@Sun.COM skip: 3688462SApril.Chin@Sun.COM for(mp=lp->child; mp; mp=mpnext) 3698462SApril.Chin@Sun.COM { 3708462SApril.Chin@Sun.COM mpnext = *((Namval_t**)mp); 3718462SApril.Chin@Sun.COM dtinsert(lp->dict,mp); 3728462SApril.Chin@Sun.COM } 3738462SApril.Chin@Sun.COM free((void*)lp); 3748462SApril.Chin@Sun.COM sp->svar = lq; 3754887Schin } 3764887Schin sp->shpwd=save; 3774887Schin } 3784887Schin 3794887Schin /* 3804887Schin * return pointer to alias tree 3814887Schin * create new one if in a subshell and one doesn't exist and create is non-zero 3824887Schin */ 3834887Schin Dt_t *sh_subaliastree(int create) 3844887Schin { 3854887Schin register struct subshell *sp = subshell_data; 3864887Schin if(!sp || sh.curenv==0) 3874887Schin return(sh.alias_tree); 3884887Schin if(!sp->salias && create) 3894887Schin { 3904887Schin sp->salias = dtopen(&_Nvdisc,Dtoset); 3914887Schin dtview(sp->salias,sh.alias_tree); 3924887Schin sh.alias_tree = sp->salias; 3934887Schin } 3944887Schin return(sp->salias); 3954887Schin } 3964887Schin 3974887Schin /* 3984887Schin * return pointer to function tree 3994887Schin * create new one if in a subshell and one doesn't exist and create is non-zero 4004887Schin */ 4014887Schin Dt_t *sh_subfuntree(int create) 4024887Schin { 4034887Schin register struct subshell *sp = subshell_data; 4044887Schin if(!sp || sh.curenv==0) 4054887Schin return(sh.fun_tree); 4064887Schin if(!sp->sfun && create) 4074887Schin { 4084887Schin sp->sfun = dtopen(&_Nvdisc,Dtoset); 4094887Schin dtview(sp->sfun,sh.fun_tree); 4104887Schin sh.fun_tree = sp->sfun; 4114887Schin } 4128462SApril.Chin@Sun.COM return(sh.fun_tree); 4134887Schin } 4144887Schin 4158462SApril.Chin@Sun.COM static void table_unset(register Dt_t *root,int fun) 4164887Schin { 4174887Schin register Namval_t *np,*nq; 4188462SApril.Chin@Sun.COM int flag; 4194887Schin for(np=(Namval_t*)dtfirst(root);np;np=nq) 4204887Schin { 4214887Schin nq = (Namval_t*)dtnext(root,np); 4228462SApril.Chin@Sun.COM flag=0; 42310898Sroland.mainz@nrubsig.org if(fun && np->nvalue.rp && np->nvalue.rp->fname && *np->nvalue.rp->fname=='/') 4248462SApril.Chin@Sun.COM { 4258462SApril.Chin@Sun.COM np->nvalue.rp->fdict = 0; 4268462SApril.Chin@Sun.COM flag = NV_NOFREE; 4278462SApril.Chin@Sun.COM } 4288462SApril.Chin@Sun.COM else 4298462SApril.Chin@Sun.COM _nv_unset(np,NV_RDONLY); 4308462SApril.Chin@Sun.COM nv_delete(np,root,flag|NV_FUNCTION); 4314887Schin } 4324887Schin } 4334887Schin 4344887Schin int sh_subsavefd(register int fd) 4354887Schin { 4364887Schin register struct subshell *sp = subshell_data; 4374887Schin register int old=0; 4384887Schin if(sp) 4394887Schin { 4404887Schin old = !(sp->fdsaved&(1<<(fd-1))); 4414887Schin sp->fdsaved |= (1<<(fd-1)); 4424887Schin } 4434887Schin return(old); 4444887Schin } 4454887Schin 4468462SApril.Chin@Sun.COM void sh_subjobcheck(pid_t pid) 4478462SApril.Chin@Sun.COM { 4488462SApril.Chin@Sun.COM register struct subshell *sp = subshell_data; 4498462SApril.Chin@Sun.COM while(sp) 4508462SApril.Chin@Sun.COM { 4518462SApril.Chin@Sun.COM if(sp->cpid==pid) 4528462SApril.Chin@Sun.COM { 4538462SApril.Chin@Sun.COM sh_close(sp->coutpipe); 4548462SApril.Chin@Sun.COM sh_close(sp->cpipe); 4558462SApril.Chin@Sun.COM sp->coutpipe = sp->cpipe = -1; 4568462SApril.Chin@Sun.COM return; 4578462SApril.Chin@Sun.COM } 4588462SApril.Chin@Sun.COM sp = sp->prev; 4598462SApril.Chin@Sun.COM } 4608462SApril.Chin@Sun.COM } 4618462SApril.Chin@Sun.COM 4624887Schin /* 4634887Schin * Run command tree <t> in a virtual sub-shell 4644887Schin * If comsub is not null, then output will be placed in temp file (or buffer) 4654887Schin * If comsub is not null, the return value will be a stream consisting of 4664887Schin * output of command <t>. Otherwise, NULL will be returned. 4674887Schin */ 4684887Schin 4694887Schin Sfio_t *sh_subshell(Shnode_t *t, int flags, int comsub) 4704887Schin { 4714887Schin Shell_t *shp = &sh; 4724887Schin struct subshell sub_data; 4734887Schin register struct subshell *sp = &sub_data; 47410898Sroland.mainz@nrubsig.org int jmpval,nsig=0,duped=0; 4754887Schin int savecurenv = shp->curenv; 4768462SApril.Chin@Sun.COM int savejobpgid = job.curpgid; 4774887Schin int16_t subshell; 4784887Schin char *savsig; 4794887Schin Sfio_t *iop=0; 4804887Schin struct checkpt buff; 4814887Schin struct sh_scoped savst; 4824887Schin struct dolnod *argsav=0; 4834887Schin memset((char*)sp, 0, sizeof(*sp)); 4844887Schin sfsync(shp->outpool); 4858462SApril.Chin@Sun.COM argsav = sh_arguse(shp); 4864887Schin if(shp->curenv==0) 4874887Schin { 4884887Schin subshell_data=0; 4894887Schin subenv = 0; 4904887Schin } 4914887Schin shp->curenv = ++subenv; 4928462SApril.Chin@Sun.COM job.curpgid = 0; 4934887Schin savst = shp->st; 4944887Schin sh_pushcontext(&buff,SH_JMPSUB); 4954887Schin subshell = shp->subshell+1; 4968462SApril.Chin@Sun.COM SH_SUBSHELLNOD->nvalue.s = subshell; 4974887Schin shp->subshell = subshell; 4984887Schin sp->prev = subshell_data; 4998462SApril.Chin@Sun.COM sp->shp = shp; 5008462SApril.Chin@Sun.COM sp->sig = 0; 5014887Schin subshell_data = sp; 5024887Schin sp->errcontext = &buff.err; 5034887Schin sp->var = shp->var_tree; 5044887Schin sp->options = shp->options; 5054887Schin sp->jobs = job_subsave(); 5064887Schin /* make sure initialization has occurred */ 5074887Schin if(!shp->pathlist) 5084887Schin path_get("."); 5094887Schin sp->pathlist = path_dup((Pathcomp_t*)shp->pathlist); 5104887Schin if(!shp->pwd) 5114887Schin path_pwd(0); 5124887Schin sp->bckpid = shp->bckpid; 5138462SApril.Chin@Sun.COM if(comsub) 5148462SApril.Chin@Sun.COM sh_stats(STAT_COMSUB); 5158810SCasper.Dik@Sun.COM sp->subshare = shp->subshare; 5168810SCasper.Dik@Sun.COM shp->subshare = comsub==2 || (comsub==1 && sh_isoption(SH_SUBSHARE)); 5178810SCasper.Dik@Sun.COM if(!comsub || !shp->subshare) 5184887Schin { 5194887Schin sp->shpwd = shp->pwd; 5204887Schin sp->pwd = (shp->pwd?strdup(shp->pwd):0); 5214887Schin sp->mask = shp->mask; 5228462SApril.Chin@Sun.COM sh_stats(STAT_SUBSHELL); 5234887Schin /* save trap table */ 5244887Schin shp->st.otrapcom = 0; 5254887Schin if((nsig=shp->st.trapmax*sizeof(char*))>0 || shp->st.trapcom[0]) 5264887Schin { 5274887Schin nsig += sizeof(char*); 5284887Schin memcpy(savsig=malloc(nsig),(char*)&shp->st.trapcom[0],nsig); 5294887Schin /* this nonsense needed for $(trap) */ 5304887Schin shp->st.otrapcom = (char**)savsig; 5314887Schin } 5328462SApril.Chin@Sun.COM sp->cpid = shp->cpid; 5338462SApril.Chin@Sun.COM sp->coutpipe = shp->coutpipe; 5348462SApril.Chin@Sun.COM sp->cpipe = shp->cpipe[1]; 5358462SApril.Chin@Sun.COM shp->cpid = 0; 5364887Schin sh_sigreset(0); 5374887Schin } 5384887Schin jmpval = sigsetjmp(buff.buff,0); 5394887Schin if(jmpval==0) 5404887Schin { 5414887Schin if(comsub) 5424887Schin { 5434887Schin /* disable job control */ 5448462SApril.Chin@Sun.COM shp->spid = 0; 5454887Schin sp->jobcontrol = job.jobcontrol; 5464887Schin sp->monitor = (sh_isstate(SH_MONITOR)!=0); 5474887Schin job.jobcontrol=0; 5484887Schin sh_offstate(SH_MONITOR); 5494887Schin sp->pipe = sp; 5504887Schin /* save sfstdout and status */ 5514887Schin sp->saveout = sfswap(sfstdout,NIL(Sfio_t*)); 5524887Schin sp->fdstatus = shp->fdstatus[1]; 5534887Schin sp->tmpfd = -1; 5544887Schin sp->pipefd = -1; 5554887Schin /* use sftmp() file for standard output */ 5564887Schin if(!(iop = sftmp(PIPE_BUF))) 5574887Schin { 5584887Schin sfswap(sp->saveout,sfstdout); 5594887Schin errormsg(SH_DICT,ERROR_system(1),e_tmpcreate); 5604887Schin } 5614887Schin sfswap(iop,sfstdout); 5624887Schin sfset(sfstdout,SF_READ,0); 5634887Schin shp->fdstatus[1] = IOWRITE; 5648462SApril.Chin@Sun.COM if(!(sp->nofork = sh_state(SH_NOFORK))) 5658462SApril.Chin@Sun.COM sh_onstate(SH_NOFORK); 5668462SApril.Chin@Sun.COM flags |= sh_state(SH_NOFORK); 5674887Schin } 5684887Schin else if(sp->prev) 5694887Schin { 5704887Schin sp->pipe = sp->prev->pipe; 5714887Schin flags &= ~sh_state(SH_NOFORK); 5724887Schin } 5734887Schin sh_exec(t,flags); 5744887Schin } 5758462SApril.Chin@Sun.COM if(comsub!=2 && jmpval!=SH_JMPSUB && shp->st.trapcom[0] && shp->subshell) 5764887Schin { 5774887Schin /* trap on EXIT not handled by child */ 5784887Schin char *trap=shp->st.trapcom[0]; 5794887Schin shp->st.trapcom[0] = 0; /* prevent recursion */ 5804887Schin shp->oldexit = shp->exitval; 5814887Schin sh_trap(trap,0); 5824887Schin free(trap); 5834887Schin } 5844887Schin sh_popcontext(&buff); 5854887Schin if(shp->subshell==0) /* must be child process */ 5864887Schin { 5874887Schin subshell_data = sp->prev; 5884887Schin if(jmpval==SH_JMPSCRIPT) 5894887Schin siglongjmp(*shp->jmplist,jmpval); 59010898Sroland.mainz@nrubsig.org shp->exitval &= SH_EXITMASK; 5918462SApril.Chin@Sun.COM sh_done(shp,0); 5924887Schin } 5934887Schin if(comsub) 5944887Schin { 5954887Schin /* re-enable job control */ 5968462SApril.Chin@Sun.COM if(!sp->nofork) 5978462SApril.Chin@Sun.COM sh_offstate(SH_NOFORK); 5984887Schin job.jobcontrol = sp->jobcontrol; 5994887Schin if(sp->monitor) 6004887Schin sh_onstate(SH_MONITOR); 6014887Schin if(sp->pipefd>=0) 6024887Schin { 6034887Schin /* sftmp() file has been returned into pipe */ 6048462SApril.Chin@Sun.COM iop = sh_iostream(shp,sp->pipefd); 6054887Schin sfclose(sfstdout); 6064887Schin } 6074887Schin else 6084887Schin { 6094887Schin /* move tmp file to iop and restore sfstdout */ 6104887Schin iop = sfswap(sfstdout,NIL(Sfio_t*)); 6114887Schin if(!iop) 6124887Schin { 6134887Schin /* maybe locked try again */ 6144887Schin sfclrlock(sfstdout); 6154887Schin iop = sfswap(sfstdout,NIL(Sfio_t*)); 6164887Schin } 6174887Schin if(iop && sffileno(iop)==1) 6184887Schin { 6194887Schin int fd=sfsetfd(iop,3); 6204887Schin if(fd<0) 62110898Sroland.mainz@nrubsig.org { 62210898Sroland.mainz@nrubsig.org shp->toomany = 1; 62310898Sroland.mainz@nrubsig.org ((struct checkpt*)shp->jmplist)->mode = SH_JMPERREXIT; 6244887Schin errormsg(SH_DICT,ERROR_system(1),e_toomany); 62510898Sroland.mainz@nrubsig.org } 6264887Schin shp->sftable[fd] = iop; 6274887Schin fcntl(fd,F_SETFD,FD_CLOEXEC); 6284887Schin shp->fdstatus[fd] = (shp->fdstatus[1]|IOCLEX); 6294887Schin shp->fdstatus[1] = IOCLOSE; 6304887Schin } 6314887Schin sfset(iop,SF_READ,1); 6324887Schin } 6334887Schin sfswap(sp->saveout,sfstdout); 6344887Schin /* check if standard output was preserved */ 6354887Schin if(sp->tmpfd>=0) 6364887Schin { 6374887Schin close(1); 63810898Sroland.mainz@nrubsig.org if (fcntl(sp->tmpfd,F_DUPFD,1) != 1) 63910898Sroland.mainz@nrubsig.org duped++; 6404887Schin sh_close(sp->tmpfd); 6414887Schin } 6424887Schin shp->fdstatus[1] = sp->fdstatus; 6434887Schin } 6444887Schin if(sp->subpid) 6458462SApril.Chin@Sun.COM { 6468462SApril.Chin@Sun.COM if(shp->exitval > SH_EXITSIG) 6478462SApril.Chin@Sun.COM sp->sig = (shp->exitval&SH_EXITMASK); 6488462SApril.Chin@Sun.COM shp->exitval = 0; 6498462SApril.Chin@Sun.COM if(comsub) 6508462SApril.Chin@Sun.COM shp->spid = sp->subpid; 6518462SApril.Chin@Sun.COM } 6528462SApril.Chin@Sun.COM if(comsub && iop && sp->pipefd<0) 6534887Schin sfseek(iop,(off_t)0,SEEK_SET); 6544887Schin path_delete((Pathcomp_t*)shp->pathlist); 6554887Schin shp->pathlist = (void*)sp->pathlist; 6564887Schin job_subrestore(sp->jobs); 6574887Schin shp->jobenv = savecurenv; 6588462SApril.Chin@Sun.COM job.curpgid = savejobpgid; 6594887Schin shp->bckpid = sp->bckpid; 6604887Schin if(sp->shpwd) /* restore environment if saved */ 6614887Schin { 6628462SApril.Chin@Sun.COM int n; 6634887Schin shp->options = sp->options; 6644887Schin nv_restore(sp); 6654887Schin if(sp->salias) 6664887Schin { 6674887Schin shp->alias_tree = dtview(sp->salias,0); 6688462SApril.Chin@Sun.COM table_unset(sp->salias,0); 6694887Schin dtclose(sp->salias); 6704887Schin } 6714887Schin if(sp->sfun) 6724887Schin { 6734887Schin shp->fun_tree = dtview(sp->sfun,0); 6748462SApril.Chin@Sun.COM table_unset(sp->sfun,1); 6754887Schin dtclose(sp->sfun); 6764887Schin } 6778462SApril.Chin@Sun.COM n = shp->st.trapmax-savst.trapmax; 6784887Schin sh_sigreset(1); 6798462SApril.Chin@Sun.COM if(n>0) 6808462SApril.Chin@Sun.COM memset(&shp->st.trapcom[savst.trapmax],0,n*sizeof(char*)); 6814887Schin shp->st = savst; 6824887Schin shp->curenv = savecurenv; 6834887Schin if(nsig) 6844887Schin { 6854887Schin memcpy((char*)&shp->st.trapcom[0],savsig,nsig); 6864887Schin free((void*)savsig); 6874887Schin } 6884887Schin shp->options = sp->options; 6894887Schin if(!shp->pwd || strcmp(sp->pwd,shp->pwd)) 6904887Schin { 6914887Schin /* restore PWDNOD */ 6928462SApril.Chin@Sun.COM Namval_t *pwdnod = sh_scoped(shp,PWDNOD); 6934887Schin if(shp->pwd) 6944887Schin { 6954887Schin chdir(shp->pwd=sp->pwd); 6964887Schin path_newdir(shp->pathlist); 6974887Schin } 6984887Schin if(nv_isattr(pwdnod,NV_NOFREE)) 6994887Schin pwdnod->nvalue.cp = (const char*)sp->pwd; 7004887Schin } 7014887Schin else if(sp->shpwd != shp->pwd) 7024887Schin { 7034887Schin shp->pwd = sp->pwd; 7044887Schin if(PWDNOD->nvalue.cp==sp->shpwd) 7054887Schin PWDNOD->nvalue.cp = sp->pwd; 7064887Schin } 7074887Schin else 7084887Schin free((void*)sp->pwd); 7094887Schin if(sp->mask!=shp->mask) 7108462SApril.Chin@Sun.COM umask(shp->mask=sp->mask); 71110898Sroland.mainz@nrubsig.org if(shp->coutpipe!=sp->coutpipe) 7128462SApril.Chin@Sun.COM { 7138462SApril.Chin@Sun.COM sh_close(shp->coutpipe); 7148462SApril.Chin@Sun.COM sh_close(shp->cpipe[1]); 7158462SApril.Chin@Sun.COM } 7168462SApril.Chin@Sun.COM shp->cpid = sp->cpid; 7178462SApril.Chin@Sun.COM shp->cpipe[1] = sp->cpipe; 7188462SApril.Chin@Sun.COM shp->coutpipe = sp->coutpipe; 7194887Schin } 7208810SCasper.Dik@Sun.COM shp->subshare = sp->subshare; 7218462SApril.Chin@Sun.COM if(shp->subshell) 7228462SApril.Chin@Sun.COM SH_SUBSHELLNOD->nvalue.s = --shp->subshell; 72310898Sroland.mainz@nrubsig.org subshell = shp->subshell; 72410898Sroland.mainz@nrubsig.org subshell_data = sp->prev; 72510898Sroland.mainz@nrubsig.org sh_argfree(shp,argsav,0); 72610898Sroland.mainz@nrubsig.org if(shp->topfd != buff.topfd) 72710898Sroland.mainz@nrubsig.org sh_iorestore(shp,buff.topfd|IOSUBSHELL,jmpval); 7288462SApril.Chin@Sun.COM if(sp->sig) 7298462SApril.Chin@Sun.COM { 7308462SApril.Chin@Sun.COM if(sp->prev) 7318462SApril.Chin@Sun.COM sp->prev->sig = sp->sig; 7328462SApril.Chin@Sun.COM else 7338462SApril.Chin@Sun.COM { 7348462SApril.Chin@Sun.COM sh_fault(sp->sig); 7358462SApril.Chin@Sun.COM sh_chktrap(); 7368462SApril.Chin@Sun.COM } 7378462SApril.Chin@Sun.COM } 73810898Sroland.mainz@nrubsig.org sh_sigcheck(); 7394887Schin shp->trapnote = 0; 74010898Sroland.mainz@nrubsig.org if(sp->subpid && !comsub) 74110898Sroland.mainz@nrubsig.org job_wait(sp->subpid); 7424887Schin if(shp->exitval > SH_EXITSIG) 7434887Schin { 7444887Schin int sig = shp->exitval&SH_EXITMASK; 7454887Schin if(sig==SIGINT || sig== SIGQUIT) 7464887Schin sh_fault(sig); 7474887Schin } 74810898Sroland.mainz@nrubsig.org if(duped) 74910898Sroland.mainz@nrubsig.org { 75010898Sroland.mainz@nrubsig.org ((struct checkpt*)shp->jmplist)->mode = SH_JMPERREXIT; 75110898Sroland.mainz@nrubsig.org shp->toomany = 1; 75210898Sroland.mainz@nrubsig.org errormsg(SH_DICT,ERROR_system(1),e_redirect); 75310898Sroland.mainz@nrubsig.org } 75410898Sroland.mainz@nrubsig.org if(jmpval && shp->toomany) 75510898Sroland.mainz@nrubsig.org siglongjmp(*shp->jmplist,jmpval); 7564887Schin return(iop); 7574887Schin } 758