1*4887Schin /***********************************************************************
2*4887Schin *                                                                      *
3*4887Schin *               This software is part of the ast package               *
4*4887Schin *           Copyright (c) 1982-2007 AT&T Knowledge Ventures            *
5*4887Schin *                      and is licensed under the                       *
6*4887Schin *                  Common Public License, Version 1.0                  *
7*4887Schin *                      by AT&T Knowledge Ventures                      *
8*4887Schin *                                                                      *
9*4887Schin *                A copy of the License is available at                 *
10*4887Schin *            http://www.opensource.org/licenses/cpl1.0.txt             *
11*4887Schin *         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
12*4887Schin *                                                                      *
13*4887Schin *              Information and Software Systems Research               *
14*4887Schin *                            AT&T Research                             *
15*4887Schin *                           Florham Park NJ                            *
16*4887Schin *                                                                      *
17*4887Schin *                  David Korn <dgk@research.att.com>                   *
18*4887Schin *                                                                      *
19*4887Schin ***********************************************************************/
20*4887Schin #pragma prototyped
21*4887Schin /*
22*4887Schin  * UNIX shell parse tree executer
23*4887Schin  *
24*4887Schin  *   David Korn
25*4887Schin  *   AT&T Labs
26*4887Schin  *
27*4887Schin  */
28*4887Schin 
29*4887Schin #include	"defs.h"
30*4887Schin #include	<fcin.h>
31*4887Schin #include	"variables.h"
32*4887Schin #include	"path.h"
33*4887Schin #include	"name.h"
34*4887Schin #include	"io.h"
35*4887Schin #include	"shnodes.h"
36*4887Schin #include	"jobs.h"
37*4887Schin #include	"test.h"
38*4887Schin #include	"builtins.h"
39*4887Schin #include	"FEATURE/time"
40*4887Schin #include	"FEATURE/externs"
41*4887Schin #include	"FEATURE/locale"
42*4887Schin #include	"streval.h"
43*4887Schin 
44*4887Schin #if !_std_malloc
45*4887Schin #   include	<vmalloc.h>
46*4887Schin #endif
47*4887Schin 
48*4887Schin #define SH_NTFORK	SH_TIMING
49*4887Schin 
50*4887Schin #if _lib_nice
51*4887Schin     extern int	nice(int);
52*4887Schin #endif /* _lib_nice */
53*4887Schin #if !_lib_spawnveg
54*4887Schin #   define spawnveg(a,b,c,d)    spawnve(a,b,c)
55*4887Schin #endif /* !_lib_spawnveg */
56*4887Schin #if SHOPT_SPAWN
57*4887Schin     static pid_t sh_ntfork(const Shnode_t*,char*[],int*,int);
58*4887Schin #endif /* SHOPT_SPAWN */
59*4887Schin 
60*4887Schin static void	sh_funct(Namval_t*, int, char*[], struct argnod*,int);
61*4887Schin static int	trim_eq(const char*, const char*);
62*4887Schin static void	coproc_init(int pipes[]);
63*4887Schin 
64*4887Schin static void	*timeout;
65*4887Schin static char	pipejob;
66*4887Schin 
67*4887Schin struct funenv
68*4887Schin {
69*4887Schin 	Namval_t	*node;
70*4887Schin 	struct argnod	*env;
71*4887Schin };
72*4887Schin 
73*4887Schin /* ========	command execution	========*/
74*4887Schin 
75*4887Schin /*
76*4887Schin  * print time <t> in h:m:s format with precision <p>
77*4887Schin  */
78*4887Schin static void     l_time(Sfio_t *outfile,register clock_t t,int p)
79*4887Schin {
80*4887Schin 	register int  min, sec, frac;
81*4887Schin 	register int hr;
82*4887Schin 	if(p)
83*4887Schin 	{
84*4887Schin 		frac = t%sh.lim.clk_tck;
85*4887Schin 		frac = (frac*100)/sh.lim.clk_tck;
86*4887Schin 	}
87*4887Schin 	t /= sh.lim.clk_tck;
88*4887Schin 	sec = t%60;
89*4887Schin 	t /= 60;
90*4887Schin 	min = t%60;
91*4887Schin 	if(hr=t/60)
92*4887Schin 		sfprintf(outfile,"%dh",hr);
93*4887Schin 	if(p)
94*4887Schin 		sfprintf(outfile,"%dm%d%c%0*ds",min,sec,GETDECIMAL(0),p,frac);
95*4887Schin 	else
96*4887Schin 		sfprintf(outfile,"%dm%ds",min,sec);
97*4887Schin }
98*4887Schin 
99*4887Schin static int p_time(Sfio_t *out, const char *format, clock_t *tm)
100*4887Schin {
101*4887Schin 	int c,p,l,n,offset = staktell();
102*4887Schin 	const char *first;
103*4887Schin 	double d;
104*4887Schin 	for(first=format ; c= *format; format++)
105*4887Schin 	{
106*4887Schin 		if(c!='%')
107*4887Schin 			continue;
108*4887Schin 		stakwrite(first, format-first);
109*4887Schin 		n = l = 0;
110*4887Schin 		p = 3;
111*4887Schin 		if((c= *++format) == '%')
112*4887Schin 		{
113*4887Schin 			first = format;
114*4887Schin 			continue;
115*4887Schin 		}
116*4887Schin 		if(c>='0' && c <='9')
117*4887Schin 		{
118*4887Schin 			p = (c>'3')?3:(c-'0');
119*4887Schin 			c = *++format;
120*4887Schin 		}
121*4887Schin 		else if(c=='P')
122*4887Schin 		{
123*4887Schin 			if(d=tm[0])
124*4887Schin 				d = 100.*(((double)(tm[1]+tm[2]))/d);
125*4887Schin 			p = 2;
126*4887Schin 			goto skip;
127*4887Schin 		}
128*4887Schin 		if(c=='l')
129*4887Schin 		{
130*4887Schin 			l = 1;
131*4887Schin 			c = *++format;
132*4887Schin 		}
133*4887Schin 		if(c=='U')
134*4887Schin 			n = 1;
135*4887Schin 		else if(c=='S')
136*4887Schin 			n = 2;
137*4887Schin 		else if(c!='R')
138*4887Schin 		{
139*4887Schin 			stakseek(offset);
140*4887Schin 			errormsg(SH_DICT,ERROR_exit(0),e_badtformat,c);
141*4887Schin 			return(0);
142*4887Schin 		}
143*4887Schin 		d = (double)tm[n]/sh.lim.clk_tck;
144*4887Schin 	skip:
145*4887Schin 		if(l)
146*4887Schin 			l_time(stkstd, tm[n], p);
147*4887Schin 		else
148*4887Schin 			sfprintf(stkstd,"%.*f",p, d);
149*4887Schin 		first = format+1;
150*4887Schin 	}
151*4887Schin 	if(format>first)
152*4887Schin 		stakwrite(first, format-first);
153*4887Schin 	stakputc('\n');
154*4887Schin 	n = staktell()-offset;
155*4887Schin 	sfwrite(out,stakptr(offset),n);
156*4887Schin 	stakseek(offset);
157*4887Schin 	return(n);
158*4887Schin }
159*4887Schin 
160*4887Schin #if SHOPT_OPTIMIZE
161*4887Schin /*
162*4887Schin  * clear argument pointers that point into the stack
163*4887Schin  */
164*4887Schin static int p_arg(struct argnod*,int);
165*4887Schin static int p_switch(struct regnod*);
166*4887Schin static int p_comarg(register struct comnod *com)
167*4887Schin {
168*4887Schin 	Namval_t *np=com->comnamp;
169*4887Schin 	int n = p_arg(com->comset,ARG_ASSIGN);
170*4887Schin 	if(com->comarg && (com->comtyp&COMSCAN))
171*4887Schin 		n+= p_arg(com->comarg,0);
172*4887Schin 	if(com->comstate  && np)
173*4887Schin 	{
174*4887Schin 		/* call builtin to cleanup state */
175*4887Schin 		Nambltin_t bdata;
176*4887Schin 		bdata.shp = &sh;
177*4887Schin 		bdata.np = com->comnamq;
178*4887Schin 		bdata.ptr =nv_context(np);
179*4887Schin 		bdata.data = com->comstate;
180*4887Schin 		bdata.flags = SH_END_OPTIM;
181*4887Schin 		(*funptr(np))(0,(char**)0, &bdata);
182*4887Schin 	}
183*4887Schin 	com->comstate = 0;
184*4887Schin 	if(com->comarg && !np)
185*4887Schin 		n++;
186*4887Schin 	return(n);
187*4887Schin }
188*4887Schin 
189*4887Schin extern void sh_optclear(Shell_t*, void*);
190*4887Schin 
191*4887Schin static int sh_tclear(register Shnode_t *t)
192*4887Schin {
193*4887Schin 	int n=0;
194*4887Schin 	if(!t)
195*4887Schin 		return(0);
196*4887Schin 	switch(t->tre.tretyp&COMMSK)
197*4887Schin 	{
198*4887Schin 		case TTIME:
199*4887Schin 		case TPAR:
200*4887Schin 			return(sh_tclear(t->par.partre));
201*4887Schin 		case TCOM:
202*4887Schin 			return(p_comarg((struct comnod*)t));
203*4887Schin 		case TSETIO:
204*4887Schin 		case TFORK:
205*4887Schin 			return(sh_tclear(t->fork.forktre));
206*4887Schin 		case TIF:
207*4887Schin 			n=sh_tclear(t->if_.iftre);
208*4887Schin 			n+=sh_tclear(t->if_.thtre);
209*4887Schin 			n+=sh_tclear(t->if_.eltre);
210*4887Schin 			return(n);
211*4887Schin 		case TWH:
212*4887Schin 			if(t->wh.whinc)
213*4887Schin 				n=sh_tclear((Shnode_t*)(t->wh.whinc));
214*4887Schin 			n+=sh_tclear(t->wh.whtre);
215*4887Schin 			n+=sh_tclear(t->wh.dotre);
216*4887Schin 			return(n);
217*4887Schin 		case TLST:
218*4887Schin 		case TAND:
219*4887Schin 		case TORF:
220*4887Schin 		case TFIL:
221*4887Schin 			n=sh_tclear(t->lst.lstlef);
222*4887Schin 			return(n+sh_tclear(t->lst.lstrit));
223*4887Schin 		case TARITH:
224*4887Schin 			return(p_arg(t->ar.arexpr,ARG_ARITH));
225*4887Schin 		case TFOR:
226*4887Schin 			n=sh_tclear(t->for_.fortre);
227*4887Schin 			return(n+sh_tclear((Shnode_t*)t->for_.forlst));
228*4887Schin 		case TSW:
229*4887Schin 			n=p_arg(t->sw.swarg,0);
230*4887Schin 			return(n+p_switch(t->sw.swlst));
231*4887Schin 		case TFUN:
232*4887Schin 			n=sh_tclear(t->funct.functtre);
233*4887Schin 			return(n+sh_tclear((Shnode_t*)t->funct.functargs));
234*4887Schin 		case TTST:
235*4887Schin 			if((t->tre.tretyp&TPAREN)==TPAREN)
236*4887Schin 				return(sh_tclear(t->lst.lstlef));
237*4887Schin 			else
238*4887Schin 			{
239*4887Schin 				n=p_arg(&(t->lst.lstlef->arg),0);
240*4887Schin 				if(t->tre.tretyp&TBINARY)
241*4887Schin 					n+=p_arg(&(t->lst.lstrit->arg),0);
242*4887Schin 			}
243*4887Schin 	}
244*4887Schin 	return(n);
245*4887Schin }
246*4887Schin 
247*4887Schin static int p_arg(register struct argnod *arg,int flag)
248*4887Schin {
249*4887Schin 	while(arg)
250*4887Schin 	{
251*4887Schin 		if(strlen(arg->argval) || (arg->argflag==ARG_RAW))
252*4887Schin 			arg->argchn.ap = 0;
253*4887Schin 		else if(flag==0)
254*4887Schin 			sh_tclear((Shnode_t*)arg->argchn.ap);
255*4887Schin 		else
256*4887Schin 			sh_tclear(((struct fornod*)arg->argchn.ap)->fortre);
257*4887Schin 		arg = arg->argnxt.ap;
258*4887Schin 	}
259*4887Schin 	return(0);
260*4887Schin }
261*4887Schin 
262*4887Schin static int p_switch(register struct regnod *reg)
263*4887Schin {
264*4887Schin 	int n=0;
265*4887Schin 	while(reg)
266*4887Schin 	{
267*4887Schin 		n+=p_arg(reg->regptr,0);
268*4887Schin 		n+=sh_tclear(reg->regcom);
269*4887Schin 		reg = reg->regnxt;
270*4887Schin 	}
271*4887Schin 	return(n);
272*4887Schin }
273*4887Schin #   define OPTIMIZE_FLAG	(ARG_OPTIMIZE)
274*4887Schin #   define OPTIMIZE		(flags&OPTIMIZE_FLAG)
275*4887Schin #else
276*4887Schin #   define OPTIMIZE_FLAG	(0)
277*4887Schin #   define OPTIMIZE		(0)
278*4887Schin #   define sh_tclear(x)
279*4887Schin #endif /* SHOPT_OPTIMIZE */
280*4887Schin 
281*4887Schin static void out_pattern(Sfio_t *iop, register const char *cp, int n)
282*4887Schin {
283*4887Schin 	register int c;
284*4887Schin 	do
285*4887Schin 	{
286*4887Schin 		switch(c= *cp)
287*4887Schin 		{
288*4887Schin 		    case 0:
289*4887Schin 			if(n<0)
290*4887Schin 				return;
291*4887Schin 			c = n;
292*4887Schin 			break;
293*4887Schin 		    case '\n':
294*4887Schin 			sfputr(iop,"$'\\n",'\'');
295*4887Schin 			continue;
296*4887Schin 		    case '\\':
297*4887Schin 			if (!(c = *++cp))
298*4887Schin 				c = '\\';
299*4887Schin 			/*FALLTHROUGH*/
300*4887Schin 		    case ' ':
301*4887Schin 		    case '<': case '>': case ';':
302*4887Schin 		    case '$': case '`': case '\t':
303*4887Schin 			sfputc(iop,'\\');
304*4887Schin 			break;
305*4887Schin 		}
306*4887Schin 		sfputc(iop,c);
307*4887Schin 	}
308*4887Schin 	while(*cp++);
309*4887Schin }
310*4887Schin 
311*4887Schin static void out_string(Sfio_t *iop, register const char *cp, int c, int quoted)
312*4887Schin {
313*4887Schin 	if(quoted)
314*4887Schin 	{
315*4887Schin 		int n = staktell();
316*4887Schin 		cp = sh_fmtq(cp);
317*4887Schin 		if(iop==stkstd && cp==stkptr(stkstd,n))
318*4887Schin 		{
319*4887Schin 			*stkptr(stkstd,stktell(stkstd)-1) = c;
320*4887Schin 			return;
321*4887Schin 		}
322*4887Schin 	}
323*4887Schin 	sfputr(iop,cp,c);
324*4887Schin }
325*4887Schin 
326*4887Schin struct Level
327*4887Schin {
328*4887Schin 	Namfun_t	hdr;
329*4887Schin 	short		maxlevel;
330*4887Schin };
331*4887Schin 
332*4887Schin /*
333*4887Schin  * this is for a debugger but it hasn't been tested yet
334*4887Schin  * if a debug script sets .sh.level it should set up the scope
335*4887Schin  *  as if you were executing in that level
336*4887Schin  */
337*4887Schin static void put_level(Namval_t* np,const char *val,int flags,Namfun_t *fp)
338*4887Schin {
339*4887Schin 	Shscope_t	*sp;
340*4887Schin 	struct Level *lp = (struct Level*)fp;
341*4887Schin 	int16_t level, oldlevel = (int16_t)nv_getnum(np);
342*4887Schin 	nv_putv(np,val,flags,fp);
343*4887Schin 	level = nv_getnum(np);
344*4887Schin 	if(level<0 || level > lp->maxlevel)
345*4887Schin 	{
346*4887Schin 		nv_putv(np, (char*)&oldlevel, flags, fp);
347*4887Schin 		/* perhaps this should be an error */
348*4887Schin 		return;
349*4887Schin 	}
350*4887Schin 	if(level==oldlevel)
351*4887Schin 		return;
352*4887Schin 	if(sp = sh_getscope(level,SEEK_SET))
353*4887Schin 	{
354*4887Schin 			sh_setscope(sp);
355*4887Schin 		error_info.line = sp->lineno;
356*4887Schin 	}
357*4887Schin 	nv_putval(SH_PATHNAMENOD, sh.st.filename ,NV_NOFREE);
358*4887Schin }
359*4887Schin 
360*4887Schin static const Namdisc_t level_disc = {  0, put_level };
361*4887Schin 
362*4887Schin /*
363*4887Schin  * write the current common on the stack and make it available as .sh.command
364*4887Schin  */
365*4887Schin int sh_debug(const char *trap, const char *name, const char *subscript, char *const argv[], int flags)
366*4887Schin {
367*4887Schin 	struct sh_scoped	savst;
368*4887Schin 	Shscope_t		*sp, *topmost;
369*4887Schin 	Namval_t		*np = SH_COMMANDNOD;
370*4887Schin 	struct Level		lev;
371*4887Schin 	char			*sav = stakptr(0);
372*4887Schin 	int			n=4, offset=staktell();
373*4887Schin 	const char		*cp = "+=( ";
374*4887Schin 	Sfio_t			*iop = stkstd;
375*4887Schin 	int16_t			level;
376*4887Schin 	if(name)
377*4887Schin 	{
378*4887Schin 		sfputr(iop,name,-1);
379*4887Schin 		if(subscript)
380*4887Schin 		{
381*4887Schin 			sfputc(iop,'[');
382*4887Schin 			out_string(iop,subscript,']',1);
383*4887Schin 		}
384*4887Schin 		if(!(flags&ARG_APPEND))
385*4887Schin 			cp+=1, n-=1;
386*4887Schin 		if(!(flags&ARG_ASSIGN))
387*4887Schin 			n -= 2;
388*4887Schin 		sfwrite(iop,cp,n);
389*4887Schin 	}
390*4887Schin 	if(!(flags&ARG_RAW))
391*4887Schin 		out_string(iop, *argv++,' ', 0);
392*4887Schin 	n = (flags&ARG_ARITH);
393*4887Schin 	while(cp = *argv++)
394*4887Schin 	{
395*4887Schin 		if((flags&ARG_EXP) && argv[1]==0)
396*4887Schin 			out_pattern(iop, cp,' ');
397*4887Schin 		else
398*4887Schin 			out_string(iop, cp,' ',n?0: (flags&(ARG_RAW|ARG_NOGLOB))||*argv);
399*4887Schin 	}
400*4887Schin 	if(flags&ARG_ASSIGN)
401*4887Schin 		sfputc(iop,')');
402*4887Schin 	else if(iop==stkstd)
403*4887Schin 		*stakptr(staktell()-1) = 0;
404*4887Schin 	np->nvalue.cp = stakfreeze(1);
405*4887Schin 	sh.st.lineno = error_info.line;
406*4887Schin 	/* now setup .sh.level variable */
407*4887Schin 	topmost = sh_getscope(0,SEEK_END);
408*4887Schin 	for(level=0, sp=topmost; sp; sp=sp->par_scope)
409*4887Schin 		level++;
410*4887Schin 	memset((void*)&lev,0,sizeof(lev));
411*4887Schin 	lev.hdr.disc = &level_disc;
412*4887Schin 	lev.maxlevel = --level;
413*4887Schin 	nv_unset(SH_LEVELNOD);
414*4887Schin 	nv_onattr(SH_LEVELNOD,NV_INT16|NV_NOFREE);
415*4887Schin 	nv_putval(SH_LEVELNOD,(char*)&level,NV_INT16);
416*4887Schin 	nv_disc(SH_LEVELNOD,&lev.hdr,NV_FIRST);
417*4887Schin 	savst = sh.st;
418*4887Schin 	sh.st.trap[SH_DEBUGTRAP] = 0;
419*4887Schin 	n = sh_trap(trap,0);
420*4887Schin 	np->nvalue.cp = 0;
421*4887Schin 	nv_putval(SH_LEVELNOD,(char*)&level,NV_INT16);
422*4887Schin 	nv_disc(SH_LEVELNOD,&lev.hdr,NV_POP);
423*4887Schin 	nv_unset(SH_LEVELNOD);
424*4887Schin 	nv_putval(SH_PATHNAMENOD, sh.st.filename ,NV_NOFREE);
425*4887Schin 	sh.st = savst;
426*4887Schin 	if(sav != stakptr(0))
427*4887Schin 		stakset(sav,0);
428*4887Schin 	else
429*4887Schin 		stakseek(offset);
430*4887Schin 	return(n);
431*4887Schin }
432*4887Schin 
433*4887Schin /*
434*4887Schin  * Given stream <iop> compile and execute
435*4887Schin  */
436*4887Schin int sh_eval(register Sfio_t *iop, int mode)
437*4887Schin {
438*4887Schin 	register Shnode_t *t;
439*4887Schin 	Shell_t  *shp = sh_getinterp();
440*4887Schin 	struct slnod *saveslp = shp->st.staklist;
441*4887Schin 	int jmpval;
442*4887Schin 	struct checkpt *pp = (struct checkpt*)shp->jmplist;
443*4887Schin 	struct checkpt buff;
444*4887Schin 	static Sfio_t *io_save;
445*4887Schin 	io_save = iop; /* preserve correct value across longjmp */
446*4887Schin 	sh_pushcontext(&buff,SH_JMPEVAL);
447*4887Schin 	buff.olist = pp->olist;
448*4887Schin 	jmpval = sigsetjmp(buff.buff,0);
449*4887Schin 	if(jmpval==0)
450*4887Schin 	{
451*4887Schin 		t = (Shnode_t*)sh_parse(shp,iop,SH_NL);
452*4887Schin 		sfclose(iop);
453*4887Schin 		io_save = 0;
454*4887Schin 		if(!sh_isoption(SH_VERBOSE))
455*4887Schin 			sh_offstate(SH_VERBOSE);
456*4887Schin 		if(mode && shp->hist_ptr)
457*4887Schin 		{
458*4887Schin 			hist_flush(shp->hist_ptr);
459*4887Schin 			mode = sh_state(SH_INTERACTIVE);
460*4887Schin 		}
461*4887Schin 		sh_exec(t,sh_isstate(SH_ERREXIT)|mode);
462*4887Schin 	}
463*4887Schin 	sh_popcontext(&buff);
464*4887Schin 	if(io_save)
465*4887Schin 		sfclose(io_save);
466*4887Schin 	sh_freeup();
467*4887Schin 	shp->st.staklist = saveslp;
468*4887Schin 	if(jmpval>SH_JMPEVAL)
469*4887Schin 		siglongjmp(*shp->jmplist,jmpval);
470*4887Schin 	return(sh.exitval);
471*4887Schin }
472*4887Schin 
473*4887Schin #if SHOPT_FASTPIPE
474*4887Schin static int pipe_exec(int pv[], Shnode_t *t, int errorflg)
475*4887Schin {
476*4887Schin 	struct checkpt buff;
477*4887Schin 	register Shnode_t *tchild = t->fork.forktre;
478*4887Schin 	Namval_t *np;
479*4887Schin 	Sfio_t *iop;
480*4887Schin 	int jmpval,r;
481*4887Schin 	if((tchild->tre.tretyp&COMMSK)!=TCOM || !(np=(Namval_t*)(tchild->com.comnamp)))
482*4887Schin 	{
483*4887Schin 		sh_pipe(pv);
484*4887Schin 		return(sh_exec(t,errorflg));
485*4887Schin 	}
486*4887Schin 	pv[0] = sh.lim.open_max;
487*4887Schin 	sh.fdstatus[pv[0]] = IOREAD|IODUP|IOSEEK;
488*4887Schin 	pv[1] = sh.lim.open_max+1;
489*4887Schin 	sh.fdstatus[pv[1]] = IOWRITE|IOSEEK;
490*4887Schin 	iop = sftmp(IOBSIZE+1);
491*4887Schin 	sh.sftable[sh.lim.open_max+1] = iop;
492*4887Schin 	sh_pushcontext(&buff,SH_JMPIO);
493*4887Schin 	if(t->tre.tretyp&FPIN)
494*4887Schin 		sh_iosave(0,sh.topfd);
495*4887Schin 	sh_iosave(1,sh.topfd);
496*4887Schin 	jmpval = sigsetjmp(buff.buff,0);
497*4887Schin 	if(jmpval==0)
498*4887Schin 	{
499*4887Schin 		if(t->tre.tretyp&FPIN)
500*4887Schin 			sh_iorenumber(sh.inpipe[0],0);
501*4887Schin 		sh_iorenumber(sh.lim.open_max+1,1);
502*4887Schin 		r = sh_exec(tchild,errorflg);
503*4887Schin 		if(sffileno(sfstdout)>=0)
504*4887Schin 			pv[0] = sfsetfd(sfstdout,10);
505*4887Schin 		iop = sfswap(sfstdout,0);
506*4887Schin 	}
507*4887Schin 	sh_popcontext(&buff);
508*4887Schin 	sh.sftable[pv[0]] = iop;
509*4887Schin 	sh.fdstatus[pv[0]] = IOREAD|IODUP|IOSEEK;
510*4887Schin 	sfset(iop,SF_WRITE,0);
511*4887Schin 	sfseek(iop,0L,SEEK_SET);
512*4887Schin 	sh_iorestore(buff.topfd,jmpval);
513*4887Schin 	if(jmpval>SH_JMPIO)
514*4887Schin 		siglongjmp(*sh.jmplist,jmpval);
515*4887Schin 	return(r);
516*4887Schin }
517*4887Schin #endif /* SHOPT_FASTPIPE */
518*4887Schin 
519*4887Schin /*
520*4887Schin  * returns 1 when option -<c> is specified
521*4887Schin  */
522*4887Schin static int checkopt(char *argv[], int c)
523*4887Schin {
524*4887Schin 	char *cp;
525*4887Schin 	while(cp = *++argv)
526*4887Schin 	{
527*4887Schin 		if(*cp=='+')
528*4887Schin 			continue;
529*4887Schin 		if(*cp!='-' || cp[1]=='-')
530*4887Schin 			break;
531*4887Schin 		if(strchr(cp,c))
532*4887Schin 			return(1);
533*4887Schin 	}
534*4887Schin 	return(0);
535*4887Schin }
536*4887Schin 
537*4887Schin static void free_list(struct openlist *olist)
538*4887Schin {
539*4887Schin 	struct openlist *item,*next;
540*4887Schin 	for(item=olist;item;item=next)
541*4887Schin 	{
542*4887Schin 		next = item->next;
543*4887Schin 		free((void*)item);
544*4887Schin 	}
545*4887Schin }
546*4887Schin 
547*4887Schin 
548*4887Schin int sh_exec(register const Shnode_t *t, int flags)
549*4887Schin {
550*4887Schin 	sh_sigcheck();
551*4887Schin 	if(t && !sh.st.execbrk && !sh_isoption(SH_NOEXEC))
552*4887Schin 	{
553*4887Schin 		register int 	type = flags;
554*4887Schin 		register char	*com0 = 0;
555*4887Schin 		int 		errorflg = (type&sh_state(SH_ERREXIT))|OPTIMIZE;
556*4887Schin 		int 		execflg = (type&sh_state(SH_NOFORK));
557*4887Schin 		int 		mainloop = (type&sh_state(SH_INTERACTIVE));
558*4887Schin #if SHOPT_SPAWN
559*4887Schin 		int		ntflag = (type&sh_state(SH_NTFORK));
560*4887Schin #endif
561*4887Schin 		int		topfd = sh.topfd;
562*4887Schin 		char 		*sav=stakptr(0);
563*4887Schin 		char		*cp=0, **com=0;
564*4887Schin 		int		argn;
565*4887Schin 		int 		skipexitset = 0;
566*4887Schin 		int		was_interactive = 0;
567*4887Schin 		int		was_errexit = sh_isstate(SH_ERREXIT);
568*4887Schin 		int		was_monitor = sh_isstate(SH_MONITOR);
569*4887Schin 		int		echeck = 0;
570*4887Schin 		if(flags&sh_state(SH_INTERACTIVE))
571*4887Schin 		{
572*4887Schin 			pipejob = 0;
573*4887Schin 			job.curpgid = 0;
574*4887Schin 			flags &= ~sh_state(SH_INTERACTIVE);
575*4887Schin 		}
576*4887Schin 		sh_offstate(SH_ERREXIT);
577*4887Schin 		sh_offstate(SH_DEFPATH);
578*4887Schin 		if(was_errexit&flags)
579*4887Schin 			sh_onstate(SH_ERREXIT);
580*4887Schin 		if(was_monitor&flags)
581*4887Schin 			sh_onstate(SH_MONITOR);
582*4887Schin 		type = t->tre.tretyp;
583*4887Schin 		if(!sh.intrap)
584*4887Schin 			sh.oldexit=sh.exitval;
585*4887Schin 		sh.exitval=0;
586*4887Schin 		sh.lastsig = 0;
587*4887Schin 		sh.lastpath = 0;
588*4887Schin 		switch(type&COMMSK)
589*4887Schin 		{
590*4887Schin 		    case TCOM:
591*4887Schin 		    {
592*4887Schin 			register struct argnod	*argp;
593*4887Schin 			char		*trap;
594*4887Schin 			Namval_t	*np, *nq, *last_table;
595*4887Schin 			struct ionod	*io;
596*4887Schin 			int		command=0;
597*4887Schin 			error_info.line = t->com.comline-sh.st.firstline;
598*4887Schin 			com = sh_argbuild(&argn,&(t->com),OPTIMIZE);
599*4887Schin 			echeck = 1;
600*4887Schin 			if(t->tre.tretyp&COMSCAN)
601*4887Schin 			{
602*4887Schin 				argp = t->com.comarg;
603*4887Schin 				if(argp && *com && !(argp->argflag&ARG_RAW))
604*4887Schin 					sh_sigcheck();
605*4887Schin 			}
606*4887Schin 			np = (Namval_t*)(t->com.comnamp);
607*4887Schin 			nq = (Namval_t*)(t->com.comnamq);
608*4887Schin 			com0 = com[0];
609*4887Schin 			sh.xargexit = 0;
610*4887Schin 			while(np==SYSCOMMAND)
611*4887Schin 			{
612*4887Schin 				register int n = b_command(0,com,&sh);
613*4887Schin 				if(n==0)
614*4887Schin 					break;
615*4887Schin 				command += n;
616*4887Schin 				np = 0;
617*4887Schin 				if(!(com0= *(com+=n)))
618*4887Schin 					break;
619*4887Schin 				np = nv_bfsearch(com0, sh.bltin_tree, &nq, &cp);
620*4887Schin 			}
621*4887Schin 			if(sh.xargexit)
622*4887Schin 			{
623*4887Schin 				sh.xargmin -= command;
624*4887Schin 				sh.xargmax -= command;
625*4887Schin 			}
626*4887Schin 			else
627*4887Schin 				sh.xargmin = 0;
628*4887Schin 			argn -= command;
629*4887Schin 			if(!command && np && is_abuiltin(np))
630*4887Schin 				np = dtsearch(sh.fun_tree,np);
631*4887Schin 			if(com0 && !np && !strchr(com0,'/'))
632*4887Schin 			{
633*4887Schin 				Dt_t *root = command?sh.bltin_tree:sh.fun_tree;
634*4887Schin 				np = nv_bfsearch(com0, root, &nq, &cp);
635*4887Schin #if SHOPT_NAMESPACE
636*4887Schin 				if(sh.namespace && !nq && !cp)
637*4887Schin 				{
638*4887Schin 					int offset = staktell();
639*4887Schin 					stakputs(nv_name(sh.namespace));
640*4887Schin 					stakputc('.');
641*4887Schin 					stakputs(com0);
642*4887Schin 					stakseek(offset);
643*4887Schin 					np = nv_bfsearch(stakptr(offset), root, &nq, &cp);
644*4887Schin 				}
645*4887Schin #endif /* SHOPT_NAMESPACE */
646*4887Schin 			}
647*4887Schin 			io = t->tre.treio;
648*4887Schin 			if(sh.envlist = argp = t->com.comset)
649*4887Schin 			{
650*4887Schin 				if(argn==0 || (np && !command && nv_isattr(np,BLT_SPC)))
651*4887Schin 				{
652*4887Schin 					register int flgs=NV_VARNAME|NV_ASSIGN;
653*4887Schin #if SHOPT_BASH
654*4887Schin 					if(np==SYSLOCAL)
655*4887Schin 					{
656*4887Schin 						if(!nv_getval(SH_FUNNAMENOD))
657*4887Schin 							errormsg(SH_DICT,ERROR_exit(1),"%s: can only be used in a function",com0);
658*4887Schin 						if(!sh.st.var_local)
659*4887Schin 						{
660*4887Schin 							nv_scope((struct argnod*)0);
661*4887Schin 							sh.st.var_local = sh.var_tree;
662*4887Schin 						}
663*4887Schin 
664*4887Schin 					}
665*4887Schin 					if(np==SYSTYPESET || np==SYSLOCAL)
666*4887Schin #else
667*4887Schin 					if(np==SYSTYPESET)
668*4887Schin #endif
669*4887Schin 					{
670*4887Schin 						if(checkopt(com,'n'))
671*4887Schin 							flgs |= NV_NOREF;
672*4887Schin #if SHOPT_TYPEDEF
673*4887Schin 						else if(checkopt(com,'T'))
674*4887Schin 						{
675*4887Schin 							sh.prefix = NV_CLASS;
676*4887Schin 							flgs |= NV_TYPE;
677*4887Schin 
678*4887Schin 						}
679*4887Schin #endif /* SHOPT_TYPEDEF */
680*4887Schin 						if(checkopt(com,'A'))
681*4887Schin 							flgs |= NV_ARRAY;
682*4887Schin 						else if(checkopt(com,'a'))
683*4887Schin 							flgs |= NV_IARRAY;
684*4887Schin 						if((sh.fn_depth && !sh.prefix) || np==SYSLOCAL)
685*4887Schin 							flgs |= NV_NOSCOPE;
686*4887Schin 					}
687*4887Schin 					else if(np==SYSEXPORT)
688*4887Schin 						flgs |= NV_EXPORT;
689*4887Schin 					else if(np)
690*4887Schin 						flgs = NV_IDENT|NV_ASSIGN;
691*4887Schin #if 0
692*4887Schin 					if(OPTIMIZE)
693*4887Schin 						flgs |= NV_TAGGED;
694*4887Schin #endif
695*4887Schin 					nv_setlist(argp,flgs);
696*4887Schin 					argp = NULL;
697*4887Schin 				}
698*4887Schin 			}
699*4887Schin 			last_table = sh.last_table;
700*4887Schin 			sh.last_table = 0;
701*4887Schin 			if((io||argn))
702*4887Schin 			{
703*4887Schin 				static char *argv[1];
704*4887Schin 				if(argn==0)
705*4887Schin 				{
706*4887Schin 					/* fake 'true' built-in */
707*4887Schin 					argn=1;
708*4887Schin 					np = SYSTRUE;
709*4887Schin 					*argv = nv_name(np);
710*4887Schin 					com = argv;
711*4887Schin 				}
712*4887Schin 				/* set +x doesn't echo */
713*4887Schin 				else if((np!=SYSSET) && sh_isoption(SH_XTRACE))
714*4887Schin 					sh_trace(com-command,1);
715*4887Schin 				else if((t->tre.tretyp&FSHOWME) && sh_isoption(SH_SHOWME))
716*4887Schin 				{
717*4887Schin 					int ison = sh_isoption(SH_XTRACE);
718*4887Schin 					if(!ison)
719*4887Schin 						sh_onoption(SH_XTRACE);
720*4887Schin 					sh_trace(com-command,1);
721*4887Schin 					if(io)
722*4887Schin 						sh_redirect(io,SH_SHOWME);
723*4887Schin 					if(!ison)
724*4887Schin 						sh_offoption(SH_XTRACE);
725*4887Schin 					break;
726*4887Schin 				}
727*4887Schin 				if(trap=sh.st.trap[SH_DEBUGTRAP])
728*4887Schin 					sh_debug(trap,(char*)0, (char*)0, com, ARG_RAW);
729*4887Schin 				if(io)
730*4887Schin 					sfsync(sh.outpool);
731*4887Schin 				sh.lastpath = 0;
732*4887Schin 				if(!np  && !strchr(com0,'/'))
733*4887Schin 				{
734*4887Schin #ifdef PATH_BFPATH
735*4887Schin 					if(path_search(com0,NIL(Pathcomp_t*),1))
736*4887Schin 						np=nv_search(com0,sh.fun_tree,0);
737*4887Schin 					else
738*4887Schin 					{
739*4887Schin 						if((np=nv_search(com0,sh.track_tree,0)) && !nv_isattr(np,NV_NOALIAS) && np->nvalue.cp)
740*4887Schin 							np=nv_search(nv_getval(np),sh.bltin_tree,0);
741*4887Schin 						else
742*4887Schin 							np = 0;
743*4887Schin 					}
744*4887Schin #else
745*4887Schin 					if(path_search(com0,NIL(char*),1))
746*4887Schin 						np=nv_search(com0,sh.fun_tree,0);
747*4887Schin 					if(sh.lastpath)
748*4887Schin 						np=nv_search(sh.lastpath,sh.bltin_tree,0);
749*4887Schin #endif
750*4887Schin 				}
751*4887Schin 				/* check for builtins */
752*4887Schin 				if(np && is_abuiltin(np))
753*4887Schin 				{
754*4887Schin 					Nambltin_t bdata;
755*4887Schin 					void *context;
756*4887Schin 					int scope=0, jmpval, save_prompt,share;
757*4887Schin 					struct checkpt buff;
758*4887Schin 					unsigned long was_vi=0, was_emacs=0, was_gmacs=0;
759*4887Schin 					struct stat statb;
760*4887Schin 					if(strchr(nv_name(np),'/'))
761*4887Schin 					{
762*4887Schin 						/*
763*4887Schin 						 * disable editors for built-in
764*4887Schin 						 * versions of commands on PATH
765*4887Schin 						 */
766*4887Schin 						was_vi = sh_isoption(SH_VI);
767*4887Schin 						was_emacs = sh_isoption(SH_EMACS);
768*4887Schin 						was_gmacs = sh_isoption(SH_GMACS);
769*4887Schin 						sh_offoption(SH_VI);
770*4887Schin 						sh_offoption(SH_EMACS);
771*4887Schin 						sh_offoption(SH_GMACS);
772*4887Schin 					}
773*4887Schin 					sh_pushcontext(&buff,SH_JMPCMD);
774*4887Schin 					jmpval = sigsetjmp(buff.buff,1);
775*4887Schin 					if(jmpval == 0)
776*4887Schin 					{
777*4887Schin 						if(!(nv_isattr(np,BLT_ENV)))
778*4887Schin 							error_info.flags |= ERROR_SILENT;
779*4887Schin 						errorpush(&buff.err,0);
780*4887Schin 						if(io)
781*4887Schin 						{
782*4887Schin 							struct openlist *item;
783*4887Schin 							if(np==SYSLOGIN)
784*4887Schin 								type=1;
785*4887Schin 							else if(np==SYSEXEC)
786*4887Schin 								type=1+!com[1];
787*4887Schin 							else
788*4887Schin 								type = (execflg && !sh.subshell && !sh.st.trapcom[0]);
789*4887Schin 							sh_redirect(io,type);
790*4887Schin 							for(item=buff.olist;item;item=item->next)
791*4887Schin 								item->strm=0;
792*4887Schin 						}
793*4887Schin 						if(!(nv_isattr(np,BLT_ENV)))
794*4887Schin 						{
795*4887Schin 							if(!sh.pwd)
796*4887Schin 								path_pwd(0);
797*4887Schin 							if(sh.pwd)
798*4887Schin 								stat(".",&statb);
799*4887Schin 							share = sfset(sfstdin,SF_SHARE,0);
800*4887Schin 							sh_onstate(SH_STOPOK);
801*4887Schin 							sfpool(sfstderr,NIL(Sfio_t*),SF_WRITE);
802*4887Schin 							sfset(sfstderr,SF_LINE,1);
803*4887Schin 							save_prompt = sh.nextprompt;
804*4887Schin 							sh.nextprompt = 0;
805*4887Schin 						}
806*4887Schin 						if(argp)
807*4887Schin 						{
808*4887Schin 							scope++;
809*4887Schin 							nv_scope(argp);
810*4887Schin 						}
811*4887Schin 						opt_info.index = opt_info.offset = 0;
812*4887Schin 						opt_info.disc = 0;
813*4887Schin 						error_info.id = *com;
814*4887Schin 						sh.exitval = 0;
815*4887Schin 						if(!(context=nv_context(np)))
816*4887Schin 							context = (void*)&sh;
817*4887Schin 						sh.bltinfun = funptr(np);
818*4887Schin 						if(nv_isattr(np,NV_BLTINOPT))
819*4887Schin 						{
820*4887Schin 							bdata.shp = &sh;
821*4887Schin 							bdata.np = nq;
822*4887Schin 							bdata.ptr = context;
823*4887Schin 							bdata.data = t->com.comstate;
824*4887Schin 							bdata.flags = (OPTIMIZE!=0);
825*4887Schin 							context = (void*)&bdata;
826*4887Schin 						}
827*4887Schin 						if(execflg && !sh.subshell &&
828*4887Schin 							!sh.st.trapcom[0] && !sh.st.trap[SH_ERRTRAP] && sh.fn_depth==0 && !nv_isattr(np,BLT_ENV))
829*4887Schin 						{
830*4887Schin 							/* do close-on-exec */
831*4887Schin 							int fd;
832*4887Schin 							for(fd=0; fd < sh.lim.open_max; fd++)
833*4887Schin 								if((sh.fdstatus[fd]&IOCLEX)&&fd!=sh.infd)
834*4887Schin 									sh_close(fd);
835*4887Schin 						}
836*4887Schin 						sh.exitval = (*sh.bltinfun)(argn,com,context);
837*4887Schin 						if(error_info.flags&ERROR_INTERACTIVE)
838*4887Schin 							tty_check(ERRIO);
839*4887Schin 						if(nv_isattr(np,NV_BLTINOPT))
840*4887Schin 							((Shnode_t*)t)->com.comstate = bdata.data;
841*4887Schin 						if(!nv_isattr(np,BLT_EXIT) && sh.exitval!=SH_RUNPROG)
842*4887Schin 							sh.exitval &= SH_EXITMASK;
843*4887Schin 					}
844*4887Schin 					else
845*4887Schin 					{
846*4887Schin 						struct openlist *item;
847*4887Schin 						for(item=buff.olist;item;item=item->next)
848*4887Schin 						{
849*4887Schin 							if(item->strm)
850*4887Schin 							{
851*4887Schin 								sfclrlock(item->strm);
852*4887Schin 								if(sh.hist_ptr && item->strm == sh.hist_ptr->histfp)
853*4887Schin 									hist_close(sh.hist_ptr);
854*4887Schin 								else
855*4887Schin 									sfclose(item->strm);
856*4887Schin 							}
857*4887Schin 						}
858*4887Schin 						/* failure on special built-ins fatal */
859*4887Schin 						if(jmpval<=SH_JMPCMD  && (!nv_isattr(np,BLT_SPC) || command))
860*4887Schin 							jmpval=0;
861*4887Schin 					}
862*4887Schin 					if(!(nv_isattr(np,BLT_ENV)))
863*4887Schin 					{
864*4887Schin 						if(sh.pwd)
865*4887Schin 						{
866*4887Schin 							struct stat stata;
867*4887Schin 							stat(".",&stata);
868*4887Schin 							/* restore directory changed */
869*4887Schin 							if(statb.st_ino!=stata.st_ino || statb.st_dev!=stata.st_dev)
870*4887Schin 								chdir(sh.pwd);
871*4887Schin 						}
872*4887Schin 						sh_offstate(SH_STOPOK);
873*4887Schin 						if(share&SF_SHARE)
874*4887Schin 							sfset(sfstdin,SF_PUBLIC|SF_SHARE,1);
875*4887Schin 						sfset(sfstderr,SF_LINE,0);
876*4887Schin 						sfpool(sfstderr,sh.outpool,SF_WRITE);
877*4887Schin 						sfpool(sfstdin,NIL(Sfio_t*),SF_WRITE);
878*4887Schin 						sh.nextprompt = save_prompt;
879*4887Schin 					}
880*4887Schin 					sh_popcontext(&buff);
881*4887Schin 					errorpop(&buff.err);
882*4887Schin 					error_info.flags &= ~ERROR_SILENT;
883*4887Schin 					sh.bltinfun = 0;
884*4887Schin 					if(buff.olist)
885*4887Schin 						free_list(buff.olist);
886*4887Schin 					if(was_vi)
887*4887Schin 						sh_onoption(SH_VI);
888*4887Schin 					else if(was_emacs)
889*4887Schin 						sh_onoption(SH_EMACS);
890*4887Schin 					else if(was_gmacs)
891*4887Schin 						sh_onoption(SH_GMACS);
892*4887Schin 					if(scope)
893*4887Schin 						nv_unscope();
894*4887Schin 					/* don't restore for subshell exec */
895*4887Schin 					if((sh.topfd>topfd) && !(sh.subshell && np==SYSEXEC))
896*4887Schin 						sh_iorestore(topfd,jmpval);
897*4887Schin 					if(jmpval)
898*4887Schin 						siglongjmp(*sh.jmplist,jmpval);
899*4887Schin 					if(sh.exitval >=0)
900*4887Schin 						goto setexit;
901*4887Schin 					np = 0;
902*4887Schin 					type=0;
903*4887Schin 				}
904*4887Schin 				/* check for functions */
905*4887Schin 				if(!command && np && nv_isattr(np,NV_FUNCTION))
906*4887Schin 				{
907*4887Schin 					int indx,jmpval=0;
908*4887Schin 					struct checkpt buff;
909*4887Schin 					Namval_t node;
910*4887Schin 					register struct slnod *slp;
911*4887Schin 					if(!np->nvalue.ip)
912*4887Schin 					{
913*4887Schin #ifdef PATH_BFPATH
914*4887Schin 						indx = path_search(com0,NIL(Pathcomp_t*),0);
915*4887Schin #else
916*4887Schin 						indx = path_search(com0,NIL(char*),0);
917*4887Schin #endif
918*4887Schin 						if(indx==1)
919*4887Schin 							np = nv_search(com0,sh.fun_tree,HASH_NOSCOPE);
920*4887Schin 						if(!np->nvalue.ip)
921*4887Schin 						{
922*4887Schin 							if(indx==1)
923*4887Schin 							{
924*4887Schin 								errormsg(SH_DICT,ERROR_exit(0),e_defined,com0);
925*4887Schin 								sh.exitval = ERROR_NOEXEC;
926*4887Schin 							}
927*4887Schin 							else
928*4887Schin 							{
929*4887Schin 								errormsg(SH_DICT,ERROR_exit(0),e_found,"function");
930*4887Schin 								sh.exitval = ERROR_NOENT;
931*4887Schin 							}
932*4887Schin 							goto setexit;
933*4887Schin 						}
934*4887Schin 					}
935*4887Schin 					/* increase refcnt for unset */
936*4887Schin 					slp = (struct slnod*)np->nvenv;
937*4887Schin 					sh_funstaks(slp->slchild,1);
938*4887Schin 					staklink(slp->slptr);
939*4887Schin 					if(nq)
940*4887Schin 					{
941*4887Schin 						struct Namref	nr;
942*4887Schin 						sh.last_table = last_table;
943*4887Schin 						memset(&nr,0,sizeof(nr));
944*4887Schin 						nr.np = nq;
945*4887Schin 						nv_putval(SH_NAMENOD, nv_name(nq), NV_NOFREE);
946*4887Schin 						memcpy(&node,L_ARGNOD,sizeof(node));
947*4887Schin 						L_ARGNOD->nvalue.nrp = &nr;
948*4887Schin 						L_ARGNOD->nvenv = 0;
949*4887Schin 						L_ARGNOD->nvfun = (Namfun_t*)sh.last_table;
950*4887Schin 						L_ARGNOD->nvflag = NV_REF|NV_NOFREE;
951*4887Schin 						if(nv_arrayptr(nq))
952*4887Schin 						{
953*4887Schin 							nv_putval(SH_SUBSCRNOD,nv_getsub(nq),NV_NOFREE);
954*4887Schin 							L_ARGNOD->nvenv = (char*)SH_SUBSCRNOD->nvalue.cp;
955*4887Schin 						}
956*4887Schin 					}
957*4887Schin 					if(io)
958*4887Schin 					{
959*4887Schin 						indx = sh.topfd;
960*4887Schin 						sh_pushcontext(&buff,SH_JMPCMD);
961*4887Schin 						jmpval = sigsetjmp(buff.buff,0);
962*4887Schin 					}
963*4887Schin 					if(jmpval == 0)
964*4887Schin 					{
965*4887Schin 						if(io)
966*4887Schin 							indx = sh_redirect(io,execflg);
967*4887Schin 						sh_funct(np,argn,com,t->com.comset,(flags&~OPTIMIZE_FLAG));
968*4887Schin 					}
969*4887Schin 					if(io)
970*4887Schin 					{
971*4887Schin 						if(buff.olist)
972*4887Schin 							free_list(buff.olist);
973*4887Schin 						sh_popcontext(&buff);
974*4887Schin 						sh_iorestore(indx,jmpval);
975*4887Schin 					}
976*4887Schin 					if(nq)
977*4887Schin 					{
978*4887Schin 						L_ARGNOD->nvalue.np = node.nvalue.np;
979*4887Schin 						L_ARGNOD->nvenv = node.nvenv;
980*4887Schin 						L_ARGNOD->nvflag = node.nvflag;
981*4887Schin 						L_ARGNOD->nvfun = node.nvfun;
982*4887Schin 						nv_unset(SH_NAMENOD);
983*4887Schin 						nv_unset(SH_SUBSCRNOD);
984*4887Schin 					}
985*4887Schin 					sh_funstaks(slp->slchild,-1);
986*4887Schin 					stakdelete(slp->slptr);
987*4887Schin 					if(jmpval > SH_JMPFUN)
988*4887Schin 						siglongjmp(*sh.jmplist,jmpval);
989*4887Schin 					goto setexit;
990*4887Schin 				}
991*4887Schin 			}
992*4887Schin 			else if(!io)
993*4887Schin 			{
994*4887Schin 			setexit:
995*4887Schin 				exitset();
996*4887Schin 				break;
997*4887Schin 			}
998*4887Schin 		    }
999*4887Schin 		    case TFORK:
1000*4887Schin 		    {
1001*4887Schin 			register pid_t parent;
1002*4887Schin 			int no_fork,jobid;
1003*4887Schin 			int pipes[2];
1004*4887Schin 			no_fork = (execflg && !(type&(FAMP|FPOU)) &&
1005*4887Schin 				!sh.subshell && !sh.st.trapcom[0] &&
1006*4887Schin 				!sh.st.trap[SH_ERRTRAP] && sh.fn_depth==0);
1007*4887Schin 			if(sh.subshell)
1008*4887Schin 				sh_subtmpfile();
1009*4887Schin 			if(sh_isstate(SH_PROFILE) || sh.dot_depth)
1010*4887Schin 			{
1011*4887Schin 				/* disable foreground job monitor */
1012*4887Schin 				if(!(type&FAMP))
1013*4887Schin 					sh_offstate(SH_MONITOR);
1014*4887Schin #if SHOPT_DEVFD
1015*4887Schin 				else if(!(type&FINT))
1016*4887Schin 					sh_offstate(SH_MONITOR);
1017*4887Schin #endif /* SHOPT_DEVFD */
1018*4887Schin 			}
1019*4887Schin 			if(no_fork)
1020*4887Schin 				job.parent=parent=0;
1021*4887Schin 			else
1022*4887Schin 			{
1023*4887Schin 				if(type&FCOOP)
1024*4887Schin 					coproc_init(pipes);
1025*4887Schin 				nv_getval(RANDNOD);
1026*4887Schin #if SHOPT_AMP
1027*4887Schin 				if((type&(FAMP|FINT)) == (FAMP|FINT))
1028*4887Schin 					parent = sh_ntfork(t,com,&jobid,ntflag);
1029*4887Schin 				else
1030*4887Schin 					parent = sh_fork(type,&jobid);
1031*4887Schin 				if(parent<0)
1032*4887Schin 					break;
1033*4887Schin #else
1034*4887Schin #if SHOPT_SPAWN
1035*4887Schin #   ifdef _lib_fork
1036*4887Schin 				if(com)
1037*4887Schin 					parent = sh_ntfork(t,com,&jobid,ntflag);
1038*4887Schin 				else
1039*4887Schin 					parent = sh_fork(type,&jobid);
1040*4887Schin #   else
1041*4887Schin 				if((parent = sh_ntfork(t,com,&jobid,ntflag))<=0)
1042*4887Schin 					break;
1043*4887Schin #   endif /* _lib_fork */
1044*4887Schin 				if(parent<0)
1045*4887Schin 					break;
1046*4887Schin #else
1047*4887Schin 				parent = sh_fork(type,&jobid);
1048*4887Schin #endif /* SHOPT_SPAWN */
1049*4887Schin #endif
1050*4887Schin 			}
1051*4887Schin 			if(job.parent=parent)
1052*4887Schin 			/* This is the parent branch of fork
1053*4887Schin 			 * It may or may not wait for the child
1054*4887Schin 			 */
1055*4887Schin 			{
1056*4887Schin 				if(type&FPCL)
1057*4887Schin 					sh_close(sh.inpipe[0]);
1058*4887Schin 				if(type&(FCOOP|FAMP))
1059*4887Schin 					sh.bckpid = parent;
1060*4887Schin 				if(!(type&(FAMP|FPOU)))
1061*4887Schin 				{
1062*4887Schin 					if(sh.topfd > topfd)
1063*4887Schin 						sh_iorestore(topfd,0);
1064*4887Schin 					job_wait(parent);
1065*4887Schin 				}
1066*4887Schin 				if(type&FAMP)
1067*4887Schin 				{
1068*4887Schin 					if(sh_isstate(SH_PROFILE) || sh_isstate(SH_INTERACTIVE))
1069*4887Schin 					{
1070*4887Schin 						/* print job number */
1071*4887Schin #ifdef JOBS
1072*4887Schin 						sfprintf(sfstderr,"[%d]\t%d\n",jobid,parent);
1073*4887Schin #else
1074*4887Schin 						sfprintf(sfstderr,"%d\n",parent);
1075*4887Schin #endif /* JOBS */
1076*4887Schin 					}
1077*4887Schin 				}
1078*4887Schin 				break;
1079*4887Schin 			}
1080*4887Schin 			else
1081*4887Schin 			/*
1082*4887Schin 			 * this is the FORKED branch (child) of execute
1083*4887Schin 			 */
1084*4887Schin 			{
1085*4887Schin 				int jmpval;
1086*4887Schin 				struct checkpt buff;
1087*4887Schin 				if(no_fork)
1088*4887Schin 					sh_sigreset(2);
1089*4887Schin 				sh_pushcontext(&buff,SH_JMPEXIT);
1090*4887Schin 				jmpval = sigsetjmp(buff.buff,0);
1091*4887Schin 				if(jmpval)
1092*4887Schin 					goto done;
1093*4887Schin 				if((type&FINT) && !sh_isstate(SH_MONITOR))
1094*4887Schin 				{
1095*4887Schin 					/* default std input for & */
1096*4887Schin 					signal(SIGINT,SIG_IGN);
1097*4887Schin 					signal(SIGQUIT,SIG_IGN);
1098*4887Schin 					if(!sh.st.ioset)
1099*4887Schin 					{
1100*4887Schin 						if(sh_close(0)>=0)
1101*4887Schin 							sh_chkopen(e_devnull);
1102*4887Schin 					}
1103*4887Schin 				}
1104*4887Schin 				sh_offstate(SH_MONITOR);
1105*4887Schin 				/* pipe in or out */
1106*4887Schin #ifdef _lib_nice
1107*4887Schin 				if((type&FAMP) && sh_isoption(SH_BGNICE))
1108*4887Schin 					nice(4);
1109*4887Schin #endif /* _lib_nice */
1110*4887Schin 				if(type&FPIN)
1111*4887Schin 				{
1112*4887Schin 					sh_iorenumber(sh.inpipe[0],0);
1113*4887Schin 					if(!(type&FPOU) || (type&FCOOP))
1114*4887Schin 						sh_close(sh.inpipe[1]);
1115*4887Schin 				}
1116*4887Schin 				if(type&FPOU)
1117*4887Schin 				{
1118*4887Schin 					sh_iorenumber(sh.outpipe[1],1);
1119*4887Schin 					sh_pclose(sh.outpipe);
1120*4887Schin 				}
1121*4887Schin 				if((type&COMMSK)!=TCOM)
1122*4887Schin 					error_info.line = t->fork.forkline-sh.st.firstline;
1123*4887Schin 				sh_redirect(t->tre.treio,1);
1124*4887Schin 				if(sh.topfd)
1125*4887Schin 					sh_iounsave();
1126*4887Schin 				if((type&COMMSK)!=TCOM)
1127*4887Schin 				{
1128*4887Schin 					/* don't clear job table for out
1129*4887Schin 					   pipes so that jobs comand can
1130*4887Schin 					   be used in a pipeline
1131*4887Schin 					 */
1132*4887Schin 					if(!no_fork && !(type&FPOU))
1133*4887Schin 						job_clear();
1134*4887Schin 					sh_exec(t->fork.forktre,flags|sh_state(SH_NOFORK));
1135*4887Schin 				}
1136*4887Schin 				else if(com0)
1137*4887Schin 				{
1138*4887Schin 					sh_offoption(SH_ERREXIT);
1139*4887Schin 					sh_freeup();
1140*4887Schin 					path_exec(com0,com,t->com.comset);
1141*4887Schin 				}
1142*4887Schin 			done:
1143*4887Schin 				sh_popcontext(&buff);
1144*4887Schin 				if(jmpval>SH_JMPEXIT)
1145*4887Schin 					siglongjmp(*sh.jmplist,jmpval);
1146*4887Schin 				sh_done(0);
1147*4887Schin 			}
1148*4887Schin 		    }
1149*4887Schin 
1150*4887Schin 		    case TSETIO:
1151*4887Schin 		    {
1152*4887Schin 		    /*
1153*4887Schin 		     * don't create a new process, just
1154*4887Schin 		     * save and restore io-streams
1155*4887Schin 		     */
1156*4887Schin 			pid_t	pid;
1157*4887Schin 			int jmpval, waitall;
1158*4887Schin 			struct checkpt buff;
1159*4887Schin 			if(sh.subshell)
1160*4887Schin 			{
1161*4887Schin 				flags &= ~sh_state(SH_NOFORK);
1162*4887Schin 				execflg = 0;
1163*4887Schin 			}
1164*4887Schin 			sh_pushcontext(&buff,SH_JMPIO);
1165*4887Schin 			if(type&FPIN)
1166*4887Schin 			{
1167*4887Schin 				was_interactive = sh_isstate(SH_INTERACTIVE);
1168*4887Schin 				sh_offstate(SH_INTERACTIVE);
1169*4887Schin 				if(!execflg)
1170*4887Schin 					sh_iosave(0,sh.topfd);
1171*4887Schin 				sh_iorenumber(sh.inpipe[0],0);
1172*4887Schin 				/*
1173*4887Schin 				 * if read end of pipe is a simple command
1174*4887Schin 				 * treat as non-sharable to improve performance
1175*4887Schin 				 */
1176*4887Schin 				if((t->fork.forktre->tre.tretyp&COMMSK)==TCOM)
1177*4887Schin 					sfset(sfstdin,SF_PUBLIC|SF_SHARE,0);
1178*4887Schin 				waitall = job.waitall;
1179*4887Schin 				job.waitall = 0;
1180*4887Schin 				pid = job.parent;
1181*4887Schin 			}
1182*4887Schin 			else
1183*4887Schin 				error_info.line = t->fork.forkline-sh.st.firstline;
1184*4887Schin 			jmpval = sigsetjmp(buff.buff,0);
1185*4887Schin 			if(jmpval==0)
1186*4887Schin 			{
1187*4887Schin 				sh_redirect(t->fork.forkio,execflg);
1188*4887Schin 				(t->fork.forktre)->tre.tretyp |= t->tre.tretyp&FSHOWME;
1189*4887Schin 				sh_exec(t->fork.forktre,flags);
1190*4887Schin 			}
1191*4887Schin 			sh_popcontext(&buff);
1192*4887Schin 			sh_iorestore(buff.topfd,jmpval);
1193*4887Schin 			if(buff.olist)
1194*4887Schin 				free_list(buff.olist);
1195*4887Schin 			if(type&FPIN)
1196*4887Schin 			{
1197*4887Schin 				job.waitall = waitall;
1198*4887Schin 				type = sh.exitval;
1199*4887Schin 				if(!(type&SH_EXITSIG))
1200*4887Schin 				{
1201*4887Schin 					/* wait for remainder of pipline */
1202*4887Schin 					job_wait(waitall?pid:0);
1203*4887Schin 					if(type || !sh_isoption(SH_PIPEFAIL))
1204*4887Schin 						sh.exitval = type;
1205*4887Schin 				}
1206*4887Schin 				sh.st.ioset = 0;
1207*4887Schin 			}
1208*4887Schin 			if(jmpval>SH_JMPIO)
1209*4887Schin 				siglongjmp(*sh.jmplist,jmpval);
1210*4887Schin 			break;
1211*4887Schin 		    }
1212*4887Schin 
1213*4887Schin 		    case TPAR:
1214*4887Schin 			echeck = 1;
1215*4887Schin 			flags &= ~OPTIMIZE_FLAG;
1216*4887Schin 			if(!sh.subshell && !sh.st.trapcom[0] && !sh.st.trap[SH_ERRTRAP] && (flags&sh_state(SH_NOFORK)))
1217*4887Schin 			{
1218*4887Schin 				int jmpval;
1219*4887Schin 				struct checkpt buff;
1220*4887Schin 				sh_pushcontext(&buff,SH_JMPEXIT);
1221*4887Schin 				jmpval = sigsetjmp(buff.buff,0);
1222*4887Schin 				if(jmpval==0)
1223*4887Schin 					sh_exec(t->par.partre,flags);
1224*4887Schin 				sh_popcontext(&buff);
1225*4887Schin 				if(jmpval > SH_JMPEXIT)
1226*4887Schin 					siglongjmp(*sh.jmplist,jmpval);
1227*4887Schin 				sh_done(0);
1228*4887Schin 			}
1229*4887Schin 			else
1230*4887Schin 				sh_subshell(t->par.partre,flags,0);
1231*4887Schin 			break;
1232*4887Schin 
1233*4887Schin 		    case TFIL:
1234*4887Schin 		    {
1235*4887Schin 		    /*
1236*4887Schin 		     * This code sets up a pipe.
1237*4887Schin 		     * All elements of the pipe are started by the parent.
1238*4887Schin 		     * The last element executes in current environment
1239*4887Schin 		     */
1240*4887Schin 			int	pvo[2];	/* old pipe for multi-stage */
1241*4887Schin 			int	pvn[2];	/* current set up pipe */
1242*4887Schin 			int	savepipe = pipejob;
1243*4887Schin 			int	showme = t->tre.tretyp&FSHOWME;
1244*4887Schin 			pid_t	savepgid = job.curpgid;
1245*4887Schin 			if(sh.subshell)
1246*4887Schin 				sh_subtmpfile();
1247*4887Schin 			sh.inpipe = pvo;
1248*4887Schin 			sh.outpipe = pvn;
1249*4887Schin 			pvo[1] = -1;
1250*4887Schin 			if(sh_isoption(SH_PIPEFAIL))
1251*4887Schin 				job.waitall = 1;
1252*4887Schin 			else
1253*4887Schin 				job.waitall |= !pipejob && sh_isstate(SH_MONITOR);
1254*4887Schin 			do
1255*4887Schin 			{
1256*4887Schin #if SHOPT_FASTPIPE
1257*4887Schin 				type = pipe_exec(pvn,t->lst.lstlef, errorflg);
1258*4887Schin #else
1259*4887Schin 				/* create the pipe */
1260*4887Schin 				sh_pipe(pvn);
1261*4887Schin 				/* execute out part of pipe no wait */
1262*4887Schin 				(t->lst.lstlef)->tre.tretyp |= showme;
1263*4887Schin 				type = sh_exec(t->lst.lstlef, errorflg);
1264*4887Schin #endif /* SHOPT_FASTPIPE */
1265*4887Schin 				pipejob=1;
1266*4887Schin 				/* save the pipe stream-ids */
1267*4887Schin 				pvo[0] = pvn[0];
1268*4887Schin 				/* close out-part of pipe */
1269*4887Schin 				sh_close(pvn[1]);
1270*4887Schin 				/* pipeline all in one process group */
1271*4887Schin 				t = t->lst.lstrit;
1272*4887Schin 			}
1273*4887Schin 			/* repeat until end of pipeline */
1274*4887Schin 			while(!type && t->tre.tretyp==TFIL);
1275*4887Schin 			sh.inpipe = pvn;
1276*4887Schin 			sh.outpipe = 0;
1277*4887Schin 			if(type == 0)
1278*4887Schin 			{
1279*4887Schin 				/*
1280*4887Schin 				 * execute last element of pipeline
1281*4887Schin 				 * in the current process
1282*4887Schin 				 */
1283*4887Schin 				((Shnode_t*)t)->tre.tretyp |= showme;
1284*4887Schin 				sh_exec(t,flags);
1285*4887Schin 			}
1286*4887Schin 			else
1287*4887Schin 				/* execution failure, close pipe */
1288*4887Schin 				sh_pclose(pvn);
1289*4887Schin 			pipejob = savepipe;
1290*4887Schin #ifdef SIGTSTP
1291*4887Schin 			if(!pipejob && sh_isstate(SH_MONITOR))
1292*4887Schin 				tcsetpgrp(JOBTTY,sh.pid);
1293*4887Schin #endif /*SIGTSTP */
1294*4887Schin 			job.curpgid = savepgid;
1295*4887Schin 			break;
1296*4887Schin 		    }
1297*4887Schin 
1298*4887Schin 		    case TLST:
1299*4887Schin 		    {
1300*4887Schin 			/*  a list of commands are executed here */
1301*4887Schin 			do
1302*4887Schin 			{
1303*4887Schin 				sh_exec(t->lst.lstlef,errorflg|OPTIMIZE);
1304*4887Schin 				t = t->lst.lstrit;
1305*4887Schin 			}
1306*4887Schin 			while(t->tre.tretyp == TLST);
1307*4887Schin 			sh_exec(t,flags);
1308*4887Schin 			break;
1309*4887Schin 		    }
1310*4887Schin 
1311*4887Schin 		    case TAND:
1312*4887Schin 			if(type&TTEST)
1313*4887Schin 				skipexitset++;
1314*4887Schin 			if(sh_exec(t->lst.lstlef,OPTIMIZE)==0)
1315*4887Schin 				sh_exec(t->lst.lstrit,flags);
1316*4887Schin 			break;
1317*4887Schin 
1318*4887Schin 		    case TORF:
1319*4887Schin 			if(type&TTEST)
1320*4887Schin 				skipexitset++;
1321*4887Schin 			if(sh_exec(t->lst.lstlef,OPTIMIZE)!=0)
1322*4887Schin 				sh_exec(t->lst.lstrit,flags);
1323*4887Schin 			break;
1324*4887Schin 
1325*4887Schin 		    case TFOR: /* for and select */
1326*4887Schin 		    {
1327*4887Schin 			register char **args;
1328*4887Schin 			register int nargs;
1329*4887Schin 			register Namval_t *np;
1330*4887Schin 			int flag = errorflg|OPTIMIZE_FLAG;
1331*4887Schin 			struct dolnod	*argsav=0;
1332*4887Schin 			struct comnod	*tp;
1333*4887Schin 			char *cp, *trap, *nullptr = 0;
1334*4887Schin 			int nameref, refresh=1;
1335*4887Schin 			static char *av[5] = { "for", 0, "in" };
1336*4887Schin #if SHOPT_OPTIMIZE
1337*4887Schin 			int  jmpval = ((struct checkpt*)sh.jmplist)->mode;
1338*4887Schin 			struct checkpt buff;
1339*4887Schin 			void *optlist = sh.optlist;
1340*4887Schin 			sh.optlist = 0;
1341*4887Schin 			sh_tclear(t->for_.fortre);
1342*4887Schin 			sh_pushcontext(&buff,jmpval);
1343*4887Schin 			jmpval = sigsetjmp(buff.buff,0);
1344*4887Schin 			if(jmpval)
1345*4887Schin 				goto endfor;
1346*4887Schin #endif /* SHOPT_OPTIMIZE */
1347*4887Schin 			error_info.line = t->for_.forline-sh.st.firstline;
1348*4887Schin 			if(!(tp=t->for_.forlst))
1349*4887Schin 			{
1350*4887Schin 				args=sh.st.dolv+1;
1351*4887Schin 				nargs = sh.st.dolc;
1352*4887Schin 				argsav=sh_arguse();
1353*4887Schin 			}
1354*4887Schin 			else
1355*4887Schin 			{
1356*4887Schin 				args=sh_argbuild(&argn,tp,0);
1357*4887Schin 				nargs = argn;
1358*4887Schin 			}
1359*4887Schin 			np = nv_open(t->for_.fornam, sh.var_tree,NV_NOASSIGN|NV_NOARRAY|NV_VARNAME|NV_NOREF);
1360*4887Schin 			nameref = nv_isref(np)!=0;
1361*4887Schin 			sh.st.loopcnt++;
1362*4887Schin 			cp = *args;
1363*4887Schin 			while(cp && sh.st.execbrk==0)
1364*4887Schin 			{
1365*4887Schin 				if(t->tre.tretyp&COMSCAN)
1366*4887Schin 				{
1367*4887Schin 					char *val;
1368*4887Schin 					int save_prompt;
1369*4887Schin 					/* reuse register */
1370*4887Schin 					if(refresh)
1371*4887Schin 					{
1372*4887Schin 						sh_menu(sfstderr,nargs,args);
1373*4887Schin 						refresh = 0;
1374*4887Schin 					}
1375*4887Schin 					save_prompt = sh.nextprompt;
1376*4887Schin 					sh.nextprompt = 3;
1377*4887Schin 					sh.timeout = 0;
1378*4887Schin 					sh.exitval=sh_readline(&sh,&nullptr,0,1,1000*sh.st.tmout);
1379*4887Schin 					sh.nextprompt = save_prompt;
1380*4887Schin 					if(sh.exitval||sfeof(sfstdin)||sferror(sfstdin))
1381*4887Schin 					{
1382*4887Schin 						sh.exitval = 1;
1383*4887Schin 						break;
1384*4887Schin 					}
1385*4887Schin 					if(!(val=nv_getval(nv_scoped(REPLYNOD))))
1386*4887Schin 						continue;
1387*4887Schin 					else
1388*4887Schin 					{
1389*4887Schin 						if(*(cp=val) == 0)
1390*4887Schin 						{
1391*4887Schin 							refresh++;
1392*4887Schin 							goto check;
1393*4887Schin 						}
1394*4887Schin 						while(type = *cp++)
1395*4887Schin 							if(type < '0' && type > '9')
1396*4887Schin 								break;
1397*4887Schin 						if(type!=0)
1398*4887Schin 							type = nargs;
1399*4887Schin 						else
1400*4887Schin 							type = (int)strtol(val, (char**)0, 10)-1;
1401*4887Schin 						if(type<0 || type >= nargs)
1402*4887Schin 							cp = "";
1403*4887Schin 						else
1404*4887Schin 							cp = args[type];
1405*4887Schin 					}
1406*4887Schin 				}
1407*4887Schin 				if(nameref)
1408*4887Schin 					nv_offattr(np,NV_REF);
1409*4887Schin 				else if(nv_isattr(np, NV_ARRAY))
1410*4887Schin 					nv_putsub(np,NIL(char*),0L);
1411*4887Schin 				nv_putval(np,cp,0);
1412*4887Schin 				if(nameref)
1413*4887Schin 					nv_setref(np,(Dt_t*)0,NV_VARNAME);
1414*4887Schin 				if(trap=sh.st.trap[SH_DEBUGTRAP])
1415*4887Schin 				{
1416*4887Schin 					av[0] = (t->tre.tretyp&COMSCAN)?"select":"for";
1417*4887Schin 					av[1] = t->for_.fornam;
1418*4887Schin 					av[3] = cp;
1419*4887Schin 					sh_debug(trap,(char*)0,(char*)0,av,0);
1420*4887Schin 				}
1421*4887Schin 				sh_exec(t->for_.fortre,flag);
1422*4887Schin 				flag &= ~OPTIMIZE_FLAG;
1423*4887Schin 				if(t->tre.tretyp&COMSCAN)
1424*4887Schin 				{
1425*4887Schin 					if((cp=nv_getval(nv_scoped(REPLYNOD))) && *cp==0)
1426*4887Schin 						refresh++;
1427*4887Schin 				}
1428*4887Schin 				else
1429*4887Schin 					cp = *++args;
1430*4887Schin 			check:
1431*4887Schin 				if(sh.st.breakcnt<0)
1432*4887Schin 					sh.st.execbrk = (++sh.st.breakcnt !=0);
1433*4887Schin 			}
1434*4887Schin #if SHOPT_OPTIMIZE
1435*4887Schin 		endfor:
1436*4887Schin 			sh_popcontext(&buff);
1437*4887Schin 			sh_tclear(t->for_.fortre);
1438*4887Schin 			sh_optclear(&sh,optlist);
1439*4887Schin 			if(jmpval)
1440*4887Schin 				siglongjmp(*sh.jmplist,jmpval);
1441*4887Schin #endif /*SHOPT_OPTIMIZE */
1442*4887Schin 			if(sh.st.breakcnt>0)
1443*4887Schin 				sh.st.execbrk = (--sh.st.breakcnt !=0);
1444*4887Schin 			sh.st.loopcnt--;
1445*4887Schin 			sh_argfree(argsav,0);
1446*4887Schin 			nv_close(np);
1447*4887Schin 			break;
1448*4887Schin 		    }
1449*4887Schin 
1450*4887Schin 		    case TWH: /* while and until */
1451*4887Schin 		    {
1452*4887Schin 			register int 	r=0;
1453*4887Schin 			int first = OPTIMIZE_FLAG;
1454*4887Schin 			Shnode_t *tt = t->wh.whtre;
1455*4887Schin #if SHOPT_FILESCAN
1456*4887Schin 			Sfio_t *iop=0;
1457*4887Schin 			int savein,fd;
1458*4887Schin #endif /*SHOPT_FILESCAN*/
1459*4887Schin #if SHOPT_OPTIMIZE
1460*4887Schin 			int  jmpval = ((struct checkpt*)sh.jmplist)->mode;
1461*4887Schin 			struct checkpt buff;
1462*4887Schin 			void *optlist = sh.optlist;
1463*4887Schin 			sh.optlist = 0;
1464*4887Schin 			sh_tclear(t->wh.whtre);
1465*4887Schin 			sh_tclear(t->wh.dotre);
1466*4887Schin 			sh_pushcontext(&buff,jmpval);
1467*4887Schin 			jmpval = sigsetjmp(buff.buff,0);
1468*4887Schin 			if(jmpval)
1469*4887Schin 				goto endwhile;
1470*4887Schin #endif /* SHOPT_OPTIMIZE */
1471*4887Schin #if SHOPT_FILESCAN
1472*4887Schin 			if(type==TWH && tt->tre.tretyp==TCOM && !tt->com.comarg && tt->com.comio)
1473*4887Schin 			{
1474*4887Schin 				fd = sh_redirect(tt->com.comio,3);
1475*4887Schin 				savein = dup(0);
1476*4887Schin 				if(fd==0)
1477*4887Schin 					fd = savein;
1478*4887Schin 				iop = sfnew(NULL,NULL,SF_UNBOUND,fd,SF_READ);
1479*4887Schin 				close(0);
1480*4887Schin 				open("/dev/null",O_RDONLY);
1481*4887Schin 				sh.offsets[0] = -1;
1482*4887Schin 				sh.offsets[1] = 0;
1483*4887Schin 				if(tt->com.comset)
1484*4887Schin 					nv_setlist(tt->com.comset,NV_IDENT|NV_ASSIGN);
1485*4887Schin 			}
1486*4887Schin #endif /*SHOPT_FILESCAN */
1487*4887Schin 			sh.st.loopcnt++;
1488*4887Schin 			while(sh.st.execbrk==0)
1489*4887Schin 			{
1490*4887Schin #if SHOPT_FILESCAN
1491*4887Schin 				if(iop)
1492*4887Schin 				{
1493*4887Schin 					if(!(sh.cur_line=sfgetr(iop,'\n',SF_STRING)))
1494*4887Schin 						break;
1495*4887Schin 				}
1496*4887Schin 				else
1497*4887Schin #endif /*SHOPT_FILESCAN */
1498*4887Schin 				if((sh_exec(tt,first)==0)!=(type==TWH))
1499*4887Schin 					break;
1500*4887Schin 				r = sh_exec(t->wh.dotre,first|errorflg);
1501*4887Schin 				if(sh.st.breakcnt<0)
1502*4887Schin 					sh.st.execbrk = (++sh.st.breakcnt !=0);
1503*4887Schin 				/* This is for the arithmetic for */
1504*4887Schin 				if(sh.st.execbrk==0 && t->wh.whinc)
1505*4887Schin 					sh_exec((Shnode_t*)t->wh.whinc,first);
1506*4887Schin 				first = 0;
1507*4887Schin 				errorflg &= ~OPTIMIZE_FLAG;
1508*4887Schin #if SHOPT_FILESCAN
1509*4887Schin 				sh.offsets[0] = -1;
1510*4887Schin 				sh.offsets[1] = 0;
1511*4887Schin #endif /*SHOPT_FILESCAN */
1512*4887Schin 			}
1513*4887Schin #if SHOPT_OPTIMIZE
1514*4887Schin 		endwhile:
1515*4887Schin 			sh_popcontext(&buff);
1516*4887Schin 			sh_tclear(t->wh.whtre);
1517*4887Schin 			sh_tclear(t->wh.dotre);
1518*4887Schin 			sh_optclear(&sh,optlist);
1519*4887Schin 			if(jmpval)
1520*4887Schin 				siglongjmp(*sh.jmplist,jmpval);
1521*4887Schin #endif /*SHOPT_OPTIMIZE */
1522*4887Schin 			if(sh.st.breakcnt>0)
1523*4887Schin 				sh.st.execbrk = (--sh.st.breakcnt !=0);
1524*4887Schin 			sh.st.loopcnt--;
1525*4887Schin 			sh.exitval= r;
1526*4887Schin #if SHOPT_FILESCAN
1527*4887Schin 			if(iop)
1528*4887Schin 			{
1529*4887Schin 				sfclose(iop);
1530*4887Schin 				close(0);
1531*4887Schin 				dup(savein);
1532*4887Schin 				sh.cur_line = 0;
1533*4887Schin 			}
1534*4887Schin #endif /*SHOPT_FILESCAN */
1535*4887Schin 			break;
1536*4887Schin 		    }
1537*4887Schin 		    case TARITH: /* (( expression )) */
1538*4887Schin 		    {
1539*4887Schin 			register char *trap;
1540*4887Schin 			static char *arg[4]=  {"((", 0, "))"};
1541*4887Schin 			error_info.line = t->ar.arline-sh.st.firstline;
1542*4887Schin 			if(!(t->ar.arexpr->argflag&ARG_RAW))
1543*4887Schin 				arg[1] = sh_macpat(t->ar.arexpr,OPTIMIZE|ARG_ARITH);
1544*4887Schin 			else
1545*4887Schin 				arg[1] = t->ar.arexpr->argval;
1546*4887Schin 			if(trap=sh.st.trap[SH_DEBUGTRAP])
1547*4887Schin 				sh_debug(trap,(char*)0, (char*)0, arg, ARG_ARITH);
1548*4887Schin 			if(sh_isoption(SH_XTRACE))
1549*4887Schin 			{
1550*4887Schin 				sh_trace(NIL(char**),0);
1551*4887Schin 				sfprintf(sfstderr,"((%s))\n",arg[1]);
1552*4887Schin 			}
1553*4887Schin 			if(t->ar.arcomp)
1554*4887Schin 				sh.exitval  = !arith_exec((Arith_t*)t->ar.arcomp);
1555*4887Schin 			else
1556*4887Schin 				sh.exitval = !sh_arith(arg[1]);
1557*4887Schin 			break;
1558*4887Schin 		    }
1559*4887Schin 
1560*4887Schin 		    case TIF:
1561*4887Schin 			if(sh_exec(t->if_.iftre,OPTIMIZE)==0)
1562*4887Schin 				sh_exec(t->if_.thtre,flags);
1563*4887Schin 			else if(t->if_.eltre)
1564*4887Schin 				sh_exec(t->if_.eltre, flags);
1565*4887Schin 			else
1566*4887Schin 				sh.exitval=0; /* force zero exit for if-then-fi */
1567*4887Schin 			break;
1568*4887Schin 
1569*4887Schin 		    case TSW:
1570*4887Schin 		    {
1571*4887Schin 			Shnode_t *tt = (Shnode_t*)t;
1572*4887Schin 			char *trap, *r = sh_macpat(tt->sw.swarg,OPTIMIZE);
1573*4887Schin 			error_info.line = t->sw.swline-sh.st.firstline;
1574*4887Schin 			t= (Shnode_t*)(tt->sw.swlst);
1575*4887Schin 			if(trap=sh.st.trap[SH_DEBUGTRAP])
1576*4887Schin 			{
1577*4887Schin 				static char *av[4] = {"case", 0, "in" };
1578*4887Schin 				av[1] = r;
1579*4887Schin 				sh_debug(trap, (char*)0, (char*)0, av, 0);
1580*4887Schin 			}
1581*4887Schin 			while(t)
1582*4887Schin 			{
1583*4887Schin 				register struct argnod	*rex=(struct argnod*)t->reg.regptr;
1584*4887Schin 				while(rex)
1585*4887Schin 				{
1586*4887Schin 					register char *s;
1587*4887Schin 					if(rex->argflag&ARG_MAC)
1588*4887Schin 					{
1589*4887Schin 						s = sh_macpat(rex,OPTIMIZE|ARG_EXP);
1590*4887Schin 						while(*s=='\\' && s[1]==0)
1591*4887Schin 							s+=2;
1592*4887Schin 					}
1593*4887Schin 					else
1594*4887Schin 						s = rex->argval;
1595*4887Schin 					type = (rex->argflag&ARG_RAW);
1596*4887Schin 					if((type && strcmp(r,s)==0) ||
1597*4887Schin 						(!type && (strmatch(r,s)
1598*4887Schin 						|| trim_eq(r,s))))
1599*4887Schin 					{
1600*4887Schin 						do	sh_exec(t->reg.regcom,(t->reg.regflag?0:flags));
1601*4887Schin 						while(t->reg.regflag &&
1602*4887Schin 							(t=(Shnode_t*)t->reg.regnxt));
1603*4887Schin 						t=0;
1604*4887Schin 						break;
1605*4887Schin 					}
1606*4887Schin 					else
1607*4887Schin 						rex=rex->argnxt.ap;
1608*4887Schin 				}
1609*4887Schin 				if(t)
1610*4887Schin 					t=(Shnode_t*)t->reg.regnxt;
1611*4887Schin 			}
1612*4887Schin 			break;
1613*4887Schin 		    }
1614*4887Schin 
1615*4887Schin 		    case TTIME:
1616*4887Schin 		    {
1617*4887Schin 			/* time the command */
1618*4887Schin 			struct tms before,after;
1619*4887Schin 			const char *format = e_timeformat;
1620*4887Schin 			clock_t at, tm[3];
1621*4887Schin #ifdef timeofday
1622*4887Schin 			struct timeval tb,ta;
1623*4887Schin #else
1624*4887Schin 			clock_t bt;
1625*4887Schin #endif	/* timeofday */
1626*4887Schin 			if(type!=TTIME)
1627*4887Schin 			{
1628*4887Schin 				sh_exec(t->par.partre,OPTIMIZE);
1629*4887Schin 				sh.exitval = !sh.exitval;
1630*4887Schin 				break;
1631*4887Schin 			}
1632*4887Schin 			if(t->par.partre)
1633*4887Schin 			{
1634*4887Schin 				long timer_on;
1635*4887Schin 				timer_on = sh_isstate(SH_TIMING);
1636*4887Schin #ifdef timeofday
1637*4887Schin 				timeofday(&tb);
1638*4887Schin 				times(&before);
1639*4887Schin #else
1640*4887Schin 				bt = times(&before);
1641*4887Schin #endif	/* timeofday */
1642*4887Schin 				job.waitall = 1;
1643*4887Schin 				sh_onstate(SH_TIMING);
1644*4887Schin 				sh_exec(t->par.partre,OPTIMIZE);
1645*4887Schin 				if(!timer_on)
1646*4887Schin 					sh_offstate(SH_TIMING);
1647*4887Schin 				job.waitall = 0;
1648*4887Schin 			}
1649*4887Schin 			else
1650*4887Schin 			{
1651*4887Schin #ifndef timeofday
1652*4887Schin 				bt = 0;
1653*4887Schin #endif	/* timeofday */
1654*4887Schin 				before.tms_utime = before.tms_cutime = 0;
1655*4887Schin 				before.tms_stime = before.tms_cstime = 0;
1656*4887Schin 			}
1657*4887Schin #ifdef timeofday
1658*4887Schin 			times(&after);
1659*4887Schin 			timeofday(&ta);
1660*4887Schin 			at = sh.lim.clk_tck*(ta.tv_sec-tb.tv_sec);
1661*4887Schin 			at +=  ((sh.lim.clk_tck*(((1000000L/2)/sh.lim.clk_tck)+(ta.tv_usec-tb.tv_usec)))/1000000L);
1662*4887Schin #else
1663*4887Schin 			at = times(&after) - bt;
1664*4887Schin #endif	/* timeofday */
1665*4887Schin 			tm[0] = at;
1666*4887Schin 			if(t->par.partre)
1667*4887Schin 			{
1668*4887Schin 				Namval_t *np = nv_open("TIMEFORMAT",sh.var_tree,NV_NOADD);
1669*4887Schin 				if(np)
1670*4887Schin 				{
1671*4887Schin 					format = nv_getval(np);
1672*4887Schin 					nv_close(np);
1673*4887Schin 				}
1674*4887Schin 				if(!format)
1675*4887Schin 					format = e_timeformat;
1676*4887Schin 			}
1677*4887Schin 			else
1678*4887Schin 			{
1679*4887Schin 				format = strchr(format+1,'\n')+1;
1680*4887Schin #if 0
1681*4887Schin 				if(sh.optcount)
1682*4887Schin 					sfprintf(sfstderr,"%d optimizations\n",sh.optcount);
1683*4887Schin #endif
1684*4887Schin 			}
1685*4887Schin 			tm[1] = after.tms_utime - before.tms_utime;
1686*4887Schin 			tm[1] += after.tms_cutime - before.tms_cutime;
1687*4887Schin 			tm[2] = after.tms_stime - before.tms_stime;
1688*4887Schin 			tm[2] += after.tms_cstime - before.tms_cstime;
1689*4887Schin 			if(format && *format)
1690*4887Schin 				p_time(sfstderr,sh_translate(format),tm);
1691*4887Schin 			break;
1692*4887Schin 		    }
1693*4887Schin 		    case TFUN:
1694*4887Schin 		    {
1695*4887Schin 			register Namval_t *np;
1696*4887Schin 			register struct slnod *slp;
1697*4887Schin 			register char *fname = ((struct functnod*)t)->functnam;
1698*4887Schin 			register char *cp = strrchr(fname,'.');
1699*4887Schin 			register Namval_t *npv=0;
1700*4887Schin #if SHOPT_NAMESPACE
1701*4887Schin 			if(t->tre.tretyp==TNSPACE)
1702*4887Schin 			{
1703*4887Schin 				Dt_t *root,*oldroot, *top=0;
1704*4887Schin 				Namval_t *oldnspace = sh.namespace;
1705*4887Schin 				int offset = staktell();
1706*4887Schin 				long optindex = sh.st.optindex;
1707*4887Schin 				if(cp)
1708*4887Schin 					errormsg(SH_DICT,ERROR_exit(1),e_ident,fname);
1709*4887Schin 				stakputc('.');
1710*4887Schin 				stakputs(fname);
1711*4887Schin 				stakputc(0);
1712*4887Schin 				np = nv_open(stakptr(offset),sh.var_base,NV_NOASSIGN|NV_NOARRAY|NV_VARNAME);
1713*4887Schin 				offset = staktell();
1714*4887Schin 				sh.namespace = np;
1715*4887Schin 				if(!(root=nv_dict(np)))
1716*4887Schin 				{
1717*4887Schin 					root = dtopen(&_Nvdisc,Dtoset);
1718*4887Schin 					nv_putval(np,(char*)root,NV_TABLE|NV_NOFREE);
1719*4887Schin 					sh.st.optindex = 1;
1720*4887Schin 				}
1721*4887Schin 				if(oldnspace && dtvnext(dtvnext(sh.var_tree)))
1722*4887Schin 					top = dtview(sh.var_tree,0);
1723*4887Schin 				else if(dtvnext(sh.var_tree))
1724*4887Schin 					top = dtview(sh.var_tree,0);
1725*4887Schin 				oldroot = sh.var_tree;
1726*4887Schin 				dtview(root,sh.var_base);
1727*4887Schin 				sh.var_tree = root;
1728*4887Schin 				if(top)
1729*4887Schin 					dtview(sh.var_tree,top);
1730*4887Schin 				sh_exec(t->for_.fortre,flags);
1731*4887Schin 				if(dtvnext(sh.var_tree))
1732*4887Schin 					top = dtview(sh.var_tree,0);
1733*4887Schin 				sh.var_tree = oldroot;
1734*4887Schin 				if(top)
1735*4887Schin 					dtview(top,sh.var_tree);
1736*4887Schin 				sh.namespace = oldnspace;
1737*4887Schin 				sh.st.optindex = optindex;
1738*4887Schin 				break;
1739*4887Schin 			}
1740*4887Schin #endif /* SHOPT_NAMESPACE */
1741*4887Schin 			/* look for discipline functions */
1742*4887Schin 			error_info.line = t->funct.functline-sh.st.firstline;
1743*4887Schin 			/* Function names cannot be special builtin */
1744*4887Schin 			if(cp || sh.prefix)
1745*4887Schin 			{
1746*4887Schin 				int offset = staktell();
1747*4887Schin 				if(sh.prefix)
1748*4887Schin 				{
1749*4887Schin 					cp = sh.prefix;
1750*4887Schin 					sh.prefix = 0;
1751*4887Schin 					npv = nv_open(cp,sh.var_tree,NV_NOASSIGN|NV_NOARRAY|NV_VARNAME);
1752*4887Schin 					sh.prefix = cp;
1753*4887Schin 					cp = fname;
1754*4887Schin 				}
1755*4887Schin 				else
1756*4887Schin 				{
1757*4887Schin 					stakwrite(fname,cp-fname);
1758*4887Schin 					stakputc(0);
1759*4887Schin 					npv = nv_open(stakptr(offset),sh.var_tree,NV_NOASSIGN|NV_NOARRAY|NV_VARNAME);
1760*4887Schin 				}
1761*4887Schin 				offset = staktell();
1762*4887Schin 				stakputs(nv_name(npv));
1763*4887Schin 				if(*cp!='.')
1764*4887Schin 					stakputc('.');
1765*4887Schin 				stakputs(cp);
1766*4887Schin 				stakputc(0);
1767*4887Schin 				fname = stakptr(offset);
1768*4887Schin 			}
1769*4887Schin 			else if((np=nv_search(fname,sh.bltin_tree,0)) && nv_isattr(np,BLT_SPC))
1770*4887Schin 				errormsg(SH_DICT,ERROR_exit(1),e_badfun,fname);
1771*4887Schin #if SHOPT_NAMESPACE
1772*4887Schin 			else if(sh.namespace)
1773*4887Schin 			{
1774*4887Schin 				int offset = staktell();
1775*4887Schin 				stakputs(nv_name(sh.namespace));
1776*4887Schin 				stakputc('.');
1777*4887Schin 				stakputs(fname);
1778*4887Schin 				stakputc(0);
1779*4887Schin 				fname = stakptr(offset);
1780*4887Schin 			}
1781*4887Schin #endif /* SHOPT_NAMESPACE */
1782*4887Schin 			np = nv_open(fname,sh_subfuntree(1),NV_NOASSIGN|NV_NOARRAY|NV_VARNAME|NV_NOSCOPE);
1783*4887Schin 			if(npv)
1784*4887Schin 			{
1785*4887Schin 				if(!sh.mktype)
1786*4887Schin 					cp = nv_setdisc(npv,cp+1,np,(Namfun_t*)npv);
1787*4887Schin 				nv_close(npv);
1788*4887Schin 				if(!cp)
1789*4887Schin 					errormsg(SH_DICT,ERROR_exit(1),e_baddisc,fname);
1790*4887Schin 			}
1791*4887Schin 			if(np->nvalue.rp)
1792*4887Schin 			{
1793*4887Schin 				slp = (struct slnod*)np->nvenv;
1794*4887Schin 				sh_funstaks(slp->slchild,-1);
1795*4887Schin 				stakdelete(slp->slptr);
1796*4887Schin 			}
1797*4887Schin 			else
1798*4887Schin 				np->nvalue.rp = new_of(struct Ufunction,0);
1799*4887Schin 			if(t->funct.functstak)
1800*4887Schin 			{
1801*4887Schin 				struct functnod *fp;
1802*4887Schin 				slp = t->funct.functstak;
1803*4887Schin 				sh_funstaks(slp->slchild,1);
1804*4887Schin 				staklink(slp->slptr);
1805*4887Schin 				np->nvenv = (char*)slp;
1806*4887Schin 				nv_funtree(np) = (int*)(t->funct.functtre);
1807*4887Schin 				np->nvalue.rp->hoffset = t->funct.functloc;
1808*4887Schin 				np->nvalue.rp->lineno = t->funct.functline;
1809*4887Schin 				np->nvalue.rp->nspace = sh.namespace;
1810*4887Schin 				np->nvalue.rp->fname = 0;
1811*4887Schin 				fp = (struct functnod*)(slp+1);
1812*4887Schin 				if(fp->functtyp==(TFUN|FAMP))
1813*4887Schin 					np->nvalue.rp->fname = fp->functnam;
1814*4887Schin 				nv_setsize(np,fp->functline);
1815*4887Schin 				nv_offattr(np,NV_FPOSIX);
1816*4887Schin 			}
1817*4887Schin 			else
1818*4887Schin 				nv_unset(np);
1819*4887Schin 			if(type&FPOSIX)
1820*4887Schin 				nv_onattr(np,NV_FUNCTION|NV_FPOSIX);
1821*4887Schin 			else
1822*4887Schin 				nv_onattr(np,NV_FUNCTION);
1823*4887Schin 			if(type&FPIN)
1824*4887Schin 				nv_onattr(np,NV_FTMP);
1825*4887Schin 			break;
1826*4887Schin 		    }
1827*4887Schin 
1828*4887Schin 		    /* new test compound command */
1829*4887Schin 		    case TTST:
1830*4887Schin 		    {
1831*4887Schin 			register int n;
1832*4887Schin 			register char *left;
1833*4887Schin 			int negate = (type&TNEGATE)!=0;
1834*4887Schin 			if(type&TTEST)
1835*4887Schin 				skipexitset++;
1836*4887Schin 			error_info.line = t->tst.tstline-sh.st.firstline;
1837*4887Schin 			echeck = 1;
1838*4887Schin 			if((type&TPAREN)==TPAREN)
1839*4887Schin 			{
1840*4887Schin 				sh_exec(t->lst.lstlef,OPTIMIZE);
1841*4887Schin 				n = !sh.exitval;
1842*4887Schin 			}
1843*4887Schin 			else
1844*4887Schin 			{
1845*4887Schin 				register int traceon=0;
1846*4887Schin 				register char *right;
1847*4887Schin 				register char *trap;
1848*4887Schin 				char *argv[6];
1849*4887Schin 				n = type>>TSHIFT;
1850*4887Schin 				left = sh_macpat(&(t->lst.lstlef->arg),OPTIMIZE);
1851*4887Schin 				if(type&TBINARY)
1852*4887Schin 					right = sh_macpat(&(t->lst.lstrit->arg),((n==TEST_PEQ||n==TEST_PNE)?ARG_EXP:0)|OPTIMIZE);
1853*4887Schin 				if(trap=sh.st.trap[SH_DEBUGTRAP])
1854*4887Schin 					argv[0] = (type&TNEGATE)?((char*)e_tstbegin):"[[";
1855*4887Schin 				if(sh_isoption(SH_XTRACE))
1856*4887Schin 				{
1857*4887Schin 					traceon = sh_trace(NIL(char**),0);
1858*4887Schin 					sfwrite(sfstderr,e_tstbegin,(type&TNEGATE?5:3));
1859*4887Schin 				}
1860*4887Schin 				if(type&TUNARY)
1861*4887Schin 				{
1862*4887Schin 					if(traceon)
1863*4887Schin 						sfprintf(sfstderr,"-%c %s",n,sh_fmtq(left));
1864*4887Schin 					if(trap)
1865*4887Schin 					{
1866*4887Schin 						char unop[3];
1867*4887Schin 						unop[0] = '-';
1868*4887Schin 						unop[1] = n;
1869*4887Schin 						unop[2] = 0;
1870*4887Schin 						argv[1] = unop;
1871*4887Schin 						argv[2] = left;
1872*4887Schin 						argv[3] = "]]";
1873*4887Schin 						argv[4] = 0;
1874*4887Schin 						sh_debug(trap,(char*)0,(char*)0,argv, 0);
1875*4887Schin 					}
1876*4887Schin 					n = test_unop(n,left);
1877*4887Schin 				}
1878*4887Schin 				else if(type&TBINARY)
1879*4887Schin 				{
1880*4887Schin 					char *op;
1881*4887Schin 					int pattern = 0;
1882*4887Schin 					if(trap || traceon)
1883*4887Schin 						op = (char*)(shtab_testops+(n&037)-1)->sh_name;
1884*4887Schin 					type >>= TSHIFT;
1885*4887Schin 					if(type==TEST_PEQ || type==TEST_PNE)
1886*4887Schin 						pattern=ARG_EXP;
1887*4887Schin 					if(trap)
1888*4887Schin 					{
1889*4887Schin 						argv[1] = left;
1890*4887Schin 						argv[2] = op;
1891*4887Schin 						argv[3] = right;
1892*4887Schin 						argv[4] = "]]";
1893*4887Schin 						argv[5] = 0;
1894*4887Schin 						sh_debug(trap,(char*)0,(char*)0,argv, pattern);
1895*4887Schin 					}
1896*4887Schin 					n = test_binop(n,left,right);
1897*4887Schin 					if(traceon)
1898*4887Schin 					{
1899*4887Schin 						sfprintf(sfstderr,"%s %s ",sh_fmtq(left),op);
1900*4887Schin 						if(pattern)
1901*4887Schin 							out_pattern(sfstderr,right,-1);
1902*4887Schin 						else
1903*4887Schin 							sfputr(sfstderr,sh_fmtq(right),-1);
1904*4887Schin 					}
1905*4887Schin 				}
1906*4887Schin 				if(traceon)
1907*4887Schin 					sfwrite(sfstderr,e_tstend,4);
1908*4887Schin 			}
1909*4887Schin 			sh.exitval = ((!n)^negate);
1910*4887Schin 			if(!skipexitset)
1911*4887Schin 				exitset();
1912*4887Schin 			break;
1913*4887Schin 		    }
1914*4887Schin 		}
1915*4887Schin 		if(sh.trapnote || (sh.exitval && sh_isstate(SH_ERREXIT)) &&
1916*4887Schin 			t && echeck)
1917*4887Schin 			sh_chktrap();
1918*4887Schin 		/* set $_ */
1919*4887Schin 		if(mainloop && com0)
1920*4887Schin 		{
1921*4887Schin 			/* store last argument here if it fits */
1922*4887Schin 			static char	lastarg[32];
1923*4887Schin 			if(sh_isstate(SH_FORKED))
1924*4887Schin 				sh_done(0);
1925*4887Schin 			if(sh.lastarg!= lastarg && sh.lastarg)
1926*4887Schin 				free(sh.lastarg);
1927*4887Schin 			if(strlen(com[argn-1]) < sizeof(lastarg))
1928*4887Schin 			{
1929*4887Schin 				nv_onattr(L_ARGNOD,NV_NOFREE);
1930*4887Schin 				sh.lastarg = strcpy(lastarg,com[argn-1]);
1931*4887Schin 			}
1932*4887Schin 			else
1933*4887Schin 			{
1934*4887Schin 				nv_offattr(L_ARGNOD,NV_NOFREE);
1935*4887Schin 				sh.lastarg = strdup(com[argn-1]);
1936*4887Schin 			}
1937*4887Schin 		}
1938*4887Schin 		if(!skipexitset)
1939*4887Schin 			exitset();
1940*4887Schin 		if(!(OPTIMIZE))
1941*4887Schin 		{
1942*4887Schin 			if(sav != stakptr(0))
1943*4887Schin 				stakset(sav,0);
1944*4887Schin 			else if(staktell())
1945*4887Schin 				stakseek(0);
1946*4887Schin 		}
1947*4887Schin 		if(sh.trapnote&SH_SIGSET)
1948*4887Schin 			sh_exit(SH_EXITSIG|sh.lastsig);
1949*4887Schin 		if(was_interactive)
1950*4887Schin 			sh_onstate(SH_INTERACTIVE);
1951*4887Schin 		if(was_monitor && sh_isoption(SH_MONITOR))
1952*4887Schin 			sh_onstate(SH_MONITOR);
1953*4887Schin 		if(was_errexit)
1954*4887Schin 			sh_onstate(SH_ERREXIT);
1955*4887Schin 	}
1956*4887Schin 	return(sh.exitval);
1957*4887Schin }
1958*4887Schin 
1959*4887Schin /*
1960*4887Schin  * test for equality with second argument trimmed
1961*4887Schin  * returns 1 if r == trim(s) otherwise 0
1962*4887Schin  */
1963*4887Schin 
1964*4887Schin static int trim_eq(register const char *r,register const char *s)
1965*4887Schin {
1966*4887Schin 	register char c;
1967*4887Schin 	while(c = *s++)
1968*4887Schin 	{
1969*4887Schin 		if(c=='\\')
1970*4887Schin 			c = *s++;
1971*4887Schin 		if(c && c != *r++)
1972*4887Schin 			return(0);
1973*4887Schin 	}
1974*4887Schin 	return(*r==0);
1975*4887Schin }
1976*4887Schin 
1977*4887Schin /*
1978*4887Schin  * print out the command line if set -x is on
1979*4887Schin  */
1980*4887Schin 
1981*4887Schin int sh_trace(register char *argv[], register int nl)
1982*4887Schin {
1983*4887Schin 	register char *cp;
1984*4887Schin 	register int bracket = 0;
1985*4887Schin 	if(sh_isoption(SH_XTRACE))
1986*4887Schin 	{
1987*4887Schin 		/* make this trace atomic */
1988*4887Schin 		sfset(sfstderr,SF_SHARE|SF_PUBLIC,0);
1989*4887Schin 		if(!(cp=nv_getval(nv_scoped(PS4NOD))))
1990*4887Schin 			cp = "+ ";
1991*4887Schin 		else
1992*4887Schin 		{
1993*4887Schin 			sh_offoption(SH_XTRACE);
1994*4887Schin 			cp = sh_mactry(cp);
1995*4887Schin 			sh_onoption(SH_XTRACE);
1996*4887Schin 		}
1997*4887Schin 		if(*cp)
1998*4887Schin 			sfputr(sfstderr,cp,-1);
1999*4887Schin 		if(argv)
2000*4887Schin 		{
2001*4887Schin 			char *argv0 = *argv;
2002*4887Schin 			nl = (nl?'\n':-1);
2003*4887Schin 			/* don't quote [ and [[ */
2004*4887Schin 			if(*(cp=argv[0])=='[' && (!cp[1] || !cp[2]&&cp[1]=='['))
2005*4887Schin 			{
2006*4887Schin 				sfputr(sfstderr,cp,*++argv?' ':nl);
2007*4887Schin 				bracket = 1;
2008*4887Schin 			}
2009*4887Schin 			while(cp = *argv++)
2010*4887Schin 			{
2011*4887Schin 				if(bracket==0 || *argv || *cp!=']')
2012*4887Schin 					cp = sh_fmtq(cp);
2013*4887Schin 				if(sh.prefix && cp!=argv0 && *cp!='-')
2014*4887Schin 				{
2015*4887Schin 					if(*cp=='.' && cp[1]==0)
2016*4887Schin 						cp = sh.prefix;
2017*4887Schin 					else
2018*4887Schin 						sfputr(sfstderr,sh.prefix,'.');
2019*4887Schin 				}
2020*4887Schin 				sfputr(sfstderr,cp,*argv?' ':nl);
2021*4887Schin 			}
2022*4887Schin 			sfset(sfstderr,SF_SHARE|SF_PUBLIC,1);
2023*4887Schin 		}
2024*4887Schin 		return(1);
2025*4887Schin 	}
2026*4887Schin 	return(0);
2027*4887Schin }
2028*4887Schin 
2029*4887Schin /*
2030*4887Schin  * This routine creates a subshell by calling fork() or vfork()
2031*4887Schin  * If ((flags&COMASK)==TCOM), then vfork() is permitted
2032*4887Schin  * If fork fails, the shell sleeps for exponentially longer periods
2033*4887Schin  *   and tries again until a limit is reached.
2034*4887Schin  * SH_FORKLIM is the max period between forks - power of 2 usually.
2035*4887Schin  * Currently shell tries after 2,4,8,16, and 32 seconds and then quits
2036*4887Schin  * Failures cause the routine to error exit.
2037*4887Schin  * Parent links to here-documents are removed by the child
2038*4887Schin  * Traps are reset by the child
2039*4887Schin  * The process-id of the child is returned to the parent, 0 to the child.
2040*4887Schin  */
2041*4887Schin 
2042*4887Schin static void timed_out(void *handle)
2043*4887Schin {
2044*4887Schin 	NOT_USED(handle);
2045*4887Schin 	timeout = 0;
2046*4887Schin }
2047*4887Schin 
2048*4887Schin 
2049*4887Schin /*
2050*4887Schin  * called by parent and child after fork by sh_fork()
2051*4887Schin  */
2052*4887Schin pid_t _sh_fork(register pid_t parent,int flags,int *jobid)
2053*4887Schin {
2054*4887Schin 	static long forkcnt = 1000L;
2055*4887Schin 	pid_t	curpgid = job.curpgid;
2056*4887Schin 	pid_t	postid = (flags&FAMP)?0:curpgid;
2057*4887Schin 	int sig;
2058*4887Schin 	if(parent<0)
2059*4887Schin 	{
2060*4887Schin 		if((forkcnt *= 2) > 1000L*SH_FORKLIM)
2061*4887Schin 		{
2062*4887Schin 			forkcnt=1000L;
2063*4887Schin 			errormsg(SH_DICT,ERROR_system(ERROR_NOEXEC),e_nofork);
2064*4887Schin 		}
2065*4887Schin 		sh_sigcheck();
2066*4887Schin 		timeout = (void*)sh_timeradd(forkcnt, 0, timed_out, NIL(void*));
2067*4887Schin 		job_wait((pid_t)1);
2068*4887Schin 		if(timeout)
2069*4887Schin 		{
2070*4887Schin 			timerdel(timeout);
2071*4887Schin 			forkcnt /= 2;
2072*4887Schin 		}
2073*4887Schin 		return(-1);
2074*4887Schin 	}
2075*4887Schin 	forkcnt=1000L;
2076*4887Schin 	if(parent)
2077*4887Schin 	{
2078*4887Schin 		int myjob;
2079*4887Schin 		sh.nforks++;
2080*4887Schin 		if(job.toclear)
2081*4887Schin 			job_clear();
2082*4887Schin #ifdef JOBS
2083*4887Schin 		/* first process defines process group */
2084*4887Schin 		if(sh_isstate(SH_MONITOR))
2085*4887Schin 		{
2086*4887Schin 			/*
2087*4887Schin 			 * errno==EPERM means that an earlier processes
2088*4887Schin 			 * completed.  Make parent the job group id.
2089*4887Schin 			 */
2090*4887Schin 			if(postid==0)
2091*4887Schin 				job.curpgid = parent;
2092*4887Schin 			if(job.jobcontrol || (flags&FAMP))
2093*4887Schin 			{
2094*4887Schin 				if(setpgid(parent,job.curpgid)<0 && errno==EPERM)
2095*4887Schin 					setpgid(parent,parent);
2096*4887Schin 			}
2097*4887Schin 		}
2098*4887Schin #endif /* JOBS */
2099*4887Schin 		if(!sh_isstate(SH_MONITOR) && job.waitall && postid==0)
2100*4887Schin 			job.curpgid = parent;
2101*4887Schin 		if(flags&FCOOP)
2102*4887Schin 			sh.cpid = parent;
2103*4887Schin 		myjob = job_post(parent,postid);
2104*4887Schin 		if(flags&FAMP)
2105*4887Schin 			job.curpgid = curpgid;
2106*4887Schin 		if(jobid)
2107*4887Schin 			*jobid = myjob;
2108*4887Schin 		return(parent);
2109*4887Schin 	}
2110*4887Schin #if !_std_malloc
2111*4887Schin 	vmtrace(-1);
2112*4887Schin #endif
2113*4887Schin 	/* This is the child process */
2114*4887Schin 	if(sh.trapnote&SH_SIGTERM)
2115*4887Schin 		sh_exit(SH_EXITSIG|SIGTERM);
2116*4887Schin 	sh.nforks=0;
2117*4887Schin 	timerdel(NIL(void*));
2118*4887Schin #ifdef JOBS
2119*4887Schin 	if(!job.jobcontrol && !(flags&FAMP))
2120*4887Schin 		sh_offstate(SH_MONITOR);
2121*4887Schin 	if(sh_isstate(SH_MONITOR))
2122*4887Schin 	{
2123*4887Schin 		parent = getpid();
2124*4887Schin 		if(postid==0)
2125*4887Schin 			job.curpgid = parent;
2126*4887Schin 		while(setpgid(0,job.curpgid)<0 && job.curpgid!=parent)
2127*4887Schin 			job.curpgid = parent;
2128*4887Schin #   ifdef SIGTSTP
2129*4887Schin 		if(job.curpgid==parent &&  !(flags&FAMP))
2130*4887Schin 			tcsetpgrp(job.fd,job.curpgid);
2131*4887Schin #   endif /* SIGTSTP */
2132*4887Schin 	}
2133*4887Schin #   ifdef SIGTSTP
2134*4887Schin 	if(job.jobcontrol)
2135*4887Schin 	{
2136*4887Schin 		signal(SIGTTIN,SIG_DFL);
2137*4887Schin 		signal(SIGTTOU,SIG_DFL);
2138*4887Schin 		signal(SIGTSTP,SIG_DFL);
2139*4887Schin 	}
2140*4887Schin #   endif /* SIGTSTP */
2141*4887Schin 	job.jobcontrol = 0;
2142*4887Schin #endif /* JOBS */
2143*4887Schin 	job.toclear = 1;
2144*4887Schin 	sh.login_sh = 0;
2145*4887Schin 	sh_offoption(SH_LOGIN_SHELL);
2146*4887Schin 	sh_onstate(SH_FORKED);
2147*4887Schin 	sh_onstate(SH_NOLOG);
2148*4887Schin 	sh.fn_depth = 0;
2149*4887Schin #if SHOPT_ACCT
2150*4887Schin 	sh_accsusp();
2151*4887Schin #endif	/* SHOPT_ACCT */
2152*4887Schin 	/* Reset remaining signals to parent */
2153*4887Schin 	/* except for those `lost' by trap   */
2154*4887Schin 	sh_sigreset(2);
2155*4887Schin 	sh.subshell = 0;
2156*4887Schin 	if((flags&FAMP) && sh.coutpipe>1)
2157*4887Schin 		sh_close(sh.coutpipe);
2158*4887Schin 	sig = sh.savesig;
2159*4887Schin 	sh.savesig = 0;
2160*4887Schin 	if(sig>0)
2161*4887Schin 		sh_fault(sig);
2162*4887Schin 	sh_sigcheck();
2163*4887Schin 	return(0);
2164*4887Schin }
2165*4887Schin 
2166*4887Schin pid_t sh_fork(int flags, int *jobid)
2167*4887Schin {
2168*4887Schin 	register pid_t parent;
2169*4887Schin 	register int sig;
2170*4887Schin #if SHOPT_FASTPIPE
2171*4887Schin 	if(sffileno(sfstdin)<0)
2172*4887Schin 	{
2173*4887Schin 		off_t current = sfseek(sfstdin,(off_t)0,SEEK_CUR);
2174*4887Schin 		sfseek(sfstdin,(off_t)0,SEEK_END);
2175*4887Schin 		sfdisc(sfstdin,SF_POPDISC);
2176*4887Schin 		fcntl(sffileno(sfstdin),F_SETFD,0);
2177*4887Schin 		sh_iostream(0);
2178*4887Schin 		sfseek(sfstdin,current,SEEK_SET);
2179*4887Schin 	}
2180*4887Schin #endif /* SHOPT_FASTPIPE */
2181*4887Schin 	if(!sh.pathlist)
2182*4887Schin 		path_get("");
2183*4887Schin 	sfsync(NIL(Sfio_t*));
2184*4887Schin 	sh.trapnote &= ~SH_SIGTERM;
2185*4887Schin 	job_fork(-1);
2186*4887Schin 	sh.savesig = -1;
2187*4887Schin 	while(_sh_fork(parent=fork(),flags,jobid) < 0);
2188*4887Schin 	sig = sh.savesig;
2189*4887Schin 	sh.savesig = 0;
2190*4887Schin 	if(sig>0)
2191*4887Schin 		sh_fault(sig);
2192*4887Schin 	job_fork(parent);
2193*4887Schin 	return(parent);
2194*4887Schin }
2195*4887Schin 
2196*4887Schin /*
2197*4887Schin  * add exports from previous scope to the new scope
2198*4887Schin  */
2199*4887Schin static void  local_exports(register Namval_t *np, void *data)
2200*4887Schin {
2201*4887Schin 	register Namval_t	*mp;
2202*4887Schin 	register char		*cp;
2203*4887Schin 	if(nv_isarray(np))
2204*4887Schin 		nv_putsub(np,NIL(char*),0);
2205*4887Schin 	if((cp = nv_getval(np)) && (mp = nv_search(nv_name(np), sh.var_tree, NV_ADD|HASH_NOSCOPE)) && nv_isnull(mp))
2206*4887Schin 		nv_putval(mp, cp, 0);
2207*4887Schin }
2208*4887Schin 
2209*4887Schin /*
2210*4887Schin  * This routine is used to execute the given function <fun> in a new scope
2211*4887Schin  * If <fun> is NULL, then arg points to a structure containing a pointer
2212*4887Schin  *  to a function that will be executed in the current environment.
2213*4887Schin  */
2214*4887Schin int sh_funscope(int argn, char *argv[],int(*fun)(void*),void *arg,int execflg)
2215*4887Schin {
2216*4887Schin 	register char	*trap;
2217*4887Schin 	register int	nsig;
2218*4887Schin 	struct dolnod	*argsav=0,*saveargfor;
2219*4887Schin 	struct sh_scoped savst, *prevscope = sh.st.self;
2220*4887Schin 	struct argnod	*envlist=0;
2221*4887Schin 	Shopt_t		savopt;
2222*4887Schin 	int		jmpval;
2223*4887Schin 	int		r = 0;
2224*4887Schin 	char 		*savstak;
2225*4887Schin 	struct funenv	*fp;
2226*4887Schin 	struct checkpt	buff;
2227*4887Schin 	Namval_t	*nspace = sh.namespace;
2228*4887Schin 	savopt = sh.options;
2229*4887Schin 	sh.st.lineno = error_info.line;
2230*4887Schin 	*prevscope = sh.st;
2231*4887Schin 	sh_offoption(SH_ERREXIT);
2232*4887Schin 	sh.st.prevst = prevscope;
2233*4887Schin 	sh.st.self = &savst;
2234*4887Schin 	sh.topscope = (Shscope_t*)sh.st.self;
2235*4887Schin 	sh.st.opterror = sh.st.optchar = 0;
2236*4887Schin 	sh.st.optindex = 1;
2237*4887Schin 	sh.st.loopcnt = 0;
2238*4887Schin 	if(!fun)
2239*4887Schin 	{
2240*4887Schin 		fp = (struct funenv*)arg;
2241*4887Schin 		envlist = fp->env;
2242*4887Schin 	}
2243*4887Schin 	prevscope->save_tree = sh.var_tree;
2244*4887Schin 	nv_scope(envlist);
2245*4887Schin 	if(dtvnext(prevscope->save_tree)!= (sh.namespace?sh.var_base:0))
2246*4887Schin 	{
2247*4887Schin 		/* eliminate parent scope */
2248*4887Schin 		Dt_t *dt = dtview(sh.var_tree,0);
2249*4887Schin 		dtview(sh.var_tree,dtvnext(prevscope->save_tree));
2250*4887Schin 		nv_scan(prevscope->save_tree, local_exports,(void*)0, NV_EXPORT, NV_EXPORT|NV_NOSCOPE);
2251*4887Schin 	}
2252*4887Schin 	sh.st.save_tree = sh.var_tree;
2253*4887Schin 	if(!fun)
2254*4887Schin 	{
2255*4887Schin 		Namval_t *np;
2256*4887Schin 		if(nv_isattr(fp->node,NV_TAGGED))
2257*4887Schin 			sh_onoption(SH_XTRACE);
2258*4887Schin 		else
2259*4887Schin 			sh_offoption(SH_XTRACE);
2260*4887Schin #if SHOPT_NAMESPACE
2261*4887Schin 		if((np=(fp->node)->nvalue.rp->nspace) && np!=sh.namespace)
2262*4887Schin 		{
2263*4887Schin 			Dt_t *dt = sh.var_tree;
2264*4887Schin 			dtview(dt,0);
2265*4887Schin 			dtview(dt,nv_dict(np));
2266*4887Schin 			sh.var_tree = nv_dict(np);
2267*4887Schin 			sh.namespace = np;
2268*4887Schin 		}
2269*4887Schin #endif /* SHOPT_NAMESPACE */
2270*4887Schin 	}
2271*4887Schin 	sh.st.cmdname = argv[0];
2272*4887Schin 	/* save trap table */
2273*4887Schin 	if((nsig=sh.st.trapmax*sizeof(char*))>0 || sh.st.trapcom[0])
2274*4887Schin 	{
2275*4887Schin 		nsig += sizeof(char*);
2276*4887Schin 		memcpy(savstak=stakalloc(nsig),(char*)&sh.st.trapcom[0],nsig);
2277*4887Schin 	}
2278*4887Schin 	sh_sigreset(0);
2279*4887Schin 	argsav = sh_argnew(argv,&saveargfor);
2280*4887Schin 	sh_pushcontext(&buff,SH_JMPFUN);
2281*4887Schin 	errorpush(&buff.err,0);
2282*4887Schin 	error_info.id = argv[0];
2283*4887Schin 	sh.st.var_local = sh.var_tree;
2284*4887Schin 	jmpval = sigsetjmp(buff.buff,0);
2285*4887Schin 	if(!fun)
2286*4887Schin 	{
2287*4887Schin 		sh.st.filename = fp->node->nvalue.rp->fname;
2288*4887Schin 		nv_putval(SH_PATHNAMENOD, sh.st.filename ,NV_NOFREE);
2289*4887Schin 		nv_putval(SH_FUNNAMENOD,nv_name(fp->node),NV_NOFREE);
2290*4887Schin 	}
2291*4887Schin 	if(jmpval == 0)
2292*4887Schin 	{
2293*4887Schin 		if(sh.fn_depth++ > MAXDEPTH)
2294*4887Schin 			siglongjmp(*sh.jmplist,SH_JMPERRFN);
2295*4887Schin 		else if(fun)
2296*4887Schin 			r= (*fun)(arg);
2297*4887Schin 		else
2298*4887Schin 		{
2299*4887Schin 			sh_exec((Shnode_t*)(nv_funtree((fp->node))),execflg|SH_ERREXIT);
2300*4887Schin 			r = sh.exitval;
2301*4887Schin 		}
2302*4887Schin 	}
2303*4887Schin 	if(--sh.fn_depth==1 && jmpval==SH_JMPERRFN)
2304*4887Schin 		errormsg(SH_DICT,ERROR_exit(1),e_toodeep,argv[0]);
2305*4887Schin 	sh_popcontext(&buff);
2306*4887Schin 	if (sh.st.self != &savst)
2307*4887Schin 		sh.var_tree = (Dt_t*)savst.save_tree;
2308*4887Schin 	nv_unscope();
2309*4887Schin 	sh.namespace = nspace;
2310*4887Schin 	sh.var_tree = (Dt_t*)prevscope->save_tree;
2311*4887Schin 	sh_argreset(argsav,saveargfor);
2312*4887Schin 	trap = sh.st.trapcom[0];
2313*4887Schin 	sh.st.trapcom[0] = 0;
2314*4887Schin 	sh_sigreset(1);
2315*4887Schin 	if (sh.st.self != &savst)
2316*4887Schin 		*sh.st.self = sh.st;
2317*4887Schin 	sh.st = *prevscope;
2318*4887Schin 	sh.topscope = (Shscope_t*)prevscope;
2319*4887Schin 	nv_getval(nv_scoped(IFSNOD));
2320*4887Schin 	if(nsig)
2321*4887Schin 		memcpy((char*)&sh.st.trapcom[0],savstak,nsig);
2322*4887Schin 	sh.trapnote=0;
2323*4887Schin 	if(nsig)
2324*4887Schin 		stakset(savstak,0);
2325*4887Schin 	sh.options = savopt;
2326*4887Schin 	if(trap)
2327*4887Schin 	{
2328*4887Schin 		sh_trap(trap,0);
2329*4887Schin 		free(trap);
2330*4887Schin 	}
2331*4887Schin 	if(sh.exitval > SH_EXITSIG)
2332*4887Schin 		sh_fault(sh.exitval&SH_EXITMASK);
2333*4887Schin 	if(jmpval > SH_JMPFUN)
2334*4887Schin 	{
2335*4887Schin 		sh_chktrap();
2336*4887Schin 		siglongjmp(*sh.jmplist,jmpval);
2337*4887Schin 	}
2338*4887Schin 	return(r);
2339*4887Schin }
2340*4887Schin 
2341*4887Schin 
2342*4887Schin static void sh_funct(Namval_t *np,int argn, char *argv[],struct argnod *envlist,int execflg)
2343*4887Schin {
2344*4887Schin 	struct funenv fun;
2345*4887Schin 	char *fname = nv_getval(SH_FUNNAMENOD);
2346*4887Schin 	if(nv_isattr(np,NV_FPOSIX))
2347*4887Schin 	{
2348*4887Schin 		char *save;
2349*4887Schin 		int loopcnt = sh.st.loopcnt;
2350*4887Schin 		sh.posix_fun = np;
2351*4887Schin 		opt_info.index = opt_info.offset = 0;
2352*4887Schin 		error_info.errors = 0;
2353*4887Schin 		save = argv[-1];
2354*4887Schin 		argv[-1] = 0;
2355*4887Schin 		nv_putval(SH_FUNNAMENOD, nv_name(np),NV_NOFREE);
2356*4887Schin 		sh.st.loopcnt = 0;
2357*4887Schin 		b_dot_cmd(argn+1,argv-1,&sh);
2358*4887Schin 		sh.st.loopcnt = loopcnt;
2359*4887Schin 		argv[-1] = save;
2360*4887Schin 	}
2361*4887Schin 	else
2362*4887Schin 	{
2363*4887Schin 		fun.env = envlist;
2364*4887Schin 		fun.node = np;
2365*4887Schin 		sh_funscope(argn,argv,0,&fun,execflg);
2366*4887Schin 	}
2367*4887Schin 	nv_putval(SH_FUNNAMENOD,fname,NV_NOFREE);
2368*4887Schin 	nv_putval(SH_PATHNAMENOD, sh.st.filename ,0);
2369*4887Schin }
2370*4887Schin 
2371*4887Schin /*
2372*4887Schin  * external interface to execute a function without arguments
2373*4887Schin  * <np> is the function node
2374*4887Schin  * If <nq> is not-null, then sh.name and sh.subscript will be set
2375*4887Schin  */
2376*4887Schin int sh_fun(Namval_t *np, Namval_t *nq, char *argv[])
2377*4887Schin {
2378*4887Schin 	register int offset;
2379*4887Schin 	register char *base;
2380*4887Schin 	Namval_t node;
2381*4887Schin 	int n=0;
2382*4887Schin 	char *av[2];
2383*4887Schin 	Fcin_t save;
2384*4887Schin 	fcsave(&save);
2385*4887Schin 	if((offset=staktell())>0)
2386*4887Schin 		base=stakfreeze(0);
2387*4887Schin 	if(!argv)
2388*4887Schin 	{
2389*4887Schin 		argv = av;
2390*4887Schin 		argv[1]=0;
2391*4887Schin 	}
2392*4887Schin 	argv[0] = nv_name(np);
2393*4887Schin 	while(argv[n])
2394*4887Schin 		n++;
2395*4887Schin 	if(nq)
2396*4887Schin 	{
2397*4887Schin 		/*
2398*4887Schin 		 * set ${.sh.name} and ${.sh.subscript}
2399*4887Schin 		 * set _ to reference for ${.sh.name}[$.sh.subscript]
2400*4887Schin 		 */
2401*4887Schin 		struct Namref	nr;
2402*4887Schin 		memset(&nr,0,sizeof(nr));
2403*4887Schin 		nr.np = nq;
2404*4887Schin 		nv_putval(SH_NAMENOD, nv_name(nq), NV_NOFREE);
2405*4887Schin 		memcpy(&node,L_ARGNOD,sizeof(node));
2406*4887Schin 		L_ARGNOD->nvalue.nrp = &nr;
2407*4887Schin 		L_ARGNOD->nvenv = 0;
2408*4887Schin 		L_ARGNOD->nvfun = (Namfun_t*)sh.last_table;
2409*4887Schin 		L_ARGNOD->nvflag = NV_REF|NV_NOFREE;
2410*4887Schin 		if(nv_arrayptr(nq))
2411*4887Schin 		{
2412*4887Schin 			nv_putval(SH_SUBSCRNOD,nv_getsub(nq),NV_NOFREE);
2413*4887Schin 			L_ARGNOD->nvenv = (char*)SH_SUBSCRNOD->nvalue.cp;
2414*4887Schin 		}
2415*4887Schin 	}
2416*4887Schin 	if(is_abuiltin(np))
2417*4887Schin 	{
2418*4887Schin 		int jmpval;
2419*4887Schin 		struct checkpt buff;
2420*4887Schin 		sh_pushcontext(&buff,SH_JMPCMD);
2421*4887Schin 		jmpval = sigsetjmp(buff.buff,1);
2422*4887Schin 		if(jmpval == 0)
2423*4887Schin 		{
2424*4887Schin 			void *context = nv_context(np);
2425*4887Schin 			errorpush(&buff.err,0);
2426*4887Schin 			error_info.id = argv[0];
2427*4887Schin 			opt_info.index = opt_info.offset = 0;
2428*4887Schin 			opt_info.disc = 0;
2429*4887Schin 			sh.exitval = 0;
2430*4887Schin 			if(!context)
2431*4887Schin 				context = (void*)&sh;
2432*4887Schin 			sh.exitval = (*funptr(np))(n,argv,context);
2433*4887Schin 		}
2434*4887Schin 		sh_popcontext(&buff);
2435*4887Schin 		if(jmpval>SH_JMPCMD)
2436*4887Schin 			siglongjmp(*sh.jmplist,jmpval);
2437*4887Schin 	}
2438*4887Schin 	else
2439*4887Schin 		sh_funct(np,n,argv,(struct argnod*)0,sh_isstate(SH_ERREXIT));
2440*4887Schin 	if(nq)
2441*4887Schin 	{
2442*4887Schin 		L_ARGNOD->nvalue.np = node.nvalue.np;
2443*4887Schin 		L_ARGNOD->nvenv = node.nvenv;
2444*4887Schin 		L_ARGNOD->nvflag = node.nvflag;
2445*4887Schin 		L_ARGNOD->nvfun = node.nvfun;
2446*4887Schin 		nv_unset(SH_NAMENOD);
2447*4887Schin 		nv_unset(SH_SUBSCRNOD);
2448*4887Schin 	}
2449*4887Schin 	fcrestore(&save);
2450*4887Schin 	if(offset>0)
2451*4887Schin 		stakset(base,offset);
2452*4887Schin 	return(sh.exitval);
2453*4887Schin }
2454*4887Schin 
2455*4887Schin /*
2456*4887Schin  * This dummy routine is called by built-ins that do recursion
2457*4887Schin  * on the file system (chmod, chgrp, chown).  It causes
2458*4887Schin  * the shell to invoke the non-builtin version in this case
2459*4887Schin  */
2460*4887Schin int cmdrecurse(int argc, char* argv[], int ac, char* av[])
2461*4887Schin {
2462*4887Schin 	NOT_USED(argc);
2463*4887Schin 	NOT_USED(argv[0]);
2464*4887Schin 	NOT_USED(ac);
2465*4887Schin 	NOT_USED(av[0]);
2466*4887Schin 	return(SH_RUNPROG);
2467*4887Schin }
2468*4887Schin 
2469*4887Schin /*
2470*4887Schin  * set up pipe for cooperating process
2471*4887Schin  */
2472*4887Schin static void coproc_init(int pipes[])
2473*4887Schin {
2474*4887Schin 	int outfd;
2475*4887Schin 	if(sh.coutpipe>=0 && sh.cpid)
2476*4887Schin 		errormsg(SH_DICT,ERROR_exit(1),e_pexists);
2477*4887Schin 	sh.cpid = 0;
2478*4887Schin 	if(sh.cpipe[0]<=0 || sh.cpipe[1]<=0)
2479*4887Schin 	{
2480*4887Schin 		/* first co-process */
2481*4887Schin 		sh_pclose(sh.cpipe);
2482*4887Schin 		sh_pipe(sh.cpipe);
2483*4887Schin 		if((outfd=sh.cpipe[1]) < 10)
2484*4887Schin 		{
2485*4887Schin 		        int fd=fcntl(sh.cpipe[1],F_DUPFD,10);
2486*4887Schin 			if(fd>=10)
2487*4887Schin 			{
2488*4887Schin 			        sh.fdstatus[fd] = (sh.fdstatus[outfd]&~IOCLEX);
2489*4887Schin 				close(outfd);
2490*4887Schin 			        sh.fdstatus[outfd] = IOCLOSE;
2491*4887Schin 				sh.cpipe[1] = fd;
2492*4887Schin 			}
2493*4887Schin 		}
2494*4887Schin 		if(fcntl(*sh.cpipe,F_SETFD,FD_CLOEXEC)>=0)
2495*4887Schin 			sh.fdstatus[sh.cpipe[0]] |= IOCLEX;
2496*4887Schin 		sh.fdptrs[sh.cpipe[0]] = sh.cpipe;
2497*4887Schin 
2498*4887Schin 		if(fcntl(sh.cpipe[1],F_SETFD,FD_CLOEXEC) >=0)
2499*4887Schin 			sh.fdstatus[sh.cpipe[1]] |= IOCLEX;
2500*4887Schin 	}
2501*4887Schin 	sh.outpipe = sh.cpipe;
2502*4887Schin 	sh_pipe(sh.inpipe=pipes);
2503*4887Schin 	sh.coutpipe = sh.inpipe[1];
2504*4887Schin 	sh.fdptrs[sh.coutpipe] = &sh.coutpipe;
2505*4887Schin 	if(fcntl(sh.outpipe[0],F_SETFD,FD_CLOEXEC)>=0)
2506*4887Schin 		sh.fdstatus[sh.outpipe[0]] |= IOCLEX;
2507*4887Schin }
2508*4887Schin 
2509*4887Schin #if SHOPT_SPAWN
2510*4887Schin 
2511*4887Schin 
2512*4887Schin #if SHOPT_AMP || !defined(_lib_fork)
2513*4887Schin /*
2514*4887Schin  * print out function definition
2515*4887Schin  */
2516*4887Schin static void print_fun(register Namval_t* np, void *data)
2517*4887Schin {
2518*4887Schin 	register char *format;
2519*4887Schin 	NOT_USED(data);
2520*4887Schin 	if(!is_afunction(np) || !np->nvalue.ip)
2521*4887Schin 		return;
2522*4887Schin 	if(nv_isattr(np,NV_FPOSIX))
2523*4887Schin 		format="%s()\n{ ";
2524*4887Schin 	else
2525*4887Schin 		format="function %s\n{ ";
2526*4887Schin 	sfprintf(sfstdout,format,nv_name(np));
2527*4887Schin 	sh_deparse(sfstdout,(Shnode_t*)(nv_funtree(np)),0);
2528*4887Schin 	sfwrite(sfstdout,"}\n",2);
2529*4887Schin }
2530*4887Schin 
2531*4887Schin /*
2532*4887Schin  * create a shell script consisting of t->fork.forktre and execute it
2533*4887Schin  */
2534*4887Schin static int run_subshell(const Shnode_t *t,pid_t grp)
2535*4887Schin {
2536*4887Schin 	static char prolog[] = "(print $(typeset +A);set; typeset -p; print .sh.dollar=$$;set +o)";
2537*4887Schin 	register int i, fd, trace = sh_isoption(SH_XTRACE);
2538*4887Schin 	int pin,pout;
2539*4887Schin 	pid_t pid;
2540*4887Schin 	char *arglist[2], *envlist[2], devfd[12], *cp;
2541*4887Schin 	Sfio_t *sp = sftmp(0);
2542*4887Schin 	envlist[0] = "_=" SH_ID;
2543*4887Schin 	envlist[1] = 0;
2544*4887Schin 	arglist[0] = error_info.id?error_info.id:sh.shname;
2545*4887Schin 	if(*arglist[0]=='-')
2546*4887Schin 		arglist[0]++;
2547*4887Schin 	arglist[1] = devfd;
2548*4887Schin 	strncpy(devfd,e_devfdNN,sizeof(devfd));
2549*4887Schin 	arglist[2] = 0;
2550*4887Schin 	sfstack(sfstdout,sp);
2551*4887Schin 	if(trace)
2552*4887Schin 		sh_offoption(SH_XTRACE);
2553*4887Schin 	sfwrite(sfstdout,"typeset -A -- ",14);
2554*4887Schin 	sh_trap(prolog,0);
2555*4887Schin 	nv_scan(sh.fun_tree, print_fun, (void*)0,0, 0);
2556*4887Schin 	if(sh.st.dolc>0)
2557*4887Schin 	{
2558*4887Schin 		/* pass the positional parameters */
2559*4887Schin 		char **argv = sh.st.dolv+1;
2560*4887Schin 		sfwrite(sfstdout,"set --",6);
2561*4887Schin 		while(*argv)
2562*4887Schin 			sfprintf(sfstdout," %s",sh_fmtq(*argv++));
2563*4887Schin 		sfputc(sfstdout,'\n');
2564*4887Schin 	}
2565*4887Schin 	pin = (sh.inpipe?sh.inpipe[1]:0);
2566*4887Schin 	pout = (sh.outpipe?sh.outpipe[0]:0);
2567*4887Schin 	for(i=3; i < 10; i++)
2568*4887Schin 	{
2569*4887Schin 		if(sh.fdstatus[i]&IOCLEX && i!=pin && i!=pout)
2570*4887Schin 		{
2571*4887Schin 			sfprintf(sfstdout,"exec %d<&%d\n",i,i);
2572*4887Schin 			fcntl(i,F_SETFD,0);
2573*4887Schin 		}
2574*4887Schin 	}
2575*4887Schin 	sfprintf(sfstdout,"LINENO=%d\n",t->fork.forkline);
2576*4887Schin 	if(trace)
2577*4887Schin 	{
2578*4887Schin 		sfwrite(sfstdout,"set -x\n",7);
2579*4887Schin 		sh_onoption(SH_XTRACE);
2580*4887Schin 	}
2581*4887Schin 	sfstack(sfstdout,NIL(Sfio_t*));
2582*4887Schin 	sh_deparse(sp,t->fork.forktre,0);
2583*4887Schin 	sfseek(sp,(Sfoff_t)0,SEEK_SET);
2584*4887Schin 	fd = sh_dup(sffileno(sp));
2585*4887Schin 	cp = devfd+8;
2586*4887Schin 	if(fd>9)
2587*4887Schin 		*cp++ = '0' + (fd/10);
2588*4887Schin 	*cp++ = '0' + fd%10;
2589*4887Schin 	*cp = 0;
2590*4887Schin 	sfclose(sp);
2591*4887Schin 	sfsync(NIL(Sfio_t*));
2592*4887Schin 	if(!sh.shpath)
2593*4887Schin 		sh.shpath = pathshell();
2594*4887Schin 	pid = spawnveg(sh.shpath,arglist,envlist,grp);
2595*4887Schin 	close(fd);
2596*4887Schin 	for(i=3; i < 10; i++)
2597*4887Schin 	{
2598*4887Schin 		if(sh.fdstatus[i]&IOCLEX && i!=pin && i!=pout)
2599*4887Schin 			fcntl(i,F_SETFD,FD_CLOEXEC);
2600*4887Schin 	}
2601*4887Schin 	if(pid <=0)
2602*4887Schin 		errormsg(SH_DICT,ERROR_system(ERROR_NOEXEC),e_exec,arglist[0]);
2603*4887Schin 	return(pid);
2604*4887Schin }
2605*4887Schin #endif /* !_lib_fork */
2606*4887Schin 
2607*4887Schin static void sigreset(int mode)
2608*4887Schin {
2609*4887Schin 	register char   *trap;
2610*4887Schin 	register int sig=sh.st.trapmax;
2611*4887Schin 	while(sig-- > 0)
2612*4887Schin 	{
2613*4887Schin 		if((trap=sh.st.trapcom[sig]) && *trap==0)
2614*4887Schin 			signal(sig,mode?sh_fault:SIG_IGN);
2615*4887Schin 	}
2616*4887Schin }
2617*4887Schin 
2618*4887Schin /*
2619*4887Schin  * A combined fork/exec for systems with slow or non-existent fork()
2620*4887Schin  */
2621*4887Schin static pid_t sh_ntfork(const Shnode_t *t,char *argv[],int *jobid,int flag)
2622*4887Schin {
2623*4887Schin 	static pid_t	spawnpid;
2624*4887Schin 	static int	savetype;
2625*4887Schin 	static int	savejobid;
2626*4887Schin 	Shell_t *shp = sh_getinterp();
2627*4887Schin 	struct checkpt buff;
2628*4887Schin 	int otype=0, scope=0, jmpval;
2629*4887Schin 	int jobwasset=0, sigwasset=0;
2630*4887Schin 	char **arge, *path;
2631*4887Schin 	pid_t grp = 0;
2632*4887Schin 	Pathcomp_t *pp;
2633*4887Schin 	if(flag)
2634*4887Schin 	{
2635*4887Schin 		otype = savetype;
2636*4887Schin 		savetype=0;
2637*4887Schin 	}
2638*4887Schin #   if SHOPT_AMP || !defined(_lib_fork)
2639*4887Schin 	if(!argv)
2640*4887Schin 	{
2641*4887Schin 		register Shnode_t *tchild = t->fork.forktre;
2642*4887Schin 		int optimize=0;
2643*4887Schin 		otype = t->tre.tretyp;
2644*4887Schin 		savetype = otype;
2645*4887Schin 		spawnpid = 0;
2646*4887Schin #	ifndef _lib_fork
2647*4887Schin 		if((tchild->tre.tretyp&COMMSK)==TCOM)
2648*4887Schin 		{
2649*4887Schin 			Namval_t *np = (Namval_t*)(tchild->com.comnamp);
2650*4887Schin 			if(np)
2651*4887Schin 			{
2652*4887Schin 				path = nv_name(np);
2653*4887Schin 				if(!nv_isattr(np,BLT_ENV))
2654*4887Schin 					np=0;
2655*4887Schin 				else if(strcmp(path,"echo")==0 || memcmp(path,"print",5)==0)
2656*4887Schin 					np=0;
2657*4887Schin 			}
2658*4887Schin 			else if(!tchild->com.comarg)
2659*4887Schin 				optimize=1;
2660*4887Schin 			else if(tchild->com.comtyp&COMSCAN)
2661*4887Schin 			{
2662*4887Schin 				if(tchild->com.comarg->argflag&ARG_RAW)
2663*4887Schin 					path = tchild->com.comarg->argval;
2664*4887Schin 				else
2665*4887Schin 					path = 0;
2666*4887Schin 			}
2667*4887Schin 			else
2668*4887Schin 				path = ((struct dolnod*)tchild->com.comarg)->dolval[ARG_SPARE];
2669*4887Schin 			if(!np && path && !nv_search(path,shp->fun_tree,0))
2670*4887Schin 				optimize=1;
2671*4887Schin 		}
2672*4887Schin #	endif
2673*4887Schin 		sh_pushcontext(&buff,SH_JMPIO);
2674*4887Schin 		jmpval = sigsetjmp(buff.buff,0);
2675*4887Schin 		{
2676*4887Schin 			if((otype&FINT) && !sh_isstate(SH_MONITOR))
2677*4887Schin 			{
2678*4887Schin 				signal(SIGQUIT,SIG_IGN);
2679*4887Schin 				signal(SIGINT,SIG_IGN);
2680*4887Schin 				if(!shp->st.ioset)
2681*4887Schin 				{
2682*4887Schin 					sh_iosave(0,buff.topfd);
2683*4887Schin 					sh_iorenumber(sh_chkopen(e_devnull),0);
2684*4887Schin 				}
2685*4887Schin 			}
2686*4887Schin 			if(otype&FPIN)
2687*4887Schin 			{
2688*4887Schin 				int fd = shp->inpipe[1];
2689*4887Schin 				sh_iosave(0,buff.topfd);
2690*4887Schin 				sh_iorenumber(shp->inpipe[0],0);
2691*4887Schin 				if(fd>=0 && (!(otype&FPOU) || (otype&FCOOP)) && fcntl(fd,F_SETFD,FD_CLOEXEC)>=0)
2692*4887Schin 					shp->fdstatus[fd] |= IOCLEX;
2693*4887Schin 			}
2694*4887Schin 			if(otype&FPOU)
2695*4887Schin 			{
2696*4887Schin 				sh_iosave(1,buff.topfd);
2697*4887Schin 				sh_iorenumber(sh_dup(shp->outpipe[1]),1);
2698*4887Schin 				if(fcntl(shp->outpipe[0],F_SETFD,FD_CLOEXEC)>=0)
2699*4887Schin 					shp->fdstatus[shp->outpipe[0]] |= IOCLEX;
2700*4887Schin 			}
2701*4887Schin 
2702*4887Schin 			if(t->fork.forkio)
2703*4887Schin 				sh_redirect(t->fork.forkio,0);
2704*4887Schin 			if(optimize==0)
2705*4887Schin 			{
2706*4887Schin #ifdef SIGTSTP
2707*4887Schin 				if(job.jobcontrol)
2708*4887Schin 				{
2709*4887Schin 					signal(SIGTTIN,SIG_DFL);
2710*4887Schin 					signal(SIGTTOU,SIG_DFL);
2711*4887Schin 				}
2712*4887Schin #endif /* SIGTSTP */
2713*4887Schin #ifdef JOBS
2714*4887Schin 				if(sh_isstate(SH_MONITOR) && (job.jobcontrol || (otype&FAMP)))
2715*4887Schin 				{
2716*4887Schin 					if((otype&FAMP) || job.curpgid==0)
2717*4887Schin 						grp = 1;
2718*4887Schin 					else
2719*4887Schin 						grp = job.curpgid;
2720*4887Schin 				}
2721*4887Schin #endif /* JOBS */
2722*4887Schin 				spawnpid = run_subshell(t,grp);
2723*4887Schin 			}
2724*4887Schin 			else
2725*4887Schin 			{
2726*4887Schin 				sh_exec(tchild,SH_NTFORK);
2727*4887Schin 				if(jobid)
2728*4887Schin 					*jobid = savejobid;
2729*4887Schin 			}
2730*4887Schin 		}
2731*4887Schin 		sh_popcontext(&buff);
2732*4887Schin 		if((otype&FINT) && !sh_isstate(SH_MONITOR))
2733*4887Schin 		{
2734*4887Schin 			signal(SIGQUIT,sh_fault);
2735*4887Schin 			signal(SIGINT,sh_fault);
2736*4887Schin 		}
2737*4887Schin 		if((otype&FPIN) && (!(otype&FPOU) || (otype&FCOOP)) && fcntl(shp->inpipe[1],F_SETFD,FD_CLOEXEC)>=0)
2738*4887Schin 			shp->fdstatus[shp->inpipe[1]] &= ~IOCLEX;
2739*4887Schin 		if(t->fork.forkio || otype)
2740*4887Schin 			sh_iorestore(buff.topfd,jmpval);
2741*4887Schin 		if(optimize==0)
2742*4887Schin 		{
2743*4887Schin #ifdef SIGTSTP
2744*4887Schin 			if(job.jobcontrol)
2745*4887Schin 			{
2746*4887Schin 				signal(SIGTTIN,SIG_IGN);
2747*4887Schin 				signal(SIGTTOU,SIG_IGN);
2748*4887Schin 			}
2749*4887Schin #endif /* SIGTSTP */
2750*4887Schin 			if(spawnpid>0)
2751*4887Schin 				_sh_fork(spawnpid,otype,jobid);
2752*4887Schin 			if(grp>0 && !(otype&FAMP))
2753*4887Schin 			{
2754*4887Schin 				while(tcsetpgrp(job.fd,job.curpgid)<0 && job.curpgid!=spawnpid)
2755*4887Schin 					job.curpgid = spawnpid;
2756*4887Schin 			}
2757*4887Schin 		}
2758*4887Schin 		savetype=0;
2759*4887Schin 		if(jmpval>SH_JMPIO)
2760*4887Schin 			siglongjmp(*shp->jmplist,jmpval);
2761*4887Schin 		if(spawnpid<0 && (otype&FCOOP))
2762*4887Schin 		{
2763*4887Schin 			sh_close(shp->coutpipe);
2764*4887Schin 			sh_close(shp->cpipe[1]);
2765*4887Schin 			shp->cpipe[1] = -1;
2766*4887Schin 			shp->coutpipe = -1;
2767*4887Schin 		}
2768*4887Schin 		shp->exitval = 0;
2769*4887Schin 		return(spawnpid);
2770*4887Schin 	}
2771*4887Schin #   endif /* !_lib_fork */
2772*4887Schin 	sh_pushcontext(&buff,SH_JMPCMD);
2773*4887Schin 	errorpush(&buff.err,ERROR_SILENT);
2774*4887Schin 	jmpval = sigsetjmp(buff.buff,0);
2775*4887Schin 	if(jmpval == 0)
2776*4887Schin 	{
2777*4887Schin 		if((otype&FINT) && !sh_isstate(SH_MONITOR))
2778*4887Schin 		{
2779*4887Schin 			signal(SIGQUIT,SIG_IGN);
2780*4887Schin 			signal(SIGINT,SIG_IGN);
2781*4887Schin 		}
2782*4887Schin 		spawnpid = -1;
2783*4887Schin 		if(t->com.comio)
2784*4887Schin 			sh_redirect(t->com.comio,0);
2785*4887Schin 		error_info.id = *argv;
2786*4887Schin 		if(t->com.comset)
2787*4887Schin 		{
2788*4887Schin 			scope++;
2789*4887Schin 			nv_scope(t->com.comset);
2790*4887Schin 		}
2791*4887Schin 		if(!strchr(path=argv[0],'/'))
2792*4887Schin 		{
2793*4887Schin #ifdef PATH_BFPATH
2794*4887Schin 			Namval_t *np;
2795*4887Schin 			if((np=nv_search(path,shp->track_tree,0)) && !nv_isattr(np,NV_NOALIAS) && np->nvalue.cp)
2796*4887Schin 				path = nv_getval(np);
2797*4887Schin 			else if(path_absolute(path,NIL(Pathcomp_t*)))
2798*4887Schin 			{
2799*4887Schin 				path = stakptr(PATH_OFFSET);
2800*4887Schin 				stakfreeze(0);
2801*4887Schin 			}
2802*4887Schin 			else
2803*4887Schin 			{
2804*4887Schin 				pp=path_get(path);
2805*4887Schin 				while(pp)
2806*4887Schin 				{
2807*4887Schin 					if(pp->len==1 && *pp->name=='.')
2808*4887Schin 						break;
2809*4887Schin 					pp = pp->next;
2810*4887Schin 				}
2811*4887Schin 				if(!pp)
2812*4887Schin 					path = 0;
2813*4887Schin 			}
2814*4887Schin #else
2815*4887Schin 			path = shp->lastpath;
2816*4887Schin #endif
2817*4887Schin 		}
2818*4887Schin 		else if(sh_isoption(SH_RESTRICTED))
2819*4887Schin 			errormsg(SH_DICT,ERROR_exit(1),e_restricted,path);
2820*4887Schin 		if(!path)
2821*4887Schin 		{
2822*4887Schin 			spawnpid = -1;
2823*4887Schin 			goto fail;
2824*4887Schin 		}
2825*4887Schin 		arge = sh_envgen();
2826*4887Schin 		shp->exitval = 0;
2827*4887Schin #ifdef SIGTSTP
2828*4887Schin 		if(job.jobcontrol)
2829*4887Schin 		{
2830*4887Schin 			signal(SIGTTIN,SIG_DFL);
2831*4887Schin 			signal(SIGTTOU,SIG_DFL);
2832*4887Schin 			jobwasset++;
2833*4887Schin 		}
2834*4887Schin #endif /* SIGTSTP */
2835*4887Schin #ifdef JOBS
2836*4887Schin 		if(sh_isstate(SH_MONITOR) && (job.jobcontrol || (otype&FAMP)))
2837*4887Schin 		{
2838*4887Schin 			if((otype&FAMP) || job.curpgid==0)
2839*4887Schin 				grp = 1;
2840*4887Schin 			else
2841*4887Schin 				grp = job.curpgid;
2842*4887Schin 		}
2843*4887Schin #endif /* JOBS */
2844*4887Schin 
2845*4887Schin 		sfsync(NIL(Sfio_t*));
2846*4887Schin 		sigreset(0);	/* set signals to ignore */
2847*4887Schin 		sigwasset++;
2848*4887Schin 	        /* find first path that has a library component */
2849*4887Schin 		for(pp=path_get(argv[0]); pp && !pp->lib ; pp=pp->next);
2850*4887Schin 		spawnpid = path_spawn(path,argv,arge,pp,(grp<<1)|1);
2851*4887Schin 		if(spawnpid < 0 && errno==ENOEXEC)
2852*4887Schin 		{
2853*4887Schin 			char *devfd;
2854*4887Schin 			int fd = open(path,O_RDONLY);
2855*4887Schin 			argv[-1] = argv[0];
2856*4887Schin 			argv[0] = path;
2857*4887Schin 			if(fd>=0)
2858*4887Schin 			{
2859*4887Schin 				struct stat statb;
2860*4887Schin 				sfprintf(sh.strbuf,"/dev/fd/%d",fd);
2861*4887Schin 				if(stat(devfd=sfstruse(sh.strbuf),&statb)>=0)
2862*4887Schin 					argv[0] =  devfd;
2863*4887Schin 			}
2864*4887Schin 			if(!shp->shpath)
2865*4887Schin 				shp->shpath = pathshell();
2866*4887Schin 			spawnpid = path_spawn(shp->shpath,&argv[-1],arge,pp,(grp<<1)|1);
2867*4887Schin 			if(fd>=0)
2868*4887Schin 				close(fd);
2869*4887Schin 			argv[0] = argv[-1];
2870*4887Schin 		}
2871*4887Schin 	fail:
2872*4887Schin 		if(spawnpid < 0) switch(errno=shp->path_err)
2873*4887Schin 		{
2874*4887Schin 		    case ENOENT:
2875*4887Schin 			errormsg(SH_DICT,ERROR_system(ERROR_NOENT),e_found+4);
2876*4887Schin 		    default:
2877*4887Schin 			errormsg(SH_DICT,ERROR_system(ERROR_NOEXEC),e_exec+4);
2878*4887Schin 		}
2879*4887Schin 	}
2880*4887Schin 	else
2881*4887Schin 		exitset();
2882*4887Schin 	sh_popcontext(&buff);
2883*4887Schin 	if(buff.olist)
2884*4887Schin 		free_list(buff.olist);
2885*4887Schin #ifdef SIGTSTP
2886*4887Schin 	if(jobwasset)
2887*4887Schin 	{
2888*4887Schin 		signal(SIGTTIN,SIG_IGN);
2889*4887Schin 		signal(SIGTTOU,SIG_IGN);
2890*4887Schin 	}
2891*4887Schin #endif /* SIGTSTP */
2892*4887Schin 	if(sigwasset)
2893*4887Schin 		sigreset(1);	/* restore ignored signals */
2894*4887Schin 	if(scope)
2895*4887Schin 	{
2896*4887Schin 		nv_unscope();
2897*4887Schin 		if(jmpval==SH_JMPSCRIPT)
2898*4887Schin 			nv_setlist(t->com.comset,NV_EXPORT|NV_IDENT|NV_ASSIGN);
2899*4887Schin 	}
2900*4887Schin 	if(t->com.comio)
2901*4887Schin 		sh_iorestore(buff.topfd,jmpval);
2902*4887Schin 	if(jmpval>SH_JMPCMD)
2903*4887Schin 		siglongjmp(*shp->jmplist,jmpval);
2904*4887Schin 	if(spawnpid>0)
2905*4887Schin 	{
2906*4887Schin 		_sh_fork(spawnpid,otype,jobid);
2907*4887Schin #ifdef JOBS
2908*4887Schin 		if(grp==1)
2909*4887Schin 			job.curpgid = spawnpid;
2910*4887Schin #   ifdef SIGTSTP
2911*4887Schin 		if(grp>0 && !(otype&FAMP))
2912*4887Schin 		{
2913*4887Schin 			while(tcsetpgrp(job.fd,job.curpgid)<0 && job.curpgid!=spawnpid)
2914*4887Schin 				job.curpgid = spawnpid;
2915*4887Schin 		}
2916*4887Schin #   endif /* SIGTSTP */
2917*4887Schin #endif /* JOBS */
2918*4887Schin 		savejobid = *jobid;
2919*4887Schin 		if(otype)
2920*4887Schin 			return(0);
2921*4887Schin 	}
2922*4887Schin 	return(spawnpid);
2923*4887Schin }
2924*4887Schin 
2925*4887Schin #   ifdef _was_lib_fork
2926*4887Schin #	define _lib_fork	1
2927*4887Schin #   endif
2928*4887Schin #   ifndef _lib_fork
2929*4887Schin 	pid_t fork(void)
2930*4887Schin 	{
2931*4887Schin 		errormsg(SH_DICT,ERROR_exit(3),e_notimp,"fork");
2932*4887Schin 		return(-1);
2933*4887Schin 	}
2934*4887Schin #   endif /* _lib_fork */
2935*4887Schin #endif /* SHOPT_SPAWN */
2936*4887Schin 
2937*4887Schin /*
2938*4887Schin  * override procrun() since it is used in libcmd
2939*4887Schin  */
2940*4887Schin #include	<proc.h>
2941*4887Schin int procrun(const char *path, char *argv[])
2942*4887Schin {
2943*4887Schin 	if(sh.subshell)
2944*4887Schin 		sh_subtmpfile();
2945*4887Schin 	return(procclose(procopen(path, argv, NiL, NiL, PROC_FOREGROUND|PROC_GID
2946*4887Schin |PROC_UID)));
2947*4887Schin }
2948