xref: /onnv-gate/usr/src/lib/libshell/common/sh/xec.c (revision 10898)
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  * UNIX shell parse tree executer
234887Schin  *
244887Schin  *   David Korn
254887Schin  *   AT&T Labs
264887Schin  *
274887Schin  */
284887Schin 
294887Schin #include	"defs.h"
304887Schin #include	<fcin.h>
314887Schin #include	"variables.h"
324887Schin #include	"path.h"
334887Schin #include	"name.h"
344887Schin #include	"io.h"
354887Schin #include	"shnodes.h"
364887Schin #include	"jobs.h"
374887Schin #include	"test.h"
384887Schin #include	"builtins.h"
394887Schin #include	"FEATURE/time"
404887Schin #include	"FEATURE/externs"
414887Schin #include	"FEATURE/locale"
424887Schin #include	"streval.h"
434887Schin 
444887Schin #if !_std_malloc
454887Schin #   include	<vmalloc.h>
464887Schin #endif
474887Schin 
488462SApril.Chin@Sun.COM #if     _lib_vfork
498462SApril.Chin@Sun.COM #   include     <ast_vfork.h>
508462SApril.Chin@Sun.COM #else
518462SApril.Chin@Sun.COM #   define vfork()      fork()
528462SApril.Chin@Sun.COM #endif
538462SApril.Chin@Sun.COM 
544887Schin #define SH_NTFORK	SH_TIMING
554887Schin 
564887Schin #if _lib_nice
574887Schin     extern int	nice(int);
584887Schin #endif /* _lib_nice */
594887Schin #if !_lib_spawnveg
604887Schin #   define spawnveg(a,b,c,d)    spawnve(a,b,c)
614887Schin #endif /* !_lib_spawnveg */
624887Schin #if SHOPT_SPAWN
638462SApril.Chin@Sun.COM     static pid_t sh_ntfork(Shell_t*,const Shnode_t*,char*[],int*,int);
644887Schin #endif /* SHOPT_SPAWN */
654887Schin 
668462SApril.Chin@Sun.COM static void	sh_funct(Shell_t *,Namval_t*, int, char*[], struct argnod*,int);
674887Schin static int	trim_eq(const char*, const char*);
688462SApril.Chin@Sun.COM static void	coproc_init(Shell_t*, int pipes[]);
694887Schin 
704887Schin static void	*timeout;
714887Schin static char	pipejob;
724887Schin 
734887Schin struct funenv
744887Schin {
754887Schin 	Namval_t	*node;
764887Schin 	struct argnod	*env;
774887Schin };
784887Schin 
794887Schin /* ========	command execution	========*/
804887Schin 
814887Schin /*
824887Schin  * print time <t> in h:m:s format with precision <p>
834887Schin  */
844887Schin static void     l_time(Sfio_t *outfile,register clock_t t,int p)
854887Schin {
864887Schin 	register int  min, sec, frac;
874887Schin 	register int hr;
884887Schin 	if(p)
894887Schin 	{
904887Schin 		frac = t%sh.lim.clk_tck;
914887Schin 		frac = (frac*100)/sh.lim.clk_tck;
924887Schin 	}
934887Schin 	t /= sh.lim.clk_tck;
944887Schin 	sec = t%60;
954887Schin 	t /= 60;
964887Schin 	min = t%60;
974887Schin 	if(hr=t/60)
984887Schin 		sfprintf(outfile,"%dh",hr);
994887Schin 	if(p)
1004887Schin 		sfprintf(outfile,"%dm%d%c%0*ds",min,sec,GETDECIMAL(0),p,frac);
1014887Schin 	else
1024887Schin 		sfprintf(outfile,"%dm%ds",min,sec);
1034887Schin }
1044887Schin 
1058462SApril.Chin@Sun.COM static int p_time(Shell_t *shp, Sfio_t *out, const char *format, clock_t *tm)
1064887Schin {
1078462SApril.Chin@Sun.COM 	int		c,p,l,n,offset = staktell();
1088462SApril.Chin@Sun.COM 	const char	*first;
1098462SApril.Chin@Sun.COM 	double		d;
1108462SApril.Chin@Sun.COM 	Stk_t		*stkp = shp->stk;
1114887Schin 	for(first=format ; c= *format; format++)
1124887Schin 	{
1134887Schin 		if(c!='%')
1144887Schin 			continue;
1158462SApril.Chin@Sun.COM 		sfwrite(stkp, first, format-first);
1164887Schin 		n = l = 0;
1174887Schin 		p = 3;
1184887Schin 		if((c= *++format) == '%')
1194887Schin 		{
1204887Schin 			first = format;
1214887Schin 			continue;
1224887Schin 		}
1234887Schin 		if(c>='0' && c <='9')
1244887Schin 		{
1254887Schin 			p = (c>'3')?3:(c-'0');
1264887Schin 			c = *++format;
1274887Schin 		}
1284887Schin 		else if(c=='P')
1294887Schin 		{
1304887Schin 			if(d=tm[0])
1314887Schin 				d = 100.*(((double)(tm[1]+tm[2]))/d);
1324887Schin 			p = 2;
1334887Schin 			goto skip;
1344887Schin 		}
1354887Schin 		if(c=='l')
1364887Schin 		{
1374887Schin 			l = 1;
1384887Schin 			c = *++format;
1394887Schin 		}
1404887Schin 		if(c=='U')
1414887Schin 			n = 1;
1424887Schin 		else if(c=='S')
1434887Schin 			n = 2;
1444887Schin 		else if(c!='R')
1454887Schin 		{
1468462SApril.Chin@Sun.COM 			stkseek(stkp,offset);
1474887Schin 			errormsg(SH_DICT,ERROR_exit(0),e_badtformat,c);
1484887Schin 			return(0);
1494887Schin 		}
1504887Schin 		d = (double)tm[n]/sh.lim.clk_tck;
1514887Schin 	skip:
1524887Schin 		if(l)
1538462SApril.Chin@Sun.COM 			l_time(stkp, tm[n], p);
1544887Schin 		else
1558462SApril.Chin@Sun.COM 			sfprintf(stkp,"%.*f",p, d);
1564887Schin 		first = format+1;
1574887Schin 	}
1584887Schin 	if(format>first)
1598462SApril.Chin@Sun.COM 		sfwrite(stkp,first, format-first);
1608462SApril.Chin@Sun.COM 	sfputc(stkp,'\n');
1618462SApril.Chin@Sun.COM 	n = stktell(stkp)-offset;
1628462SApril.Chin@Sun.COM 	sfwrite(out,stkptr(stkp,offset),n);
1638462SApril.Chin@Sun.COM 	stkseek(stkp,offset);
1644887Schin 	return(n);
1654887Schin }
1664887Schin 
1674887Schin #if SHOPT_OPTIMIZE
1684887Schin /*
1694887Schin  * clear argument pointers that point into the stack
1704887Schin  */
1714887Schin static int p_arg(struct argnod*,int);
1724887Schin static int p_switch(struct regnod*);
1734887Schin static int p_comarg(register struct comnod *com)
1744887Schin {
1754887Schin 	Namval_t *np=com->comnamp;
1764887Schin 	int n = p_arg(com->comset,ARG_ASSIGN);
1774887Schin 	if(com->comarg && (com->comtyp&COMSCAN))
1784887Schin 		n+= p_arg(com->comarg,0);
1794887Schin 	if(com->comstate  && np)
1804887Schin 	{
1814887Schin 		/* call builtin to cleanup state */
1828462SApril.Chin@Sun.COM 		Shbltin_t *bp = &sh.bltindata;
1838462SApril.Chin@Sun.COM 		void  *save_ptr = bp->ptr;
1848462SApril.Chin@Sun.COM 		void  *save_data = bp->data;
1858462SApril.Chin@Sun.COM 		bp->bnode = np;
1868462SApril.Chin@Sun.COM 		bp->vnode = com->comnamq;
1878462SApril.Chin@Sun.COM 		bp->ptr = nv_context(np);
1888462SApril.Chin@Sun.COM 		bp->data = com->comstate;
1898462SApril.Chin@Sun.COM 		bp->flags = SH_END_OPTIM;
1908462SApril.Chin@Sun.COM 		(*funptr(np))(0,(char**)0, bp);
1918462SApril.Chin@Sun.COM 		bp->ptr = save_ptr;
1928462SApril.Chin@Sun.COM 		bp->data = save_data;
1934887Schin 	}
1944887Schin 	com->comstate = 0;
1954887Schin 	if(com->comarg && !np)
1964887Schin 		n++;
1974887Schin 	return(n);
1984887Schin }
1994887Schin 
2004887Schin extern void sh_optclear(Shell_t*, void*);
2014887Schin 
2024887Schin static int sh_tclear(register Shnode_t *t)
2034887Schin {
2044887Schin 	int n=0;
2054887Schin 	if(!t)
2064887Schin 		return(0);
2074887Schin 	switch(t->tre.tretyp&COMMSK)
2084887Schin 	{
2094887Schin 		case TTIME:
2104887Schin 		case TPAR:
2114887Schin 			return(sh_tclear(t->par.partre));
2124887Schin 		case TCOM:
2134887Schin 			return(p_comarg((struct comnod*)t));
2144887Schin 		case TSETIO:
2154887Schin 		case TFORK:
2164887Schin 			return(sh_tclear(t->fork.forktre));
2174887Schin 		case TIF:
2184887Schin 			n=sh_tclear(t->if_.iftre);
2194887Schin 			n+=sh_tclear(t->if_.thtre);
2204887Schin 			n+=sh_tclear(t->if_.eltre);
2214887Schin 			return(n);
2224887Schin 		case TWH:
2234887Schin 			if(t->wh.whinc)
2244887Schin 				n=sh_tclear((Shnode_t*)(t->wh.whinc));
2254887Schin 			n+=sh_tclear(t->wh.whtre);
2264887Schin 			n+=sh_tclear(t->wh.dotre);
2274887Schin 			return(n);
2284887Schin 		case TLST:
2294887Schin 		case TAND:
2304887Schin 		case TORF:
2314887Schin 		case TFIL:
2324887Schin 			n=sh_tclear(t->lst.lstlef);
2334887Schin 			return(n+sh_tclear(t->lst.lstrit));
2344887Schin 		case TARITH:
2354887Schin 			return(p_arg(t->ar.arexpr,ARG_ARITH));
2364887Schin 		case TFOR:
2374887Schin 			n=sh_tclear(t->for_.fortre);
2384887Schin 			return(n+sh_tclear((Shnode_t*)t->for_.forlst));
2394887Schin 		case TSW:
2404887Schin 			n=p_arg(t->sw.swarg,0);
2414887Schin 			return(n+p_switch(t->sw.swlst));
2424887Schin 		case TFUN:
2434887Schin 			n=sh_tclear(t->funct.functtre);
2444887Schin 			return(n+sh_tclear((Shnode_t*)t->funct.functargs));
2454887Schin 		case TTST:
2464887Schin 			if((t->tre.tretyp&TPAREN)==TPAREN)
2474887Schin 				return(sh_tclear(t->lst.lstlef));
2484887Schin 			else
2494887Schin 			{
2504887Schin 				n=p_arg(&(t->lst.lstlef->arg),0);
2514887Schin 				if(t->tre.tretyp&TBINARY)
2524887Schin 					n+=p_arg(&(t->lst.lstrit->arg),0);
2534887Schin 			}
2544887Schin 	}
2554887Schin 	return(n);
2564887Schin }
2574887Schin 
2584887Schin static int p_arg(register struct argnod *arg,int flag)
2594887Schin {
2604887Schin 	while(arg)
2614887Schin 	{
2624887Schin 		if(strlen(arg->argval) || (arg->argflag==ARG_RAW))
2634887Schin 			arg->argchn.ap = 0;
2644887Schin 		else if(flag==0)
2654887Schin 			sh_tclear((Shnode_t*)arg->argchn.ap);
2664887Schin 		else
2674887Schin 			sh_tclear(((struct fornod*)arg->argchn.ap)->fortre);
2684887Schin 		arg = arg->argnxt.ap;
2694887Schin 	}
2704887Schin 	return(0);
2714887Schin }
2724887Schin 
2734887Schin static int p_switch(register struct regnod *reg)
2744887Schin {
2754887Schin 	int n=0;
2764887Schin 	while(reg)
2774887Schin 	{
2784887Schin 		n+=p_arg(reg->regptr,0);
2794887Schin 		n+=sh_tclear(reg->regcom);
2804887Schin 		reg = reg->regnxt;
2814887Schin 	}
2824887Schin 	return(n);
2834887Schin }
2844887Schin #   define OPTIMIZE_FLAG	(ARG_OPTIMIZE)
2854887Schin #   define OPTIMIZE		(flags&OPTIMIZE_FLAG)
2864887Schin #else
2874887Schin #   define OPTIMIZE_FLAG	(0)
2884887Schin #   define OPTIMIZE		(0)
2894887Schin #   define sh_tclear(x)
2904887Schin #endif /* SHOPT_OPTIMIZE */
2914887Schin 
2924887Schin static void out_pattern(Sfio_t *iop, register const char *cp, int n)
2934887Schin {
2944887Schin 	register int c;
2954887Schin 	do
2964887Schin 	{
2974887Schin 		switch(c= *cp)
2984887Schin 		{
2994887Schin 		    case 0:
3004887Schin 			if(n<0)
3014887Schin 				return;
3024887Schin 			c = n;
3034887Schin 			break;
3044887Schin 		    case '\n':
3054887Schin 			sfputr(iop,"$'\\n",'\'');
3064887Schin 			continue;
3074887Schin 		    case '\\':
3084887Schin 			if (!(c = *++cp))
3094887Schin 				c = '\\';
3104887Schin 			/*FALLTHROUGH*/
3114887Schin 		    case ' ':
3124887Schin 		    case '<': case '>': case ';':
3134887Schin 		    case '$': case '`': case '\t':
3144887Schin 			sfputc(iop,'\\');
3154887Schin 			break;
3164887Schin 		}
3174887Schin 		sfputc(iop,c);
3184887Schin 	}
3194887Schin 	while(*cp++);
3204887Schin }
3214887Schin 
3224887Schin static void out_string(Sfio_t *iop, register const char *cp, int c, int quoted)
3234887Schin {
3244887Schin 	if(quoted)
3254887Schin 	{
3268462SApril.Chin@Sun.COM 		int n = stktell(stkstd);
3274887Schin 		cp = sh_fmtq(cp);
3284887Schin 		if(iop==stkstd && cp==stkptr(stkstd,n))
3294887Schin 		{
3304887Schin 			*stkptr(stkstd,stktell(stkstd)-1) = c;
3314887Schin 			return;
3324887Schin 		}
3334887Schin 	}
3344887Schin 	sfputr(iop,cp,c);
3354887Schin }
3364887Schin 
3374887Schin struct Level
3384887Schin {
3394887Schin 	Namfun_t	hdr;
3404887Schin 	short		maxlevel;
3414887Schin };
3424887Schin 
3434887Schin /*
3444887Schin  * this is for a debugger but it hasn't been tested yet
3454887Schin  * if a debug script sets .sh.level it should set up the scope
3464887Schin  *  as if you were executing in that level
3474887Schin  */
3484887Schin static void put_level(Namval_t* np,const char *val,int flags,Namfun_t *fp)
3494887Schin {
3504887Schin 	Shscope_t	*sp;
3514887Schin 	struct Level *lp = (struct Level*)fp;
3524887Schin 	int16_t level, oldlevel = (int16_t)nv_getnum(np);
3534887Schin 	nv_putv(np,val,flags,fp);
3548462SApril.Chin@Sun.COM 	if(!val)
355*10898Sroland.mainz@nrubsig.org 	{
356*10898Sroland.mainz@nrubsig.org 		fp = nv_stack(np, NIL(Namfun_t*));
357*10898Sroland.mainz@nrubsig.org 		if(fp && !fp->nofree)
358*10898Sroland.mainz@nrubsig.org 			free((void*)fp);
3598462SApril.Chin@Sun.COM 		return;
360*10898Sroland.mainz@nrubsig.org 	}
3614887Schin 	level = nv_getnum(np);
3624887Schin 	if(level<0 || level > lp->maxlevel)
3634887Schin 	{
3648462SApril.Chin@Sun.COM 		nv_putv(np, (char*)&oldlevel, NV_INT16, fp);
3654887Schin 		/* perhaps this should be an error */
3664887Schin 		return;
3674887Schin 	}
3684887Schin 	if(level==oldlevel)
3694887Schin 		return;
3704887Schin 	if(sp = sh_getscope(level,SEEK_SET))
3714887Schin 	{
3728462SApril.Chin@Sun.COM 		sh_setscope(sp);
3738462SApril.Chin@Sun.COM 		error_info.id = sp->cmdname;
3748462SApril.Chin@Sun.COM 
3754887Schin 	}
3764887Schin }
3774887Schin 
3788462SApril.Chin@Sun.COM static const Namdisc_t level_disc = {  sizeof(struct Level), put_level };
3798462SApril.Chin@Sun.COM 
3808462SApril.Chin@Sun.COM static struct Level *init_level(int level)
3818462SApril.Chin@Sun.COM {
3828462SApril.Chin@Sun.COM 	struct Level *lp = newof(NiL,struct Level,1,0);
3838462SApril.Chin@Sun.COM 	lp->maxlevel = level;
3848462SApril.Chin@Sun.COM 	_nv_unset(SH_LEVELNOD,0);
3858462SApril.Chin@Sun.COM 	nv_onattr(SH_LEVELNOD,NV_INT16|NV_NOFREE);
3868462SApril.Chin@Sun.COM 	nv_putval(SH_LEVELNOD,(char*)&lp->maxlevel,NV_INT16);
3878462SApril.Chin@Sun.COM 	lp->hdr.disc = &level_disc;
3888462SApril.Chin@Sun.COM 	nv_disc(SH_LEVELNOD,&lp->hdr,NV_FIRST);
3898462SApril.Chin@Sun.COM 	return(lp);
3908462SApril.Chin@Sun.COM }
3914887Schin 
3924887Schin /*
3934887Schin  * write the current common on the stack and make it available as .sh.command
3944887Schin  */
3958462SApril.Chin@Sun.COM int sh_debug(Shell_t *shp, const char *trap, const char *name, const char *subscript, char *const argv[], int flags)
3964887Schin {
3978462SApril.Chin@Sun.COM 	Stk_t			*stkp=shp->stk;
3984887Schin 	struct sh_scoped	savst;
3994887Schin 	Namval_t		*np = SH_COMMANDNOD;
4008462SApril.Chin@Sun.COM 	char			*sav = stkptr(stkp,0);
4018462SApril.Chin@Sun.COM 	int			n=4, offset=stktell(stkp);
4024887Schin 	const char		*cp = "+=( ";
4034887Schin 	Sfio_t			*iop = stkstd;
4048462SApril.Chin@Sun.COM 	short			level;
4058462SApril.Chin@Sun.COM 	if(shp->indebug)
4068462SApril.Chin@Sun.COM 		return(0);
4078462SApril.Chin@Sun.COM 	shp->indebug = 1;
4084887Schin 	if(name)
4094887Schin 	{
4104887Schin 		sfputr(iop,name,-1);
4114887Schin 		if(subscript)
4124887Schin 		{
4134887Schin 			sfputc(iop,'[');
4144887Schin 			out_string(iop,subscript,']',1);
4154887Schin 		}
4164887Schin 		if(!(flags&ARG_APPEND))
4174887Schin 			cp+=1, n-=1;
4184887Schin 		if(!(flags&ARG_ASSIGN))
4194887Schin 			n -= 2;
4204887Schin 		sfwrite(iop,cp,n);
4214887Schin 	}
422*10898Sroland.mainz@nrubsig.org 	if(*argv && !(flags&ARG_RAW))
4234887Schin 		out_string(iop, *argv++,' ', 0);
4244887Schin 	n = (flags&ARG_ARITH);
4254887Schin 	while(cp = *argv++)
4264887Schin 	{
4274887Schin 		if((flags&ARG_EXP) && argv[1]==0)
4284887Schin 			out_pattern(iop, cp,' ');
4294887Schin 		else
4304887Schin 			out_string(iop, cp,' ',n?0: (flags&(ARG_RAW|ARG_NOGLOB))||*argv);
4314887Schin 	}
4324887Schin 	if(flags&ARG_ASSIGN)
4334887Schin 		sfputc(iop,')');
4344887Schin 	else if(iop==stkstd)
4358462SApril.Chin@Sun.COM 		*stkptr(stkp,stktell(stkp)-1) = 0;
4368462SApril.Chin@Sun.COM 	np->nvalue.cp = stkfreeze(stkp,1);
4374887Schin 	/* now setup .sh.level variable */
4388462SApril.Chin@Sun.COM 	shp->st.lineno = error_info.line;
4398462SApril.Chin@Sun.COM 	level  = shp->fn_depth+shp->dot_depth;
4408462SApril.Chin@Sun.COM 	if(!SH_LEVELNOD->nvfun || !SH_LEVELNOD->nvfun->disc || nv_isattr(SH_LEVELNOD,NV_INT16|NV_NOFREE)!=(NV_INT16|NV_NOFREE))
4418462SApril.Chin@Sun.COM 		init_level(level);
4428462SApril.Chin@Sun.COM 	else
4438462SApril.Chin@Sun.COM 		nv_putval(SH_LEVELNOD,(char*)&level,NV_INT16);
4448462SApril.Chin@Sun.COM 	savst = shp->st;
4458462SApril.Chin@Sun.COM 	shp->st.trap[SH_DEBUGTRAP] = 0;
4464887Schin 	n = sh_trap(trap,0);
4474887Schin 	np->nvalue.cp = 0;
4488462SApril.Chin@Sun.COM 	shp->indebug = 0;
4498462SApril.Chin@Sun.COM 	if(shp->st.cmdname)
4508462SApril.Chin@Sun.COM 		error_info.id = shp->st.cmdname;
4518462SApril.Chin@Sun.COM 	nv_putval(SH_PATHNAMENOD,shp->st.filename,NV_NOFREE);
4528462SApril.Chin@Sun.COM 	nv_putval(SH_FUNNAMENOD,shp->st.funname,NV_NOFREE);
4538462SApril.Chin@Sun.COM 	shp->st = savst;
4548462SApril.Chin@Sun.COM 	if(sav != stkptr(stkp,0))
4558462SApril.Chin@Sun.COM 		stkset(stkp,sav,0);
4564887Schin 	else
4578462SApril.Chin@Sun.COM 		stkseek(stkp,offset);
4584887Schin 	return(n);
4594887Schin }
4604887Schin 
4614887Schin /*
4624887Schin  * Given stream <iop> compile and execute
4634887Schin  */
4644887Schin int sh_eval(register Sfio_t *iop, int mode)
4654887Schin {
4664887Schin 	register Shnode_t *t;
4674887Schin 	Shell_t  *shp = sh_getinterp();
4684887Schin 	struct slnod *saveslp = shp->st.staklist;
4694887Schin 	int jmpval;
4704887Schin 	struct checkpt *pp = (struct checkpt*)shp->jmplist;
4714887Schin 	struct checkpt buff;
4724887Schin 	static Sfio_t *io_save;
4738462SApril.Chin@Sun.COM 	volatile int traceon=0, lineno=0;
474*10898Sroland.mainz@nrubsig.org 	int binscript=shp->binscript;
4754887Schin 	io_save = iop; /* preserve correct value across longjmp */
476*10898Sroland.mainz@nrubsig.org 	shp->binscript = 0;
4778462SApril.Chin@Sun.COM #define SH_TOPFUN	0x8000	/* this is a temporary tksh hack */
4788462SApril.Chin@Sun.COM 	if (mode & SH_TOPFUN)
4798462SApril.Chin@Sun.COM 	{
4808462SApril.Chin@Sun.COM 		mode ^= SH_TOPFUN;
4818462SApril.Chin@Sun.COM 		shp->fn_reset = 1;
4828462SApril.Chin@Sun.COM 	}
4834887Schin 	sh_pushcontext(&buff,SH_JMPEVAL);
4844887Schin 	buff.olist = pp->olist;
4854887Schin 	jmpval = sigsetjmp(buff.buff,0);
486*10898Sroland.mainz@nrubsig.org 	while(jmpval==0)
4874887Schin 	{
4888462SApril.Chin@Sun.COM 		if(mode&SH_READEVAL)
4898462SApril.Chin@Sun.COM 		{
4908462SApril.Chin@Sun.COM 			lineno = shp->inlineno;
4918462SApril.Chin@Sun.COM 			if(traceon=sh_isoption(SH_XTRACE))
4928462SApril.Chin@Sun.COM 				sh_offoption(SH_XTRACE);
4938462SApril.Chin@Sun.COM 		}
494*10898Sroland.mainz@nrubsig.org 		t = (Shnode_t*)sh_parse(shp,iop,(mode&(SH_READEVAL|SH_FUNEVAL))?mode&SH_FUNEVAL:SH_NL);
495*10898Sroland.mainz@nrubsig.org 		if(!(mode&SH_FUNEVAL) || !sfreserve(iop,0,0))
496*10898Sroland.mainz@nrubsig.org 		{
497*10898Sroland.mainz@nrubsig.org 			if(!(mode&SH_READEVAL))
498*10898Sroland.mainz@nrubsig.org 				sfclose(iop);
499*10898Sroland.mainz@nrubsig.org 			io_save = 0;
500*10898Sroland.mainz@nrubsig.org 			mode &= ~SH_FUNEVAL;
501*10898Sroland.mainz@nrubsig.org 		}
502*10898Sroland.mainz@nrubsig.org 		mode &= ~SH_READEVAL;
5034887Schin 		if(!sh_isoption(SH_VERBOSE))
5044887Schin 			sh_offstate(SH_VERBOSE);
505*10898Sroland.mainz@nrubsig.org 		if((mode&~SH_FUNEVAL) && shp->hist_ptr)
5064887Schin 		{
5074887Schin 			hist_flush(shp->hist_ptr);
5084887Schin 			mode = sh_state(SH_INTERACTIVE);
5094887Schin 		}
510*10898Sroland.mainz@nrubsig.org 		sh_exec(t,sh_isstate(SH_ERREXIT)|sh_isstate(SH_NOFORK)|(mode&~SH_FUNEVAL));
511*10898Sroland.mainz@nrubsig.org 		if(!(mode&SH_FUNEVAL))
512*10898Sroland.mainz@nrubsig.org 			break;
5134887Schin 	}
5144887Schin 	sh_popcontext(&buff);
515*10898Sroland.mainz@nrubsig.org 	shp->binscript = binscript;
5168462SApril.Chin@Sun.COM 	if(traceon)
5178462SApril.Chin@Sun.COM 		sh_onoption(SH_XTRACE);
5188462SApril.Chin@Sun.COM 	if(lineno)
5198462SApril.Chin@Sun.COM 		shp->inlineno = lineno;
5204887Schin 	if(io_save)
5214887Schin 		sfclose(io_save);
5228462SApril.Chin@Sun.COM 	sh_freeup(shp);
5234887Schin 	shp->st.staklist = saveslp;
5248462SApril.Chin@Sun.COM 	shp->fn_reset = 0;
5254887Schin 	if(jmpval>SH_JMPEVAL)
5264887Schin 		siglongjmp(*shp->jmplist,jmpval);
5278462SApril.Chin@Sun.COM 	return(shp->exitval);
5284887Schin }
5294887Schin 
5304887Schin #if SHOPT_FASTPIPE
5318462SApril.Chin@Sun.COM static int pipe_exec(Shell_t* shp,int pv[], Shnode_t *t, int errorflg)
5324887Schin {
5334887Schin 	struct checkpt buff;
5344887Schin 	register Shnode_t *tchild = t->fork.forktre;
5354887Schin 	Namval_t *np;
5368462SApril.Chin@Sun.COM 	int jmpval;
5378462SApril.Chin@Sun.COM 	volatile Sfio_t *iop;
5388462SApril.Chin@Sun.COM 	volatile int r;
5394887Schin 	if((tchild->tre.tretyp&COMMSK)!=TCOM || !(np=(Namval_t*)(tchild->com.comnamp)))
5404887Schin 	{
5414887Schin 		sh_pipe(pv);
5424887Schin 		return(sh_exec(t,errorflg));
5434887Schin 	}
5448462SApril.Chin@Sun.COM 	pv[0] = shp->lim.open_max;
5458462SApril.Chin@Sun.COM 	shp->fdstatus[pv[0]] = IOREAD|IODUP|IOSEEK;
5468462SApril.Chin@Sun.COM 	pv[1] = shp->lim.open_max+1;
5478462SApril.Chin@Sun.COM 	shp->fdstatus[pv[1]] = IOWRITE|IOSEEK;
5484887Schin 	iop = sftmp(IOBSIZE+1);
5498462SApril.Chin@Sun.COM 	shp->sftable[shp->lim.open_max+1] = iop;
5504887Schin 	sh_pushcontext(&buff,SH_JMPIO);
5514887Schin 	if(t->tre.tretyp&FPIN)
5528462SApril.Chin@Sun.COM 		sh_iosave(shp,0,shp->topfd,(char*)0);
5538462SApril.Chin@Sun.COM 	sh_iosave(shp,1,shp->topfd,(char*)0);
5544887Schin 	jmpval = sigsetjmp(buff.buff,0);
5554887Schin 	if(jmpval==0)
5564887Schin 	{
5574887Schin 		if(t->tre.tretyp&FPIN)
5588462SApril.Chin@Sun.COM 			sh_iorenumber(shp,shp->inpipe[0],0);
5598462SApril.Chin@Sun.COM 		sh_iorenumber(shp,shp->lim.open_max+1,1);
5604887Schin 		r = sh_exec(tchild,errorflg);
5614887Schin 		if(sffileno(sfstdout)>=0)
5624887Schin 			pv[0] = sfsetfd(sfstdout,10);
5634887Schin 		iop = sfswap(sfstdout,0);
5644887Schin 	}
5654887Schin 	sh_popcontext(&buff);
5668462SApril.Chin@Sun.COM 	shp->sftable[pv[0]] = iop;
5678462SApril.Chin@Sun.COM 	shp->fdstatus[pv[0]] = IOREAD|IODUP|IOSEEK;
5684887Schin 	sfset(iop,SF_WRITE,0);
5694887Schin 	sfseek(iop,0L,SEEK_SET);
5708462SApril.Chin@Sun.COM 	sh_iorestore(shp,buff.topfd,jmpval);
5714887Schin 	if(jmpval>SH_JMPIO)
5728462SApril.Chin@Sun.COM 		siglongjmp(*shp->jmplist,jmpval);
5734887Schin 	return(r);
5744887Schin }
5754887Schin #endif /* SHOPT_FASTPIPE */
5764887Schin 
5774887Schin /*
5784887Schin  * returns 1 when option -<c> is specified
5794887Schin  */
5804887Schin static int checkopt(char *argv[], int c)
5814887Schin {
5824887Schin 	char *cp;
5834887Schin 	while(cp = *++argv)
5844887Schin 	{
5854887Schin 		if(*cp=='+')
5864887Schin 			continue;
5874887Schin 		if(*cp!='-' || cp[1]=='-')
5884887Schin 			break;
5898462SApril.Chin@Sun.COM 		if(strchr(++cp,c))
5904887Schin 			return(1);
5918462SApril.Chin@Sun.COM 		if(*cp=='h' && cp[1]==0 && *++argv==0)
5928462SApril.Chin@Sun.COM 			break;
5934887Schin 	}
5944887Schin 	return(0);
5954887Schin }
5964887Schin 
5974887Schin static void free_list(struct openlist *olist)
5984887Schin {
5994887Schin 	struct openlist *item,*next;
6004887Schin 	for(item=olist;item;item=next)
6014887Schin 	{
6024887Schin 		next = item->next;
6034887Schin 		free((void*)item);
6044887Schin 	}
6054887Schin }
6064887Schin 
6078462SApril.Chin@Sun.COM /*
6088462SApril.Chin@Sun.COM  * set ${.sh.name} and ${.sh.subscript}
6098462SApril.Chin@Sun.COM  * set _ to reference for ${.sh.name}[$.sh.subscript]
6108462SApril.Chin@Sun.COM  */
6118462SApril.Chin@Sun.COM static int set_instance(Namval_t *nq, Namval_t *node, struct Namref *nr)
6128462SApril.Chin@Sun.COM {
613*10898Sroland.mainz@nrubsig.org 	char		*sp=0,*cp = nv_name(nq);
6148462SApril.Chin@Sun.COM 	Namarr_t	*ap;
6158462SApril.Chin@Sun.COM 	memset(nr,0,sizeof(*nr));
6168462SApril.Chin@Sun.COM 	nr->np = nq;
6178462SApril.Chin@Sun.COM 	nr->root = sh.var_tree;
6188462SApril.Chin@Sun.COM 	nr->table = sh.last_table;
619*10898Sroland.mainz@nrubsig.org 	if((ap=nv_arrayptr(nq)) && (sp = nv_getsub(nq)))
620*10898Sroland.mainz@nrubsig.org 		sp = strdup(sp);
6218462SApril.Chin@Sun.COM 	if(sh.var_tree!=sh.var_base && !nv_open(cp,nr->root,NV_VARNAME|NV_NOREF|NV_NOSCOPE|NV_NOADD|NV_NOFAIL))
6228462SApril.Chin@Sun.COM 		nr->root = sh.var_base;
6238462SApril.Chin@Sun.COM 	nv_putval(SH_NAMENOD, cp, NV_NOFREE);
6248462SApril.Chin@Sun.COM 	memcpy(node,L_ARGNOD,sizeof(*node));
6258462SApril.Chin@Sun.COM 	L_ARGNOD->nvalue.nrp = nr;
6268462SApril.Chin@Sun.COM 	L_ARGNOD->nvflag = NV_REF|NV_NOFREE;
6278462SApril.Chin@Sun.COM 	L_ARGNOD->nvfun = 0;
6288462SApril.Chin@Sun.COM 	L_ARGNOD->nvenv = 0;
629*10898Sroland.mainz@nrubsig.org 	if(sp)
6308462SApril.Chin@Sun.COM 	{
631*10898Sroland.mainz@nrubsig.org 		nv_putval(SH_SUBSCRNOD,nr->sub=sp,NV_NOFREE);
6328462SApril.Chin@Sun.COM 		return(ap->nelem&ARRAY_SCAN);
6338462SApril.Chin@Sun.COM 	}
6348462SApril.Chin@Sun.COM 	return(0);
6358462SApril.Chin@Sun.COM }
6368462SApril.Chin@Sun.COM 
6378462SApril.Chin@Sun.COM static void unset_instance(Namval_t *nq, Namval_t *node, struct Namref *nr,long mode)
6388462SApril.Chin@Sun.COM {
6398462SApril.Chin@Sun.COM 	L_ARGNOD->nvalue.nrp = node->nvalue.nrp;
6408462SApril.Chin@Sun.COM 	L_ARGNOD->nvflag = node->nvflag;
6418462SApril.Chin@Sun.COM 	L_ARGNOD->nvfun = node->nvfun;
6428462SApril.Chin@Sun.COM 	if(nr->sub)
6438462SApril.Chin@Sun.COM 	{
6448462SApril.Chin@Sun.COM 		nv_putsub(nq, nr->sub, mode);
6458462SApril.Chin@Sun.COM 		free((void*)nr->sub);
6468462SApril.Chin@Sun.COM 	}
6478462SApril.Chin@Sun.COM 	nv_unset(SH_NAMENOD);
6488462SApril.Chin@Sun.COM 	nv_unset(SH_SUBSCRNOD);
6498462SApril.Chin@Sun.COM }
6504887Schin 
6514887Schin int sh_exec(register const Shnode_t *t, int flags)
6524887Schin {
6538462SApril.Chin@Sun.COM 	register Shell_t	*shp = &sh;
6548462SApril.Chin@Sun.COM 	Stk_t			*stkp = shp->stk;
6554887Schin 	sh_sigcheck();
6568462SApril.Chin@Sun.COM 	if(t && !shp->st.execbrk && !sh_isoption(SH_NOEXEC))
6574887Schin 	{
6584887Schin 		register int 	type = flags;
6594887Schin 		register char	*com0 = 0;
6604887Schin 		int 		errorflg = (type&sh_state(SH_ERREXIT))|OPTIMIZE;
6614887Schin 		int 		execflg = (type&sh_state(SH_NOFORK));
662*10898Sroland.mainz@nrubsig.org 		int 		execflg2 = (type&sh_state(SH_FORKED));
6634887Schin 		int 		mainloop = (type&sh_state(SH_INTERACTIVE));
6648462SApril.Chin@Sun.COM #if SHOPT_AMP || SHOPT_SPAWN
6654887Schin 		int		ntflag = (type&sh_state(SH_NTFORK));
666*10898Sroland.mainz@nrubsig.org #else
667*10898Sroland.mainz@nrubsig.org 		int		ntflag = 0;
6684887Schin #endif
6698462SApril.Chin@Sun.COM 		int		topfd = shp->topfd;
6708462SApril.Chin@Sun.COM 		char 		*sav=stkptr(stkp,0);
6718462SApril.Chin@Sun.COM 		char		*cp=0, **com=0, *comn;
6724887Schin 		int		argn;
6734887Schin 		int 		skipexitset = 0;
6744887Schin 		int		was_interactive = 0;
6754887Schin 		int		was_errexit = sh_isstate(SH_ERREXIT);
6764887Schin 		int		was_monitor = sh_isstate(SH_MONITOR);
6774887Schin 		int		echeck = 0;
6784887Schin 		if(flags&sh_state(SH_INTERACTIVE))
6794887Schin 		{
680*10898Sroland.mainz@nrubsig.org 			if(pipejob==2)
681*10898Sroland.mainz@nrubsig.org 				job_unlock();
6824887Schin 			pipejob = 0;
6834887Schin 			job.curpgid = 0;
6844887Schin 			flags &= ~sh_state(SH_INTERACTIVE);
6854887Schin 		}
6864887Schin 		sh_offstate(SH_ERREXIT);
6874887Schin 		sh_offstate(SH_DEFPATH);
6884887Schin 		if(was_errexit&flags)
6894887Schin 			sh_onstate(SH_ERREXIT);
6904887Schin 		if(was_monitor&flags)
6914887Schin 			sh_onstate(SH_MONITOR);
6924887Schin 		type = t->tre.tretyp;
6938462SApril.Chin@Sun.COM 		if(!shp->intrap)
6948462SApril.Chin@Sun.COM 			shp->oldexit=shp->exitval;
6958462SApril.Chin@Sun.COM 		shp->exitval=0;
6968462SApril.Chin@Sun.COM 		shp->lastsig = 0;
6978462SApril.Chin@Sun.COM 		shp->lastpath = 0;
6984887Schin 		switch(type&COMMSK)
6994887Schin 		{
7004887Schin 		    case TCOM:
7014887Schin 		    {
7024887Schin 			register struct argnod	*argp;
7034887Schin 			char		*trap;
7044887Schin 			Namval_t	*np, *nq, *last_table;
7054887Schin 			struct ionod	*io;
7068462SApril.Chin@Sun.COM 			int		command=0, flgs=NV_ASSIGN;
7078462SApril.Chin@Sun.COM 			shp->bltindata.invariant = type>>(COMBITS+2);
7088462SApril.Chin@Sun.COM 			type &= (COMMSK|COMSCAN);
7098462SApril.Chin@Sun.COM 			sh_stats(STAT_SCMDS);
7108462SApril.Chin@Sun.COM 			error_info.line = t->com.comline-shp->st.firstline;
7118462SApril.Chin@Sun.COM 			com = sh_argbuild(shp,&argn,&(t->com),OPTIMIZE);
7124887Schin 			echeck = 1;
7134887Schin 			if(t->tre.tretyp&COMSCAN)
7144887Schin 			{
7154887Schin 				argp = t->com.comarg;
7164887Schin 				if(argp && *com && !(argp->argflag&ARG_RAW))
7174887Schin 					sh_sigcheck();
7184887Schin 			}
7194887Schin 			np = (Namval_t*)(t->com.comnamp);
7204887Schin 			nq = (Namval_t*)(t->com.comnamq);
7214887Schin 			com0 = com[0];
7228462SApril.Chin@Sun.COM 			shp->xargexit = 0;
7234887Schin 			while(np==SYSCOMMAND)
7244887Schin 			{
7258462SApril.Chin@Sun.COM 				register int n = b_command(0,com,&shp->bltindata);
7264887Schin 				if(n==0)
7274887Schin 					break;
7284887Schin 				command += n;
7294887Schin 				np = 0;
7304887Schin 				if(!(com0= *(com+=n)))
7314887Schin 					break;
7328462SApril.Chin@Sun.COM 				np = nv_bfsearch(com0, shp->bltin_tree, &nq, &cp);
7334887Schin 			}
7348462SApril.Chin@Sun.COM 			if(shp->xargexit)
7354887Schin 			{
7368462SApril.Chin@Sun.COM 				shp->xargmin -= command;
7378462SApril.Chin@Sun.COM 				shp->xargmax -= command;
7384887Schin 			}
7394887Schin 			else
7408462SApril.Chin@Sun.COM 				shp->xargmin = 0;
7414887Schin 			argn -= command;
7424887Schin 			if(!command && np && is_abuiltin(np))
7438462SApril.Chin@Sun.COM 				np = dtsearch(shp->fun_tree,np);
7448462SApril.Chin@Sun.COM 			if(com0)
7454887Schin 			{
7468462SApril.Chin@Sun.COM 				if(!np && !strchr(com0,'/'))
7474887Schin 				{
7488462SApril.Chin@Sun.COM 					Dt_t *root = command?shp->bltin_tree:shp->fun_tree;
7498462SApril.Chin@Sun.COM 					np = nv_bfsearch(com0, root, &nq, &cp);
7508462SApril.Chin@Sun.COM #if SHOPT_NAMESPACE
7518462SApril.Chin@Sun.COM 					if(shp->namespace && !nq && !cp)
7528462SApril.Chin@Sun.COM 					{
7538462SApril.Chin@Sun.COM 						int offset = stktell(stkp);
7548462SApril.Chin@Sun.COM 						sfputr(stkp,nv_name(shp->namespace),-1);
7558462SApril.Chin@Sun.COM 						sfputc(stkp,'.');
7568462SApril.Chin@Sun.COM 						sfputr(stkp,com0,0);
7578462SApril.Chin@Sun.COM 						stkseek(stkp,offset);
7588462SApril.Chin@Sun.COM 						np = nv_bfsearch(stkptr(stkp,offset), root, &nq, &cp);
7598462SApril.Chin@Sun.COM 					}
7608462SApril.Chin@Sun.COM #endif /* SHOPT_NAMESPACE */
7614887Schin 				}
7628462SApril.Chin@Sun.COM 				comn = com[argn-1];
7634887Schin 			}
7644887Schin 			io = t->tre.treio;
7658462SApril.Chin@Sun.COM 			if(shp->envlist = argp = t->com.comset)
7664887Schin 			{
7678462SApril.Chin@Sun.COM 				if(argn==0 || (np && nv_isattr(np,BLT_SPC)))
7684887Schin 				{
769*10898Sroland.mainz@nrubsig.org 					Namval_t *tp=0;
7708462SApril.Chin@Sun.COM 					if(argn)
7718462SApril.Chin@Sun.COM 					{
7728462SApril.Chin@Sun.COM 						if(checkopt(com,'A'))
7738462SApril.Chin@Sun.COM 							flgs |= NV_ARRAY;
7748462SApril.Chin@Sun.COM 						else if(checkopt(com,'a'))
7758462SApril.Chin@Sun.COM 							flgs |= NV_IARRAY;
7768462SApril.Chin@Sun.COM 					}
7774887Schin #if SHOPT_BASH
7784887Schin 					if(np==SYSLOCAL)
7794887Schin 					{
7804887Schin 						if(!nv_getval(SH_FUNNAMENOD))
7814887Schin 							errormsg(SH_DICT,ERROR_exit(1),"%s: can only be used in a function",com0);
7828462SApril.Chin@Sun.COM 						if(!shp->st.var_local)
7834887Schin 						{
7848462SApril.Chin@Sun.COM 							sh_scope(shp,(struct argnod*)0,0);
7858462SApril.Chin@Sun.COM 							shp->st.var_local = shp->var_tree;
7864887Schin 						}
7874887Schin 
7884887Schin 					}
7894887Schin 					if(np==SYSTYPESET || np==SYSLOCAL)
7904887Schin #else
7918462SApril.Chin@Sun.COM 					if(np==SYSTYPESET ||  (np && np->nvalue.bfp==SYSTYPESET->nvalue.bfp))
7924887Schin #endif
7934887Schin 					{
7948462SApril.Chin@Sun.COM 						if(np!=SYSTYPESET)
795*10898Sroland.mainz@nrubsig.org 						{
7968462SApril.Chin@Sun.COM 							shp->typeinit = np;
797*10898Sroland.mainz@nrubsig.org 							tp = nv_type(np);
798*10898Sroland.mainz@nrubsig.org 						}
7998462SApril.Chin@Sun.COM 						if(checkopt(com,'C'))
8008462SApril.Chin@Sun.COM 							flgs |= NV_COMVAR;
8018462SApril.Chin@Sun.COM 						if(checkopt(com,'S'))
8028462SApril.Chin@Sun.COM 							flgs |= NV_STATIC;
8034887Schin 						if(checkopt(com,'n'))
8044887Schin 							flgs |= NV_NOREF;
805*10898Sroland.mainz@nrubsig.org 						else if(!shp->typeinit && (checkopt(com,'L') || checkopt(com,'R') || checkopt(com,'Z')))
806*10898Sroland.mainz@nrubsig.org 							flgs |= NV_UNJUST;
8074887Schin #if SHOPT_TYPEDEF
8088462SApril.Chin@Sun.COM 						else if(argn>=3 && checkopt(com,'T'))
8094887Schin 						{
8108462SApril.Chin@Sun.COM 							shp->prefix = NV_CLASS;
8114887Schin 							flgs |= NV_TYPE;
8124887Schin 
8134887Schin 						}
8144887Schin #endif /* SHOPT_TYPEDEF */
8158462SApril.Chin@Sun.COM 						if((shp->fn_depth && !shp->prefix) || np==SYSLOCAL)
8164887Schin 							flgs |= NV_NOSCOPE;
8174887Schin 					}
8184887Schin 					else if(np==SYSEXPORT)
8194887Schin 						flgs |= NV_EXPORT;
8208462SApril.Chin@Sun.COM 					if(flgs&(NV_EXPORT|NV_NOREF))
8218462SApril.Chin@Sun.COM 						flgs |= NV_IDENT;
8228462SApril.Chin@Sun.COM 					else
8238462SApril.Chin@Sun.COM 						flgs |= NV_VARNAME;
8244887Schin #if 0
8254887Schin 					if(OPTIMIZE)
8264887Schin 						flgs |= NV_TAGGED;
8274887Schin #endif
828*10898Sroland.mainz@nrubsig.org 					nv_setlist(argp,flgs,tp);
8298462SApril.Chin@Sun.COM 					if(np==shp->typeinit)
8308462SApril.Chin@Sun.COM 						shp->typeinit = 0;
8318462SApril.Chin@Sun.COM 					shp->envlist = argp;
8324887Schin 					argp = NULL;
8334887Schin 				}
8344887Schin 			}
8358462SApril.Chin@Sun.COM 			last_table = shp->last_table;
8368462SApril.Chin@Sun.COM 			shp->last_table = 0;
8374887Schin 			if((io||argn))
8384887Schin 			{
8398462SApril.Chin@Sun.COM 				Shbltin_t *bp=0;
8404887Schin 				static char *argv[1];
8418462SApril.Chin@Sun.COM 				int tflags = 1;
8428462SApril.Chin@Sun.COM 				if(np &&  nv_isattr(np,BLT_DCL))
8438462SApril.Chin@Sun.COM 					tflags |= 2;
8444887Schin 				if(argn==0)
8454887Schin 				{
8464887Schin 					/* fake 'true' built-in */
8474887Schin 					np = SYSTRUE;
8484887Schin 					*argv = nv_name(np);
8494887Schin 					com = argv;
8504887Schin 				}
8514887Schin 				/* set +x doesn't echo */
8524887Schin 				else if((np!=SYSSET) && sh_isoption(SH_XTRACE))
8538462SApril.Chin@Sun.COM 					sh_trace(com-command,tflags);
8544887Schin 				else if((t->tre.tretyp&FSHOWME) && sh_isoption(SH_SHOWME))
8554887Schin 				{
8564887Schin 					int ison = sh_isoption(SH_XTRACE);
8574887Schin 					if(!ison)
8584887Schin 						sh_onoption(SH_XTRACE);
8598462SApril.Chin@Sun.COM 					sh_trace(com-command,tflags);
8604887Schin 					if(io)
8618462SApril.Chin@Sun.COM 						sh_redirect(shp,io,SH_SHOWME);
8624887Schin 					if(!ison)
8634887Schin 						sh_offoption(SH_XTRACE);
8644887Schin 					break;
8654887Schin 				}
8668462SApril.Chin@Sun.COM 				if(trap=shp->st.trap[SH_DEBUGTRAP])
8678462SApril.Chin@Sun.COM 				{
8688462SApril.Chin@Sun.COM 					int n = sh_debug(shp,trap,(char*)0,(char*)0, com, ARG_RAW);
8698462SApril.Chin@Sun.COM 					if(n==255 && shp->fn_depth+shp->dot_depth)
8708462SApril.Chin@Sun.COM 					{
8718462SApril.Chin@Sun.COM 						np = SYSRETURN;
8728462SApril.Chin@Sun.COM 						argn = 1;
8738462SApril.Chin@Sun.COM 						com[0] = np->nvname;
8748462SApril.Chin@Sun.COM 						com[1] = 0;
8758462SApril.Chin@Sun.COM 						io = 0;
8768462SApril.Chin@Sun.COM 						argp = 0;
8778462SApril.Chin@Sun.COM 					}
8788462SApril.Chin@Sun.COM 					else if(n==2)
8798462SApril.Chin@Sun.COM 						break;
8808462SApril.Chin@Sun.COM 				}
8814887Schin 				if(io)
8828462SApril.Chin@Sun.COM 					sfsync(shp->outpool);
8838462SApril.Chin@Sun.COM 				shp->lastpath = 0;
8844887Schin 				if(!np  && !strchr(com0,'/'))
8854887Schin 				{
8868462SApril.Chin@Sun.COM 					if(path_search(com0,NIL(Pathcomp_t**),1))
8878462SApril.Chin@Sun.COM 					{
8888462SApril.Chin@Sun.COM 						error_info.line = t->com.comline-shp->st.firstline;
8898462SApril.Chin@Sun.COM 						if((np=nv_search(com0,shp->fun_tree,0)) && !np->nvalue.ip)
8908462SApril.Chin@Sun.COM 						{
8918462SApril.Chin@Sun.COM 							Namval_t *mp=nv_search(com0,shp->bltin_tree,0);
8928462SApril.Chin@Sun.COM 							if(mp)
8938462SApril.Chin@Sun.COM 								np = mp;
8948462SApril.Chin@Sun.COM 						}
8958462SApril.Chin@Sun.COM 					}
8964887Schin 					else
8974887Schin 					{
8988462SApril.Chin@Sun.COM 						if((np=nv_search(com0,shp->track_tree,0)) && !nv_isattr(np,NV_NOALIAS) && np->nvalue.cp)
8998462SApril.Chin@Sun.COM 							np=nv_search(nv_getval(np),shp->bltin_tree,0);
9004887Schin 						else
9014887Schin 							np = 0;
9024887Schin 					}
9034887Schin 				}
904*10898Sroland.mainz@nrubsig.org 				if(np && pipejob==2)
905*10898Sroland.mainz@nrubsig.org 				{
906*10898Sroland.mainz@nrubsig.org 					job_unlock();
907*10898Sroland.mainz@nrubsig.org 					pipejob = 1;
908*10898Sroland.mainz@nrubsig.org 				}
9094887Schin 				/* check for builtins */
9104887Schin 				if(np && is_abuiltin(np))
9114887Schin 				{
9128462SApril.Chin@Sun.COM 					volatile int scope=0, share=0;
9138462SApril.Chin@Sun.COM 					volatile void *save_ptr;
9148462SApril.Chin@Sun.COM 					volatile void *save_data;
9158462SApril.Chin@Sun.COM 					int jmpval, save_prompt;
916*10898Sroland.mainz@nrubsig.org 					int was_nofork = execflg?sh_isstate(SH_NOFORK):0;
9174887Schin 					struct checkpt buff;
9184887Schin 					unsigned long was_vi=0, was_emacs=0, was_gmacs=0;
9194887Schin 					struct stat statb;
9208462SApril.Chin@Sun.COM 					bp = &shp->bltindata;
9218462SApril.Chin@Sun.COM 					save_ptr = bp->ptr;
9228462SApril.Chin@Sun.COM 					save_data = bp->data;
9238462SApril.Chin@Sun.COM 					memset(&statb, 0, sizeof(struct stat));
9244887Schin 					if(strchr(nv_name(np),'/'))
9254887Schin 					{
9264887Schin 						/*
9274887Schin 						 * disable editors for built-in
9284887Schin 						 * versions of commands on PATH
9294887Schin 						 */
9304887Schin 						was_vi = sh_isoption(SH_VI);
9314887Schin 						was_emacs = sh_isoption(SH_EMACS);
9324887Schin 						was_gmacs = sh_isoption(SH_GMACS);
9334887Schin 						sh_offoption(SH_VI);
9344887Schin 						sh_offoption(SH_EMACS);
9354887Schin 						sh_offoption(SH_GMACS);
9364887Schin 					}
937*10898Sroland.mainz@nrubsig.org 					if(execflg)
938*10898Sroland.mainz@nrubsig.org 						sh_onstate(SH_NOFORK);
9394887Schin 					sh_pushcontext(&buff,SH_JMPCMD);
9404887Schin 					jmpval = sigsetjmp(buff.buff,1);
9414887Schin 					if(jmpval == 0)
9424887Schin 					{
9434887Schin 						if(!(nv_isattr(np,BLT_ENV)))
9444887Schin 							error_info.flags |= ERROR_SILENT;
9454887Schin 						errorpush(&buff.err,0);
9464887Schin 						if(io)
9474887Schin 						{
9484887Schin 							struct openlist *item;
9494887Schin 							if(np==SYSLOGIN)
9504887Schin 								type=1;
9514887Schin 							else if(np==SYSEXEC)
9524887Schin 								type=1+!com[1];
9534887Schin 							else
9548462SApril.Chin@Sun.COM 								type = (execflg && !shp->subshell && !shp->st.trapcom[0]);
9558462SApril.Chin@Sun.COM 							sh_redirect(shp,io,type);
9564887Schin 							for(item=buff.olist;item;item=item->next)
9574887Schin 								item->strm=0;
9584887Schin 						}
9594887Schin 						if(!(nv_isattr(np,BLT_ENV)))
9604887Schin 						{
9618462SApril.Chin@Sun.COM 							if(bp->nosfio)
9628462SApril.Chin@Sun.COM 							{
9638462SApril.Chin@Sun.COM 								if(!shp->pwd)
9648462SApril.Chin@Sun.COM 									path_pwd(0);
9658462SApril.Chin@Sun.COM 								if(shp->pwd)
9668462SApril.Chin@Sun.COM 									stat(".",&statb);
9678462SApril.Chin@Sun.COM 							}
9688462SApril.Chin@Sun.COM 							sfsync(NULL);
9694887Schin 							share = sfset(sfstdin,SF_SHARE,0);
9704887Schin 							sh_onstate(SH_STOPOK);
9714887Schin 							sfpool(sfstderr,NIL(Sfio_t*),SF_WRITE);
9724887Schin 							sfset(sfstderr,SF_LINE,1);
9738462SApril.Chin@Sun.COM 							save_prompt = shp->nextprompt;
9748462SApril.Chin@Sun.COM 							shp->nextprompt = 0;
9754887Schin 						}
9764887Schin 						if(argp)
9774887Schin 						{
9784887Schin 							scope++;
9798462SApril.Chin@Sun.COM 							sh_scope(shp,argp,0);
9804887Schin 						}
9814887Schin 						opt_info.index = opt_info.offset = 0;
9824887Schin 						opt_info.disc = 0;
9834887Schin 						error_info.id = *com;
9848462SApril.Chin@Sun.COM 						if(argn)
9858462SApril.Chin@Sun.COM 							shp->exitval = 0;
9868462SApril.Chin@Sun.COM 						shp->bltinfun = funptr(np);
9878462SApril.Chin@Sun.COM 						bp->bnode = np;
9888462SApril.Chin@Sun.COM 						bp->vnode = nq;
9898462SApril.Chin@Sun.COM 						bp->ptr = nv_context(np);
9908462SApril.Chin@Sun.COM 						bp->data = t->com.comstate;
9918462SApril.Chin@Sun.COM 						bp->sigset = 0;
9928462SApril.Chin@Sun.COM 						bp->notify = 0;
9938462SApril.Chin@Sun.COM 						bp->flags = (OPTIMIZE!=0);
9948462SApril.Chin@Sun.COM 						if(shp->subshell && nv_isattr(np,BLT_NOSFIO))
9958462SApril.Chin@Sun.COM 							sh_subtmpfile(0);
9968462SApril.Chin@Sun.COM 						if(execflg && !shp->subshell &&
9978462SApril.Chin@Sun.COM 							!shp->st.trapcom[0] && !shp->st.trap[SH_ERRTRAP] && shp->fn_depth==0 && !nv_isattr(np,BLT_ENV))
9984887Schin 						{
9994887Schin 							/* do close-on-exec */
10004887Schin 							int fd;
10018462SApril.Chin@Sun.COM 							for(fd=0; fd < shp->lim.open_max; fd++)
10028462SApril.Chin@Sun.COM 								if((shp->fdstatus[fd]&IOCLEX)&&fd!=shp->infd)
10034887Schin 									sh_close(fd);
10044887Schin 						}
10058462SApril.Chin@Sun.COM 						if(argn)
10068462SApril.Chin@Sun.COM 							shp->exitval = (*shp->bltinfun)(argn,com,(void*)bp);
10074887Schin 						if(error_info.flags&ERROR_INTERACTIVE)
10084887Schin 							tty_check(ERRIO);
10098462SApril.Chin@Sun.COM 						((Shnode_t*)t)->com.comstate = shp->bltindata.data;
10108462SApril.Chin@Sun.COM 						bp->data = (void*)save_data;
10118462SApril.Chin@Sun.COM 						if(!nv_isattr(np,BLT_EXIT) && shp->exitval!=SH_RUNPROG)
10128462SApril.Chin@Sun.COM 							shp->exitval &= SH_EXITMASK;
10134887Schin 					}
10144887Schin 					else
10154887Schin 					{
10164887Schin 						struct openlist *item;
10174887Schin 						for(item=buff.olist;item;item=item->next)
10184887Schin 						{
10194887Schin 							if(item->strm)
10204887Schin 							{
10214887Schin 								sfclrlock(item->strm);
10228462SApril.Chin@Sun.COM 								if(shp->hist_ptr && item->strm == shp->hist_ptr->histfp)
10238462SApril.Chin@Sun.COM 									hist_close(shp->hist_ptr);
10244887Schin 								else
10254887Schin 									sfclose(item->strm);
10264887Schin 							}
10274887Schin 						}
10288462SApril.Chin@Sun.COM 						if(shp->bltinfun && (error_info.flags&ERROR_NOTIFY))
10298462SApril.Chin@Sun.COM 							(*shp->bltinfun)(-2,com,(void*)bp);
10304887Schin 						/* failure on special built-ins fatal */
10314887Schin 						if(jmpval<=SH_JMPCMD  && (!nv_isattr(np,BLT_SPC) || command))
10324887Schin 							jmpval=0;
10334887Schin 					}
10348462SApril.Chin@Sun.COM 					if(bp && bp->ptr!= nv_context(np))
10358462SApril.Chin@Sun.COM 						np->nvfun = (Namfun_t*)bp->ptr;
1036*10898Sroland.mainz@nrubsig.org 					if(execflg && !was_nofork)
1037*10898Sroland.mainz@nrubsig.org 						sh_offstate(SH_NOFORK);
10384887Schin 					if(!(nv_isattr(np,BLT_ENV)))
10394887Schin 					{
10408462SApril.Chin@Sun.COM 						if(bp->nosfio && shp->pwd)
10414887Schin 						{
10424887Schin 							struct stat stata;
10434887Schin 							stat(".",&stata);
10444887Schin 							/* restore directory changed */
10454887Schin 							if(statb.st_ino!=stata.st_ino || statb.st_dev!=stata.st_dev)
10468462SApril.Chin@Sun.COM 								chdir(shp->pwd);
10474887Schin 						}
10484887Schin 						sh_offstate(SH_STOPOK);
10494887Schin 						if(share&SF_SHARE)
10504887Schin 							sfset(sfstdin,SF_PUBLIC|SF_SHARE,1);
10514887Schin 						sfset(sfstderr,SF_LINE,0);
10528462SApril.Chin@Sun.COM 						sfpool(sfstderr,shp->outpool,SF_WRITE);
10534887Schin 						sfpool(sfstdin,NIL(Sfio_t*),SF_WRITE);
10548462SApril.Chin@Sun.COM 						shp->nextprompt = save_prompt;
10554887Schin 					}
10564887Schin 					sh_popcontext(&buff);
10574887Schin 					errorpop(&buff.err);
1058*10898Sroland.mainz@nrubsig.org 					error_info.flags &= ~(ERROR_SILENT|ERROR_NOTIFY);
10598462SApril.Chin@Sun.COM 					shp->bltinfun = 0;
10604887Schin 					if(buff.olist)
10614887Schin 						free_list(buff.olist);
10624887Schin 					if(was_vi)
10634887Schin 						sh_onoption(SH_VI);
10644887Schin 					else if(was_emacs)
10654887Schin 						sh_onoption(SH_EMACS);
10664887Schin 					else if(was_gmacs)
10674887Schin 						sh_onoption(SH_GMACS);
10684887Schin 					if(scope)
10698462SApril.Chin@Sun.COM 						sh_unscope(shp);
10708462SApril.Chin@Sun.COM 					bp->ptr = (void*)save_ptr;
10718462SApril.Chin@Sun.COM 					bp->data = (void*)save_data;
10724887Schin 					/* don't restore for subshell exec */
10738462SApril.Chin@Sun.COM 					if((shp->topfd>topfd) && !(shp->subshell && np==SYSEXEC))
10748462SApril.Chin@Sun.COM 						sh_iorestore(shp,topfd,jmpval);
10754887Schin 					if(jmpval)
10768462SApril.Chin@Sun.COM 						siglongjmp(*shp->jmplist,jmpval);
10778462SApril.Chin@Sun.COM #if 0
10788462SApril.Chin@Sun.COM 					if(flgs&NV_STATIC)
10798462SApril.Chin@Sun.COM 						((Shnode_t*)t)->com.comset = 0;
10808462SApril.Chin@Sun.COM #endif
10818462SApril.Chin@Sun.COM 					if(shp->exitval >=0)
10824887Schin 						goto setexit;
10834887Schin 					np = 0;
10844887Schin 					type=0;
10854887Schin 				}
10864887Schin 				/* check for functions */
10874887Schin 				if(!command && np && nv_isattr(np,NV_FUNCTION))
10884887Schin 				{
10898462SApril.Chin@Sun.COM 					volatile int indx;
10908462SApril.Chin@Sun.COM 					int jmpval=0;
10914887Schin 					struct checkpt buff;
10924887Schin 					Namval_t node;
10938462SApril.Chin@Sun.COM 					struct Namref	nr;
10948462SApril.Chin@Sun.COM 					long		mode;
10954887Schin 					register struct slnod *slp;
10964887Schin 					if(!np->nvalue.ip)
10974887Schin 					{
10988462SApril.Chin@Sun.COM 						indx = path_search(com0,NIL(Pathcomp_t**),0);
10994887Schin 						if(indx==1)
11008462SApril.Chin@Sun.COM 							np = nv_search(com0,shp->fun_tree,HASH_NOSCOPE);
11018462SApril.Chin@Sun.COM 
11024887Schin 						if(!np->nvalue.ip)
11034887Schin 						{
11044887Schin 							if(indx==1)
11054887Schin 							{
11064887Schin 								errormsg(SH_DICT,ERROR_exit(0),e_defined,com0);
11078462SApril.Chin@Sun.COM 								shp->exitval = ERROR_NOEXEC;
11084887Schin 							}
11094887Schin 							else
11104887Schin 							{
11114887Schin 								errormsg(SH_DICT,ERROR_exit(0),e_found,"function");
11128462SApril.Chin@Sun.COM 								shp->exitval = ERROR_NOENT;
11134887Schin 							}
11144887Schin 							goto setexit;
11154887Schin 						}
11164887Schin 					}
11174887Schin 					/* increase refcnt for unset */
11184887Schin 					slp = (struct slnod*)np->nvenv;
11194887Schin 					sh_funstaks(slp->slchild,1);
11204887Schin 					staklink(slp->slptr);
11214887Schin 					if(nq)
11224887Schin 					{
11238462SApril.Chin@Sun.COM 						shp->last_table = last_table;
11248462SApril.Chin@Sun.COM 						mode = set_instance(nq,&node,&nr);
11254887Schin 					}
11264887Schin 					if(io)
11274887Schin 					{
11288462SApril.Chin@Sun.COM 						indx = shp->topfd;
11294887Schin 						sh_pushcontext(&buff,SH_JMPCMD);
11304887Schin 						jmpval = sigsetjmp(buff.buff,0);
11314887Schin 					}
11324887Schin 					if(jmpval == 0)
11334887Schin 					{
11344887Schin 						if(io)
11358462SApril.Chin@Sun.COM 							indx = sh_redirect(shp,io,execflg);
11368462SApril.Chin@Sun.COM 						sh_funct(shp,np,argn,com,t->com.comset,(flags&~OPTIMIZE_FLAG));
11374887Schin 					}
11384887Schin 					if(io)
11394887Schin 					{
11404887Schin 						if(buff.olist)
11414887Schin 							free_list(buff.olist);
11424887Schin 						sh_popcontext(&buff);
11438462SApril.Chin@Sun.COM 						sh_iorestore(shp,indx,jmpval);
11444887Schin 					}
11454887Schin 					if(nq)
11468462SApril.Chin@Sun.COM 						unset_instance(nq,&node,&nr,mode);
11474887Schin 					sh_funstaks(slp->slchild,-1);
11484887Schin 					stakdelete(slp->slptr);
11494887Schin 					if(jmpval > SH_JMPFUN)
11508462SApril.Chin@Sun.COM 						siglongjmp(*shp->jmplist,jmpval);
11514887Schin 					goto setexit;
11524887Schin 				}
11534887Schin 			}
11544887Schin 			else if(!io)
11554887Schin 			{
11564887Schin 			setexit:
11574887Schin 				exitset();
11584887Schin 				break;
11594887Schin 			}
11604887Schin 		    }
11614887Schin 		    case TFORK:
11624887Schin 		    {
11634887Schin 			register pid_t parent;
11644887Schin 			int no_fork,jobid;
11654887Schin 			int pipes[2];
11668462SApril.Chin@Sun.COM 			if(shp->subshell)
1167*10898Sroland.mainz@nrubsig.org 			{
1168*10898Sroland.mainz@nrubsig.org 				if(shp->subshare)
1169*10898Sroland.mainz@nrubsig.org 					sh_subtmpfile(1);
1170*10898Sroland.mainz@nrubsig.org 				else
1171*10898Sroland.mainz@nrubsig.org 					sh_subfork();
1172*10898Sroland.mainz@nrubsig.org 			}
1173*10898Sroland.mainz@nrubsig.org 			no_fork = !ntflag && !(type&(FAMP|FPOU)) &&
1174*10898Sroland.mainz@nrubsig.org 			    !shp->st.trapcom[0] && !shp->st.trap[SH_ERRTRAP] &&
1175*10898Sroland.mainz@nrubsig.org 				(execflg2 || (execflg &&
1176*10898Sroland.mainz@nrubsig.org 				!shp->subshell && shp->fn_depth==0 &&
1177*10898Sroland.mainz@nrubsig.org 				!(pipejob && sh_isoption(SH_PIPEFAIL))
1178*10898Sroland.mainz@nrubsig.org 			    ));
11798462SApril.Chin@Sun.COM 			if(sh_isstate(SH_PROFILE) || shp->dot_depth)
11804887Schin 			{
11814887Schin 				/* disable foreground job monitor */
11824887Schin 				if(!(type&FAMP))
11834887Schin 					sh_offstate(SH_MONITOR);
11844887Schin #if SHOPT_DEVFD
11854887Schin 				else if(!(type&FINT))
11864887Schin 					sh_offstate(SH_MONITOR);
11874887Schin #endif /* SHOPT_DEVFD */
11884887Schin 			}
11894887Schin 			if(no_fork)
11904887Schin 				job.parent=parent=0;
11914887Schin 			else
11924887Schin 			{
1193*10898Sroland.mainz@nrubsig.org #ifdef SHOPT_BGX
1194*10898Sroland.mainz@nrubsig.org 				int maxjob;
1195*10898Sroland.mainz@nrubsig.org 				if(((type&(FAMP|FINT)) == (FAMP|FINT)) && (maxjob=nv_getnum(JOBMAXNOD))>0)
1196*10898Sroland.mainz@nrubsig.org 				{
1197*10898Sroland.mainz@nrubsig.org 					while(job.numbjob >= maxjob)
1198*10898Sroland.mainz@nrubsig.org 					{
1199*10898Sroland.mainz@nrubsig.org 						job_lock();
1200*10898Sroland.mainz@nrubsig.org 						job_reap(0);
1201*10898Sroland.mainz@nrubsig.org 						job_unlock();
1202*10898Sroland.mainz@nrubsig.org 					}
1203*10898Sroland.mainz@nrubsig.org 				}
1204*10898Sroland.mainz@nrubsig.org #endif /* SHOPT_BGX */
12054887Schin 				if(type&FCOOP)
12068462SApril.Chin@Sun.COM 					coproc_init(shp,pipes);
12074887Schin 				nv_getval(RANDNOD);
12084887Schin #if SHOPT_AMP
12094887Schin 				if((type&(FAMP|FINT)) == (FAMP|FINT))
12108462SApril.Chin@Sun.COM 					parent = sh_ntfork(shp,t,com,&jobid,ntflag);
12114887Schin 				else
12124887Schin 					parent = sh_fork(type,&jobid);
12134887Schin 				if(parent<0)
12144887Schin 					break;
12154887Schin #else
12164887Schin #if SHOPT_SPAWN
12174887Schin #   ifdef _lib_fork
12184887Schin 				if(com)
12198462SApril.Chin@Sun.COM 					parent = sh_ntfork(shp,t,com,&jobid,ntflag);
12204887Schin 				else
12214887Schin 					parent = sh_fork(type,&jobid);
12224887Schin #   else
12238462SApril.Chin@Sun.COM 				if((parent = sh_ntfork(shp,t,com,&jobid,ntflag))<=0)
12244887Schin 					break;
12254887Schin #   endif /* _lib_fork */
12264887Schin 				if(parent<0)
12274887Schin 					break;
12284887Schin #else
12294887Schin 				parent = sh_fork(type,&jobid);
12304887Schin #endif /* SHOPT_SPAWN */
12314887Schin #endif
12324887Schin 			}
12334887Schin 			if(job.parent=parent)
12344887Schin 			/* This is the parent branch of fork
12354887Schin 			 * It may or may not wait for the child
12364887Schin 			 */
12374887Schin 			{
1238*10898Sroland.mainz@nrubsig.org 				if(pipejob==2)
1239*10898Sroland.mainz@nrubsig.org 				{
1240*10898Sroland.mainz@nrubsig.org 					pipejob = 1;
1241*10898Sroland.mainz@nrubsig.org 					job_unlock();
1242*10898Sroland.mainz@nrubsig.org 				}
12434887Schin 				if(type&FPCL)
12448462SApril.Chin@Sun.COM 					sh_close(shp->inpipe[0]);
12454887Schin 				if(type&(FCOOP|FAMP))
12468462SApril.Chin@Sun.COM 					shp->bckpid = parent;
12478462SApril.Chin@Sun.COM 				else if(!(type&(FAMP|FPOU)))
12484887Schin 				{
12498462SApril.Chin@Sun.COM 					if(shp->topfd > topfd)
12508462SApril.Chin@Sun.COM 						sh_iorestore(shp,topfd,0);
12518462SApril.Chin@Sun.COM 					if(!sh_isoption(SH_MONITOR))
12528462SApril.Chin@Sun.COM 					{
12538462SApril.Chin@Sun.COM 						if(!(shp->sigflag[SIGINT]&(SH_SIGFAULT|SH_SIGOFF)))
12548462SApril.Chin@Sun.COM 							sh_sigtrap(SIGINT);
12558462SApril.Chin@Sun.COM 						shp->trapnote |= SH_SIGIGNORE;
12568462SApril.Chin@Sun.COM 					}
1257*10898Sroland.mainz@nrubsig.org 					if(execflg && shp->subshell && !shp->subshare)
12588462SApril.Chin@Sun.COM 					{
12598462SApril.Chin@Sun.COM 						shp->spid = parent;
12608462SApril.Chin@Sun.COM 						job.pwlist->p_env--;
12618462SApril.Chin@Sun.COM 					}
1262*10898Sroland.mainz@nrubsig.org 					else if(shp->pipepid)
1263*10898Sroland.mainz@nrubsig.org 						shp->pipepid = parent;
12648462SApril.Chin@Sun.COM 					else
12658462SApril.Chin@Sun.COM 						job_wait(parent);
12668462SApril.Chin@Sun.COM 					if(!sh_isoption(SH_MONITOR))
12678462SApril.Chin@Sun.COM 					{
12688462SApril.Chin@Sun.COM 						shp->trapnote &= ~SH_SIGIGNORE;
12698462SApril.Chin@Sun.COM 						if(shp->exitval == (SH_EXITSIG|SIGINT))
12708462SApril.Chin@Sun.COM 							sh_fault(SIGINT);
12718462SApril.Chin@Sun.COM 					}
12724887Schin 				}
12734887Schin 				if(type&FAMP)
12744887Schin 				{
12754887Schin 					if(sh_isstate(SH_PROFILE) || sh_isstate(SH_INTERACTIVE))
12764887Schin 					{
12774887Schin 						/* print job number */
12784887Schin #ifdef JOBS
12794887Schin 						sfprintf(sfstderr,"[%d]\t%d\n",jobid,parent);
12804887Schin #else
12814887Schin 						sfprintf(sfstderr,"%d\n",parent);
12824887Schin #endif /* JOBS */
12834887Schin 					}
12844887Schin 				}
12854887Schin 				break;
12864887Schin 			}
12874887Schin 			else
12884887Schin 			/*
12894887Schin 			 * this is the FORKED branch (child) of execute
12904887Schin 			 */
12914887Schin 			{
12928462SApril.Chin@Sun.COM 				volatile int jmpval;
12934887Schin 				struct checkpt buff;
12944887Schin 				if(no_fork)
12954887Schin 					sh_sigreset(2);
12964887Schin 				sh_pushcontext(&buff,SH_JMPEXIT);
12974887Schin 				jmpval = sigsetjmp(buff.buff,0);
12984887Schin 				if(jmpval)
12994887Schin 					goto done;
13004887Schin 				if((type&FINT) && !sh_isstate(SH_MONITOR))
13014887Schin 				{
13024887Schin 					/* default std input for & */
13034887Schin 					signal(SIGINT,SIG_IGN);
13044887Schin 					signal(SIGQUIT,SIG_IGN);
13058462SApril.Chin@Sun.COM 					if(!shp->st.ioset)
13064887Schin 					{
13074887Schin 						if(sh_close(0)>=0)
13084887Schin 							sh_chkopen(e_devnull);
13094887Schin 					}
13104887Schin 				}
13114887Schin 				sh_offstate(SH_MONITOR);
13124887Schin 				/* pipe in or out */
13134887Schin #ifdef _lib_nice
13144887Schin 				if((type&FAMP) && sh_isoption(SH_BGNICE))
13154887Schin 					nice(4);
13164887Schin #endif /* _lib_nice */
13174887Schin 				if(type&FPIN)
13184887Schin 				{
13198462SApril.Chin@Sun.COM 					sh_iorenumber(shp,shp->inpipe[0],0);
13204887Schin 					if(!(type&FPOU) || (type&FCOOP))
13218462SApril.Chin@Sun.COM 						sh_close(shp->inpipe[1]);
13224887Schin 				}
13234887Schin 				if(type&FPOU)
13244887Schin 				{
13258462SApril.Chin@Sun.COM 					sh_iorenumber(shp,shp->outpipe[1],1);
13268462SApril.Chin@Sun.COM 					sh_pclose(shp->outpipe);
13274887Schin 				}
13284887Schin 				if((type&COMMSK)!=TCOM)
13298462SApril.Chin@Sun.COM 					error_info.line = t->fork.forkline-shp->st.firstline;
13308462SApril.Chin@Sun.COM 				if(shp->topfd)
13318462SApril.Chin@Sun.COM 					sh_iounsave(shp);
13328462SApril.Chin@Sun.COM 				topfd = shp->topfd;
13338462SApril.Chin@Sun.COM 				sh_redirect(shp,t->tre.treio,1);
13348462SApril.Chin@Sun.COM 				if(shp->topfd > topfd)
13358462SApril.Chin@Sun.COM 				{
13368462SApril.Chin@Sun.COM 					while((parent = vfork()) < 0)
13378462SApril.Chin@Sun.COM 						_sh_fork(parent, 0, (int*)0);
13388462SApril.Chin@Sun.COM 					if(parent)
13398462SApril.Chin@Sun.COM 					{
13408462SApril.Chin@Sun.COM 						job_clear();
13418462SApril.Chin@Sun.COM 						job_post(parent,0);
13428462SApril.Chin@Sun.COM 						job_wait(parent);
13438462SApril.Chin@Sun.COM 						sh_iorestore(shp,topfd,SH_JMPCMD);
13448462SApril.Chin@Sun.COM 						sh_done(shp,(shp->exitval&SH_EXITSIG)?(shp->exitval&SH_EXITMASK):0);
13458462SApril.Chin@Sun.COM 
13468462SApril.Chin@Sun.COM 					}
13478462SApril.Chin@Sun.COM 				}
13484887Schin 				if((type&COMMSK)!=TCOM)
13494887Schin 				{
13504887Schin 					/* don't clear job table for out
13514887Schin 					   pipes so that jobs comand can
13524887Schin 					   be used in a pipeline
13534887Schin 					 */
13544887Schin 					if(!no_fork && !(type&FPOU))
13554887Schin 						job_clear();
1356*10898Sroland.mainz@nrubsig.org 					sh_exec(t->fork.forktre,flags|sh_state(SH_NOFORK)|sh_state(SH_FORKED));
13574887Schin 				}
13584887Schin 				else if(com0)
13594887Schin 				{
13604887Schin 					sh_offoption(SH_ERREXIT);
13618462SApril.Chin@Sun.COM 					sh_freeup(shp);
13624887Schin 					path_exec(com0,com,t->com.comset);
13634887Schin 				}
13644887Schin 			done:
13654887Schin 				sh_popcontext(&buff);
13664887Schin 				if(jmpval>SH_JMPEXIT)
13678462SApril.Chin@Sun.COM 					siglongjmp(*shp->jmplist,jmpval);
13688462SApril.Chin@Sun.COM 				sh_done(shp,0);
13694887Schin 			}
13704887Schin 		    }
13714887Schin 
13724887Schin 		    case TSETIO:
13734887Schin 		    {
13744887Schin 		    /*
13754887Schin 		     * don't create a new process, just
13764887Schin 		     * save and restore io-streams
13774887Schin 		     */
13784887Schin 			pid_t	pid;
1379*10898Sroland.mainz@nrubsig.org 			int 	jmpval, waitall;
1380*10898Sroland.mainz@nrubsig.org 			int 	simple = (t->fork.forktre->tre.tretyp&COMMSK)==TCOM;
13814887Schin 			struct checkpt buff;
13828462SApril.Chin@Sun.COM 			if(shp->subshell)
13834887Schin 				execflg = 0;
13844887Schin 			sh_pushcontext(&buff,SH_JMPIO);
13854887Schin 			if(type&FPIN)
13864887Schin 			{
13874887Schin 				was_interactive = sh_isstate(SH_INTERACTIVE);
13884887Schin 				sh_offstate(SH_INTERACTIVE);
1389*10898Sroland.mainz@nrubsig.org 				sh_iosave(shp,0,shp->topfd,(char*)0);
1390*10898Sroland.mainz@nrubsig.org 				shp->pipepid = simple;
13918462SApril.Chin@Sun.COM 				sh_iorenumber(shp,shp->inpipe[0],0);
13924887Schin 				/*
13934887Schin 				 * if read end of pipe is a simple command
13944887Schin 				 * treat as non-sharable to improve performance
13954887Schin 				 */
1396*10898Sroland.mainz@nrubsig.org 				if(simple)
13974887Schin 					sfset(sfstdin,SF_PUBLIC|SF_SHARE,0);
13984887Schin 				waitall = job.waitall;
13994887Schin 				job.waitall = 0;
14004887Schin 				pid = job.parent;
14014887Schin 			}
14024887Schin 			else
14038462SApril.Chin@Sun.COM 				error_info.line = t->fork.forkline-shp->st.firstline;
14044887Schin 			jmpval = sigsetjmp(buff.buff,0);
14054887Schin 			if(jmpval==0)
14064887Schin 			{
14078462SApril.Chin@Sun.COM 				sh_redirect(shp,t->fork.forkio,execflg);
14084887Schin 				(t->fork.forktre)->tre.tretyp |= t->tre.tretyp&FSHOWME;
1409*10898Sroland.mainz@nrubsig.org 				sh_exec(t->fork.forktre,flags&~simple);
14104887Schin 			}
14118462SApril.Chin@Sun.COM 			else
14128462SApril.Chin@Sun.COM 				sfsync(shp->outpool);
14134887Schin 			sh_popcontext(&buff);
14148462SApril.Chin@Sun.COM 			sh_iorestore(shp,buff.topfd,jmpval);
14154887Schin 			if(buff.olist)
14164887Schin 				free_list(buff.olist);
14174887Schin 			if(type&FPIN)
14184887Schin 			{
14194887Schin 				job.waitall = waitall;
14208462SApril.Chin@Sun.COM 				type = shp->exitval;
14214887Schin 				if(!(type&SH_EXITSIG))
14224887Schin 				{
14234887Schin 					/* wait for remainder of pipline */
1424*10898Sroland.mainz@nrubsig.org 					if(shp->pipepid>1)
1425*10898Sroland.mainz@nrubsig.org 					{
1426*10898Sroland.mainz@nrubsig.org 						job_wait(shp->pipepid);
1427*10898Sroland.mainz@nrubsig.org 						type = shp->exitval;
1428*10898Sroland.mainz@nrubsig.org 					}
1429*10898Sroland.mainz@nrubsig.org 					else
1430*10898Sroland.mainz@nrubsig.org 						job_wait(waitall?pid:0);
14314887Schin 					if(type || !sh_isoption(SH_PIPEFAIL))
14328462SApril.Chin@Sun.COM 						shp->exitval = type;
14334887Schin 				}
1434*10898Sroland.mainz@nrubsig.org 				shp->pipepid = 0;
14358462SApril.Chin@Sun.COM 				shp->st.ioset = 0;
1436*10898Sroland.mainz@nrubsig.org 				if(simple && was_errexit)
1437*10898Sroland.mainz@nrubsig.org 				{
1438*10898Sroland.mainz@nrubsig.org 					echeck = 1;
1439*10898Sroland.mainz@nrubsig.org 					sh_onstate(SH_ERREXIT);
1440*10898Sroland.mainz@nrubsig.org 				}
14414887Schin 			}
14424887Schin 			if(jmpval>SH_JMPIO)
14438462SApril.Chin@Sun.COM 				siglongjmp(*shp->jmplist,jmpval);
14444887Schin 			break;
14454887Schin 		    }
14464887Schin 
14474887Schin 		    case TPAR:
14484887Schin 			echeck = 1;
14494887Schin 			flags &= ~OPTIMIZE_FLAG;
14508462SApril.Chin@Sun.COM 			if(!shp->subshell && !shp->st.trapcom[0] && !shp->st.trap[SH_ERRTRAP] && (flags&sh_state(SH_NOFORK)))
14514887Schin 			{
1452*10898Sroland.mainz@nrubsig.org 				char *savsig;
1453*10898Sroland.mainz@nrubsig.org 				int nsig,jmpval;
14544887Schin 				struct checkpt buff;
1455*10898Sroland.mainz@nrubsig.org 				shp->st.otrapcom = 0;
1456*10898Sroland.mainz@nrubsig.org 				if((nsig=shp->st.trapmax*sizeof(char*))>0 || shp->st.trapcom[0])
1457*10898Sroland.mainz@nrubsig.org 				{
1458*10898Sroland.mainz@nrubsig.org 					nsig += sizeof(char*);
1459*10898Sroland.mainz@nrubsig.org 					memcpy(savsig=malloc(nsig),(char*)&shp->st.trapcom[0],nsig);
1460*10898Sroland.mainz@nrubsig.org 					shp->st.otrapcom = (char**)savsig;
1461*10898Sroland.mainz@nrubsig.org 				}
1462*10898Sroland.mainz@nrubsig.org 				sh_sigreset(0);
14634887Schin 				sh_pushcontext(&buff,SH_JMPEXIT);
14644887Schin 				jmpval = sigsetjmp(buff.buff,0);
14654887Schin 				if(jmpval==0)
14664887Schin 					sh_exec(t->par.partre,flags);
14674887Schin 				sh_popcontext(&buff);
14684887Schin 				if(jmpval > SH_JMPEXIT)
14698462SApril.Chin@Sun.COM 					siglongjmp(*shp->jmplist,jmpval);
14708462SApril.Chin@Sun.COM 				sh_done(shp,0);
14714887Schin 			}
14724887Schin 			else
14734887Schin 				sh_subshell(t->par.partre,flags,0);
14744887Schin 			break;
14754887Schin 
14764887Schin 		    case TFIL:
14774887Schin 		    {
14784887Schin 		    /*
14794887Schin 		     * This code sets up a pipe.
14804887Schin 		     * All elements of the pipe are started by the parent.
14814887Schin 		     * The last element executes in current environment
14824887Schin 		     */
14834887Schin 			int	pvo[2];	/* old pipe for multi-stage */
14844887Schin 			int	pvn[2];	/* current set up pipe */
14854887Schin 			int	savepipe = pipejob;
14864887Schin 			int	showme = t->tre.tretyp&FSHOWME;
14874887Schin 			pid_t	savepgid = job.curpgid;
14888462SApril.Chin@Sun.COM 			job.curpgid = 0;
14898462SApril.Chin@Sun.COM 			if(shp->subshell)
14908810SCasper.Dik@Sun.COM 			{
14918810SCasper.Dik@Sun.COM 				if(shp->subshare)
14928810SCasper.Dik@Sun.COM 					sh_subtmpfile(0);
14938810SCasper.Dik@Sun.COM 				else
14948810SCasper.Dik@Sun.COM 					sh_subfork();
14958810SCasper.Dik@Sun.COM 			}
14968462SApril.Chin@Sun.COM 			shp->inpipe = pvo;
14978462SApril.Chin@Sun.COM 			shp->outpipe = pvn;
14984887Schin 			pvo[1] = -1;
14994887Schin 			if(sh_isoption(SH_PIPEFAIL))
15004887Schin 				job.waitall = 1;
15014887Schin 			else
15024887Schin 				job.waitall |= !pipejob && sh_isstate(SH_MONITOR);
1503*10898Sroland.mainz@nrubsig.org 			job_lock();
15044887Schin 			do
15054887Schin 			{
15064887Schin #if SHOPT_FASTPIPE
15078462SApril.Chin@Sun.COM 				type = pipe_exec(shp,pvn,t->lst.lstlef, errorflg);
15084887Schin #else
15094887Schin 				/* create the pipe */
15104887Schin 				sh_pipe(pvn);
15114887Schin 				/* execute out part of pipe no wait */
15124887Schin 				(t->lst.lstlef)->tre.tretyp |= showme;
15134887Schin 				type = sh_exec(t->lst.lstlef, errorflg);
15144887Schin #endif /* SHOPT_FASTPIPE */
15154887Schin 				pipejob=1;
15164887Schin 				/* save the pipe stream-ids */
15174887Schin 				pvo[0] = pvn[0];
15184887Schin 				/* close out-part of pipe */
15194887Schin 				sh_close(pvn[1]);
15204887Schin 				/* pipeline all in one process group */
15214887Schin 				t = t->lst.lstrit;
15224887Schin 			}
15234887Schin 			/* repeat until end of pipeline */
15244887Schin 			while(!type && t->tre.tretyp==TFIL);
15258462SApril.Chin@Sun.COM 			shp->inpipe = pvn;
15268462SApril.Chin@Sun.COM 			shp->outpipe = 0;
1527*10898Sroland.mainz@nrubsig.org 			pipejob = 2;
15284887Schin 			if(type == 0)
15294887Schin 			{
15304887Schin 				/*
15314887Schin 				 * execute last element of pipeline
15324887Schin 				 * in the current process
15334887Schin 				 */
15344887Schin 				((Shnode_t*)t)->tre.tretyp |= showme;
15354887Schin 				sh_exec(t,flags);
15364887Schin 			}
15374887Schin 			else
15384887Schin 				/* execution failure, close pipe */
15394887Schin 				sh_pclose(pvn);
1540*10898Sroland.mainz@nrubsig.org 			if(pipejob==2)
1541*10898Sroland.mainz@nrubsig.org 				job_unlock();
15424887Schin 			pipejob = savepipe;
15434887Schin #ifdef SIGTSTP
15444887Schin 			if(!pipejob && sh_isstate(SH_MONITOR))
15458462SApril.Chin@Sun.COM 				tcsetpgrp(JOBTTY,shp->pid);
15464887Schin #endif /*SIGTSTP */
15474887Schin 			job.curpgid = savepgid;
15484887Schin 			break;
15494887Schin 		    }
15504887Schin 
15514887Schin 		    case TLST:
15524887Schin 		    {
15534887Schin 			/*  a list of commands are executed here */
15544887Schin 			do
15554887Schin 			{
15564887Schin 				sh_exec(t->lst.lstlef,errorflg|OPTIMIZE);
15574887Schin 				t = t->lst.lstrit;
15584887Schin 			}
15594887Schin 			while(t->tre.tretyp == TLST);
15604887Schin 			sh_exec(t,flags);
15614887Schin 			break;
15624887Schin 		    }
15634887Schin 
15644887Schin 		    case TAND:
15654887Schin 			if(type&TTEST)
15664887Schin 				skipexitset++;
15674887Schin 			if(sh_exec(t->lst.lstlef,OPTIMIZE)==0)
15684887Schin 				sh_exec(t->lst.lstrit,flags);
15694887Schin 			break;
15704887Schin 
15714887Schin 		    case TORF:
15724887Schin 			if(type&TTEST)
15734887Schin 				skipexitset++;
15744887Schin 			if(sh_exec(t->lst.lstlef,OPTIMIZE)!=0)
15754887Schin 				sh_exec(t->lst.lstrit,flags);
15764887Schin 			break;
15774887Schin 
15784887Schin 		    case TFOR: /* for and select */
15794887Schin 		    {
15804887Schin 			register char **args;
15814887Schin 			register int nargs;
15824887Schin 			register Namval_t *np;
15834887Schin 			int flag = errorflg|OPTIMIZE_FLAG;
15844887Schin 			struct dolnod	*argsav=0;
15854887Schin 			struct comnod	*tp;
15864887Schin 			char *cp, *trap, *nullptr = 0;
15874887Schin 			int nameref, refresh=1;
15888462SApril.Chin@Sun.COM 			char *av[5];
15894887Schin #if SHOPT_OPTIMIZE
15908462SApril.Chin@Sun.COM 			int  jmpval = ((struct checkpt*)shp->jmplist)->mode;
15914887Schin 			struct checkpt buff;
15928462SApril.Chin@Sun.COM 			void *optlist = shp->optlist;
15938462SApril.Chin@Sun.COM 			shp->optlist = 0;
15944887Schin 			sh_tclear(t->for_.fortre);
15954887Schin 			sh_pushcontext(&buff,jmpval);
15964887Schin 			jmpval = sigsetjmp(buff.buff,0);
15974887Schin 			if(jmpval)
15984887Schin 				goto endfor;
15994887Schin #endif /* SHOPT_OPTIMIZE */
16008462SApril.Chin@Sun.COM 			error_info.line = t->for_.forline-shp->st.firstline;
16014887Schin 			if(!(tp=t->for_.forlst))
16024887Schin 			{
16038462SApril.Chin@Sun.COM 				args=shp->st.dolv+1;
16048462SApril.Chin@Sun.COM 				nargs = shp->st.dolc;
16058462SApril.Chin@Sun.COM 				argsav=sh_arguse(shp);
16064887Schin 			}
16074887Schin 			else
16084887Schin 			{
16098462SApril.Chin@Sun.COM 				args=sh_argbuild(shp,&argn,tp,0);
16104887Schin 				nargs = argn;
16114887Schin 			}
16128462SApril.Chin@Sun.COM 			np = nv_open(t->for_.fornam, shp->var_tree,NV_NOASSIGN|NV_NOARRAY|NV_VARNAME|NV_NOREF);
16134887Schin 			nameref = nv_isref(np)!=0;
16148462SApril.Chin@Sun.COM 			shp->st.loopcnt++;
16154887Schin 			cp = *args;
16168462SApril.Chin@Sun.COM 			while(cp && shp->st.execbrk==0)
16174887Schin 			{
16184887Schin 				if(t->tre.tretyp&COMSCAN)
16194887Schin 				{
16204887Schin 					char *val;
16214887Schin 					int save_prompt;
16224887Schin 					/* reuse register */
16234887Schin 					if(refresh)
16244887Schin 					{
16254887Schin 						sh_menu(sfstderr,nargs,args);
16264887Schin 						refresh = 0;
16274887Schin 					}
16288462SApril.Chin@Sun.COM 					save_prompt = shp->nextprompt;
16298462SApril.Chin@Sun.COM 					shp->nextprompt = 3;
16308462SApril.Chin@Sun.COM 					shp->timeout = 0;
16318462SApril.Chin@Sun.COM 					shp->exitval=sh_readline(shp,&nullptr,0,1,1000*shp->st.tmout);
16328462SApril.Chin@Sun.COM 					shp->nextprompt = save_prompt;
16338462SApril.Chin@Sun.COM 					if(shp->exitval||sfeof(sfstdin)||sferror(sfstdin))
16344887Schin 					{
16358462SApril.Chin@Sun.COM 						shp->exitval = 1;
16364887Schin 						break;
16374887Schin 					}
16388462SApril.Chin@Sun.COM 					if(!(val=nv_getval(sh_scoped(shp,REPLYNOD))))
16394887Schin 						continue;
16404887Schin 					else
16414887Schin 					{
16424887Schin 						if(*(cp=val) == 0)
16434887Schin 						{
16444887Schin 							refresh++;
16454887Schin 							goto check;
16464887Schin 						}
16474887Schin 						while(type = *cp++)
16484887Schin 							if(type < '0' && type > '9')
16494887Schin 								break;
16504887Schin 						if(type!=0)
16514887Schin 							type = nargs;
16524887Schin 						else
16534887Schin 							type = (int)strtol(val, (char**)0, 10)-1;
16544887Schin 						if(type<0 || type >= nargs)
16554887Schin 							cp = "";
16564887Schin 						else
16574887Schin 							cp = args[type];
16584887Schin 					}
16594887Schin 				}
16604887Schin 				if(nameref)
16614887Schin 					nv_offattr(np,NV_REF);
16624887Schin 				else if(nv_isattr(np, NV_ARRAY))
16634887Schin 					nv_putsub(np,NIL(char*),0L);
16644887Schin 				nv_putval(np,cp,0);
16654887Schin 				if(nameref)
16664887Schin 					nv_setref(np,(Dt_t*)0,NV_VARNAME);
16678462SApril.Chin@Sun.COM 				if(trap=shp->st.trap[SH_DEBUGTRAP])
16684887Schin 				{
16694887Schin 					av[0] = (t->tre.tretyp&COMSCAN)?"select":"for";
16704887Schin 					av[1] = t->for_.fornam;
16718462SApril.Chin@Sun.COM 					av[2] = "in";
16724887Schin 					av[3] = cp;
16738462SApril.Chin@Sun.COM 					av[4] = 0;
16748462SApril.Chin@Sun.COM 					sh_debug(shp,trap,(char*)0,(char*)0,av,0);
16754887Schin 				}
16764887Schin 				sh_exec(t->for_.fortre,flag);
16774887Schin 				flag &= ~OPTIMIZE_FLAG;
16784887Schin 				if(t->tre.tretyp&COMSCAN)
16794887Schin 				{
16808462SApril.Chin@Sun.COM 					if((cp=nv_getval(sh_scoped(shp,REPLYNOD))) && *cp==0)
16814887Schin 						refresh++;
16824887Schin 				}
16834887Schin 				else
16844887Schin 					cp = *++args;
16854887Schin 			check:
16868462SApril.Chin@Sun.COM 				if(shp->st.breakcnt<0)
16878462SApril.Chin@Sun.COM 					shp->st.execbrk = (++shp->st.breakcnt !=0);
16884887Schin 			}
16894887Schin #if SHOPT_OPTIMIZE
16904887Schin 		endfor:
16914887Schin 			sh_popcontext(&buff);
16924887Schin 			sh_tclear(t->for_.fortre);
16938462SApril.Chin@Sun.COM 			sh_optclear(shp,optlist);
16944887Schin 			if(jmpval)
16958462SApril.Chin@Sun.COM 				siglongjmp(*shp->jmplist,jmpval);
16964887Schin #endif /*SHOPT_OPTIMIZE */
16978462SApril.Chin@Sun.COM 			if(shp->st.breakcnt>0)
16988462SApril.Chin@Sun.COM 				shp->st.execbrk = (--shp->st.breakcnt !=0);
16998462SApril.Chin@Sun.COM 			shp->st.loopcnt--;
17008462SApril.Chin@Sun.COM 			sh_argfree(shp,argsav,0);
17014887Schin 			nv_close(np);
17024887Schin 			break;
17034887Schin 		    }
17044887Schin 
17054887Schin 		    case TWH: /* while and until */
17064887Schin 		    {
17078462SApril.Chin@Sun.COM 			volatile int 	r=0;
17084887Schin 			int first = OPTIMIZE_FLAG;
17094887Schin 			Shnode_t *tt = t->wh.whtre;
17104887Schin #if SHOPT_FILESCAN
17114887Schin 			Sfio_t *iop=0;
17124887Schin 			int savein,fd;
17134887Schin #endif /*SHOPT_FILESCAN*/
17144887Schin #if SHOPT_OPTIMIZE
17158462SApril.Chin@Sun.COM 			int  jmpval = ((struct checkpt*)shp->jmplist)->mode;
17164887Schin 			struct checkpt buff;
17178462SApril.Chin@Sun.COM 			void *optlist = shp->optlist;
17188462SApril.Chin@Sun.COM 			shp->optlist = 0;
17194887Schin 			sh_tclear(t->wh.whtre);
17204887Schin 			sh_tclear(t->wh.dotre);
17214887Schin 			sh_pushcontext(&buff,jmpval);
17224887Schin 			jmpval = sigsetjmp(buff.buff,0);
17234887Schin 			if(jmpval)
17244887Schin 				goto endwhile;
17254887Schin #endif /* SHOPT_OPTIMIZE */
17264887Schin #if SHOPT_FILESCAN
17274887Schin 			if(type==TWH && tt->tre.tretyp==TCOM && !tt->com.comarg && tt->com.comio)
17284887Schin 			{
17298462SApril.Chin@Sun.COM 				fd = sh_redirect(shp,tt->com.comio,3);
17304887Schin 				savein = dup(0);
17314887Schin 				if(fd==0)
17324887Schin 					fd = savein;
17334887Schin 				iop = sfnew(NULL,NULL,SF_UNBOUND,fd,SF_READ);
17344887Schin 				close(0);
17354887Schin 				open("/dev/null",O_RDONLY);
17368462SApril.Chin@Sun.COM 				shp->offsets[0] = -1;
17378462SApril.Chin@Sun.COM 				shp->offsets[1] = 0;
17384887Schin 				if(tt->com.comset)
1739*10898Sroland.mainz@nrubsig.org 					nv_setlist(tt->com.comset,NV_IDENT|NV_ASSIGN,0);
17404887Schin 			}
17414887Schin #endif /*SHOPT_FILESCAN */
17428462SApril.Chin@Sun.COM 			shp->st.loopcnt++;
17438462SApril.Chin@Sun.COM 			while(shp->st.execbrk==0)
17444887Schin 			{
17454887Schin #if SHOPT_FILESCAN
17464887Schin 				if(iop)
17474887Schin 				{
17488462SApril.Chin@Sun.COM 					if(!(shp->cur_line=sfgetr(iop,'\n',SF_STRING)))
17494887Schin 						break;
17504887Schin 				}
17514887Schin 				else
17524887Schin #endif /*SHOPT_FILESCAN */
17534887Schin 				if((sh_exec(tt,first)==0)!=(type==TWH))
17544887Schin 					break;
17554887Schin 				r = sh_exec(t->wh.dotre,first|errorflg);
17568462SApril.Chin@Sun.COM 				if(shp->st.breakcnt<0)
17578462SApril.Chin@Sun.COM 					shp->st.execbrk = (++shp->st.breakcnt !=0);
17584887Schin 				/* This is for the arithmetic for */
17598462SApril.Chin@Sun.COM 				if(shp->st.execbrk==0 && t->wh.whinc)
17604887Schin 					sh_exec((Shnode_t*)t->wh.whinc,first);
17614887Schin 				first = 0;
17624887Schin 				errorflg &= ~OPTIMIZE_FLAG;
17634887Schin #if SHOPT_FILESCAN
17648462SApril.Chin@Sun.COM 				shp->offsets[0] = -1;
17658462SApril.Chin@Sun.COM 				shp->offsets[1] = 0;
17664887Schin #endif /*SHOPT_FILESCAN */
17674887Schin 			}
17684887Schin #if SHOPT_OPTIMIZE
17694887Schin 		endwhile:
17704887Schin 			sh_popcontext(&buff);
17714887Schin 			sh_tclear(t->wh.whtre);
17724887Schin 			sh_tclear(t->wh.dotre);
17738462SApril.Chin@Sun.COM 			sh_optclear(shp,optlist);
17744887Schin 			if(jmpval)
17758462SApril.Chin@Sun.COM 				siglongjmp(*shp->jmplist,jmpval);
17764887Schin #endif /*SHOPT_OPTIMIZE */
17778462SApril.Chin@Sun.COM 			if(shp->st.breakcnt>0)
17788462SApril.Chin@Sun.COM 				shp->st.execbrk = (--shp->st.breakcnt !=0);
17798462SApril.Chin@Sun.COM 			shp->st.loopcnt--;
17808462SApril.Chin@Sun.COM 			shp->exitval= r;
17814887Schin #if SHOPT_FILESCAN
17824887Schin 			if(iop)
17834887Schin 			{
17844887Schin 				sfclose(iop);
17854887Schin 				close(0);
17864887Schin 				dup(savein);
17878462SApril.Chin@Sun.COM 				shp->cur_line = 0;
17884887Schin 			}
17894887Schin #endif /*SHOPT_FILESCAN */
17904887Schin 			break;
17914887Schin 		    }
17924887Schin 		    case TARITH: /* (( expression )) */
17934887Schin 		    {
17944887Schin 			register char *trap;
17958462SApril.Chin@Sun.COM 			char *arg[4];
17968462SApril.Chin@Sun.COM 			error_info.line = t->ar.arline-shp->st.firstline;
17978462SApril.Chin@Sun.COM 			arg[0] = "((";
17984887Schin 			if(!(t->ar.arexpr->argflag&ARG_RAW))
17998462SApril.Chin@Sun.COM 				arg[1] = sh_macpat(shp,t->ar.arexpr,OPTIMIZE|ARG_ARITH);
18004887Schin 			else
18014887Schin 				arg[1] = t->ar.arexpr->argval;
18028462SApril.Chin@Sun.COM 			arg[2] = "))";
18038462SApril.Chin@Sun.COM 			arg[3] = 0;
18048462SApril.Chin@Sun.COM 			if(trap=shp->st.trap[SH_DEBUGTRAP])
18058462SApril.Chin@Sun.COM 				sh_debug(shp,trap,(char*)0, (char*)0, arg, ARG_ARITH);
18064887Schin 			if(sh_isoption(SH_XTRACE))
18074887Schin 			{
18084887Schin 				sh_trace(NIL(char**),0);
18094887Schin 				sfprintf(sfstderr,"((%s))\n",arg[1]);
18104887Schin 			}
18114887Schin 			if(t->ar.arcomp)
18128462SApril.Chin@Sun.COM 				shp->exitval  = !arith_exec((Arith_t*)t->ar.arcomp);
18134887Schin 			else
18148462SApril.Chin@Sun.COM 				shp->exitval = !sh_arith(arg[1]);
18154887Schin 			break;
18164887Schin 		    }
18174887Schin 
18184887Schin 		    case TIF:
18194887Schin 			if(sh_exec(t->if_.iftre,OPTIMIZE)==0)
18204887Schin 				sh_exec(t->if_.thtre,flags);
18214887Schin 			else if(t->if_.eltre)
18224887Schin 				sh_exec(t->if_.eltre, flags);
18234887Schin 			else
18248462SApril.Chin@Sun.COM 				shp->exitval=0; /* force zero exit for if-then-fi */
18254887Schin 			break;
18264887Schin 
18274887Schin 		    case TSW:
18284887Schin 		    {
18294887Schin 			Shnode_t *tt = (Shnode_t*)t;
18308462SApril.Chin@Sun.COM 			char *trap, *r = sh_macpat(shp,tt->sw.swarg,OPTIMIZE);
18318462SApril.Chin@Sun.COM 			error_info.line = t->sw.swline-shp->st.firstline;
18324887Schin 			t= (Shnode_t*)(tt->sw.swlst);
18338462SApril.Chin@Sun.COM 			if(trap=shp->st.trap[SH_DEBUGTRAP])
18344887Schin 			{
18358462SApril.Chin@Sun.COM 				char *av[4];
18368462SApril.Chin@Sun.COM 				av[0] = "case";
18374887Schin 				av[1] = r;
18388462SApril.Chin@Sun.COM 				av[2] = "in";
18398462SApril.Chin@Sun.COM 				av[3] = 0;
18408462SApril.Chin@Sun.COM 				sh_debug(shp,trap, (char*)0, (char*)0, av, 0);
18414887Schin 			}
18424887Schin 			while(t)
18434887Schin 			{
18444887Schin 				register struct argnod	*rex=(struct argnod*)t->reg.regptr;
18454887Schin 				while(rex)
18464887Schin 				{
18474887Schin 					register char *s;
18484887Schin 					if(rex->argflag&ARG_MAC)
18494887Schin 					{
18508462SApril.Chin@Sun.COM 						s = sh_macpat(shp,rex,OPTIMIZE|ARG_EXP);
18514887Schin 						while(*s=='\\' && s[1]==0)
18524887Schin 							s+=2;
18534887Schin 					}
18544887Schin 					else
18554887Schin 						s = rex->argval;
18564887Schin 					type = (rex->argflag&ARG_RAW);
18574887Schin 					if((type && strcmp(r,s)==0) ||
18584887Schin 						(!type && (strmatch(r,s)
18594887Schin 						|| trim_eq(r,s))))
18604887Schin 					{
18614887Schin 						do	sh_exec(t->reg.regcom,(t->reg.regflag?0:flags));
18624887Schin 						while(t->reg.regflag &&
18634887Schin 							(t=(Shnode_t*)t->reg.regnxt));
18644887Schin 						t=0;
18654887Schin 						break;
18664887Schin 					}
18674887Schin 					else
18684887Schin 						rex=rex->argnxt.ap;
18694887Schin 				}
18704887Schin 				if(t)
18714887Schin 					t=(Shnode_t*)t->reg.regnxt;
18724887Schin 			}
18734887Schin 			break;
18744887Schin 		    }
18754887Schin 
18764887Schin 		    case TTIME:
18774887Schin 		    {
18784887Schin 			/* time the command */
18794887Schin 			struct tms before,after;
18804887Schin 			const char *format = e_timeformat;
18814887Schin 			clock_t at, tm[3];
18824887Schin #ifdef timeofday
18834887Schin 			struct timeval tb,ta;
18844887Schin #else
18854887Schin 			clock_t bt;
18864887Schin #endif	/* timeofday */
18874887Schin 			if(type!=TTIME)
18884887Schin 			{
18894887Schin 				sh_exec(t->par.partre,OPTIMIZE);
18908462SApril.Chin@Sun.COM 				shp->exitval = !shp->exitval;
18914887Schin 				break;
18924887Schin 			}
18934887Schin 			if(t->par.partre)
18944887Schin 			{
18954887Schin 				long timer_on;
18964887Schin 				timer_on = sh_isstate(SH_TIMING);
18974887Schin #ifdef timeofday
18984887Schin 				timeofday(&tb);
18994887Schin 				times(&before);
19004887Schin #else
19014887Schin 				bt = times(&before);
19024887Schin #endif	/* timeofday */
19034887Schin 				job.waitall = 1;
19044887Schin 				sh_onstate(SH_TIMING);
19054887Schin 				sh_exec(t->par.partre,OPTIMIZE);
19064887Schin 				if(!timer_on)
19074887Schin 					sh_offstate(SH_TIMING);
19084887Schin 				job.waitall = 0;
19094887Schin 			}
19104887Schin 			else
19114887Schin 			{
19124887Schin #ifndef timeofday
19134887Schin 				bt = 0;
19144887Schin #endif	/* timeofday */
19154887Schin 				before.tms_utime = before.tms_cutime = 0;
19164887Schin 				before.tms_stime = before.tms_cstime = 0;
19174887Schin 			}
19184887Schin #ifdef timeofday
19194887Schin 			times(&after);
19204887Schin 			timeofday(&ta);
19218462SApril.Chin@Sun.COM 			at = shp->lim.clk_tck*(ta.tv_sec-tb.tv_sec);
19228462SApril.Chin@Sun.COM 			at +=  ((shp->lim.clk_tck*(((1000000L/2)/shp->lim.clk_tck)+(ta.tv_usec-tb.tv_usec)))/1000000L);
19234887Schin #else
19244887Schin 			at = times(&after) - bt;
19254887Schin #endif	/* timeofday */
19264887Schin 			tm[0] = at;
19274887Schin 			if(t->par.partre)
19284887Schin 			{
19298462SApril.Chin@Sun.COM 				Namval_t *np = nv_open("TIMEFORMAT",shp->var_tree,NV_NOADD);
19304887Schin 				if(np)
19314887Schin 				{
19324887Schin 					format = nv_getval(np);
19334887Schin 					nv_close(np);
19344887Schin 				}
19354887Schin 				if(!format)
19364887Schin 					format = e_timeformat;
19374887Schin 			}
19384887Schin 			else
19394887Schin 				format = strchr(format+1,'\n')+1;
19404887Schin 			tm[1] = after.tms_utime - before.tms_utime;
19414887Schin 			tm[1] += after.tms_cutime - before.tms_cutime;
19424887Schin 			tm[2] = after.tms_stime - before.tms_stime;
19434887Schin 			tm[2] += after.tms_cstime - before.tms_cstime;
19444887Schin 			if(format && *format)
19458462SApril.Chin@Sun.COM 				p_time(shp,sfstderr,sh_translate(format),tm);
19464887Schin 			break;
19474887Schin 		    }
19484887Schin 		    case TFUN:
19494887Schin 		    {
19504887Schin 			register Namval_t *np;
19514887Schin 			register struct slnod *slp;
19524887Schin 			register char *fname = ((struct functnod*)t)->functnam;
19534887Schin 			register char *cp = strrchr(fname,'.');
19544887Schin 			register Namval_t *npv=0;
19554887Schin #if SHOPT_NAMESPACE
19564887Schin 			if(t->tre.tretyp==TNSPACE)
19574887Schin 			{
19584887Schin 				Dt_t *root,*oldroot, *top=0;
19598462SApril.Chin@Sun.COM 				Namval_t *oldnspace = shp->namespace;
19608462SApril.Chin@Sun.COM 				int offset = stktell(stkp);
19618462SApril.Chin@Sun.COM 				long optindex = shp->st.optindex;
19624887Schin 				if(cp)
19634887Schin 					errormsg(SH_DICT,ERROR_exit(1),e_ident,fname);
19648462SApril.Chin@Sun.COM 				sfputc(stkp,'.');
19658462SApril.Chin@Sun.COM 				sfputr(stkp,fname,0);
19668462SApril.Chin@Sun.COM 				np = nv_open(stkptr(stkp,offset),shp->var_base,NV_NOASSIGN|NV_NOARRAY|NV_VARNAME);
19678462SApril.Chin@Sun.COM 				offset = stktell(stkp);
19688462SApril.Chin@Sun.COM 				shp->namespace = np;
19694887Schin 				if(!(root=nv_dict(np)))
19704887Schin 				{
19714887Schin 					root = dtopen(&_Nvdisc,Dtoset);
19724887Schin 					nv_putval(np,(char*)root,NV_TABLE|NV_NOFREE);
19738462SApril.Chin@Sun.COM 					shp->st.optindex = 1;
19744887Schin 				}
19758462SApril.Chin@Sun.COM 				if(oldnspace && dtvnext(dtvnext(shp->var_tree)))
19768462SApril.Chin@Sun.COM 					top = dtview(shp->var_tree,0);
19778462SApril.Chin@Sun.COM 				else if(dtvnext(shp->var_tree))
19788462SApril.Chin@Sun.COM 					top = dtview(shp->var_tree,0);
19798462SApril.Chin@Sun.COM 				oldroot = shp->var_tree;
19808462SApril.Chin@Sun.COM 				dtview(root,shp->var_base);
19818462SApril.Chin@Sun.COM 				shp->var_tree = root;
19824887Schin 				if(top)
19838462SApril.Chin@Sun.COM 					dtview(shp->var_tree,top);
19844887Schin 				sh_exec(t->for_.fortre,flags);
19858462SApril.Chin@Sun.COM 				if(dtvnext(shp->var_tree))
19868462SApril.Chin@Sun.COM 					top = dtview(shp->var_tree,0);
19878462SApril.Chin@Sun.COM 				shp->var_tree = oldroot;
19884887Schin 				if(top)
19898462SApril.Chin@Sun.COM 					dtview(top,shp->var_tree);
19908462SApril.Chin@Sun.COM 				shp->namespace = oldnspace;
19918462SApril.Chin@Sun.COM 				shp->st.optindex = optindex;
19924887Schin 				break;
19934887Schin 			}
19944887Schin #endif /* SHOPT_NAMESPACE */
19954887Schin 			/* look for discipline functions */
19968462SApril.Chin@Sun.COM 			error_info.line = t->funct.functline-shp->st.firstline;
19974887Schin 			/* Function names cannot be special builtin */
19988462SApril.Chin@Sun.COM 			if(cp || shp->prefix)
19994887Schin 			{
20008462SApril.Chin@Sun.COM 				int offset = stktell(stkp);
20018462SApril.Chin@Sun.COM 				if(shp->prefix)
20024887Schin 				{
20038462SApril.Chin@Sun.COM 					cp = shp->prefix;
20048462SApril.Chin@Sun.COM 					shp->prefix = 0;
20058462SApril.Chin@Sun.COM 					npv = nv_open(cp,shp->var_tree,NV_NOASSIGN|NV_NOARRAY|NV_VARNAME);
20068462SApril.Chin@Sun.COM 					shp->prefix = cp;
20074887Schin 					cp = fname;
20084887Schin 				}
20094887Schin 				else
20104887Schin 				{
20118462SApril.Chin@Sun.COM 					sfwrite(stkp,fname,cp++-fname);
20128462SApril.Chin@Sun.COM 					sfputc(stkp,0);
20138462SApril.Chin@Sun.COM 					npv = nv_open(stkptr(stkp,offset),shp->var_tree,NV_NOASSIGN|NV_NOARRAY|NV_VARNAME);
20144887Schin 				}
20158462SApril.Chin@Sun.COM 				offset = stktell(stkp);
20168462SApril.Chin@Sun.COM 				sfprintf(stkp,"%s.%s%c",nv_name(npv),cp,0);
20178462SApril.Chin@Sun.COM 				fname = stkptr(stkp,offset);
20184887Schin 			}
20198462SApril.Chin@Sun.COM 			else if((np=nv_search(fname,shp->bltin_tree,0)) && nv_isattr(np,BLT_SPC))
20204887Schin 				errormsg(SH_DICT,ERROR_exit(1),e_badfun,fname);
20214887Schin #if SHOPT_NAMESPACE
20228462SApril.Chin@Sun.COM 			else if(shp->namespace)
20234887Schin 			{
20248462SApril.Chin@Sun.COM 				int offset = stktell(stkp);
20258462SApril.Chin@Sun.COM 				sfputr(stkp,nv_name(shp->namespace),-1);
20268462SApril.Chin@Sun.COM 				sfputc(stkp,'.');
20278462SApril.Chin@Sun.COM 				sfputr(stkp,fname,0);
20288462SApril.Chin@Sun.COM 				fname = stkptr(stkp,offset);
20294887Schin 			}
20304887Schin #endif /* SHOPT_NAMESPACE */
20314887Schin 			np = nv_open(fname,sh_subfuntree(1),NV_NOASSIGN|NV_NOARRAY|NV_VARNAME|NV_NOSCOPE);
20324887Schin 			if(npv)
20334887Schin 			{
20348462SApril.Chin@Sun.COM 				Namval_t *tp = npv;
20358462SApril.Chin@Sun.COM 				if(!shp->mktype)
20368462SApril.Chin@Sun.COM 				{
20378462SApril.Chin@Sun.COM 					if(shp->typeinit)
20388462SApril.Chin@Sun.COM 					{
20398462SApril.Chin@Sun.COM 						if(tp=nv_open(shp->typeinit->nvname,shp->typedict,NV_IDENT|NV_NOFAIL))
20408462SApril.Chin@Sun.COM 							nv_close(npv);
20418462SApril.Chin@Sun.COM 						else
20428462SApril.Chin@Sun.COM 							tp = npv;
20438462SApril.Chin@Sun.COM 					}
20448462SApril.Chin@Sun.COM 					cp = nv_setdisc(tp,cp,np,(Namfun_t*)tp);
20458462SApril.Chin@Sun.COM 				}
20468462SApril.Chin@Sun.COM 				nv_close(tp);
20474887Schin 				if(!cp)
20484887Schin 					errormsg(SH_DICT,ERROR_exit(1),e_baddisc,fname);
20494887Schin 			}
20504887Schin 			if(np->nvalue.rp)
20514887Schin 			{
20524887Schin 				slp = (struct slnod*)np->nvenv;
20534887Schin 				sh_funstaks(slp->slchild,-1);
20544887Schin 				stakdelete(slp->slptr);
20558462SApril.Chin@Sun.COM 				if(shp->funload)
20568462SApril.Chin@Sun.COM 				{
20578462SApril.Chin@Sun.COM 					free((void*)np->nvalue.rp);
20588462SApril.Chin@Sun.COM 					np->nvalue.rp = 0;
20598462SApril.Chin@Sun.COM 				}
20608462SApril.Chin@Sun.COM 
20614887Schin 			}
20628462SApril.Chin@Sun.COM 			if(!np->nvalue.rp)
20638462SApril.Chin@Sun.COM 			{
20648462SApril.Chin@Sun.COM 				np->nvalue.rp = new_of(struct Ufunction,shp->funload?sizeof(Dtlink_t):0);
20658462SApril.Chin@Sun.COM 				memset((void*)np->nvalue.rp,0,sizeof(struct Ufunction));
20668462SApril.Chin@Sun.COM 			}
20674887Schin 			if(t->funct.functstak)
20684887Schin 			{
20698462SApril.Chin@Sun.COM 				static Dtdisc_t		_Rpdisc =
20708462SApril.Chin@Sun.COM 				{
20718462SApril.Chin@Sun.COM 				        offsetof(struct Ufunction,fname), -1, sizeof(struct Ufunction)
20728462SApril.Chin@Sun.COM 				};
20734887Schin 				struct functnod *fp;
20744887Schin 				slp = t->funct.functstak;
20754887Schin 				sh_funstaks(slp->slchild,1);
20764887Schin 				staklink(slp->slptr);
20774887Schin 				np->nvenv = (char*)slp;
20784887Schin 				nv_funtree(np) = (int*)(t->funct.functtre);
20794887Schin 				np->nvalue.rp->hoffset = t->funct.functloc;
20804887Schin 				np->nvalue.rp->lineno = t->funct.functline;
20818462SApril.Chin@Sun.COM 				np->nvalue.rp->nspace = shp->namespace;
20824887Schin 				np->nvalue.rp->fname = 0;
20838462SApril.Chin@Sun.COM 				np->nvalue.rp->fdict = shp->fun_tree;
20844887Schin 				fp = (struct functnod*)(slp+1);
20854887Schin 				if(fp->functtyp==(TFUN|FAMP))
20864887Schin 					np->nvalue.rp->fname = fp->functnam;
20874887Schin 				nv_setsize(np,fp->functline);
20884887Schin 				nv_offattr(np,NV_FPOSIX);
20898462SApril.Chin@Sun.COM 				if(shp->funload)
20908462SApril.Chin@Sun.COM 				{
20918462SApril.Chin@Sun.COM 					struct Ufunction *rp = np->nvalue.rp;
20928462SApril.Chin@Sun.COM 					rp->np = np;
20938462SApril.Chin@Sun.COM 					if(!shp->fpathdict)
20948462SApril.Chin@Sun.COM 						shp->fpathdict = dtopen(&_Rpdisc,Dtbag);
20958462SApril.Chin@Sun.COM 					if(shp->fpathdict)
20968462SApril.Chin@Sun.COM 						dtinsert(shp->fpathdict,rp);
20978462SApril.Chin@Sun.COM 				}
20984887Schin 			}
20994887Schin 			else
21004887Schin 				nv_unset(np);
21014887Schin 			if(type&FPOSIX)
21024887Schin 				nv_onattr(np,NV_FUNCTION|NV_FPOSIX);
21034887Schin 			else
21044887Schin 				nv_onattr(np,NV_FUNCTION);
21054887Schin 			if(type&FPIN)
21064887Schin 				nv_onattr(np,NV_FTMP);
21078462SApril.Chin@Sun.COM 			if(type&FOPTGET)
21088462SApril.Chin@Sun.COM 				nv_onattr(np,NV_OPTGET);
21094887Schin 			break;
21104887Schin 		    }
21114887Schin 
21124887Schin 		    /* new test compound command */
21134887Schin 		    case TTST:
21144887Schin 		    {
21154887Schin 			register int n;
21164887Schin 			register char *left;
21174887Schin 			int negate = (type&TNEGATE)!=0;
21184887Schin 			if(type&TTEST)
21194887Schin 				skipexitset++;
21208462SApril.Chin@Sun.COM 			error_info.line = t->tst.tstline-shp->st.firstline;
21214887Schin 			echeck = 1;
21224887Schin 			if((type&TPAREN)==TPAREN)
21234887Schin 			{
21244887Schin 				sh_exec(t->lst.lstlef,OPTIMIZE);
21258462SApril.Chin@Sun.COM 				n = !shp->exitval;
21264887Schin 			}
21274887Schin 			else
21284887Schin 			{
21294887Schin 				register int traceon=0;
21304887Schin 				register char *right;
21314887Schin 				register char *trap;
21324887Schin 				char *argv[6];
21334887Schin 				n = type>>TSHIFT;
21348462SApril.Chin@Sun.COM 				left = sh_macpat(shp,&(t->lst.lstlef->arg),OPTIMIZE);
21354887Schin 				if(type&TBINARY)
21368462SApril.Chin@Sun.COM 					right = sh_macpat(shp,&(t->lst.lstrit->arg),((n==TEST_PEQ||n==TEST_PNE)?ARG_EXP:0)|OPTIMIZE);
21378462SApril.Chin@Sun.COM 				if(trap=shp->st.trap[SH_DEBUGTRAP])
21384887Schin 					argv[0] = (type&TNEGATE)?((char*)e_tstbegin):"[[";
21394887Schin 				if(sh_isoption(SH_XTRACE))
21404887Schin 				{
21414887Schin 					traceon = sh_trace(NIL(char**),0);
21424887Schin 					sfwrite(sfstderr,e_tstbegin,(type&TNEGATE?5:3));
21434887Schin 				}
21444887Schin 				if(type&TUNARY)
21454887Schin 				{
21464887Schin 					if(traceon)
21474887Schin 						sfprintf(sfstderr,"-%c %s",n,sh_fmtq(left));
21484887Schin 					if(trap)
21494887Schin 					{
21504887Schin 						char unop[3];
21514887Schin 						unop[0] = '-';
21524887Schin 						unop[1] = n;
21534887Schin 						unop[2] = 0;
21544887Schin 						argv[1] = unop;
21554887Schin 						argv[2] = left;
21564887Schin 						argv[3] = "]]";
21574887Schin 						argv[4] = 0;
21588462SApril.Chin@Sun.COM 						sh_debug(shp,trap,(char*)0,(char*)0,argv, 0);
21594887Schin 					}
21604887Schin 					n = test_unop(n,left);
21614887Schin 				}
21624887Schin 				else if(type&TBINARY)
21634887Schin 				{
21644887Schin 					char *op;
21654887Schin 					int pattern = 0;
21664887Schin 					if(trap || traceon)
21674887Schin 						op = (char*)(shtab_testops+(n&037)-1)->sh_name;
21684887Schin 					type >>= TSHIFT;
21694887Schin 					if(type==TEST_PEQ || type==TEST_PNE)
21704887Schin 						pattern=ARG_EXP;
21714887Schin 					if(trap)
21724887Schin 					{
21734887Schin 						argv[1] = left;
21744887Schin 						argv[2] = op;
21754887Schin 						argv[3] = right;
21764887Schin 						argv[4] = "]]";
21774887Schin 						argv[5] = 0;
21788462SApril.Chin@Sun.COM 						sh_debug(shp,trap,(char*)0,(char*)0,argv, pattern);
21794887Schin 					}
21804887Schin 					n = test_binop(n,left,right);
21814887Schin 					if(traceon)
21824887Schin 					{
21834887Schin 						sfprintf(sfstderr,"%s %s ",sh_fmtq(left),op);
21844887Schin 						if(pattern)
21854887Schin 							out_pattern(sfstderr,right,-1);
21864887Schin 						else
21874887Schin 							sfputr(sfstderr,sh_fmtq(right),-1);
21884887Schin 					}
21894887Schin 				}
21904887Schin 				if(traceon)
21914887Schin 					sfwrite(sfstderr,e_tstend,4);
21924887Schin 			}
21938462SApril.Chin@Sun.COM 			shp->exitval = ((!n)^negate);
21944887Schin 			if(!skipexitset)
21954887Schin 				exitset();
21964887Schin 			break;
21974887Schin 		    }
21984887Schin 		}
21998462SApril.Chin@Sun.COM 		if(shp->trapnote || (shp->exitval && sh_isstate(SH_ERREXIT)) &&
22004887Schin 			t && echeck)
22014887Schin 			sh_chktrap();
22024887Schin 		/* set $_ */
22034887Schin 		if(mainloop && com0)
22044887Schin 		{
22054887Schin 			/* store last argument here if it fits */
22064887Schin 			static char	lastarg[32];
22074887Schin 			if(sh_isstate(SH_FORKED))
22088462SApril.Chin@Sun.COM 				sh_done(shp,0);
22098462SApril.Chin@Sun.COM 			if(shp->lastarg!= lastarg && shp->lastarg)
22108462SApril.Chin@Sun.COM 				free(shp->lastarg);
22118462SApril.Chin@Sun.COM 			if(strlen(comn) < sizeof(lastarg))
22124887Schin 			{
22134887Schin 				nv_onattr(L_ARGNOD,NV_NOFREE);
22148462SApril.Chin@Sun.COM 				shp->lastarg = strcpy(lastarg,comn);
22154887Schin 			}
22164887Schin 			else
22174887Schin 			{
22184887Schin 				nv_offattr(L_ARGNOD,NV_NOFREE);
22198462SApril.Chin@Sun.COM 				shp->lastarg = strdup(comn);
22204887Schin 			}
22214887Schin 		}
22224887Schin 		if(!skipexitset)
22234887Schin 			exitset();
22244887Schin 		if(!(OPTIMIZE))
22254887Schin 		{
22268462SApril.Chin@Sun.COM 			if(sav != stkptr(stkp,0))
22278462SApril.Chin@Sun.COM 				stkset(stkp,sav,0);
22288462SApril.Chin@Sun.COM 			else if(stktell(stkp))
22298462SApril.Chin@Sun.COM 				stkseek(stkp,0);
22304887Schin 		}
22318462SApril.Chin@Sun.COM 		if(shp->trapnote&SH_SIGSET)
22328462SApril.Chin@Sun.COM 			sh_exit(SH_EXITSIG|shp->lastsig);
22334887Schin 		if(was_interactive)
22344887Schin 			sh_onstate(SH_INTERACTIVE);
22354887Schin 		if(was_monitor && sh_isoption(SH_MONITOR))
22364887Schin 			sh_onstate(SH_MONITOR);
22374887Schin 		if(was_errexit)
22384887Schin 			sh_onstate(SH_ERREXIT);
22394887Schin 	}
22408462SApril.Chin@Sun.COM 	return(shp->exitval);
22418462SApril.Chin@Sun.COM }
22428462SApril.Chin@Sun.COM 
22438462SApril.Chin@Sun.COM int sh_run(int argn, char *argv[])
22448462SApril.Chin@Sun.COM {
22458462SApril.Chin@Sun.COM 	register struct dolnod	*dp;
22468462SApril.Chin@Sun.COM 	register struct comnod	*t = (struct comnod*)stakalloc(sizeof(struct comnod));
22478462SApril.Chin@Sun.COM 	int			savtop = staktell();
22488462SApril.Chin@Sun.COM 	char			*savptr = stakfreeze(0);
22498462SApril.Chin@Sun.COM 	Opt_t			*op, *np = optctx(0, 0);
22508462SApril.Chin@Sun.COM 	Shbltin_t		bltindata;
22518462SApril.Chin@Sun.COM 	bltindata = sh.bltindata;
22528462SApril.Chin@Sun.COM 	op = optctx(np, 0);
22538462SApril.Chin@Sun.COM 	memset(t, 0, sizeof(struct comnod));
22548462SApril.Chin@Sun.COM 	dp = (struct dolnod*)stakalloc((unsigned)sizeof(struct dolnod) + ARG_SPARE*sizeof(char*) + argn*sizeof(char*));
22558462SApril.Chin@Sun.COM 	dp->dolnum = argn;
22568462SApril.Chin@Sun.COM 	dp->dolbot = ARG_SPARE;
22578462SApril.Chin@Sun.COM 	memcpy(dp->dolval+ARG_SPARE, argv, (argn+1)*sizeof(char*));
22588462SApril.Chin@Sun.COM 	t->comarg = (struct argnod*)dp;
22598462SApril.Chin@Sun.COM 	if(!strchr(argv[0],'/'))
22608462SApril.Chin@Sun.COM 		t->comnamp = (void*)nv_bfsearch(argv[0],sh.fun_tree,(Namval_t**)&t->comnamq,(char**)0);
22618462SApril.Chin@Sun.COM 	argn=sh_exec((Shnode_t*)t,sh_isstate(SH_ERREXIT));
22628462SApril.Chin@Sun.COM 	optctx(op,np);
22638462SApril.Chin@Sun.COM 	sh.bltindata = bltindata;
22648462SApril.Chin@Sun.COM 	if(savptr!=stakptr(0))
22658462SApril.Chin@Sun.COM 		stakset(savptr,savtop);
22668462SApril.Chin@Sun.COM 	else
22678462SApril.Chin@Sun.COM 		stakseek(savtop);
22688462SApril.Chin@Sun.COM 	return(argn);
22694887Schin }
22704887Schin 
22714887Schin /*
22724887Schin  * test for equality with second argument trimmed
22734887Schin  * returns 1 if r == trim(s) otherwise 0
22744887Schin  */
22754887Schin 
22764887Schin static int trim_eq(register const char *r,register const char *s)
22774887Schin {
22784887Schin 	register char c;
22794887Schin 	while(c = *s++)
22804887Schin 	{
22814887Schin 		if(c=='\\')
22824887Schin 			c = *s++;
22834887Schin 		if(c && c != *r++)
22844887Schin 			return(0);
22854887Schin 	}
22864887Schin 	return(*r==0);
22874887Schin }
22884887Schin 
22894887Schin /*
22904887Schin  * print out the command line if set -x is on
22914887Schin  */
22924887Schin 
22934887Schin int sh_trace(register char *argv[], register int nl)
22944887Schin {
22958462SApril.Chin@Sun.COM 	Shell_t	*shp = &sh;
22964887Schin 	register char *cp;
22974887Schin 	register int bracket = 0;
22988462SApril.Chin@Sun.COM 	int decl = (nl&2);
22998462SApril.Chin@Sun.COM 	nl &= ~2;
23004887Schin 	if(sh_isoption(SH_XTRACE))
23014887Schin 	{
23024887Schin 		/* make this trace atomic */
23034887Schin 		sfset(sfstderr,SF_SHARE|SF_PUBLIC,0);
23048462SApril.Chin@Sun.COM 		if(!(cp=nv_getval(sh_scoped(shp,PS4NOD))))
23054887Schin 			cp = "+ ";
23064887Schin 		else
23074887Schin 		{
23084887Schin 			sh_offoption(SH_XTRACE);
23098462SApril.Chin@Sun.COM 			cp = sh_mactry(shp,cp);
23104887Schin 			sh_onoption(SH_XTRACE);
23114887Schin 		}
23124887Schin 		if(*cp)
23134887Schin 			sfputr(sfstderr,cp,-1);
23144887Schin 		if(argv)
23154887Schin 		{
23164887Schin 			char *argv0 = *argv;
23174887Schin 			nl = (nl?'\n':-1);
23184887Schin 			/* don't quote [ and [[ */
23194887Schin 			if(*(cp=argv[0])=='[' && (!cp[1] || !cp[2]&&cp[1]=='['))
23204887Schin 			{
23214887Schin 				sfputr(sfstderr,cp,*++argv?' ':nl);
23224887Schin 				bracket = 1;
23234887Schin 			}
23244887Schin 			while(cp = *argv++)
23254887Schin 			{
23264887Schin 				if(bracket==0 || *argv || *cp!=']')
23274887Schin 					cp = sh_fmtq(cp);
23288462SApril.Chin@Sun.COM 				if(decl && shp->prefix && cp!=argv0 && *cp!='-')
23294887Schin 				{
23304887Schin 					if(*cp=='.' && cp[1]==0)
23318462SApril.Chin@Sun.COM 						cp = shp->prefix;
23324887Schin 					else
23338462SApril.Chin@Sun.COM 						sfputr(sfstderr,shp->prefix,'.');
23344887Schin 				}
23354887Schin 				sfputr(sfstderr,cp,*argv?' ':nl);
23364887Schin 			}
23374887Schin 			sfset(sfstderr,SF_SHARE|SF_PUBLIC,1);
23384887Schin 		}
23394887Schin 		return(1);
23404887Schin 	}
23414887Schin 	return(0);
23424887Schin }
23434887Schin 
23444887Schin /*
23454887Schin  * This routine creates a subshell by calling fork() or vfork()
23464887Schin  * If ((flags&COMASK)==TCOM), then vfork() is permitted
23474887Schin  * If fork fails, the shell sleeps for exponentially longer periods
23484887Schin  *   and tries again until a limit is reached.
23494887Schin  * SH_FORKLIM is the max period between forks - power of 2 usually.
23504887Schin  * Currently shell tries after 2,4,8,16, and 32 seconds and then quits
23514887Schin  * Failures cause the routine to error exit.
23524887Schin  * Parent links to here-documents are removed by the child
23534887Schin  * Traps are reset by the child
23544887Schin  * The process-id of the child is returned to the parent, 0 to the child.
23554887Schin  */
23564887Schin 
23574887Schin static void timed_out(void *handle)
23584887Schin {
23594887Schin 	NOT_USED(handle);
23604887Schin 	timeout = 0;
23614887Schin }
23624887Schin 
23634887Schin 
23644887Schin /*
23654887Schin  * called by parent and child after fork by sh_fork()
23664887Schin  */
23674887Schin pid_t _sh_fork(register pid_t parent,int flags,int *jobid)
23684887Schin {
23694887Schin 	static long forkcnt = 1000L;
23708462SApril.Chin@Sun.COM 	Shell_t	*shp = &sh;
23714887Schin 	pid_t	curpgid = job.curpgid;
23724887Schin 	pid_t	postid = (flags&FAMP)?0:curpgid;
23738462SApril.Chin@Sun.COM 	int	sig,nochild;
23744887Schin 	if(parent<0)
23754887Schin 	{
23768462SApril.Chin@Sun.COM 		sh_sigcheck();
23774887Schin 		if((forkcnt *= 2) > 1000L*SH_FORKLIM)
23784887Schin 		{
23794887Schin 			forkcnt=1000L;
23804887Schin 			errormsg(SH_DICT,ERROR_system(ERROR_NOEXEC),e_nofork);
23814887Schin 		}
23824887Schin 		timeout = (void*)sh_timeradd(forkcnt, 0, timed_out, NIL(void*));
23838462SApril.Chin@Sun.COM 		nochild = job_wait((pid_t)1);
23844887Schin 		if(timeout)
23854887Schin 		{
23868462SApril.Chin@Sun.COM 			if(nochild)
23878462SApril.Chin@Sun.COM 				pause();
23888462SApril.Chin@Sun.COM 			else if(forkcnt>1000L)
23898462SApril.Chin@Sun.COM 				forkcnt /= 2;
23904887Schin 			timerdel(timeout);
23918462SApril.Chin@Sun.COM 			timeout = 0;
23924887Schin 		}
23934887Schin 		return(-1);
23944887Schin 	}
23958462SApril.Chin@Sun.COM 	forkcnt = 1000L;
23964887Schin 	if(parent)
23974887Schin 	{
23988462SApril.Chin@Sun.COM 		int myjob,waitall=job.waitall;
23998462SApril.Chin@Sun.COM 		shp->nforks++;
24004887Schin 		if(job.toclear)
24014887Schin 			job_clear();
24028462SApril.Chin@Sun.COM 		job.waitall = waitall;
24034887Schin #ifdef JOBS
24044887Schin 		/* first process defines process group */
24054887Schin 		if(sh_isstate(SH_MONITOR))
24064887Schin 		{
24074887Schin 			/*
24084887Schin 			 * errno==EPERM means that an earlier processes
24094887Schin 			 * completed.  Make parent the job group id.
24104887Schin 			 */
24114887Schin 			if(postid==0)
24124887Schin 				job.curpgid = parent;
24134887Schin 			if(job.jobcontrol || (flags&FAMP))
24144887Schin 			{
24154887Schin 				if(setpgid(parent,job.curpgid)<0 && errno==EPERM)
24164887Schin 					setpgid(parent,parent);
24174887Schin 			}
24184887Schin 		}
24194887Schin #endif /* JOBS */
24204887Schin 		if(!sh_isstate(SH_MONITOR) && job.waitall && postid==0)
24214887Schin 			job.curpgid = parent;
24224887Schin 		if(flags&FCOOP)
24238462SApril.Chin@Sun.COM 			shp->cpid = parent;
2424*10898Sroland.mainz@nrubsig.org #ifdef SHOPT_BGX
2425*10898Sroland.mainz@nrubsig.org 		if(!postid && (flags&(FAMP|FINT)) == (FAMP|FINT))
2426*10898Sroland.mainz@nrubsig.org 			postid = 1;
24274887Schin 		myjob = job_post(parent,postid);
2428*10898Sroland.mainz@nrubsig.org 		if(postid==1)
2429*10898Sroland.mainz@nrubsig.org 			postid = 0;
2430*10898Sroland.mainz@nrubsig.org #else
2431*10898Sroland.mainz@nrubsig.org 		myjob = job_post(parent,postid);
2432*10898Sroland.mainz@nrubsig.org #endif /* SHOPT_BGX */
24334887Schin 		if(flags&FAMP)
24344887Schin 			job.curpgid = curpgid;
24354887Schin 		if(jobid)
24364887Schin 			*jobid = myjob;
24374887Schin 		return(parent);
24384887Schin 	}
24394887Schin #if !_std_malloc
24404887Schin 	vmtrace(-1);
24414887Schin #endif
24424887Schin 	/* This is the child process */
24438462SApril.Chin@Sun.COM 	if(shp->trapnote&SH_SIGTERM)
24444887Schin 		sh_exit(SH_EXITSIG|SIGTERM);
24458462SApril.Chin@Sun.COM 	shp->nforks=0;
24464887Schin 	timerdel(NIL(void*));
24474887Schin #ifdef JOBS
24484887Schin 	if(!job.jobcontrol && !(flags&FAMP))
24494887Schin 		sh_offstate(SH_MONITOR);
24504887Schin 	if(sh_isstate(SH_MONITOR))
24514887Schin 	{
24524887Schin 		parent = getpid();
24534887Schin 		if(postid==0)
24544887Schin 			job.curpgid = parent;
24554887Schin 		while(setpgid(0,job.curpgid)<0 && job.curpgid!=parent)
24564887Schin 			job.curpgid = parent;
24574887Schin #   ifdef SIGTSTP
24584887Schin 		if(job.curpgid==parent &&  !(flags&FAMP))
24594887Schin 			tcsetpgrp(job.fd,job.curpgid);
24604887Schin #   endif /* SIGTSTP */
24614887Schin 	}
24624887Schin #   ifdef SIGTSTP
24634887Schin 	if(job.jobcontrol)
24644887Schin 	{
24654887Schin 		signal(SIGTTIN,SIG_DFL);
24664887Schin 		signal(SIGTTOU,SIG_DFL);
24674887Schin 		signal(SIGTSTP,SIG_DFL);
24684887Schin 	}
24694887Schin #   endif /* SIGTSTP */
24704887Schin 	job.jobcontrol = 0;
24714887Schin #endif /* JOBS */
24724887Schin 	job.toclear = 1;
24738462SApril.Chin@Sun.COM 	shp->login_sh = 0;
24744887Schin 	sh_offoption(SH_LOGIN_SHELL);
24754887Schin 	sh_onstate(SH_FORKED);
24764887Schin 	sh_onstate(SH_NOLOG);
24778462SApril.Chin@Sun.COM 	if (shp->fn_reset)
24788462SApril.Chin@Sun.COM 		shp->fn_depth = shp->fn_reset = 0;
24794887Schin #if SHOPT_ACCT
24804887Schin 	sh_accsusp();
24814887Schin #endif	/* SHOPT_ACCT */
24824887Schin 	/* Reset remaining signals to parent */
24834887Schin 	/* except for those `lost' by trap   */
2484*10898Sroland.mainz@nrubsig.org 	if(!(flags&FSHOWME))
2485*10898Sroland.mainz@nrubsig.org 		sh_sigreset(2);
24868462SApril.Chin@Sun.COM 	shp->subshell = 0;
24878462SApril.Chin@Sun.COM 	if((flags&FAMP) && shp->coutpipe>1)
24888462SApril.Chin@Sun.COM 		sh_close(shp->coutpipe);
24898462SApril.Chin@Sun.COM 	sig = shp->savesig;
24908462SApril.Chin@Sun.COM 	shp->savesig = 0;
24914887Schin 	if(sig>0)
24924887Schin 		sh_fault(sig);
24934887Schin 	sh_sigcheck();
24944887Schin 	return(0);
24954887Schin }
24964887Schin 
24974887Schin pid_t sh_fork(int flags, int *jobid)
24984887Schin {
24994887Schin 	register pid_t parent;
25004887Schin 	register int sig;
25014887Schin #if SHOPT_FASTPIPE
25024887Schin 	if(sffileno(sfstdin)<0)
25034887Schin 	{
25044887Schin 		off_t current = sfseek(sfstdin,(off_t)0,SEEK_CUR);
25054887Schin 		sfseek(sfstdin,(off_t)0,SEEK_END);
25064887Schin 		sfdisc(sfstdin,SF_POPDISC);
25074887Schin 		fcntl(sffileno(sfstdin),F_SETFD,0);
25084887Schin 		sh_iostream(0);
25094887Schin 		sfseek(sfstdin,current,SEEK_SET);
25104887Schin 	}
25114887Schin #endif /* SHOPT_FASTPIPE */
25124887Schin 	if(!sh.pathlist)
25134887Schin 		path_get("");
25144887Schin 	sfsync(NIL(Sfio_t*));
25154887Schin 	sh.trapnote &= ~SH_SIGTERM;
25164887Schin 	job_fork(-1);
25174887Schin 	sh.savesig = -1;
25184887Schin 	while(_sh_fork(parent=fork(),flags,jobid) < 0);
25198462SApril.Chin@Sun.COM 	sh_stats(STAT_FORKS);
25204887Schin 	sig = sh.savesig;
25214887Schin 	sh.savesig = 0;
25224887Schin 	if(sig>0)
25234887Schin 		sh_fault(sig);
25244887Schin 	job_fork(parent);
25254887Schin 	return(parent);
25264887Schin }
25274887Schin 
25284887Schin /*
25294887Schin  * add exports from previous scope to the new scope
25304887Schin  */
25314887Schin static void  local_exports(register Namval_t *np, void *data)
25324887Schin {
25334887Schin 	register Namval_t	*mp;
25344887Schin 	register char		*cp;
25354887Schin 	if(nv_isarray(np))
25364887Schin 		nv_putsub(np,NIL(char*),0);
25374887Schin 	if((cp = nv_getval(np)) && (mp = nv_search(nv_name(np), sh.var_tree, NV_ADD|HASH_NOSCOPE)) && nv_isnull(mp))
25384887Schin 		nv_putval(mp, cp, 0);
25394887Schin }
25404887Schin 
25414887Schin /*
25424887Schin  * This routine is used to execute the given function <fun> in a new scope
25434887Schin  * If <fun> is NULL, then arg points to a structure containing a pointer
25444887Schin  *  to a function that will be executed in the current environment.
25454887Schin  */
25464887Schin int sh_funscope(int argn, char *argv[],int(*fun)(void*),void *arg,int execflg)
25474887Schin {
25488462SApril.Chin@Sun.COM 	register char		*trap;
25498462SApril.Chin@Sun.COM 	register int		nsig;
25508462SApril.Chin@Sun.COM 	register Shell_t	*shp =  &sh;
25518462SApril.Chin@Sun.COM 	struct dolnod		*argsav=0,*saveargfor;
25528462SApril.Chin@Sun.COM 	struct sh_scoped	savst, *prevscope = shp->st.self;
25538462SApril.Chin@Sun.COM 	struct argnod		*envlist=0;
25548462SApril.Chin@Sun.COM 	int			jmpval;
25558462SApril.Chin@Sun.COM 	volatile int		r = 0;
25568462SApril.Chin@Sun.COM 	char 			*savstak;
25578462SApril.Chin@Sun.COM 	struct funenv		*fp;
25588462SApril.Chin@Sun.COM 	struct checkpt		buff;
25598462SApril.Chin@Sun.COM 	Namval_t		*nspace = shp->namespace;
2560*10898Sroland.mainz@nrubsig.org 	Dt_t			*last_root = shp->last_root;
2561*10898Sroland.mainz@nrubsig.org 	Shopt_t			options = shp->options;
25628462SApril.Chin@Sun.COM 	if(shp->fn_depth==0)
25638462SApril.Chin@Sun.COM 		shp->glob_options =  shp->options;
25648462SApril.Chin@Sun.COM 	else
25658462SApril.Chin@Sun.COM 		shp->options = shp->glob_options;
25668462SApril.Chin@Sun.COM #if 0
25678462SApril.Chin@Sun.COM 	shp->st.lineno = error_info.line;
25688462SApril.Chin@Sun.COM #endif
25698462SApril.Chin@Sun.COM 	*prevscope = shp->st;
25704887Schin 	sh_offoption(SH_ERREXIT);
25718462SApril.Chin@Sun.COM 	shp->st.prevst = prevscope;
25728462SApril.Chin@Sun.COM 	shp->st.self = &savst;
25738462SApril.Chin@Sun.COM 	shp->topscope = (Shscope_t*)shp->st.self;
25748462SApril.Chin@Sun.COM 	shp->st.opterror = shp->st.optchar = 0;
25758462SApril.Chin@Sun.COM 	shp->st.optindex = 1;
25768462SApril.Chin@Sun.COM 	shp->st.loopcnt = 0;
25774887Schin 	if(!fun)
25784887Schin 	{
25794887Schin 		fp = (struct funenv*)arg;
25808462SApril.Chin@Sun.COM 		shp->st.real_fun = (fp->node)->nvalue.rp;
25814887Schin 		envlist = fp->env;
25824887Schin 	}
25838462SApril.Chin@Sun.COM 	prevscope->save_tree = shp->var_tree;
25848462SApril.Chin@Sun.COM 	sh_scope(shp,envlist,1);
25858462SApril.Chin@Sun.COM 	if(dtvnext(prevscope->save_tree)!= (shp->namespace?shp->var_base:0))
25864887Schin 	{
25874887Schin 		/* eliminate parent scope */
25884887Schin 		nv_scan(prevscope->save_tree, local_exports,(void*)0, NV_EXPORT, NV_EXPORT|NV_NOSCOPE);
25894887Schin 	}
25908462SApril.Chin@Sun.COM 	shp->st.save_tree = shp->var_tree;
25914887Schin 	if(!fun)
25924887Schin 	{
25934887Schin 		Namval_t *np;
25944887Schin 		if(nv_isattr(fp->node,NV_TAGGED))
25954887Schin 			sh_onoption(SH_XTRACE);
25964887Schin 		else
25974887Schin 			sh_offoption(SH_XTRACE);
25984887Schin #if SHOPT_NAMESPACE
25998462SApril.Chin@Sun.COM 		if((np=(fp->node)->nvalue.rp->nspace) && np!=shp->namespace)
26004887Schin 		{
26018462SApril.Chin@Sun.COM 			Dt_t *dt = shp->var_tree;
26024887Schin 			dtview(dt,0);
26034887Schin 			dtview(dt,nv_dict(np));
26048462SApril.Chin@Sun.COM 			shp->var_tree = nv_dict(np);
26058462SApril.Chin@Sun.COM 			shp->namespace = np;
26064887Schin 		}
26074887Schin #endif /* SHOPT_NAMESPACE */
26084887Schin 	}
26098462SApril.Chin@Sun.COM 	shp->st.cmdname = argv[0];
26104887Schin 	/* save trap table */
26118462SApril.Chin@Sun.COM 	if((nsig=shp->st.trapmax*sizeof(char*))>0 || shp->st.trapcom[0])
26124887Schin 	{
26134887Schin 		nsig += sizeof(char*);
26148462SApril.Chin@Sun.COM 		memcpy(savstak=stakalloc(nsig),(char*)&shp->st.trapcom[0],nsig);
26154887Schin 	}
26164887Schin 	sh_sigreset(0);
26178462SApril.Chin@Sun.COM 	argsav = sh_argnew(shp,argv,&saveargfor);
26184887Schin 	sh_pushcontext(&buff,SH_JMPFUN);
26194887Schin 	errorpush(&buff.err,0);
26204887Schin 	error_info.id = argv[0];
26218462SApril.Chin@Sun.COM 	shp->st.var_local = shp->var_tree;
26224887Schin 	jmpval = sigsetjmp(buff.buff,0);
26234887Schin 	if(!fun)
26244887Schin 	{
26258462SApril.Chin@Sun.COM 		shp->st.filename = fp->node->nvalue.rp->fname;
26268462SApril.Chin@Sun.COM 		shp->st.funname = nv_name(fp->node);
26278462SApril.Chin@Sun.COM 		nv_putval(SH_PATHNAMENOD,shp->st.filename,NV_NOFREE);
26288462SApril.Chin@Sun.COM 		nv_putval(SH_FUNNAMENOD,shp->st.funname,NV_NOFREE);
26294887Schin 	}
26304887Schin 	if(jmpval == 0)
26314887Schin 	{
26328462SApril.Chin@Sun.COM 		if(shp->fn_depth++ > MAXDEPTH)
2633*10898Sroland.mainz@nrubsig.org 		{
2634*10898Sroland.mainz@nrubsig.org 			shp->toomany = 1;
26358462SApril.Chin@Sun.COM 			siglongjmp(*shp->jmplist,SH_JMPERRFN);
2636*10898Sroland.mainz@nrubsig.org 		}
26374887Schin 		else if(fun)
26384887Schin 			r= (*fun)(arg);
26394887Schin 		else
26404887Schin 		{
26414887Schin 			sh_exec((Shnode_t*)(nv_funtree((fp->node))),execflg|SH_ERREXIT);
26428462SApril.Chin@Sun.COM 			r = shp->exitval;
26434887Schin 		}
26444887Schin 	}
26458462SApril.Chin@Sun.COM 	if(--shp->fn_depth==1 && jmpval==SH_JMPERRFN)
26464887Schin 		errormsg(SH_DICT,ERROR_exit(1),e_toodeep,argv[0]);
26474887Schin 	sh_popcontext(&buff);
26488462SApril.Chin@Sun.COM 	if (shp->st.self != &savst)
26498462SApril.Chin@Sun.COM 		shp->var_tree = (Dt_t*)savst.save_tree;
26508462SApril.Chin@Sun.COM 	sh_unscope(shp);
26518462SApril.Chin@Sun.COM 	shp->namespace = nspace;
26528462SApril.Chin@Sun.COM 	shp->var_tree = (Dt_t*)prevscope->save_tree;
26538462SApril.Chin@Sun.COM 	if(shp->topscope != (Shscope_t*)shp->st.self)
26548462SApril.Chin@Sun.COM 		sh_setscope(shp->topscope);
26558462SApril.Chin@Sun.COM 	sh_argreset(shp,argsav,saveargfor);
26568462SApril.Chin@Sun.COM 	trap = shp->st.trapcom[0];
26578462SApril.Chin@Sun.COM 	shp->st.trapcom[0] = 0;
26584887Schin 	sh_sigreset(1);
26598462SApril.Chin@Sun.COM 	if (shp->st.self != &savst)
26608462SApril.Chin@Sun.COM 		*shp->st.self = shp->st;
26618462SApril.Chin@Sun.COM 	shp->st = *prevscope;
26628462SApril.Chin@Sun.COM 	shp->topscope = (Shscope_t*)prevscope;
26638462SApril.Chin@Sun.COM 	nv_getval(sh_scoped(shp,IFSNOD));
26644887Schin 	if(nsig)
26658462SApril.Chin@Sun.COM 		memcpy((char*)&shp->st.trapcom[0],savstak,nsig);
26668462SApril.Chin@Sun.COM 	shp->trapnote=0;
26674887Schin 	if(nsig)
26684887Schin 		stakset(savstak,0);
2669*10898Sroland.mainz@nrubsig.org 	shp->options = options;
2670*10898Sroland.mainz@nrubsig.org 	shp->last_root = last_root;
26714887Schin 	if(trap)
26724887Schin 	{
26734887Schin 		sh_trap(trap,0);
26744887Schin 		free(trap);
26754887Schin 	}
26768462SApril.Chin@Sun.COM 	if(shp->exitval > SH_EXITSIG)
26778462SApril.Chin@Sun.COM 		sh_fault(shp->exitval&SH_EXITMASK);
26784887Schin 	if(jmpval > SH_JMPFUN)
26794887Schin 	{
26804887Schin 		sh_chktrap();
26818462SApril.Chin@Sun.COM 		siglongjmp(*shp->jmplist,jmpval);
26824887Schin 	}
26834887Schin 	return(r);
26844887Schin }
26854887Schin 
26868462SApril.Chin@Sun.COM static void sh_funct(Shell_t *shp,Namval_t *np,int argn, char *argv[],struct argnod *envlist,int execflg)
26874887Schin {
26884887Schin 	struct funenv fun;
26894887Schin 	char *fname = nv_getval(SH_FUNNAMENOD);
26908462SApril.Chin@Sun.COM 	struct Level	*lp =(struct Level*)(SH_LEVELNOD->nvfun);
2691*10898Sroland.mainz@nrubsig.org 	int		level, pipepid=shp->pipepid;
2692*10898Sroland.mainz@nrubsig.org 	shp->pipepid = 0;
26938462SApril.Chin@Sun.COM 	sh_stats(STAT_FUNCT);
26948462SApril.Chin@Sun.COM 	if(!lp->hdr.disc)
26958462SApril.Chin@Sun.COM 		lp = init_level(0);
26968462SApril.Chin@Sun.COM 	if((struct sh_scoped*)shp->topscope != shp->st.self)
26978462SApril.Chin@Sun.COM 		sh_setscope(shp->topscope);
26988462SApril.Chin@Sun.COM 	level = lp->maxlevel = shp->dot_depth + shp->fn_depth+1;
26998462SApril.Chin@Sun.COM 	SH_LEVELNOD->nvalue.s = lp->maxlevel;
27008462SApril.Chin@Sun.COM 	shp->st.lineno = error_info.line;
27014887Schin 	if(nv_isattr(np,NV_FPOSIX))
27024887Schin 	{
27034887Schin 		char *save;
27048462SApril.Chin@Sun.COM 		int loopcnt = shp->st.loopcnt;
27058462SApril.Chin@Sun.COM 		shp->posix_fun = np;
27068462SApril.Chin@Sun.COM 		save = argv[-1];
27078462SApril.Chin@Sun.COM 		argv[-1] = 0;
27088462SApril.Chin@Sun.COM 		shp->st.funname = nv_name(np);
27098462SApril.Chin@Sun.COM 		nv_putval(SH_FUNNAMENOD, nv_name(np),NV_NOFREE);
27104887Schin 		opt_info.index = opt_info.offset = 0;
27114887Schin 		error_info.errors = 0;
27128462SApril.Chin@Sun.COM 		shp->st.loopcnt = 0;
27138462SApril.Chin@Sun.COM 		b_dot_cmd(argn+1,argv-1,&shp->bltindata);
27148462SApril.Chin@Sun.COM 		shp->st.loopcnt = loopcnt;
27154887Schin 		argv[-1] = save;
27164887Schin 	}
27174887Schin 	else
27184887Schin 	{
27194887Schin 		fun.env = envlist;
27204887Schin 		fun.node = np;
27214887Schin 		sh_funscope(argn,argv,0,&fun,execflg);
27224887Schin 	}
27238462SApril.Chin@Sun.COM 	if(level-- != nv_getnum(SH_LEVELNOD))
27248462SApril.Chin@Sun.COM 	{
27258462SApril.Chin@Sun.COM 		Shscope_t *sp = sh_getscope(0,SEEK_END);
27268462SApril.Chin@Sun.COM 		sh_setscope(sp);
27278462SApril.Chin@Sun.COM 	}
27288462SApril.Chin@Sun.COM 	lp->maxlevel = level;
27298462SApril.Chin@Sun.COM 	SH_LEVELNOD->nvalue.s = lp->maxlevel;
27308462SApril.Chin@Sun.COM #if 0
27318462SApril.Chin@Sun.COM 	nv_putval(SH_FUNNAMENOD,shp->st.funname,NV_NOFREE);
27328462SApril.Chin@Sun.COM #else
27334887Schin 	nv_putval(SH_FUNNAMENOD,fname,NV_NOFREE);
27348462SApril.Chin@Sun.COM #endif
27358462SApril.Chin@Sun.COM 	nv_putval(SH_PATHNAMENOD,shp->st.filename,NV_NOFREE);
2736*10898Sroland.mainz@nrubsig.org 	shp->pipepid = pipepid;
27374887Schin }
27384887Schin 
27394887Schin /*
27404887Schin  * external interface to execute a function without arguments
27414887Schin  * <np> is the function node
27424887Schin  * If <nq> is not-null, then sh.name and sh.subscript will be set
27434887Schin  */
27444887Schin int sh_fun(Namval_t *np, Namval_t *nq, char *argv[])
27454887Schin {
27468462SApril.Chin@Sun.COM 	Shell_t		*shp = &sh;
27474887Schin 	register int offset;
27484887Schin 	register char *base;
27494887Schin 	Namval_t node;
27508462SApril.Chin@Sun.COM 	struct Namref	nr;
27518462SApril.Chin@Sun.COM 	long		mode;
27528462SApril.Chin@Sun.COM 	char		*prefix = shp->prefix;
27534887Schin 	int n=0;
27544887Schin 	char *av[2];
27554887Schin 	Fcin_t save;
27564887Schin 	fcsave(&save);
27574887Schin 	if((offset=staktell())>0)
27584887Schin 		base=stakfreeze(0);
27598462SApril.Chin@Sun.COM 	shp->prefix = 0;
27604887Schin 	if(!argv)
27614887Schin 	{
27624887Schin 		argv = av;
27634887Schin 		argv[1]=0;
27644887Schin 	}
27654887Schin 	argv[0] = nv_name(np);
27664887Schin 	while(argv[n])
27674887Schin 		n++;
27684887Schin 	if(nq)
27698462SApril.Chin@Sun.COM 		mode = set_instance(nq,&node, &nr);
27704887Schin 	if(is_abuiltin(np))
27714887Schin 	{
27724887Schin 		int jmpval;
27734887Schin 		struct checkpt buff;
27748462SApril.Chin@Sun.COM 		Shbltin_t *bp = &sh.bltindata;
27754887Schin 		sh_pushcontext(&buff,SH_JMPCMD);
27764887Schin 		jmpval = sigsetjmp(buff.buff,1);
27774887Schin 		if(jmpval == 0)
27784887Schin 		{
27798462SApril.Chin@Sun.COM 			bp->bnode = np;
27808462SApril.Chin@Sun.COM 			bp->ptr = nv_context(np);
27814887Schin 			errorpush(&buff.err,0);
27824887Schin 			error_info.id = argv[0];
27834887Schin 			opt_info.index = opt_info.offset = 0;
27844887Schin 			opt_info.disc = 0;
27854887Schin 			sh.exitval = 0;
27868462SApril.Chin@Sun.COM 			sh.exitval = (*funptr(np))(n,argv,(void*)bp);
27874887Schin 		}
27884887Schin 		sh_popcontext(&buff);
27894887Schin 		if(jmpval>SH_JMPCMD)
27904887Schin 			siglongjmp(*sh.jmplist,jmpval);
27914887Schin 	}
27924887Schin 	else
27938462SApril.Chin@Sun.COM 		sh_funct(shp,np,n,argv,(struct argnod*)0,sh_isstate(SH_ERREXIT));
27944887Schin 	if(nq)
27958462SApril.Chin@Sun.COM 		unset_instance(nq, &node, &nr, mode);
27964887Schin 	fcrestore(&save);
27974887Schin 	if(offset>0)
27984887Schin 		stakset(base,offset);
27998462SApril.Chin@Sun.COM 	shp->prefix = prefix;
28004887Schin 	return(sh.exitval);
28014887Schin }
28024887Schin 
28034887Schin /*
28044887Schin  * This dummy routine is called by built-ins that do recursion
28054887Schin  * on the file system (chmod, chgrp, chown).  It causes
28064887Schin  * the shell to invoke the non-builtin version in this case
28074887Schin  */
28084887Schin int cmdrecurse(int argc, char* argv[], int ac, char* av[])
28094887Schin {
28104887Schin 	NOT_USED(argc);
28114887Schin 	NOT_USED(argv[0]);
28124887Schin 	NOT_USED(ac);
28134887Schin 	NOT_USED(av[0]);
28144887Schin 	return(SH_RUNPROG);
28154887Schin }
28164887Schin 
28174887Schin /*
28184887Schin  * set up pipe for cooperating process
28194887Schin  */
28208462SApril.Chin@Sun.COM static void coproc_init(Shell_t *shp, int pipes[])
28214887Schin {
28224887Schin 	int outfd;
28238462SApril.Chin@Sun.COM 	if(shp->coutpipe>=0 && shp->cpid)
28244887Schin 		errormsg(SH_DICT,ERROR_exit(1),e_pexists);
28258462SApril.Chin@Sun.COM 	shp->cpid = 0;
28268462SApril.Chin@Sun.COM 	if(shp->cpipe[0]<=0 || shp->cpipe[1]<=0)
28274887Schin 	{
28284887Schin 		/* first co-process */
28298462SApril.Chin@Sun.COM 		sh_pclose(shp->cpipe);
28308462SApril.Chin@Sun.COM 		sh_pipe(shp->cpipe);
28318462SApril.Chin@Sun.COM 		if((outfd=shp->cpipe[1]) < 10)
28324887Schin 		{
28338462SApril.Chin@Sun.COM 		        int fd=fcntl(shp->cpipe[1],F_DUPFD,10);
28344887Schin 			if(fd>=10)
28354887Schin 			{
28368462SApril.Chin@Sun.COM 			        shp->fdstatus[fd] = (shp->fdstatus[outfd]&~IOCLEX);
28374887Schin 				close(outfd);
28388462SApril.Chin@Sun.COM 			        shp->fdstatus[outfd] = IOCLOSE;
28398462SApril.Chin@Sun.COM 				shp->cpipe[1] = fd;
28404887Schin 			}
28414887Schin 		}
28428462SApril.Chin@Sun.COM 		if(fcntl(*shp->cpipe,F_SETFD,FD_CLOEXEC)>=0)
28438462SApril.Chin@Sun.COM 			shp->fdstatus[shp->cpipe[0]] |= IOCLEX;
28448462SApril.Chin@Sun.COM 		shp->fdptrs[shp->cpipe[0]] = shp->cpipe;
28454887Schin 
28468462SApril.Chin@Sun.COM 		if(fcntl(shp->cpipe[1],F_SETFD,FD_CLOEXEC) >=0)
28478462SApril.Chin@Sun.COM 			shp->fdstatus[shp->cpipe[1]] |= IOCLEX;
28484887Schin 	}
28498462SApril.Chin@Sun.COM 	shp->outpipe = shp->cpipe;
28508462SApril.Chin@Sun.COM 	sh_pipe(shp->inpipe=pipes);
28518462SApril.Chin@Sun.COM 	shp->coutpipe = shp->inpipe[1];
28528462SApril.Chin@Sun.COM 	shp->fdptrs[shp->coutpipe] = &shp->coutpipe;
28538462SApril.Chin@Sun.COM 	if(fcntl(shp->outpipe[0],F_SETFD,FD_CLOEXEC)>=0)
28548462SApril.Chin@Sun.COM 		shp->fdstatus[shp->outpipe[0]] |= IOCLEX;
28554887Schin }
28564887Schin 
28574887Schin #if SHOPT_SPAWN
28584887Schin 
28594887Schin 
28604887Schin #if SHOPT_AMP || !defined(_lib_fork)
28614887Schin /*
28624887Schin  * print out function definition
28634887Schin  */
28644887Schin static void print_fun(register Namval_t* np, void *data)
28654887Schin {
28664887Schin 	register char *format;
28674887Schin 	NOT_USED(data);
28684887Schin 	if(!is_afunction(np) || !np->nvalue.ip)
28694887Schin 		return;
28704887Schin 	if(nv_isattr(np,NV_FPOSIX))
28714887Schin 		format="%s()\n{ ";
28724887Schin 	else
28734887Schin 		format="function %s\n{ ";
28744887Schin 	sfprintf(sfstdout,format,nv_name(np));
28754887Schin 	sh_deparse(sfstdout,(Shnode_t*)(nv_funtree(np)),0);
28764887Schin 	sfwrite(sfstdout,"}\n",2);
28774887Schin }
28784887Schin 
28794887Schin /*
28804887Schin  * create a shell script consisting of t->fork.forktre and execute it
28814887Schin  */
28824887Schin static int run_subshell(const Shnode_t *t,pid_t grp)
28834887Schin {
28848462SApril.Chin@Sun.COM 	static const char prolog[] = "(print $(typeset +A);set; typeset -p; print .sh.dollar=$$;set +o)";
28854887Schin 	register int i, fd, trace = sh_isoption(SH_XTRACE);
28864887Schin 	int pin,pout;
28874887Schin 	pid_t pid;
28884887Schin 	char *arglist[2], *envlist[2], devfd[12], *cp;
28894887Schin 	Sfio_t *sp = sftmp(0);
28904887Schin 	envlist[0] = "_=" SH_ID;
28914887Schin 	envlist[1] = 0;
28924887Schin 	arglist[0] = error_info.id?error_info.id:sh.shname;
28934887Schin 	if(*arglist[0]=='-')
28944887Schin 		arglist[0]++;
28954887Schin 	arglist[1] = devfd;
28964887Schin 	strncpy(devfd,e_devfdNN,sizeof(devfd));
28974887Schin 	arglist[2] = 0;
28984887Schin 	sfstack(sfstdout,sp);
28994887Schin 	if(trace)
29004887Schin 		sh_offoption(SH_XTRACE);
29014887Schin 	sfwrite(sfstdout,"typeset -A -- ",14);
29024887Schin 	sh_trap(prolog,0);
29034887Schin 	nv_scan(sh.fun_tree, print_fun, (void*)0,0, 0);
29044887Schin 	if(sh.st.dolc>0)
29054887Schin 	{
29064887Schin 		/* pass the positional parameters */
29074887Schin 		char **argv = sh.st.dolv+1;
29084887Schin 		sfwrite(sfstdout,"set --",6);
29094887Schin 		while(*argv)
29104887Schin 			sfprintf(sfstdout," %s",sh_fmtq(*argv++));
29114887Schin 		sfputc(sfstdout,'\n');
29124887Schin 	}
29134887Schin 	pin = (sh.inpipe?sh.inpipe[1]:0);
29144887Schin 	pout = (sh.outpipe?sh.outpipe[0]:0);
29154887Schin 	for(i=3; i < 10; i++)
29164887Schin 	{
29174887Schin 		if(sh.fdstatus[i]&IOCLEX && i!=pin && i!=pout)
29184887Schin 		{
29194887Schin 			sfprintf(sfstdout,"exec %d<&%d\n",i,i);
29204887Schin 			fcntl(i,F_SETFD,0);
29214887Schin 		}
29224887Schin 	}
29234887Schin 	sfprintf(sfstdout,"LINENO=%d\n",t->fork.forkline);
29244887Schin 	if(trace)
29254887Schin 	{
29264887Schin 		sfwrite(sfstdout,"set -x\n",7);
29274887Schin 		sh_onoption(SH_XTRACE);
29284887Schin 	}
29294887Schin 	sfstack(sfstdout,NIL(Sfio_t*));
29304887Schin 	sh_deparse(sp,t->fork.forktre,0);
29314887Schin 	sfseek(sp,(Sfoff_t)0,SEEK_SET);
29324887Schin 	fd = sh_dup(sffileno(sp));
29334887Schin 	cp = devfd+8;
29344887Schin 	if(fd>9)
29354887Schin 		*cp++ = '0' + (fd/10);
29364887Schin 	*cp++ = '0' + fd%10;
29374887Schin 	*cp = 0;
29384887Schin 	sfclose(sp);
29394887Schin 	sfsync(NIL(Sfio_t*));
29404887Schin 	if(!sh.shpath)
29414887Schin 		sh.shpath = pathshell();
29424887Schin 	pid = spawnveg(sh.shpath,arglist,envlist,grp);
29434887Schin 	close(fd);
29444887Schin 	for(i=3; i < 10; i++)
29454887Schin 	{
29464887Schin 		if(sh.fdstatus[i]&IOCLEX && i!=pin && i!=pout)
29474887Schin 			fcntl(i,F_SETFD,FD_CLOEXEC);
29484887Schin 	}
29494887Schin 	if(pid <=0)
29504887Schin 		errormsg(SH_DICT,ERROR_system(ERROR_NOEXEC),e_exec,arglist[0]);
29514887Schin 	return(pid);
29524887Schin }
29534887Schin #endif /* !_lib_fork */
29544887Schin 
29554887Schin static void sigreset(int mode)
29564887Schin {
29574887Schin 	register char   *trap;
29584887Schin 	register int sig=sh.st.trapmax;
29594887Schin 	while(sig-- > 0)
29604887Schin 	{
29614887Schin 		if((trap=sh.st.trapcom[sig]) && *trap==0)
29624887Schin 			signal(sig,mode?sh_fault:SIG_IGN);
29634887Schin 	}
29644887Schin }
29654887Schin 
29664887Schin /*
29674887Schin  * A combined fork/exec for systems with slow or non-existent fork()
29684887Schin  */
29698462SApril.Chin@Sun.COM static pid_t sh_ntfork(Shell_t *shp,const Shnode_t *t,char *argv[],int *jobid,int flag)
29704887Schin {
29714887Schin 	static pid_t	spawnpid;
29724887Schin 	static int	savetype;
29734887Schin 	static int	savejobid;
29748462SApril.Chin@Sun.COM 	struct checkpt	buff;
29758462SApril.Chin@Sun.COM 	int		otype=0, jmpval;
29768462SApril.Chin@Sun.COM 	volatile int	jobwasset=0, scope=0, sigwasset=0;
29778462SApril.Chin@Sun.COM 	char		**arge, *path;
29788462SApril.Chin@Sun.COM 	volatile pid_t	grp = 0;
29798462SApril.Chin@Sun.COM 	Pathcomp_t	*pp;
29804887Schin 	if(flag)
29814887Schin 	{
29824887Schin 		otype = savetype;
29834887Schin 		savetype=0;
29844887Schin 	}
29854887Schin #   if SHOPT_AMP || !defined(_lib_fork)
29864887Schin 	if(!argv)
29874887Schin 	{
29884887Schin 		register Shnode_t *tchild = t->fork.forktre;
29894887Schin 		int optimize=0;
29904887Schin 		otype = t->tre.tretyp;
29914887Schin 		savetype = otype;
29924887Schin 		spawnpid = 0;
29934887Schin #	ifndef _lib_fork
29944887Schin 		if((tchild->tre.tretyp&COMMSK)==TCOM)
29954887Schin 		{
29964887Schin 			Namval_t *np = (Namval_t*)(tchild->com.comnamp);
29974887Schin 			if(np)
29984887Schin 			{
29994887Schin 				path = nv_name(np);
30004887Schin 				if(!nv_isattr(np,BLT_ENV))
30014887Schin 					np=0;
30024887Schin 				else if(strcmp(path,"echo")==0 || memcmp(path,"print",5)==0)
30034887Schin 					np=0;
30044887Schin 			}
30054887Schin 			else if(!tchild->com.comarg)
30064887Schin 				optimize=1;
30074887Schin 			else if(tchild->com.comtyp&COMSCAN)
30084887Schin 			{
30094887Schin 				if(tchild->com.comarg->argflag&ARG_RAW)
30104887Schin 					path = tchild->com.comarg->argval;
30114887Schin 				else
30124887Schin 					path = 0;
30134887Schin 			}
30144887Schin 			else
30154887Schin 				path = ((struct dolnod*)tchild->com.comarg)->dolval[ARG_SPARE];
30164887Schin 			if(!np && path && !nv_search(path,shp->fun_tree,0))
30174887Schin 				optimize=1;
30184887Schin 		}
30194887Schin #	endif
30204887Schin 		sh_pushcontext(&buff,SH_JMPIO);
30214887Schin 		jmpval = sigsetjmp(buff.buff,0);
30224887Schin 		{
30234887Schin 			if((otype&FINT) && !sh_isstate(SH_MONITOR))
30244887Schin 			{
30254887Schin 				signal(SIGQUIT,SIG_IGN);
30264887Schin 				signal(SIGINT,SIG_IGN);
30274887Schin 				if(!shp->st.ioset)
30284887Schin 				{
30298462SApril.Chin@Sun.COM 					sh_iosave(shp,0,buff.topfd,(char*)0);
30308462SApril.Chin@Sun.COM 					sh_iorenumber(shp,sh_chkopen(e_devnull),0);
30314887Schin 				}
30324887Schin 			}
30334887Schin 			if(otype&FPIN)
30344887Schin 			{
30354887Schin 				int fd = shp->inpipe[1];
30368462SApril.Chin@Sun.COM 				sh_iosave(shp,0,buff.topfd,(char*)0);
30378462SApril.Chin@Sun.COM 				sh_iorenumber(shp,shp->inpipe[0],0);
30384887Schin 				if(fd>=0 && (!(otype&FPOU) || (otype&FCOOP)) && fcntl(fd,F_SETFD,FD_CLOEXEC)>=0)
30394887Schin 					shp->fdstatus[fd] |= IOCLEX;
30404887Schin 			}
30414887Schin 			if(otype&FPOU)
30424887Schin 			{
30438462SApril.Chin@Sun.COM 				sh_iosave(shp,1,buff.topfd,(char*)0);
30448462SApril.Chin@Sun.COM 				sh_iorenumber(shp,sh_dup(shp->outpipe[1]),1);
30454887Schin 				if(fcntl(shp->outpipe[0],F_SETFD,FD_CLOEXEC)>=0)
30464887Schin 					shp->fdstatus[shp->outpipe[0]] |= IOCLEX;
30474887Schin 			}
30484887Schin 
30494887Schin 			if(t->fork.forkio)
30508462SApril.Chin@Sun.COM 				sh_redirect(shp,t->fork.forkio,0);
30514887Schin 			if(optimize==0)
30524887Schin 			{
30534887Schin #ifdef SIGTSTP
30544887Schin 				if(job.jobcontrol)
30554887Schin 				{
30564887Schin 					signal(SIGTTIN,SIG_DFL);
30574887Schin 					signal(SIGTTOU,SIG_DFL);
30584887Schin 				}
30594887Schin #endif /* SIGTSTP */
30604887Schin #ifdef JOBS
30614887Schin 				if(sh_isstate(SH_MONITOR) && (job.jobcontrol || (otype&FAMP)))
30624887Schin 				{
30634887Schin 					if((otype&FAMP) || job.curpgid==0)
30644887Schin 						grp = 1;
30654887Schin 					else
30664887Schin 						grp = job.curpgid;
30674887Schin 				}
30684887Schin #endif /* JOBS */
30694887Schin 				spawnpid = run_subshell(t,grp);
30704887Schin 			}
30714887Schin 			else
30724887Schin 			{
30734887Schin 				sh_exec(tchild,SH_NTFORK);
30744887Schin 				if(jobid)
30754887Schin 					*jobid = savejobid;
30764887Schin 			}
30774887Schin 		}
30784887Schin 		sh_popcontext(&buff);
30794887Schin 		if((otype&FINT) && !sh_isstate(SH_MONITOR))
30804887Schin 		{
30814887Schin 			signal(SIGQUIT,sh_fault);
30824887Schin 			signal(SIGINT,sh_fault);
30834887Schin 		}
30844887Schin 		if((otype&FPIN) && (!(otype&FPOU) || (otype&FCOOP)) && fcntl(shp->inpipe[1],F_SETFD,FD_CLOEXEC)>=0)
30854887Schin 			shp->fdstatus[shp->inpipe[1]] &= ~IOCLEX;
30864887Schin 		if(t->fork.forkio || otype)
30878462SApril.Chin@Sun.COM 			sh_iorestore(shp,buff.topfd,jmpval);
30884887Schin 		if(optimize==0)
30894887Schin 		{
30904887Schin #ifdef SIGTSTP
30914887Schin 			if(job.jobcontrol)
30924887Schin 			{
30934887Schin 				signal(SIGTTIN,SIG_IGN);
30944887Schin 				signal(SIGTTOU,SIG_IGN);
30954887Schin 			}
30964887Schin #endif /* SIGTSTP */
30974887Schin 			if(spawnpid>0)
30984887Schin 				_sh_fork(spawnpid,otype,jobid);
30994887Schin 			if(grp>0 && !(otype&FAMP))
31004887Schin 			{
31014887Schin 				while(tcsetpgrp(job.fd,job.curpgid)<0 && job.curpgid!=spawnpid)
31024887Schin 					job.curpgid = spawnpid;
31034887Schin 			}
31044887Schin 		}
31054887Schin 		savetype=0;
31064887Schin 		if(jmpval>SH_JMPIO)
31074887Schin 			siglongjmp(*shp->jmplist,jmpval);
31084887Schin 		if(spawnpid<0 && (otype&FCOOP))
31094887Schin 		{
31104887Schin 			sh_close(shp->coutpipe);
31114887Schin 			sh_close(shp->cpipe[1]);
31124887Schin 			shp->cpipe[1] = -1;
31134887Schin 			shp->coutpipe = -1;
31144887Schin 		}
31154887Schin 		shp->exitval = 0;
31164887Schin 		return(spawnpid);
31174887Schin 	}
31184887Schin #   endif /* !_lib_fork */
31194887Schin 	sh_pushcontext(&buff,SH_JMPCMD);
31204887Schin 	errorpush(&buff.err,ERROR_SILENT);
31214887Schin 	jmpval = sigsetjmp(buff.buff,0);
31224887Schin 	if(jmpval == 0)
31234887Schin 	{
31244887Schin 		if((otype&FINT) && !sh_isstate(SH_MONITOR))
31254887Schin 		{
31264887Schin 			signal(SIGQUIT,SIG_IGN);
31274887Schin 			signal(SIGINT,SIG_IGN);
31284887Schin 		}
31294887Schin 		spawnpid = -1;
31304887Schin 		if(t->com.comio)
31318462SApril.Chin@Sun.COM 			sh_redirect(shp,t->com.comio,0);
31324887Schin 		error_info.id = *argv;
31334887Schin 		if(t->com.comset)
31344887Schin 		{
31354887Schin 			scope++;
31368462SApril.Chin@Sun.COM 			sh_scope(shp,t->com.comset,0);
31374887Schin 		}
31384887Schin 		if(!strchr(path=argv[0],'/'))
31394887Schin 		{
31404887Schin 			Namval_t *np;
31414887Schin 			if((np=nv_search(path,shp->track_tree,0)) && !nv_isattr(np,NV_NOALIAS) && np->nvalue.cp)
31424887Schin 				path = nv_getval(np);
31434887Schin 			else if(path_absolute(path,NIL(Pathcomp_t*)))
31444887Schin 			{
31458462SApril.Chin@Sun.COM 			path = stkptr(shp->stk,PATH_OFFSET);
31468462SApril.Chin@Sun.COM 			stkfreeze(shp->stk,0);
31478462SApril.Chin@Sun.COM 		}
31488462SApril.Chin@Sun.COM 		else
31498462SApril.Chin@Sun.COM 		{
31508462SApril.Chin@Sun.COM 			pp=path_get(path);
31518462SApril.Chin@Sun.COM 			while(pp)
31524887Schin 			{
31538462SApril.Chin@Sun.COM 				if(pp->len==1 && *pp->name=='.')
31548462SApril.Chin@Sun.COM 					break;
31558462SApril.Chin@Sun.COM 				pp = pp->next;
31564887Schin 			}
31578462SApril.Chin@Sun.COM 			if(!pp)
31588462SApril.Chin@Sun.COM 				path = 0;
31594887Schin 		}
31608462SApril.Chin@Sun.COM 	}
31618462SApril.Chin@Sun.COM 	else if(sh_isoption(SH_RESTRICTED))
31628462SApril.Chin@Sun.COM 		errormsg(SH_DICT,ERROR_exit(1),e_restricted,path);
31638462SApril.Chin@Sun.COM 	if(!path)
31648462SApril.Chin@Sun.COM 	{
31658462SApril.Chin@Sun.COM 		spawnpid = -1;
31668462SApril.Chin@Sun.COM 		goto fail;
31678462SApril.Chin@Sun.COM 	}
31688462SApril.Chin@Sun.COM 	arge = sh_envgen();
31698462SApril.Chin@Sun.COM 	shp->exitval = 0;
31704887Schin #ifdef SIGTSTP
31714887Schin 		if(job.jobcontrol)
31724887Schin 		{
31734887Schin 			signal(SIGTTIN,SIG_DFL);
31744887Schin 			signal(SIGTTOU,SIG_DFL);
31754887Schin 			jobwasset++;
31764887Schin 		}
31774887Schin #endif /* SIGTSTP */
31784887Schin #ifdef JOBS
31794887Schin 		if(sh_isstate(SH_MONITOR) && (job.jobcontrol || (otype&FAMP)))
31804887Schin 		{
31814887Schin 			if((otype&FAMP) || job.curpgid==0)
31824887Schin 				grp = 1;
31834887Schin 			else
31844887Schin 				grp = job.curpgid;
31854887Schin 		}
31864887Schin #endif /* JOBS */
31874887Schin 
31884887Schin 		sfsync(NIL(Sfio_t*));
31894887Schin 		sigreset(0);	/* set signals to ignore */
31904887Schin 		sigwasset++;
31914887Schin 	        /* find first path that has a library component */
31924887Schin 		for(pp=path_get(argv[0]); pp && !pp->lib ; pp=pp->next);
31934887Schin 		spawnpid = path_spawn(path,argv,arge,pp,(grp<<1)|1);
31944887Schin 		if(spawnpid < 0 && errno==ENOEXEC)
31954887Schin 		{
31964887Schin 			char *devfd;
31974887Schin 			int fd = open(path,O_RDONLY);
31984887Schin 			argv[-1] = argv[0];
31994887Schin 			argv[0] = path;
32004887Schin 			if(fd>=0)
32014887Schin 			{
32024887Schin 				struct stat statb;
32034887Schin 				sfprintf(sh.strbuf,"/dev/fd/%d",fd);
32044887Schin 				if(stat(devfd=sfstruse(sh.strbuf),&statb)>=0)
32054887Schin 					argv[0] =  devfd;
32064887Schin 			}
32074887Schin 			if(!shp->shpath)
32084887Schin 				shp->shpath = pathshell();
32094887Schin 			spawnpid = path_spawn(shp->shpath,&argv[-1],arge,pp,(grp<<1)|1);
32104887Schin 			if(fd>=0)
32114887Schin 				close(fd);
32124887Schin 			argv[0] = argv[-1];
32134887Schin 		}
32144887Schin 	fail:
32154887Schin 		if(spawnpid < 0) switch(errno=shp->path_err)
32164887Schin 		{
32174887Schin 		    case ENOENT:
32184887Schin 			errormsg(SH_DICT,ERROR_system(ERROR_NOENT),e_found+4);
32194887Schin 		    default:
32204887Schin 			errormsg(SH_DICT,ERROR_system(ERROR_NOEXEC),e_exec+4);
32214887Schin 		}
32224887Schin 	}
32234887Schin 	else
32244887Schin 		exitset();
32254887Schin 	sh_popcontext(&buff);
32264887Schin 	if(buff.olist)
32274887Schin 		free_list(buff.olist);
32284887Schin #ifdef SIGTSTP
32294887Schin 	if(jobwasset)
32304887Schin 	{
32314887Schin 		signal(SIGTTIN,SIG_IGN);
32324887Schin 		signal(SIGTTOU,SIG_IGN);
32334887Schin 	}
32344887Schin #endif /* SIGTSTP */
32354887Schin 	if(sigwasset)
32364887Schin 		sigreset(1);	/* restore ignored signals */
32374887Schin 	if(scope)
32384887Schin 	{
32398462SApril.Chin@Sun.COM 		sh_unscope(shp);
32404887Schin 		if(jmpval==SH_JMPSCRIPT)
3241*10898Sroland.mainz@nrubsig.org 			nv_setlist(t->com.comset,NV_EXPORT|NV_IDENT|NV_ASSIGN,0);
32424887Schin 	}
32434887Schin 	if(t->com.comio)
32448462SApril.Chin@Sun.COM 		sh_iorestore(shp,buff.topfd,jmpval);
32454887Schin 	if(jmpval>SH_JMPCMD)
32464887Schin 		siglongjmp(*shp->jmplist,jmpval);
32474887Schin 	if(spawnpid>0)
32484887Schin 	{
32494887Schin 		_sh_fork(spawnpid,otype,jobid);
32504887Schin #ifdef JOBS
32514887Schin 		if(grp==1)
32524887Schin 			job.curpgid = spawnpid;
32534887Schin #   ifdef SIGTSTP
32544887Schin 		if(grp>0 && !(otype&FAMP))
32554887Schin 		{
32564887Schin 			while(tcsetpgrp(job.fd,job.curpgid)<0 && job.curpgid!=spawnpid)
32574887Schin 				job.curpgid = spawnpid;
32584887Schin 		}
32594887Schin #   endif /* SIGTSTP */
32604887Schin #endif /* JOBS */
32614887Schin 		savejobid = *jobid;
32624887Schin 		if(otype)
32634887Schin 			return(0);
32644887Schin 	}
32654887Schin 	return(spawnpid);
32664887Schin }
32674887Schin 
32684887Schin #   ifdef _was_lib_fork
32694887Schin #	define _lib_fork	1
32704887Schin #   endif
32714887Schin #   ifndef _lib_fork
32724887Schin 	pid_t fork(void)
32734887Schin 	{
32744887Schin 		errormsg(SH_DICT,ERROR_exit(3),e_notimp,"fork");
32754887Schin 		return(-1);
32764887Schin 	}
32774887Schin #   endif /* _lib_fork */
32784887Schin #endif /* SHOPT_SPAWN */
3279