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 */
sh_subtmpfile(int pflag)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 */
sh_subfork(void)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
nv_subsaved(register Namval_t * np)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 */
sh_assignok(register Namval_t * np,int add)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 */
nv_restore(struct subshell * sp)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 */
sh_subaliastree(int create)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 */
sh_subfuntree(int create)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
table_unset(register Dt_t * root,int fun)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
sh_subsavefd(register int fd)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
sh_subjobcheck(pid_t pid)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
sh_subshell(Shnode_t * t,int flags,int comsub)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