xref: /titanic_44/usr/src/lib/libshell/common/sh/xec.c (revision 3e14f97f673e8a630f076077de35afdd43dc1587)
1da2e3ebdSchin /***********************************************************************
2da2e3ebdSchin *                                                                      *
3da2e3ebdSchin *               This software is part of the ast package               *
4*3e14f97fSRoger A. Faulkner *          Copyright (c) 1982-2010 AT&T Intellectual Property          *
5da2e3ebdSchin *                      and is licensed under the                       *
6da2e3ebdSchin *                  Common Public License, Version 1.0                  *
77c2fbfb3SApril Chin *                    by AT&T Intellectual Property                     *
8da2e3ebdSchin *                                                                      *
9da2e3ebdSchin *                A copy of the License is available at                 *
10da2e3ebdSchin *            http://www.opensource.org/licenses/cpl1.0.txt             *
11da2e3ebdSchin *         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
12da2e3ebdSchin *                                                                      *
13da2e3ebdSchin *              Information and Software Systems Research               *
14da2e3ebdSchin *                            AT&T Research                             *
15da2e3ebdSchin *                           Florham Park NJ                            *
16da2e3ebdSchin *                                                                      *
17da2e3ebdSchin *                  David Korn <dgk@research.att.com>                   *
18da2e3ebdSchin *                                                                      *
19da2e3ebdSchin ***********************************************************************/
20da2e3ebdSchin #pragma prototyped
21da2e3ebdSchin /*
22da2e3ebdSchin  * UNIX shell parse tree executer
23da2e3ebdSchin  *
24da2e3ebdSchin  *   David Korn
25da2e3ebdSchin  *   AT&T Labs
26da2e3ebdSchin  *
27da2e3ebdSchin  */
28da2e3ebdSchin 
29da2e3ebdSchin #include	"defs.h"
30da2e3ebdSchin #include	<fcin.h>
31da2e3ebdSchin #include	"variables.h"
32da2e3ebdSchin #include	"path.h"
33da2e3ebdSchin #include	"name.h"
34da2e3ebdSchin #include	"io.h"
35da2e3ebdSchin #include	"shnodes.h"
36da2e3ebdSchin #include	"jobs.h"
37da2e3ebdSchin #include	"test.h"
38da2e3ebdSchin #include	"builtins.h"
39da2e3ebdSchin #include	"FEATURE/time"
40da2e3ebdSchin #include	"FEATURE/externs"
41da2e3ebdSchin #include	"FEATURE/locale"
42da2e3ebdSchin #include	"streval.h"
43da2e3ebdSchin 
44da2e3ebdSchin #if !_std_malloc
45da2e3ebdSchin #   include	<vmalloc.h>
46da2e3ebdSchin #endif
47da2e3ebdSchin 
487c2fbfb3SApril Chin #if     _lib_vfork
497c2fbfb3SApril Chin #   include     <ast_vfork.h>
507c2fbfb3SApril Chin #else
517c2fbfb3SApril Chin #   define vfork()      fork()
527c2fbfb3SApril Chin #endif
537c2fbfb3SApril Chin 
54da2e3ebdSchin #define SH_NTFORK	SH_TIMING
55da2e3ebdSchin 
56da2e3ebdSchin #if _lib_nice
57da2e3ebdSchin     extern int	nice(int);
58da2e3ebdSchin #endif /* _lib_nice */
59da2e3ebdSchin #if !_lib_spawnveg
60da2e3ebdSchin #   define spawnveg(a,b,c,d)    spawnve(a,b,c)
61da2e3ebdSchin #endif /* !_lib_spawnveg */
62da2e3ebdSchin #if SHOPT_SPAWN
637c2fbfb3SApril Chin     static pid_t sh_ntfork(Shell_t*,const Shnode_t*,char*[],int*,int);
64da2e3ebdSchin #endif /* SHOPT_SPAWN */
65da2e3ebdSchin 
667c2fbfb3SApril Chin static void	sh_funct(Shell_t *,Namval_t*, int, char*[], struct argnod*,int);
67da2e3ebdSchin static int	trim_eq(const char*, const char*);
687c2fbfb3SApril Chin static void	coproc_init(Shell_t*, int pipes[]);
69da2e3ebdSchin 
70da2e3ebdSchin static void	*timeout;
71da2e3ebdSchin static char	pipejob;
72da2e3ebdSchin 
73da2e3ebdSchin struct funenv
74da2e3ebdSchin {
75da2e3ebdSchin 	Namval_t	*node;
76da2e3ebdSchin 	struct argnod	*env;
77da2e3ebdSchin };
78da2e3ebdSchin 
79da2e3ebdSchin /* ========	command execution	========*/
80da2e3ebdSchin 
81da2e3ebdSchin /*
82da2e3ebdSchin  * print time <t> in h:m:s format with precision <p>
83da2e3ebdSchin  */
l_time(Sfio_t * outfile,register clock_t t,int p)84da2e3ebdSchin static void     l_time(Sfio_t *outfile,register clock_t t,int p)
85da2e3ebdSchin {
86da2e3ebdSchin 	register int  min, sec, frac;
87da2e3ebdSchin 	register int hr;
88da2e3ebdSchin 	if(p)
89da2e3ebdSchin 	{
90da2e3ebdSchin 		frac = t%sh.lim.clk_tck;
91da2e3ebdSchin 		frac = (frac*100)/sh.lim.clk_tck;
92da2e3ebdSchin 	}
93da2e3ebdSchin 	t /= sh.lim.clk_tck;
94da2e3ebdSchin 	sec = t%60;
95da2e3ebdSchin 	t /= 60;
96da2e3ebdSchin 	min = t%60;
97da2e3ebdSchin 	if(hr=t/60)
98da2e3ebdSchin 		sfprintf(outfile,"%dh",hr);
99da2e3ebdSchin 	if(p)
100da2e3ebdSchin 		sfprintf(outfile,"%dm%d%c%0*ds",min,sec,GETDECIMAL(0),p,frac);
101da2e3ebdSchin 	else
102da2e3ebdSchin 		sfprintf(outfile,"%dm%ds",min,sec);
103da2e3ebdSchin }
104da2e3ebdSchin 
p_time(Shell_t * shp,Sfio_t * out,const char * format,clock_t * tm)1057c2fbfb3SApril Chin static int p_time(Shell_t *shp, Sfio_t *out, const char *format, clock_t *tm)
106da2e3ebdSchin {
107da2e3ebdSchin 	int		c,p,l,n,offset = staktell();
108da2e3ebdSchin 	const char	*first;
109da2e3ebdSchin 	double		d;
1107c2fbfb3SApril Chin 	Stk_t		*stkp = shp->stk;
111da2e3ebdSchin 	for(first=format ; c= *format; format++)
112da2e3ebdSchin 	{
113da2e3ebdSchin 		if(c!='%')
114da2e3ebdSchin 			continue;
1157c2fbfb3SApril Chin 		sfwrite(stkp, first, format-first);
116da2e3ebdSchin 		n = l = 0;
117da2e3ebdSchin 		p = 3;
118da2e3ebdSchin 		if((c= *++format) == '%')
119da2e3ebdSchin 		{
120da2e3ebdSchin 			first = format;
121da2e3ebdSchin 			continue;
122da2e3ebdSchin 		}
123da2e3ebdSchin 		if(c>='0' && c <='9')
124da2e3ebdSchin 		{
125da2e3ebdSchin 			p = (c>'3')?3:(c-'0');
126da2e3ebdSchin 			c = *++format;
127da2e3ebdSchin 		}
128da2e3ebdSchin 		else if(c=='P')
129da2e3ebdSchin 		{
130da2e3ebdSchin 			if(d=tm[0])
131da2e3ebdSchin 				d = 100.*(((double)(tm[1]+tm[2]))/d);
132da2e3ebdSchin 			p = 2;
133da2e3ebdSchin 			goto skip;
134da2e3ebdSchin 		}
135da2e3ebdSchin 		if(c=='l')
136da2e3ebdSchin 		{
137da2e3ebdSchin 			l = 1;
138da2e3ebdSchin 			c = *++format;
139da2e3ebdSchin 		}
140da2e3ebdSchin 		if(c=='U')
141da2e3ebdSchin 			n = 1;
142da2e3ebdSchin 		else if(c=='S')
143da2e3ebdSchin 			n = 2;
144da2e3ebdSchin 		else if(c!='R')
145da2e3ebdSchin 		{
1467c2fbfb3SApril Chin 			stkseek(stkp,offset);
147da2e3ebdSchin 			errormsg(SH_DICT,ERROR_exit(0),e_badtformat,c);
148da2e3ebdSchin 			return(0);
149da2e3ebdSchin 		}
150da2e3ebdSchin 		d = (double)tm[n]/sh.lim.clk_tck;
151da2e3ebdSchin 	skip:
152da2e3ebdSchin 		if(l)
1537c2fbfb3SApril Chin 			l_time(stkp, tm[n], p);
154da2e3ebdSchin 		else
1557c2fbfb3SApril Chin 			sfprintf(stkp,"%.*f",p, d);
156da2e3ebdSchin 		first = format+1;
157da2e3ebdSchin 	}
158da2e3ebdSchin 	if(format>first)
1597c2fbfb3SApril Chin 		sfwrite(stkp,first, format-first);
1607c2fbfb3SApril Chin 	sfputc(stkp,'\n');
1617c2fbfb3SApril Chin 	n = stktell(stkp)-offset;
1627c2fbfb3SApril Chin 	sfwrite(out,stkptr(stkp,offset),n);
1637c2fbfb3SApril Chin 	stkseek(stkp,offset);
164da2e3ebdSchin 	return(n);
165da2e3ebdSchin }
166da2e3ebdSchin 
167da2e3ebdSchin #if SHOPT_OPTIMIZE
168da2e3ebdSchin /*
169da2e3ebdSchin  * clear argument pointers that point into the stack
170da2e3ebdSchin  */
171da2e3ebdSchin static int p_arg(struct argnod*,int);
172da2e3ebdSchin static int p_switch(struct regnod*);
p_comarg(register struct comnod * com)173da2e3ebdSchin static int p_comarg(register struct comnod *com)
174da2e3ebdSchin {
175da2e3ebdSchin 	Namval_t *np=com->comnamp;
176da2e3ebdSchin 	int n = p_arg(com->comset,ARG_ASSIGN);
177da2e3ebdSchin 	if(com->comarg && (com->comtyp&COMSCAN))
178da2e3ebdSchin 		n+= p_arg(com->comarg,0);
179da2e3ebdSchin 	if(com->comstate  && np)
180da2e3ebdSchin 	{
181da2e3ebdSchin 		/* call builtin to cleanup state */
1827c2fbfb3SApril Chin 		Shbltin_t *bp = &sh.bltindata;
1837c2fbfb3SApril Chin 		void  *save_ptr = bp->ptr;
1847c2fbfb3SApril Chin 		void  *save_data = bp->data;
1857c2fbfb3SApril Chin 		bp->bnode = np;
1867c2fbfb3SApril Chin 		bp->vnode = com->comnamq;
1877c2fbfb3SApril Chin 		bp->ptr = nv_context(np);
1887c2fbfb3SApril Chin 		bp->data = com->comstate;
1897c2fbfb3SApril Chin 		bp->flags = SH_END_OPTIM;
1907c2fbfb3SApril Chin 		(*funptr(np))(0,(char**)0, bp);
1917c2fbfb3SApril Chin 		bp->ptr = save_ptr;
1927c2fbfb3SApril Chin 		bp->data = save_data;
193da2e3ebdSchin 	}
194da2e3ebdSchin 	com->comstate = 0;
195da2e3ebdSchin 	if(com->comarg && !np)
196da2e3ebdSchin 		n++;
197da2e3ebdSchin 	return(n);
198da2e3ebdSchin }
199da2e3ebdSchin 
200da2e3ebdSchin extern void sh_optclear(Shell_t*, void*);
201da2e3ebdSchin 
sh_tclear(register Shnode_t * t)202da2e3ebdSchin static int sh_tclear(register Shnode_t *t)
203da2e3ebdSchin {
204da2e3ebdSchin 	int n=0;
205da2e3ebdSchin 	if(!t)
206da2e3ebdSchin 		return(0);
207da2e3ebdSchin 	switch(t->tre.tretyp&COMMSK)
208da2e3ebdSchin 	{
209da2e3ebdSchin 		case TTIME:
210da2e3ebdSchin 		case TPAR:
211da2e3ebdSchin 			return(sh_tclear(t->par.partre));
212da2e3ebdSchin 		case TCOM:
213da2e3ebdSchin 			return(p_comarg((struct comnod*)t));
214da2e3ebdSchin 		case TSETIO:
215da2e3ebdSchin 		case TFORK:
216da2e3ebdSchin 			return(sh_tclear(t->fork.forktre));
217da2e3ebdSchin 		case TIF:
218da2e3ebdSchin 			n=sh_tclear(t->if_.iftre);
219da2e3ebdSchin 			n+=sh_tclear(t->if_.thtre);
220da2e3ebdSchin 			n+=sh_tclear(t->if_.eltre);
221da2e3ebdSchin 			return(n);
222da2e3ebdSchin 		case TWH:
223da2e3ebdSchin 			if(t->wh.whinc)
224da2e3ebdSchin 				n=sh_tclear((Shnode_t*)(t->wh.whinc));
225da2e3ebdSchin 			n+=sh_tclear(t->wh.whtre);
226da2e3ebdSchin 			n+=sh_tclear(t->wh.dotre);
227da2e3ebdSchin 			return(n);
228da2e3ebdSchin 		case TLST:
229da2e3ebdSchin 		case TAND:
230da2e3ebdSchin 		case TORF:
231da2e3ebdSchin 		case TFIL:
232da2e3ebdSchin 			n=sh_tclear(t->lst.lstlef);
233da2e3ebdSchin 			return(n+sh_tclear(t->lst.lstrit));
234da2e3ebdSchin 		case TARITH:
235da2e3ebdSchin 			return(p_arg(t->ar.arexpr,ARG_ARITH));
236da2e3ebdSchin 		case TFOR:
237da2e3ebdSchin 			n=sh_tclear(t->for_.fortre);
238da2e3ebdSchin 			return(n+sh_tclear((Shnode_t*)t->for_.forlst));
239da2e3ebdSchin 		case TSW:
240da2e3ebdSchin 			n=p_arg(t->sw.swarg,0);
241da2e3ebdSchin 			return(n+p_switch(t->sw.swlst));
242da2e3ebdSchin 		case TFUN:
243da2e3ebdSchin 			n=sh_tclear(t->funct.functtre);
244da2e3ebdSchin 			return(n+sh_tclear((Shnode_t*)t->funct.functargs));
245da2e3ebdSchin 		case TTST:
246da2e3ebdSchin 			if((t->tre.tretyp&TPAREN)==TPAREN)
247da2e3ebdSchin 				return(sh_tclear(t->lst.lstlef));
248da2e3ebdSchin 			else
249da2e3ebdSchin 			{
250da2e3ebdSchin 				n=p_arg(&(t->lst.lstlef->arg),0);
251da2e3ebdSchin 				if(t->tre.tretyp&TBINARY)
252da2e3ebdSchin 					n+=p_arg(&(t->lst.lstrit->arg),0);
253da2e3ebdSchin 			}
254da2e3ebdSchin 	}
255da2e3ebdSchin 	return(n);
256da2e3ebdSchin }
257da2e3ebdSchin 
p_arg(register struct argnod * arg,int flag)258da2e3ebdSchin static int p_arg(register struct argnod *arg,int flag)
259da2e3ebdSchin {
260da2e3ebdSchin 	while(arg)
261da2e3ebdSchin 	{
262da2e3ebdSchin 		if(strlen(arg->argval) || (arg->argflag==ARG_RAW))
263da2e3ebdSchin 			arg->argchn.ap = 0;
264da2e3ebdSchin 		else if(flag==0)
265da2e3ebdSchin 			sh_tclear((Shnode_t*)arg->argchn.ap);
266da2e3ebdSchin 		else
267da2e3ebdSchin 			sh_tclear(((struct fornod*)arg->argchn.ap)->fortre);
268da2e3ebdSchin 		arg = arg->argnxt.ap;
269da2e3ebdSchin 	}
270da2e3ebdSchin 	return(0);
271da2e3ebdSchin }
272da2e3ebdSchin 
p_switch(register struct regnod * reg)273da2e3ebdSchin static int p_switch(register struct regnod *reg)
274da2e3ebdSchin {
275da2e3ebdSchin 	int n=0;
276da2e3ebdSchin 	while(reg)
277da2e3ebdSchin 	{
278da2e3ebdSchin 		n+=p_arg(reg->regptr,0);
279da2e3ebdSchin 		n+=sh_tclear(reg->regcom);
280da2e3ebdSchin 		reg = reg->regnxt;
281da2e3ebdSchin 	}
282da2e3ebdSchin 	return(n);
283da2e3ebdSchin }
284da2e3ebdSchin #   define OPTIMIZE_FLAG	(ARG_OPTIMIZE)
285da2e3ebdSchin #   define OPTIMIZE		(flags&OPTIMIZE_FLAG)
286da2e3ebdSchin #else
287da2e3ebdSchin #   define OPTIMIZE_FLAG	(0)
288da2e3ebdSchin #   define OPTIMIZE		(0)
289da2e3ebdSchin #   define sh_tclear(x)
290da2e3ebdSchin #endif /* SHOPT_OPTIMIZE */
291da2e3ebdSchin 
out_pattern(Sfio_t * iop,register const char * cp,int n)292da2e3ebdSchin static void out_pattern(Sfio_t *iop, register const char *cp, int n)
293da2e3ebdSchin {
294da2e3ebdSchin 	register int c;
295da2e3ebdSchin 	do
296da2e3ebdSchin 	{
297da2e3ebdSchin 		switch(c= *cp)
298da2e3ebdSchin 		{
299da2e3ebdSchin 		    case 0:
300da2e3ebdSchin 			if(n<0)
301da2e3ebdSchin 				return;
302da2e3ebdSchin 			c = n;
303da2e3ebdSchin 			break;
304da2e3ebdSchin 		    case '\n':
305da2e3ebdSchin 			sfputr(iop,"$'\\n",'\'');
306da2e3ebdSchin 			continue;
307da2e3ebdSchin 		    case '\\':
308da2e3ebdSchin 			if (!(c = *++cp))
309da2e3ebdSchin 				c = '\\';
310da2e3ebdSchin 			/*FALLTHROUGH*/
311da2e3ebdSchin 		    case ' ':
312da2e3ebdSchin 		    case '<': case '>': case ';':
313da2e3ebdSchin 		    case '$': case '`': case '\t':
314da2e3ebdSchin 			sfputc(iop,'\\');
315da2e3ebdSchin 			break;
316da2e3ebdSchin 		}
317da2e3ebdSchin 		sfputc(iop,c);
318da2e3ebdSchin 	}
319da2e3ebdSchin 	while(*cp++);
320da2e3ebdSchin }
321da2e3ebdSchin 
out_string(Sfio_t * iop,register const char * cp,int c,int quoted)322da2e3ebdSchin static void out_string(Sfio_t *iop, register const char *cp, int c, int quoted)
323da2e3ebdSchin {
324da2e3ebdSchin 	if(quoted)
325da2e3ebdSchin 	{
3267c2fbfb3SApril Chin 		int n = stktell(stkstd);
327da2e3ebdSchin 		cp = sh_fmtq(cp);
328da2e3ebdSchin 		if(iop==stkstd && cp==stkptr(stkstd,n))
329da2e3ebdSchin 		{
330da2e3ebdSchin 			*stkptr(stkstd,stktell(stkstd)-1) = c;
331da2e3ebdSchin 			return;
332da2e3ebdSchin 		}
333da2e3ebdSchin 	}
334da2e3ebdSchin 	sfputr(iop,cp,c);
335da2e3ebdSchin }
336da2e3ebdSchin 
337da2e3ebdSchin struct Level
338da2e3ebdSchin {
339da2e3ebdSchin 	Namfun_t	hdr;
340da2e3ebdSchin 	short		maxlevel;
341da2e3ebdSchin };
342da2e3ebdSchin 
343da2e3ebdSchin /*
344da2e3ebdSchin  * this is for a debugger but it hasn't been tested yet
345da2e3ebdSchin  * if a debug script sets .sh.level it should set up the scope
346da2e3ebdSchin  *  as if you were executing in that level
347da2e3ebdSchin  */
put_level(Namval_t * np,const char * val,int flags,Namfun_t * fp)348da2e3ebdSchin static void put_level(Namval_t* np,const char *val,int flags,Namfun_t *fp)
349da2e3ebdSchin {
350da2e3ebdSchin 	Shscope_t	*sp;
351da2e3ebdSchin 	struct Level *lp = (struct Level*)fp;
352da2e3ebdSchin 	int16_t level, oldlevel = (int16_t)nv_getnum(np);
353da2e3ebdSchin 	nv_putv(np,val,flags,fp);
3547c2fbfb3SApril Chin 	if(!val)
35534f9b3eeSRoland Mainz 	{
35634f9b3eeSRoland Mainz 		fp = nv_stack(np, NIL(Namfun_t*));
35734f9b3eeSRoland Mainz 		if(fp && !fp->nofree)
35834f9b3eeSRoland Mainz 			free((void*)fp);
3597c2fbfb3SApril Chin 		return;
36034f9b3eeSRoland Mainz 	}
361da2e3ebdSchin 	level = nv_getnum(np);
362da2e3ebdSchin 	if(level<0 || level > lp->maxlevel)
363da2e3ebdSchin 	{
3647c2fbfb3SApril Chin 		nv_putv(np, (char*)&oldlevel, NV_INT16, fp);
365da2e3ebdSchin 		/* perhaps this should be an error */
366da2e3ebdSchin 		return;
367da2e3ebdSchin 	}
368da2e3ebdSchin 	if(level==oldlevel)
369da2e3ebdSchin 		return;
370da2e3ebdSchin 	if(sp = sh_getscope(level,SEEK_SET))
371da2e3ebdSchin 	{
372da2e3ebdSchin 		sh_setscope(sp);
3737c2fbfb3SApril Chin 		error_info.id = sp->cmdname;
3747c2fbfb3SApril Chin 
375da2e3ebdSchin 	}
376da2e3ebdSchin }
377da2e3ebdSchin 
3787c2fbfb3SApril Chin static const Namdisc_t level_disc = {  sizeof(struct Level), put_level };
3797c2fbfb3SApril Chin 
init_level(int level)3807c2fbfb3SApril Chin static struct Level *init_level(int level)
3817c2fbfb3SApril Chin {
3827c2fbfb3SApril Chin 	struct Level *lp = newof(NiL,struct Level,1,0);
3837c2fbfb3SApril Chin 	lp->maxlevel = level;
3847c2fbfb3SApril Chin 	_nv_unset(SH_LEVELNOD,0);
3857c2fbfb3SApril Chin 	nv_onattr(SH_LEVELNOD,NV_INT16|NV_NOFREE);
3867c2fbfb3SApril Chin 	nv_putval(SH_LEVELNOD,(char*)&lp->maxlevel,NV_INT16);
3877c2fbfb3SApril Chin 	lp->hdr.disc = &level_disc;
3887c2fbfb3SApril Chin 	nv_disc(SH_LEVELNOD,&lp->hdr,NV_FIRST);
3897c2fbfb3SApril Chin 	return(lp);
3907c2fbfb3SApril Chin }
391da2e3ebdSchin 
392da2e3ebdSchin /*
393da2e3ebdSchin  * write the current common on the stack and make it available as .sh.command
394da2e3ebdSchin  */
sh_debug(Shell_t * shp,const char * trap,const char * name,const char * subscript,char * const argv[],int flags)3957c2fbfb3SApril Chin int sh_debug(Shell_t *shp, const char *trap, const char *name, const char *subscript, char *const argv[], int flags)
396da2e3ebdSchin {
3977c2fbfb3SApril Chin 	Stk_t			*stkp=shp->stk;
398da2e3ebdSchin 	struct sh_scoped	savst;
399da2e3ebdSchin 	Namval_t		*np = SH_COMMANDNOD;
4007c2fbfb3SApril Chin 	char			*sav = stkptr(stkp,0);
4017c2fbfb3SApril Chin 	int			n=4, offset=stktell(stkp);
402da2e3ebdSchin 	const char		*cp = "+=( ";
403da2e3ebdSchin 	Sfio_t			*iop = stkstd;
4047c2fbfb3SApril Chin 	short			level;
4057c2fbfb3SApril Chin 	if(shp->indebug)
4067c2fbfb3SApril Chin 		return(0);
4077c2fbfb3SApril Chin 	shp->indebug = 1;
408da2e3ebdSchin 	if(name)
409da2e3ebdSchin 	{
410da2e3ebdSchin 		sfputr(iop,name,-1);
411da2e3ebdSchin 		if(subscript)
412da2e3ebdSchin 		{
413da2e3ebdSchin 			sfputc(iop,'[');
414da2e3ebdSchin 			out_string(iop,subscript,']',1);
415da2e3ebdSchin 		}
416da2e3ebdSchin 		if(!(flags&ARG_APPEND))
417da2e3ebdSchin 			cp+=1, n-=1;
418da2e3ebdSchin 		if(!(flags&ARG_ASSIGN))
419da2e3ebdSchin 			n -= 2;
420da2e3ebdSchin 		sfwrite(iop,cp,n);
421da2e3ebdSchin 	}
42234f9b3eeSRoland Mainz 	if(*argv && !(flags&ARG_RAW))
423da2e3ebdSchin 		out_string(iop, *argv++,' ', 0);
424da2e3ebdSchin 	n = (flags&ARG_ARITH);
425da2e3ebdSchin 	while(cp = *argv++)
426da2e3ebdSchin 	{
427da2e3ebdSchin 		if((flags&ARG_EXP) && argv[1]==0)
428da2e3ebdSchin 			out_pattern(iop, cp,' ');
429da2e3ebdSchin 		else
430da2e3ebdSchin 			out_string(iop, cp,' ',n?0: (flags&(ARG_RAW|ARG_NOGLOB))||*argv);
431da2e3ebdSchin 	}
432da2e3ebdSchin 	if(flags&ARG_ASSIGN)
433da2e3ebdSchin 		sfputc(iop,')');
434da2e3ebdSchin 	else if(iop==stkstd)
4357c2fbfb3SApril Chin 		*stkptr(stkp,stktell(stkp)-1) = 0;
4367c2fbfb3SApril Chin 	np->nvalue.cp = stkfreeze(stkp,1);
437da2e3ebdSchin 	/* now setup .sh.level variable */
4387c2fbfb3SApril Chin 	shp->st.lineno = error_info.line;
4397c2fbfb3SApril Chin 	level  = shp->fn_depth+shp->dot_depth;
4407c2fbfb3SApril Chin 	if(!SH_LEVELNOD->nvfun || !SH_LEVELNOD->nvfun->disc || nv_isattr(SH_LEVELNOD,NV_INT16|NV_NOFREE)!=(NV_INT16|NV_NOFREE))
4417c2fbfb3SApril Chin 		init_level(level);
4427c2fbfb3SApril Chin 	else
443da2e3ebdSchin 		nv_putval(SH_LEVELNOD,(char*)&level,NV_INT16);
4447c2fbfb3SApril Chin 	savst = shp->st;
4457c2fbfb3SApril Chin 	shp->st.trap[SH_DEBUGTRAP] = 0;
446da2e3ebdSchin 	n = sh_trap(trap,0);
447da2e3ebdSchin 	np->nvalue.cp = 0;
4487c2fbfb3SApril Chin 	shp->indebug = 0;
4497c2fbfb3SApril Chin 	if(shp->st.cmdname)
4507c2fbfb3SApril Chin 		error_info.id = shp->st.cmdname;
4517c2fbfb3SApril Chin 	nv_putval(SH_PATHNAMENOD,shp->st.filename,NV_NOFREE);
4527c2fbfb3SApril Chin 	nv_putval(SH_FUNNAMENOD,shp->st.funname,NV_NOFREE);
4537c2fbfb3SApril Chin 	shp->st = savst;
4547c2fbfb3SApril Chin 	if(sav != stkptr(stkp,0))
4557c2fbfb3SApril Chin 		stkset(stkp,sav,0);
456da2e3ebdSchin 	else
4577c2fbfb3SApril Chin 		stkseek(stkp,offset);
458da2e3ebdSchin 	return(n);
459da2e3ebdSchin }
460da2e3ebdSchin 
461da2e3ebdSchin /*
462da2e3ebdSchin  * Given stream <iop> compile and execute
463da2e3ebdSchin  */
sh_eval(register Sfio_t * iop,int mode)464da2e3ebdSchin int sh_eval(register Sfio_t *iop, int mode)
465da2e3ebdSchin {
466da2e3ebdSchin 	register Shnode_t *t;
467da2e3ebdSchin 	Shell_t  *shp = sh_getinterp();
468da2e3ebdSchin 	struct slnod *saveslp = shp->st.staklist;
469da2e3ebdSchin 	int jmpval;
470da2e3ebdSchin 	struct checkpt *pp = (struct checkpt*)shp->jmplist;
471da2e3ebdSchin 	struct checkpt buff;
472da2e3ebdSchin 	static Sfio_t *io_save;
4737c2fbfb3SApril Chin 	volatile int traceon=0, lineno=0;
47434f9b3eeSRoland Mainz 	int binscript=shp->binscript;
475da2e3ebdSchin 	io_save = iop; /* preserve correct value across longjmp */
47634f9b3eeSRoland Mainz 	shp->binscript = 0;
4777c2fbfb3SApril Chin #define SH_TOPFUN	0x8000	/* this is a temporary tksh hack */
4787c2fbfb3SApril Chin 	if (mode & SH_TOPFUN)
4797c2fbfb3SApril Chin 	{
4807c2fbfb3SApril Chin 		mode ^= SH_TOPFUN;
4817c2fbfb3SApril Chin 		shp->fn_reset = 1;
4827c2fbfb3SApril Chin 	}
483da2e3ebdSchin 	sh_pushcontext(&buff,SH_JMPEVAL);
484da2e3ebdSchin 	buff.olist = pp->olist;
485da2e3ebdSchin 	jmpval = sigsetjmp(buff.buff,0);
48634f9b3eeSRoland Mainz 	while(jmpval==0)
487da2e3ebdSchin 	{
4887c2fbfb3SApril Chin 		if(mode&SH_READEVAL)
4897c2fbfb3SApril Chin 		{
4907c2fbfb3SApril Chin 			lineno = shp->inlineno;
4917c2fbfb3SApril Chin 			if(traceon=sh_isoption(SH_XTRACE))
4927c2fbfb3SApril Chin 				sh_offoption(SH_XTRACE);
4937c2fbfb3SApril Chin 		}
49434f9b3eeSRoland Mainz 		t = (Shnode_t*)sh_parse(shp,iop,(mode&(SH_READEVAL|SH_FUNEVAL))?mode&SH_FUNEVAL:SH_NL);
49534f9b3eeSRoland Mainz 		if(!(mode&SH_FUNEVAL) || !sfreserve(iop,0,0))
49634f9b3eeSRoland Mainz 		{
49734f9b3eeSRoland Mainz 			if(!(mode&SH_READEVAL))
498da2e3ebdSchin 				sfclose(iop);
499da2e3ebdSchin 			io_save = 0;
50034f9b3eeSRoland Mainz 			mode &= ~SH_FUNEVAL;
50134f9b3eeSRoland Mainz 		}
50234f9b3eeSRoland Mainz 		mode &= ~SH_READEVAL;
503da2e3ebdSchin 		if(!sh_isoption(SH_VERBOSE))
504da2e3ebdSchin 			sh_offstate(SH_VERBOSE);
50534f9b3eeSRoland Mainz 		if((mode&~SH_FUNEVAL) && shp->hist_ptr)
506da2e3ebdSchin 		{
507da2e3ebdSchin 			hist_flush(shp->hist_ptr);
508da2e3ebdSchin 			mode = sh_state(SH_INTERACTIVE);
509da2e3ebdSchin 		}
51034f9b3eeSRoland Mainz 		sh_exec(t,sh_isstate(SH_ERREXIT)|sh_isstate(SH_NOFORK)|(mode&~SH_FUNEVAL));
51134f9b3eeSRoland Mainz 		if(!(mode&SH_FUNEVAL))
51234f9b3eeSRoland Mainz 			break;
513da2e3ebdSchin 	}
514da2e3ebdSchin 	sh_popcontext(&buff);
51534f9b3eeSRoland Mainz 	shp->binscript = binscript;
5167c2fbfb3SApril Chin 	if(traceon)
5177c2fbfb3SApril Chin 		sh_onoption(SH_XTRACE);
5187c2fbfb3SApril Chin 	if(lineno)
5197c2fbfb3SApril Chin 		shp->inlineno = lineno;
520da2e3ebdSchin 	if(io_save)
521da2e3ebdSchin 		sfclose(io_save);
5227c2fbfb3SApril Chin 	sh_freeup(shp);
523da2e3ebdSchin 	shp->st.staklist = saveslp;
5247c2fbfb3SApril Chin 	shp->fn_reset = 0;
525da2e3ebdSchin 	if(jmpval>SH_JMPEVAL)
526da2e3ebdSchin 		siglongjmp(*shp->jmplist,jmpval);
5277c2fbfb3SApril Chin 	return(shp->exitval);
528da2e3ebdSchin }
529da2e3ebdSchin 
530da2e3ebdSchin #if SHOPT_FASTPIPE
pipe_exec(Shell_t * shp,int pv[],Shnode_t * t,int errorflg)5317c2fbfb3SApril Chin static int pipe_exec(Shell_t* shp,int pv[], Shnode_t *t, int errorflg)
532da2e3ebdSchin {
533da2e3ebdSchin 	struct checkpt buff;
534da2e3ebdSchin 	register Shnode_t *tchild = t->fork.forktre;
535da2e3ebdSchin 	Namval_t *np;
5367c2fbfb3SApril Chin 	int jmpval;
5377c2fbfb3SApril Chin 	volatile Sfio_t *iop;
5387c2fbfb3SApril Chin 	volatile int r;
539da2e3ebdSchin 	if((tchild->tre.tretyp&COMMSK)!=TCOM || !(np=(Namval_t*)(tchild->com.comnamp)))
540da2e3ebdSchin 	{
541da2e3ebdSchin 		sh_pipe(pv);
542da2e3ebdSchin 		return(sh_exec(t,errorflg));
543da2e3ebdSchin 	}
5447c2fbfb3SApril Chin 	pv[0] = shp->lim.open_max;
5457c2fbfb3SApril Chin 	shp->fdstatus[pv[0]] = IOREAD|IODUP|IOSEEK;
5467c2fbfb3SApril Chin 	pv[1] = shp->lim.open_max+1;
5477c2fbfb3SApril Chin 	shp->fdstatus[pv[1]] = IOWRITE|IOSEEK;
548da2e3ebdSchin 	iop = sftmp(IOBSIZE+1);
5497c2fbfb3SApril Chin 	shp->sftable[shp->lim.open_max+1] = iop;
550da2e3ebdSchin 	sh_pushcontext(&buff,SH_JMPIO);
551da2e3ebdSchin 	if(t->tre.tretyp&FPIN)
5527c2fbfb3SApril Chin 		sh_iosave(shp,0,shp->topfd,(char*)0);
5537c2fbfb3SApril Chin 	sh_iosave(shp,1,shp->topfd,(char*)0);
554da2e3ebdSchin 	jmpval = sigsetjmp(buff.buff,0);
555da2e3ebdSchin 	if(jmpval==0)
556da2e3ebdSchin 	{
557da2e3ebdSchin 		if(t->tre.tretyp&FPIN)
5587c2fbfb3SApril Chin 			sh_iorenumber(shp,shp->inpipe[0],0);
5597c2fbfb3SApril Chin 		sh_iorenumber(shp,shp->lim.open_max+1,1);
560da2e3ebdSchin 		r = sh_exec(tchild,errorflg);
561da2e3ebdSchin 		if(sffileno(sfstdout)>=0)
562da2e3ebdSchin 			pv[0] = sfsetfd(sfstdout,10);
563da2e3ebdSchin 		iop = sfswap(sfstdout,0);
564da2e3ebdSchin 	}
565da2e3ebdSchin 	sh_popcontext(&buff);
5667c2fbfb3SApril Chin 	shp->sftable[pv[0]] = iop;
5677c2fbfb3SApril Chin 	shp->fdstatus[pv[0]] = IOREAD|IODUP|IOSEEK;
568da2e3ebdSchin 	sfset(iop,SF_WRITE,0);
569da2e3ebdSchin 	sfseek(iop,0L,SEEK_SET);
5707c2fbfb3SApril Chin 	sh_iorestore(shp,buff.topfd,jmpval);
571da2e3ebdSchin 	if(jmpval>SH_JMPIO)
5727c2fbfb3SApril Chin 		siglongjmp(*shp->jmplist,jmpval);
573da2e3ebdSchin 	return(r);
574da2e3ebdSchin }
575da2e3ebdSchin #endif /* SHOPT_FASTPIPE */
576da2e3ebdSchin 
577da2e3ebdSchin /*
578da2e3ebdSchin  * returns 1 when option -<c> is specified
579da2e3ebdSchin  */
checkopt(char * argv[],int c)580da2e3ebdSchin static int checkopt(char *argv[], int c)
581da2e3ebdSchin {
582da2e3ebdSchin 	char *cp;
583da2e3ebdSchin 	while(cp = *++argv)
584da2e3ebdSchin 	{
585da2e3ebdSchin 		if(*cp=='+')
586da2e3ebdSchin 			continue;
587da2e3ebdSchin 		if(*cp!='-' || cp[1]=='-')
588da2e3ebdSchin 			break;
5897c2fbfb3SApril Chin 		if(strchr(++cp,c))
590da2e3ebdSchin 			return(1);
5917c2fbfb3SApril Chin 		if(*cp=='h' && cp[1]==0 && *++argv==0)
5927c2fbfb3SApril Chin 			break;
593da2e3ebdSchin 	}
594da2e3ebdSchin 	return(0);
595da2e3ebdSchin }
596da2e3ebdSchin 
free_list(struct openlist * olist)597da2e3ebdSchin static void free_list(struct openlist *olist)
598da2e3ebdSchin {
599da2e3ebdSchin 	struct openlist *item,*next;
600da2e3ebdSchin 	for(item=olist;item;item=next)
601da2e3ebdSchin 	{
602da2e3ebdSchin 		next = item->next;
603da2e3ebdSchin 		free((void*)item);
604da2e3ebdSchin 	}
605da2e3ebdSchin }
606da2e3ebdSchin 
6077c2fbfb3SApril Chin /*
6087c2fbfb3SApril Chin  * set ${.sh.name} and ${.sh.subscript}
6097c2fbfb3SApril Chin  * set _ to reference for ${.sh.name}[$.sh.subscript]
6107c2fbfb3SApril Chin  */
set_instance(Shell_t * shp,Namval_t * nq,Namval_t * node,struct Namref * nr)611*3e14f97fSRoger A. Faulkner static int set_instance(Shell_t *shp,Namval_t *nq, Namval_t *node, struct Namref *nr)
6127c2fbfb3SApril Chin {
61334f9b3eeSRoland Mainz 	char		*sp=0,*cp = nv_name(nq);
6147c2fbfb3SApril Chin 	Namarr_t	*ap;
6157c2fbfb3SApril Chin 	memset(nr,0,sizeof(*nr));
6167c2fbfb3SApril Chin 	nr->np = nq;
6177c2fbfb3SApril Chin 	nr->root = sh.var_tree;
6187c2fbfb3SApril Chin 	nr->table = sh.last_table;
619*3e14f97fSRoger A. Faulkner 	shp->instance = 1;
62034f9b3eeSRoland Mainz 	if((ap=nv_arrayptr(nq)) && (sp = nv_getsub(nq)))
62134f9b3eeSRoland Mainz 		sp = strdup(sp);
622*3e14f97fSRoger A. Faulkner 	shp->instance = 0;
6237c2fbfb3SApril Chin 	if(sh.var_tree!=sh.var_base && !nv_open(cp,nr->root,NV_VARNAME|NV_NOREF|NV_NOSCOPE|NV_NOADD|NV_NOFAIL))
6247c2fbfb3SApril Chin 		nr->root = sh.var_base;
6257c2fbfb3SApril Chin 	nv_putval(SH_NAMENOD, cp, NV_NOFREE);
6267c2fbfb3SApril Chin 	memcpy(node,L_ARGNOD,sizeof(*node));
6277c2fbfb3SApril Chin 	L_ARGNOD->nvalue.nrp = nr;
6287c2fbfb3SApril Chin 	L_ARGNOD->nvflag = NV_REF|NV_NOFREE;
6297c2fbfb3SApril Chin 	L_ARGNOD->nvfun = 0;
6307c2fbfb3SApril Chin 	L_ARGNOD->nvenv = 0;
63134f9b3eeSRoland Mainz 	if(sp)
6327c2fbfb3SApril Chin 	{
63334f9b3eeSRoland Mainz 		nv_putval(SH_SUBSCRNOD,nr->sub=sp,NV_NOFREE);
6347c2fbfb3SApril Chin 		return(ap->nelem&ARRAY_SCAN);
6357c2fbfb3SApril Chin 	}
6367c2fbfb3SApril Chin 	return(0);
6377c2fbfb3SApril Chin }
6387c2fbfb3SApril Chin 
unset_instance(Namval_t * nq,Namval_t * node,struct Namref * nr,long mode)6397c2fbfb3SApril Chin static void unset_instance(Namval_t *nq, Namval_t *node, struct Namref *nr,long mode)
6407c2fbfb3SApril Chin {
6417c2fbfb3SApril Chin 	L_ARGNOD->nvalue.nrp = node->nvalue.nrp;
6427c2fbfb3SApril Chin 	L_ARGNOD->nvflag = node->nvflag;
6437c2fbfb3SApril Chin 	L_ARGNOD->nvfun = node->nvfun;
6447c2fbfb3SApril Chin 	if(nr->sub)
6457c2fbfb3SApril Chin 	{
6467c2fbfb3SApril Chin 		nv_putsub(nq, nr->sub, mode);
6477c2fbfb3SApril Chin 		free((void*)nr->sub);
6487c2fbfb3SApril Chin 	}
6497c2fbfb3SApril Chin 	nv_unset(SH_NAMENOD);
6507c2fbfb3SApril Chin 	nv_unset(SH_SUBSCRNOD);
6517c2fbfb3SApril Chin }
652da2e3ebdSchin 
sh_exec(register const Shnode_t * t,int flags)653da2e3ebdSchin int sh_exec(register const Shnode_t *t, int flags)
654da2e3ebdSchin {
6557c2fbfb3SApril Chin 	register Shell_t	*shp = &sh;
6567c2fbfb3SApril Chin 	Stk_t			*stkp = shp->stk;
657da2e3ebdSchin 	sh_sigcheck();
6587c2fbfb3SApril Chin 	if(t && !shp->st.execbrk && !sh_isoption(SH_NOEXEC))
659da2e3ebdSchin 	{
660da2e3ebdSchin 		register int 	type = flags;
661da2e3ebdSchin 		register char	*com0 = 0;
662da2e3ebdSchin 		int 		errorflg = (type&sh_state(SH_ERREXIT))|OPTIMIZE;
663da2e3ebdSchin 		int 		execflg = (type&sh_state(SH_NOFORK));
66434f9b3eeSRoland Mainz 		int 		execflg2 = (type&sh_state(SH_FORKED));
665da2e3ebdSchin 		int 		mainloop = (type&sh_state(SH_INTERACTIVE));
6667c2fbfb3SApril Chin #if SHOPT_AMP || SHOPT_SPAWN
667da2e3ebdSchin 		int		ntflag = (type&sh_state(SH_NTFORK));
66834f9b3eeSRoland Mainz #else
66934f9b3eeSRoland Mainz 		int		ntflag = 0;
670da2e3ebdSchin #endif
6717c2fbfb3SApril Chin 		int		topfd = shp->topfd;
6727c2fbfb3SApril Chin 		char 		*sav=stkptr(stkp,0);
6737c2fbfb3SApril Chin 		char		*cp=0, **com=0, *comn;
674da2e3ebdSchin 		int		argn;
675da2e3ebdSchin 		int 		skipexitset = 0;
676da2e3ebdSchin 		int		was_interactive = 0;
677da2e3ebdSchin 		int		was_errexit = sh_isstate(SH_ERREXIT);
678da2e3ebdSchin 		int		was_monitor = sh_isstate(SH_MONITOR);
679da2e3ebdSchin 		int		echeck = 0;
680da2e3ebdSchin 		if(flags&sh_state(SH_INTERACTIVE))
681da2e3ebdSchin 		{
68234f9b3eeSRoland Mainz 			if(pipejob==2)
68334f9b3eeSRoland Mainz 				job_unlock();
684da2e3ebdSchin 			pipejob = 0;
685da2e3ebdSchin 			job.curpgid = 0;
686da2e3ebdSchin 			flags &= ~sh_state(SH_INTERACTIVE);
687da2e3ebdSchin 		}
688da2e3ebdSchin 		sh_offstate(SH_ERREXIT);
689da2e3ebdSchin 		sh_offstate(SH_DEFPATH);
690da2e3ebdSchin 		if(was_errexit&flags)
691da2e3ebdSchin 			sh_onstate(SH_ERREXIT);
692da2e3ebdSchin 		if(was_monitor&flags)
693da2e3ebdSchin 			sh_onstate(SH_MONITOR);
694da2e3ebdSchin 		type = t->tre.tretyp;
6957c2fbfb3SApril Chin 		if(!shp->intrap)
6967c2fbfb3SApril Chin 			shp->oldexit=shp->exitval;
6977c2fbfb3SApril Chin 		shp->exitval=0;
6987c2fbfb3SApril Chin 		shp->lastsig = 0;
6997c2fbfb3SApril Chin 		shp->lastpath = 0;
700da2e3ebdSchin 		switch(type&COMMSK)
701da2e3ebdSchin 		{
702da2e3ebdSchin 		    case TCOM:
703da2e3ebdSchin 		    {
704da2e3ebdSchin 			register struct argnod	*argp;
705da2e3ebdSchin 			char		*trap;
706da2e3ebdSchin 			Namval_t	*np, *nq, *last_table;
707da2e3ebdSchin 			struct ionod	*io;
7087c2fbfb3SApril Chin 			int		command=0, flgs=NV_ASSIGN;
7097c2fbfb3SApril Chin 			shp->bltindata.invariant = type>>(COMBITS+2);
7107c2fbfb3SApril Chin 			type &= (COMMSK|COMSCAN);
7117c2fbfb3SApril Chin 			sh_stats(STAT_SCMDS);
7127c2fbfb3SApril Chin 			error_info.line = t->com.comline-shp->st.firstline;
7137c2fbfb3SApril Chin 			com = sh_argbuild(shp,&argn,&(t->com),OPTIMIZE);
714da2e3ebdSchin 			echeck = 1;
715da2e3ebdSchin 			if(t->tre.tretyp&COMSCAN)
716da2e3ebdSchin 			{
717da2e3ebdSchin 				argp = t->com.comarg;
718da2e3ebdSchin 				if(argp && *com && !(argp->argflag&ARG_RAW))
719da2e3ebdSchin 					sh_sigcheck();
720da2e3ebdSchin 			}
721da2e3ebdSchin 			np = (Namval_t*)(t->com.comnamp);
722da2e3ebdSchin 			nq = (Namval_t*)(t->com.comnamq);
723da2e3ebdSchin 			com0 = com[0];
7247c2fbfb3SApril Chin 			shp->xargexit = 0;
725da2e3ebdSchin 			while(np==SYSCOMMAND)
726da2e3ebdSchin 			{
7277c2fbfb3SApril Chin 				register int n = b_command(0,com,&shp->bltindata);
728da2e3ebdSchin 				if(n==0)
729da2e3ebdSchin 					break;
730da2e3ebdSchin 				command += n;
731da2e3ebdSchin 				np = 0;
732da2e3ebdSchin 				if(!(com0= *(com+=n)))
733da2e3ebdSchin 					break;
7347c2fbfb3SApril Chin 				np = nv_bfsearch(com0, shp->bltin_tree, &nq, &cp);
735da2e3ebdSchin 			}
7367c2fbfb3SApril Chin 			if(shp->xargexit)
737da2e3ebdSchin 			{
7387c2fbfb3SApril Chin 				shp->xargmin -= command;
7397c2fbfb3SApril Chin 				shp->xargmax -= command;
740da2e3ebdSchin 			}
741da2e3ebdSchin 			else
7427c2fbfb3SApril Chin 				shp->xargmin = 0;
743da2e3ebdSchin 			argn -= command;
744da2e3ebdSchin 			if(!command && np && is_abuiltin(np))
7457c2fbfb3SApril Chin 				np = dtsearch(shp->fun_tree,np);
7467c2fbfb3SApril Chin 			if(com0)
747da2e3ebdSchin 			{
7487c2fbfb3SApril Chin 				if(!np && !strchr(com0,'/'))
7497c2fbfb3SApril Chin 				{
7507c2fbfb3SApril Chin 					Dt_t *root = command?shp->bltin_tree:shp->fun_tree;
751da2e3ebdSchin 					np = nv_bfsearch(com0, root, &nq, &cp);
752da2e3ebdSchin #if SHOPT_NAMESPACE
7537c2fbfb3SApril Chin 					if(shp->namespace && !nq && !cp)
754da2e3ebdSchin 					{
7557c2fbfb3SApril Chin 						int offset = stktell(stkp);
7567c2fbfb3SApril Chin 						sfputr(stkp,nv_name(shp->namespace),-1);
7577c2fbfb3SApril Chin 						sfputc(stkp,'.');
7587c2fbfb3SApril Chin 						sfputr(stkp,com0,0);
7597c2fbfb3SApril Chin 						stkseek(stkp,offset);
7607c2fbfb3SApril Chin 						np = nv_bfsearch(stkptr(stkp,offset), root, &nq, &cp);
761da2e3ebdSchin 					}
762da2e3ebdSchin #endif /* SHOPT_NAMESPACE */
763da2e3ebdSchin 				}
7647c2fbfb3SApril Chin 				comn = com[argn-1];
7657c2fbfb3SApril Chin 			}
766da2e3ebdSchin 			io = t->tre.treio;
7677c2fbfb3SApril Chin 			if(shp->envlist = argp = t->com.comset)
768da2e3ebdSchin 			{
7697c2fbfb3SApril Chin 				if(argn==0 || (np && nv_isattr(np,BLT_SPC)))
770da2e3ebdSchin 				{
77134f9b3eeSRoland Mainz 					Namval_t *tp=0;
7727c2fbfb3SApril Chin 					if(argn)
7737c2fbfb3SApril Chin 					{
7747c2fbfb3SApril Chin 						if(checkopt(com,'A'))
7757c2fbfb3SApril Chin 							flgs |= NV_ARRAY;
7767c2fbfb3SApril Chin 						else if(checkopt(com,'a'))
7777c2fbfb3SApril Chin 							flgs |= NV_IARRAY;
7787c2fbfb3SApril Chin 					}
779da2e3ebdSchin #if SHOPT_BASH
780da2e3ebdSchin 					if(np==SYSLOCAL)
781da2e3ebdSchin 					{
782da2e3ebdSchin 						if(!nv_getval(SH_FUNNAMENOD))
783da2e3ebdSchin 							errormsg(SH_DICT,ERROR_exit(1),"%s: can only be used in a function",com0);
7847c2fbfb3SApril Chin 						if(!shp->st.var_local)
785da2e3ebdSchin 						{
7867c2fbfb3SApril Chin 							sh_scope(shp,(struct argnod*)0,0);
7877c2fbfb3SApril Chin 							shp->st.var_local = shp->var_tree;
788da2e3ebdSchin 						}
789da2e3ebdSchin 
790da2e3ebdSchin 					}
791da2e3ebdSchin 					if(np==SYSTYPESET || np==SYSLOCAL)
792da2e3ebdSchin #else
7937c2fbfb3SApril Chin 					if(np==SYSTYPESET ||  (np && np->nvalue.bfp==SYSTYPESET->nvalue.bfp))
794da2e3ebdSchin #endif
795da2e3ebdSchin 					{
7967c2fbfb3SApril Chin 						if(np!=SYSTYPESET)
79734f9b3eeSRoland Mainz 						{
7987c2fbfb3SApril Chin 							shp->typeinit = np;
79934f9b3eeSRoland Mainz 							tp = nv_type(np);
80034f9b3eeSRoland Mainz 						}
8017c2fbfb3SApril Chin 						if(checkopt(com,'C'))
8027c2fbfb3SApril Chin 							flgs |= NV_COMVAR;
8037c2fbfb3SApril Chin 						if(checkopt(com,'S'))
8047c2fbfb3SApril Chin 							flgs |= NV_STATIC;
805da2e3ebdSchin 						if(checkopt(com,'n'))
806da2e3ebdSchin 							flgs |= NV_NOREF;
80734f9b3eeSRoland Mainz 						else if(!shp->typeinit && (checkopt(com,'L') || checkopt(com,'R') || checkopt(com,'Z')))
80834f9b3eeSRoland Mainz 							flgs |= NV_UNJUST;
809da2e3ebdSchin #if SHOPT_TYPEDEF
8107c2fbfb3SApril Chin 						else if(argn>=3 && checkopt(com,'T'))
811da2e3ebdSchin 						{
8127c2fbfb3SApril Chin 							shp->prefix = NV_CLASS;
813da2e3ebdSchin 							flgs |= NV_TYPE;
814da2e3ebdSchin 
815da2e3ebdSchin 						}
816da2e3ebdSchin #endif /* SHOPT_TYPEDEF */
8177c2fbfb3SApril Chin 						if((shp->fn_depth && !shp->prefix) || np==SYSLOCAL)
818da2e3ebdSchin 							flgs |= NV_NOSCOPE;
819da2e3ebdSchin 					}
820da2e3ebdSchin 					else if(np==SYSEXPORT)
821da2e3ebdSchin 						flgs |= NV_EXPORT;
8227c2fbfb3SApril Chin 					if(flgs&(NV_EXPORT|NV_NOREF))
8237c2fbfb3SApril Chin 						flgs |= NV_IDENT;
8247c2fbfb3SApril Chin 					else
8257c2fbfb3SApril Chin 						flgs |= NV_VARNAME;
826da2e3ebdSchin #if 0
827da2e3ebdSchin 					if(OPTIMIZE)
828da2e3ebdSchin 						flgs |= NV_TAGGED;
829da2e3ebdSchin #endif
83034f9b3eeSRoland Mainz 					nv_setlist(argp,flgs,tp);
8317c2fbfb3SApril Chin 					if(np==shp->typeinit)
8327c2fbfb3SApril Chin 						shp->typeinit = 0;
8337c2fbfb3SApril Chin 					shp->envlist = argp;
834da2e3ebdSchin 					argp = NULL;
835da2e3ebdSchin 				}
836da2e3ebdSchin 			}
8377c2fbfb3SApril Chin 			last_table = shp->last_table;
8387c2fbfb3SApril Chin 			shp->last_table = 0;
839da2e3ebdSchin 			if((io||argn))
840da2e3ebdSchin 			{
8417c2fbfb3SApril Chin 				Shbltin_t *bp=0;
842da2e3ebdSchin 				static char *argv[1];
8437c2fbfb3SApril Chin 				int tflags = 1;
8447c2fbfb3SApril Chin 				if(np &&  nv_isattr(np,BLT_DCL))
8457c2fbfb3SApril Chin 					tflags |= 2;
846da2e3ebdSchin 				if(argn==0)
847da2e3ebdSchin 				{
848da2e3ebdSchin 					/* fake 'true' built-in */
849da2e3ebdSchin 					np = SYSTRUE;
850da2e3ebdSchin 					*argv = nv_name(np);
851da2e3ebdSchin 					com = argv;
852da2e3ebdSchin 				}
853da2e3ebdSchin 				/* set +x doesn't echo */
854da2e3ebdSchin 				else if((np!=SYSSET) && sh_isoption(SH_XTRACE))
8557c2fbfb3SApril Chin 					sh_trace(com-command,tflags);
856da2e3ebdSchin 				else if((t->tre.tretyp&FSHOWME) && sh_isoption(SH_SHOWME))
857da2e3ebdSchin 				{
858da2e3ebdSchin 					int ison = sh_isoption(SH_XTRACE);
859da2e3ebdSchin 					if(!ison)
860da2e3ebdSchin 						sh_onoption(SH_XTRACE);
8617c2fbfb3SApril Chin 					sh_trace(com-command,tflags);
862da2e3ebdSchin 					if(io)
8637c2fbfb3SApril Chin 						sh_redirect(shp,io,SH_SHOWME);
864da2e3ebdSchin 					if(!ison)
865da2e3ebdSchin 						sh_offoption(SH_XTRACE);
866da2e3ebdSchin 					break;
867da2e3ebdSchin 				}
8687c2fbfb3SApril Chin 				if(trap=shp->st.trap[SH_DEBUGTRAP])
8697c2fbfb3SApril Chin 				{
8707c2fbfb3SApril Chin 					int n = sh_debug(shp,trap,(char*)0,(char*)0, com, ARG_RAW);
8717c2fbfb3SApril Chin 					if(n==255 && shp->fn_depth+shp->dot_depth)
8727c2fbfb3SApril Chin 					{
8737c2fbfb3SApril Chin 						np = SYSRETURN;
8747c2fbfb3SApril Chin 						argn = 1;
8757c2fbfb3SApril Chin 						com[0] = np->nvname;
8767c2fbfb3SApril Chin 						com[1] = 0;
8777c2fbfb3SApril Chin 						io = 0;
8787c2fbfb3SApril Chin 						argp = 0;
8797c2fbfb3SApril Chin 					}
8807c2fbfb3SApril Chin 					else if(n==2)
8817c2fbfb3SApril Chin 						break;
8827c2fbfb3SApril Chin 				}
883da2e3ebdSchin 				if(io)
8847c2fbfb3SApril Chin 					sfsync(shp->outpool);
8857c2fbfb3SApril Chin 				shp->lastpath = 0;
886da2e3ebdSchin 				if(!np  && !strchr(com0,'/'))
887da2e3ebdSchin 				{
8887c2fbfb3SApril Chin 					if(path_search(com0,NIL(Pathcomp_t**),1))
8897c2fbfb3SApril Chin 					{
8907c2fbfb3SApril Chin 						error_info.line = t->com.comline-shp->st.firstline;
8917c2fbfb3SApril Chin 						if((np=nv_search(com0,shp->fun_tree,0)) && !np->nvalue.ip)
8927c2fbfb3SApril Chin 						{
8937c2fbfb3SApril Chin 							Namval_t *mp=nv_search(com0,shp->bltin_tree,0);
8947c2fbfb3SApril Chin 							if(mp)
8957c2fbfb3SApril Chin 								np = mp;
8967c2fbfb3SApril Chin 						}
8977c2fbfb3SApril Chin 					}
898da2e3ebdSchin 					else
899da2e3ebdSchin 					{
9007c2fbfb3SApril Chin 						if((np=nv_search(com0,shp->track_tree,0)) && !nv_isattr(np,NV_NOALIAS) && np->nvalue.cp)
9017c2fbfb3SApril Chin 							np=nv_search(nv_getval(np),shp->bltin_tree,0);
902da2e3ebdSchin 						else
903da2e3ebdSchin 							np = 0;
904da2e3ebdSchin 					}
905da2e3ebdSchin 				}
90634f9b3eeSRoland Mainz 				if(np && pipejob==2)
90734f9b3eeSRoland Mainz 				{
90834f9b3eeSRoland Mainz 					job_unlock();
90934f9b3eeSRoland Mainz 					pipejob = 1;
91034f9b3eeSRoland Mainz 				}
911da2e3ebdSchin 				/* check for builtins */
912da2e3ebdSchin 				if(np && is_abuiltin(np))
913da2e3ebdSchin 				{
9147c2fbfb3SApril Chin 					volatile int scope=0, share=0;
9157c2fbfb3SApril Chin 					volatile void *save_ptr;
9167c2fbfb3SApril Chin 					volatile void *save_data;
9177c2fbfb3SApril Chin 					int jmpval, save_prompt;
91834f9b3eeSRoland Mainz 					int was_nofork = execflg?sh_isstate(SH_NOFORK):0;
919da2e3ebdSchin 					struct checkpt buff;
920da2e3ebdSchin 					unsigned long was_vi=0, was_emacs=0, was_gmacs=0;
921da2e3ebdSchin 					struct stat statb;
9227c2fbfb3SApril Chin 					bp = &shp->bltindata;
9237c2fbfb3SApril Chin 					save_ptr = bp->ptr;
9247c2fbfb3SApril Chin 					save_data = bp->data;
9257c2fbfb3SApril Chin 					memset(&statb, 0, sizeof(struct stat));
926da2e3ebdSchin 					if(strchr(nv_name(np),'/'))
927da2e3ebdSchin 					{
928da2e3ebdSchin 						/*
929da2e3ebdSchin 						 * disable editors for built-in
930da2e3ebdSchin 						 * versions of commands on PATH
931da2e3ebdSchin 						 */
932da2e3ebdSchin 						was_vi = sh_isoption(SH_VI);
933da2e3ebdSchin 						was_emacs = sh_isoption(SH_EMACS);
934da2e3ebdSchin 						was_gmacs = sh_isoption(SH_GMACS);
935da2e3ebdSchin 						sh_offoption(SH_VI);
936da2e3ebdSchin 						sh_offoption(SH_EMACS);
937da2e3ebdSchin 						sh_offoption(SH_GMACS);
938da2e3ebdSchin 					}
93934f9b3eeSRoland Mainz 					if(execflg)
94034f9b3eeSRoland Mainz 						sh_onstate(SH_NOFORK);
941da2e3ebdSchin 					sh_pushcontext(&buff,SH_JMPCMD);
942da2e3ebdSchin 					jmpval = sigsetjmp(buff.buff,1);
943da2e3ebdSchin 					if(jmpval == 0)
944da2e3ebdSchin 					{
945da2e3ebdSchin 						if(!(nv_isattr(np,BLT_ENV)))
946da2e3ebdSchin 							error_info.flags |= ERROR_SILENT;
947da2e3ebdSchin 						errorpush(&buff.err,0);
948da2e3ebdSchin 						if(io)
949da2e3ebdSchin 						{
950da2e3ebdSchin 							struct openlist *item;
951da2e3ebdSchin 							if(np==SYSLOGIN)
952da2e3ebdSchin 								type=1;
953da2e3ebdSchin 							else if(np==SYSEXEC)
954da2e3ebdSchin 								type=1+!com[1];
955da2e3ebdSchin 							else
9567c2fbfb3SApril Chin 								type = (execflg && !shp->subshell && !shp->st.trapcom[0]);
9577c2fbfb3SApril Chin 							sh_redirect(shp,io,type);
958da2e3ebdSchin 							for(item=buff.olist;item;item=item->next)
959da2e3ebdSchin 								item->strm=0;
960da2e3ebdSchin 						}
961da2e3ebdSchin 						if(!(nv_isattr(np,BLT_ENV)))
962da2e3ebdSchin 						{
9637c2fbfb3SApril Chin 							if(bp->nosfio)
9647c2fbfb3SApril Chin 							{
9657c2fbfb3SApril Chin 								if(!shp->pwd)
966da2e3ebdSchin 									path_pwd(0);
9677c2fbfb3SApril Chin 								if(shp->pwd)
968da2e3ebdSchin 									stat(".",&statb);
9697c2fbfb3SApril Chin 							}
9707c2fbfb3SApril Chin 							sfsync(NULL);
971da2e3ebdSchin 							share = sfset(sfstdin,SF_SHARE,0);
972da2e3ebdSchin 							sh_onstate(SH_STOPOK);
973da2e3ebdSchin 							sfpool(sfstderr,NIL(Sfio_t*),SF_WRITE);
974da2e3ebdSchin 							sfset(sfstderr,SF_LINE,1);
9757c2fbfb3SApril Chin 							save_prompt = shp->nextprompt;
9767c2fbfb3SApril Chin 							shp->nextprompt = 0;
977da2e3ebdSchin 						}
978da2e3ebdSchin 						if(argp)
979da2e3ebdSchin 						{
980da2e3ebdSchin 							scope++;
9817c2fbfb3SApril Chin 							sh_scope(shp,argp,0);
982da2e3ebdSchin 						}
983da2e3ebdSchin 						opt_info.index = opt_info.offset = 0;
984da2e3ebdSchin 						opt_info.disc = 0;
985da2e3ebdSchin 						error_info.id = *com;
9867c2fbfb3SApril Chin 						if(argn)
9877c2fbfb3SApril Chin 							shp->exitval = 0;
9887c2fbfb3SApril Chin 						shp->bltinfun = funptr(np);
9897c2fbfb3SApril Chin 						bp->bnode = np;
9907c2fbfb3SApril Chin 						bp->vnode = nq;
9917c2fbfb3SApril Chin 						bp->ptr = nv_context(np);
9927c2fbfb3SApril Chin 						bp->data = t->com.comstate;
9937c2fbfb3SApril Chin 						bp->sigset = 0;
9947c2fbfb3SApril Chin 						bp->notify = 0;
9957c2fbfb3SApril Chin 						bp->flags = (OPTIMIZE!=0);
9967c2fbfb3SApril Chin 						if(shp->subshell && nv_isattr(np,BLT_NOSFIO))
9977c2fbfb3SApril Chin 							sh_subtmpfile(0);
9987c2fbfb3SApril Chin 						if(execflg && !shp->subshell &&
9997c2fbfb3SApril Chin 							!shp->st.trapcom[0] && !shp->st.trap[SH_ERRTRAP] && shp->fn_depth==0 && !nv_isattr(np,BLT_ENV))
1000da2e3ebdSchin 						{
1001da2e3ebdSchin 							/* do close-on-exec */
1002da2e3ebdSchin 							int fd;
10037c2fbfb3SApril Chin 							for(fd=0; fd < shp->lim.open_max; fd++)
10047c2fbfb3SApril Chin 								if((shp->fdstatus[fd]&IOCLEX)&&fd!=shp->infd)
1005da2e3ebdSchin 									sh_close(fd);
1006da2e3ebdSchin 						}
10077c2fbfb3SApril Chin 						if(argn)
10087c2fbfb3SApril Chin 							shp->exitval = (*shp->bltinfun)(argn,com,(void*)bp);
1009da2e3ebdSchin 						if(error_info.flags&ERROR_INTERACTIVE)
1010da2e3ebdSchin 							tty_check(ERRIO);
10117c2fbfb3SApril Chin 						((Shnode_t*)t)->com.comstate = shp->bltindata.data;
10127c2fbfb3SApril Chin 						bp->data = (void*)save_data;
10137c2fbfb3SApril Chin 						if(!nv_isattr(np,BLT_EXIT) && shp->exitval!=SH_RUNPROG)
10147c2fbfb3SApril Chin 							shp->exitval &= SH_EXITMASK;
1015da2e3ebdSchin 					}
1016da2e3ebdSchin 					else
1017da2e3ebdSchin 					{
1018da2e3ebdSchin 						struct openlist *item;
1019da2e3ebdSchin 						for(item=buff.olist;item;item=item->next)
1020da2e3ebdSchin 						{
1021da2e3ebdSchin 							if(item->strm)
1022da2e3ebdSchin 							{
1023da2e3ebdSchin 								sfclrlock(item->strm);
10247c2fbfb3SApril Chin 								if(shp->hist_ptr && item->strm == shp->hist_ptr->histfp)
10257c2fbfb3SApril Chin 									hist_close(shp->hist_ptr);
1026da2e3ebdSchin 								else
1027da2e3ebdSchin 									sfclose(item->strm);
1028da2e3ebdSchin 							}
1029da2e3ebdSchin 						}
10307c2fbfb3SApril Chin 						if(shp->bltinfun && (error_info.flags&ERROR_NOTIFY))
10317c2fbfb3SApril Chin 							(*shp->bltinfun)(-2,com,(void*)bp);
1032da2e3ebdSchin 						/* failure on special built-ins fatal */
1033da2e3ebdSchin 						if(jmpval<=SH_JMPCMD  && (!nv_isattr(np,BLT_SPC) || command))
1034da2e3ebdSchin 							jmpval=0;
1035da2e3ebdSchin 					}
10367c2fbfb3SApril Chin 					if(bp && bp->ptr!= nv_context(np))
10377c2fbfb3SApril Chin 						np->nvfun = (Namfun_t*)bp->ptr;
103834f9b3eeSRoland Mainz 					if(execflg && !was_nofork)
103934f9b3eeSRoland Mainz 						sh_offstate(SH_NOFORK);
1040da2e3ebdSchin 					if(!(nv_isattr(np,BLT_ENV)))
1041da2e3ebdSchin 					{
10427c2fbfb3SApril Chin 						if(bp->nosfio && shp->pwd)
1043da2e3ebdSchin 						{
1044da2e3ebdSchin 							struct stat stata;
1045da2e3ebdSchin 							stat(".",&stata);
1046da2e3ebdSchin 							/* restore directory changed */
1047da2e3ebdSchin 							if(statb.st_ino!=stata.st_ino || statb.st_dev!=stata.st_dev)
10487c2fbfb3SApril Chin 								chdir(shp->pwd);
1049da2e3ebdSchin 						}
1050da2e3ebdSchin 						sh_offstate(SH_STOPOK);
1051da2e3ebdSchin 						if(share&SF_SHARE)
1052da2e3ebdSchin 							sfset(sfstdin,SF_PUBLIC|SF_SHARE,1);
1053da2e3ebdSchin 						sfset(sfstderr,SF_LINE,0);
10547c2fbfb3SApril Chin 						sfpool(sfstderr,shp->outpool,SF_WRITE);
1055da2e3ebdSchin 						sfpool(sfstdin,NIL(Sfio_t*),SF_WRITE);
10567c2fbfb3SApril Chin 						shp->nextprompt = save_prompt;
1057da2e3ebdSchin 					}
1058da2e3ebdSchin 					sh_popcontext(&buff);
1059da2e3ebdSchin 					errorpop(&buff.err);
106034f9b3eeSRoland Mainz 					error_info.flags &= ~(ERROR_SILENT|ERROR_NOTIFY);
10617c2fbfb3SApril Chin 					shp->bltinfun = 0;
1062da2e3ebdSchin 					if(buff.olist)
1063da2e3ebdSchin 						free_list(buff.olist);
1064da2e3ebdSchin 					if(was_vi)
1065da2e3ebdSchin 						sh_onoption(SH_VI);
1066da2e3ebdSchin 					else if(was_emacs)
1067da2e3ebdSchin 						sh_onoption(SH_EMACS);
1068da2e3ebdSchin 					else if(was_gmacs)
1069da2e3ebdSchin 						sh_onoption(SH_GMACS);
1070da2e3ebdSchin 					if(scope)
10717c2fbfb3SApril Chin 						sh_unscope(shp);
10727c2fbfb3SApril Chin 					bp->ptr = (void*)save_ptr;
10737c2fbfb3SApril Chin 					bp->data = (void*)save_data;
1074da2e3ebdSchin 					/* don't restore for subshell exec */
10757c2fbfb3SApril Chin 					if((shp->topfd>topfd) && !(shp->subshell && np==SYSEXEC))
10767c2fbfb3SApril Chin 						sh_iorestore(shp,topfd,jmpval);
1077da2e3ebdSchin 					if(jmpval)
10787c2fbfb3SApril Chin 						siglongjmp(*shp->jmplist,jmpval);
10797c2fbfb3SApril Chin #if 0
10807c2fbfb3SApril Chin 					if(flgs&NV_STATIC)
10817c2fbfb3SApril Chin 						((Shnode_t*)t)->com.comset = 0;
10827c2fbfb3SApril Chin #endif
10837c2fbfb3SApril Chin 					if(shp->exitval >=0)
1084da2e3ebdSchin 						goto setexit;
1085da2e3ebdSchin 					np = 0;
1086da2e3ebdSchin 					type=0;
1087da2e3ebdSchin 				}
1088da2e3ebdSchin 				/* check for functions */
1089da2e3ebdSchin 				if(!command && np && nv_isattr(np,NV_FUNCTION))
1090da2e3ebdSchin 				{
10917c2fbfb3SApril Chin 					volatile int indx;
10927c2fbfb3SApril Chin 					int jmpval=0;
1093da2e3ebdSchin 					struct checkpt buff;
1094da2e3ebdSchin 					Namval_t node;
10957c2fbfb3SApril Chin 					struct Namref	nr;
10967c2fbfb3SApril Chin 					long		mode;
1097da2e3ebdSchin 					register struct slnod *slp;
1098da2e3ebdSchin 					if(!np->nvalue.ip)
1099da2e3ebdSchin 					{
11007c2fbfb3SApril Chin 						indx = path_search(com0,NIL(Pathcomp_t**),0);
1101da2e3ebdSchin 						if(indx==1)
11027c2fbfb3SApril Chin 							np = nv_search(com0,shp->fun_tree,HASH_NOSCOPE);
11037c2fbfb3SApril Chin 
1104da2e3ebdSchin 						if(!np->nvalue.ip)
1105da2e3ebdSchin 						{
1106da2e3ebdSchin 							if(indx==1)
1107da2e3ebdSchin 							{
1108da2e3ebdSchin 								errormsg(SH_DICT,ERROR_exit(0),e_defined,com0);
11097c2fbfb3SApril Chin 								shp->exitval = ERROR_NOEXEC;
1110da2e3ebdSchin 							}
1111da2e3ebdSchin 							else
1112da2e3ebdSchin 							{
1113da2e3ebdSchin 								errormsg(SH_DICT,ERROR_exit(0),e_found,"function");
11147c2fbfb3SApril Chin 								shp->exitval = ERROR_NOENT;
1115da2e3ebdSchin 							}
1116da2e3ebdSchin 							goto setexit;
1117da2e3ebdSchin 						}
1118da2e3ebdSchin 					}
1119da2e3ebdSchin 					/* increase refcnt for unset */
1120da2e3ebdSchin 					slp = (struct slnod*)np->nvenv;
1121da2e3ebdSchin 					sh_funstaks(slp->slchild,1);
1122da2e3ebdSchin 					staklink(slp->slptr);
1123da2e3ebdSchin 					if(nq)
1124da2e3ebdSchin 					{
11257c2fbfb3SApril Chin 						shp->last_table = last_table;
1126*3e14f97fSRoger A. Faulkner 						mode = set_instance(shp,nq,&node,&nr);
1127da2e3ebdSchin 					}
1128da2e3ebdSchin 					if(io)
1129da2e3ebdSchin 					{
11307c2fbfb3SApril Chin 						indx = shp->topfd;
1131da2e3ebdSchin 						sh_pushcontext(&buff,SH_JMPCMD);
1132da2e3ebdSchin 						jmpval = sigsetjmp(buff.buff,0);
1133da2e3ebdSchin 					}
1134da2e3ebdSchin 					if(jmpval == 0)
1135da2e3ebdSchin 					{
1136da2e3ebdSchin 						if(io)
11377c2fbfb3SApril Chin 							indx = sh_redirect(shp,io,execflg);
11387c2fbfb3SApril Chin 						sh_funct(shp,np,argn,com,t->com.comset,(flags&~OPTIMIZE_FLAG));
1139da2e3ebdSchin 					}
1140da2e3ebdSchin 					if(io)
1141da2e3ebdSchin 					{
1142da2e3ebdSchin 						if(buff.olist)
1143da2e3ebdSchin 							free_list(buff.olist);
1144da2e3ebdSchin 						sh_popcontext(&buff);
11457c2fbfb3SApril Chin 						sh_iorestore(shp,indx,jmpval);
1146da2e3ebdSchin 					}
1147da2e3ebdSchin 					if(nq)
11487c2fbfb3SApril Chin 						unset_instance(nq,&node,&nr,mode);
1149da2e3ebdSchin 					sh_funstaks(slp->slchild,-1);
1150da2e3ebdSchin 					stakdelete(slp->slptr);
1151da2e3ebdSchin 					if(jmpval > SH_JMPFUN)
11527c2fbfb3SApril Chin 						siglongjmp(*shp->jmplist,jmpval);
1153da2e3ebdSchin 					goto setexit;
1154da2e3ebdSchin 				}
1155da2e3ebdSchin 			}
1156da2e3ebdSchin 			else if(!io)
1157da2e3ebdSchin 			{
1158da2e3ebdSchin 			setexit:
1159da2e3ebdSchin 				exitset();
1160da2e3ebdSchin 				break;
1161da2e3ebdSchin 			}
1162da2e3ebdSchin 		    }
1163da2e3ebdSchin 		    case TFORK:
1164da2e3ebdSchin 		    {
1165da2e3ebdSchin 			register pid_t parent;
1166da2e3ebdSchin 			int no_fork,jobid;
1167da2e3ebdSchin 			int pipes[2];
11687c2fbfb3SApril Chin 			if(shp->subshell)
116934f9b3eeSRoland Mainz 			{
117034f9b3eeSRoland Mainz 				if(shp->subshare)
11717c2fbfb3SApril Chin 					sh_subtmpfile(1);
117234f9b3eeSRoland Mainz 				else
117334f9b3eeSRoland Mainz 					sh_subfork();
117434f9b3eeSRoland Mainz 			}
117534f9b3eeSRoland Mainz 			no_fork = !ntflag && !(type&(FAMP|FPOU)) &&
117634f9b3eeSRoland Mainz 			    !shp->st.trapcom[0] && !shp->st.trap[SH_ERRTRAP] &&
1177*3e14f97fSRoger A. Faulkner 				((struct checkpt*)shp->jmplist)->mode!=SH_JMPEVAL &&
117834f9b3eeSRoland Mainz 				(execflg2 || (execflg &&
117934f9b3eeSRoland Mainz 				!shp->subshell && shp->fn_depth==0 &&
118034f9b3eeSRoland Mainz 				!(pipejob && sh_isoption(SH_PIPEFAIL))
118134f9b3eeSRoland Mainz 			    ));
11827c2fbfb3SApril Chin 			if(sh_isstate(SH_PROFILE) || shp->dot_depth)
1183da2e3ebdSchin 			{
1184da2e3ebdSchin 				/* disable foreground job monitor */
1185da2e3ebdSchin 				if(!(type&FAMP))
1186da2e3ebdSchin 					sh_offstate(SH_MONITOR);
1187da2e3ebdSchin #if SHOPT_DEVFD
1188da2e3ebdSchin 				else if(!(type&FINT))
1189da2e3ebdSchin 					sh_offstate(SH_MONITOR);
1190da2e3ebdSchin #endif /* SHOPT_DEVFD */
1191da2e3ebdSchin 			}
1192da2e3ebdSchin 			if(no_fork)
1193da2e3ebdSchin 				job.parent=parent=0;
1194da2e3ebdSchin 			else
1195da2e3ebdSchin 			{
119634f9b3eeSRoland Mainz #ifdef SHOPT_BGX
119734f9b3eeSRoland Mainz 				int maxjob;
119834f9b3eeSRoland Mainz 				if(((type&(FAMP|FINT)) == (FAMP|FINT)) && (maxjob=nv_getnum(JOBMAXNOD))>0)
119934f9b3eeSRoland Mainz 				{
120034f9b3eeSRoland Mainz 					while(job.numbjob >= maxjob)
120134f9b3eeSRoland Mainz 					{
120234f9b3eeSRoland Mainz 						job_lock();
120334f9b3eeSRoland Mainz 						job_reap(0);
120434f9b3eeSRoland Mainz 						job_unlock();
120534f9b3eeSRoland Mainz 					}
120634f9b3eeSRoland Mainz 				}
120734f9b3eeSRoland Mainz #endif /* SHOPT_BGX */
1208da2e3ebdSchin 				if(type&FCOOP)
12097c2fbfb3SApril Chin 					coproc_init(shp,pipes);
1210da2e3ebdSchin 				nv_getval(RANDNOD);
1211da2e3ebdSchin #if SHOPT_AMP
1212da2e3ebdSchin 				if((type&(FAMP|FINT)) == (FAMP|FINT))
12137c2fbfb3SApril Chin 					parent = sh_ntfork(shp,t,com,&jobid,ntflag);
1214da2e3ebdSchin 				else
1215da2e3ebdSchin 					parent = sh_fork(type,&jobid);
1216da2e3ebdSchin 				if(parent<0)
1217da2e3ebdSchin 					break;
1218da2e3ebdSchin #else
1219da2e3ebdSchin #if SHOPT_SPAWN
1220da2e3ebdSchin #   ifdef _lib_fork
1221da2e3ebdSchin 				if(com)
12227c2fbfb3SApril Chin 					parent = sh_ntfork(shp,t,com,&jobid,ntflag);
1223da2e3ebdSchin 				else
1224da2e3ebdSchin 					parent = sh_fork(type,&jobid);
1225da2e3ebdSchin #   else
12267c2fbfb3SApril Chin 				if((parent = sh_ntfork(shp,t,com,&jobid,ntflag))<=0)
1227da2e3ebdSchin 					break;
1228da2e3ebdSchin #   endif /* _lib_fork */
1229da2e3ebdSchin 				if(parent<0)
1230da2e3ebdSchin 					break;
1231da2e3ebdSchin #else
1232da2e3ebdSchin 				parent = sh_fork(type,&jobid);
1233da2e3ebdSchin #endif /* SHOPT_SPAWN */
1234da2e3ebdSchin #endif
1235da2e3ebdSchin 			}
1236da2e3ebdSchin 			if(job.parent=parent)
1237da2e3ebdSchin 			/* This is the parent branch of fork
1238da2e3ebdSchin 			 * It may or may not wait for the child
1239da2e3ebdSchin 			 */
1240da2e3ebdSchin 			{
124134f9b3eeSRoland Mainz 				if(pipejob==2)
124234f9b3eeSRoland Mainz 				{
124334f9b3eeSRoland Mainz 					pipejob = 1;
124434f9b3eeSRoland Mainz 					job_unlock();
124534f9b3eeSRoland Mainz 				}
1246da2e3ebdSchin 				if(type&FPCL)
12477c2fbfb3SApril Chin 					sh_close(shp->inpipe[0]);
1248da2e3ebdSchin 				if(type&(FCOOP|FAMP))
12497c2fbfb3SApril Chin 					shp->bckpid = parent;
12507c2fbfb3SApril Chin 				else if(!(type&(FAMP|FPOU)))
1251da2e3ebdSchin 				{
12527c2fbfb3SApril Chin 					if(shp->topfd > topfd)
12537c2fbfb3SApril Chin 						sh_iorestore(shp,topfd,0);
12547c2fbfb3SApril Chin 					if(!sh_isoption(SH_MONITOR))
12557c2fbfb3SApril Chin 					{
12567c2fbfb3SApril Chin 						if(!(shp->sigflag[SIGINT]&(SH_SIGFAULT|SH_SIGOFF)))
12577c2fbfb3SApril Chin 							sh_sigtrap(SIGINT);
12587c2fbfb3SApril Chin 						shp->trapnote |= SH_SIGIGNORE;
12597c2fbfb3SApril Chin 					}
126034f9b3eeSRoland Mainz 					if(execflg && shp->subshell && !shp->subshare)
12617c2fbfb3SApril Chin 					{
12627c2fbfb3SApril Chin 						shp->spid = parent;
12637c2fbfb3SApril Chin 						job.pwlist->p_env--;
12647c2fbfb3SApril Chin 					}
126534f9b3eeSRoland Mainz 					else if(shp->pipepid)
126634f9b3eeSRoland Mainz 						shp->pipepid = parent;
12677c2fbfb3SApril Chin 					else
1268da2e3ebdSchin 						job_wait(parent);
12697c2fbfb3SApril Chin 					if(!sh_isoption(SH_MONITOR))
12707c2fbfb3SApril Chin 					{
12717c2fbfb3SApril Chin 						shp->trapnote &= ~SH_SIGIGNORE;
12727c2fbfb3SApril Chin 						if(shp->exitval == (SH_EXITSIG|SIGINT))
12737c2fbfb3SApril Chin 							sh_fault(SIGINT);
12747c2fbfb3SApril Chin 					}
1275da2e3ebdSchin 				}
1276da2e3ebdSchin 				if(type&FAMP)
1277da2e3ebdSchin 				{
1278da2e3ebdSchin 					if(sh_isstate(SH_PROFILE) || sh_isstate(SH_INTERACTIVE))
1279da2e3ebdSchin 					{
1280da2e3ebdSchin 						/* print job number */
1281da2e3ebdSchin #ifdef JOBS
1282da2e3ebdSchin 						sfprintf(sfstderr,"[%d]\t%d\n",jobid,parent);
1283da2e3ebdSchin #else
1284da2e3ebdSchin 						sfprintf(sfstderr,"%d\n",parent);
1285da2e3ebdSchin #endif /* JOBS */
1286da2e3ebdSchin 					}
1287da2e3ebdSchin 				}
1288da2e3ebdSchin 				break;
1289da2e3ebdSchin 			}
1290da2e3ebdSchin 			else
1291da2e3ebdSchin 			/*
1292da2e3ebdSchin 			 * this is the FORKED branch (child) of execute
1293da2e3ebdSchin 			 */
1294da2e3ebdSchin 			{
12957c2fbfb3SApril Chin 				volatile int jmpval;
1296da2e3ebdSchin 				struct checkpt buff;
1297da2e3ebdSchin 				if(no_fork)
1298da2e3ebdSchin 					sh_sigreset(2);
1299da2e3ebdSchin 				sh_pushcontext(&buff,SH_JMPEXIT);
1300da2e3ebdSchin 				jmpval = sigsetjmp(buff.buff,0);
1301da2e3ebdSchin 				if(jmpval)
1302da2e3ebdSchin 					goto done;
1303da2e3ebdSchin 				if((type&FINT) && !sh_isstate(SH_MONITOR))
1304da2e3ebdSchin 				{
1305da2e3ebdSchin 					/* default std input for & */
1306da2e3ebdSchin 					signal(SIGINT,SIG_IGN);
1307da2e3ebdSchin 					signal(SIGQUIT,SIG_IGN);
13087c2fbfb3SApril Chin 					if(!shp->st.ioset)
1309da2e3ebdSchin 					{
1310da2e3ebdSchin 						if(sh_close(0)>=0)
1311da2e3ebdSchin 							sh_chkopen(e_devnull);
1312da2e3ebdSchin 					}
1313da2e3ebdSchin 				}
1314da2e3ebdSchin 				sh_offstate(SH_MONITOR);
1315da2e3ebdSchin 				/* pipe in or out */
1316da2e3ebdSchin #ifdef _lib_nice
1317da2e3ebdSchin 				if((type&FAMP) && sh_isoption(SH_BGNICE))
1318da2e3ebdSchin 					nice(4);
1319da2e3ebdSchin #endif /* _lib_nice */
1320da2e3ebdSchin 				if(type&FPIN)
1321da2e3ebdSchin 				{
13227c2fbfb3SApril Chin 					sh_iorenumber(shp,shp->inpipe[0],0);
1323da2e3ebdSchin 					if(!(type&FPOU) || (type&FCOOP))
13247c2fbfb3SApril Chin 						sh_close(shp->inpipe[1]);
1325da2e3ebdSchin 				}
1326da2e3ebdSchin 				if(type&FPOU)
1327da2e3ebdSchin 				{
13287c2fbfb3SApril Chin 					sh_iorenumber(shp,shp->outpipe[1],1);
13297c2fbfb3SApril Chin 					sh_pclose(shp->outpipe);
1330da2e3ebdSchin 				}
1331da2e3ebdSchin 				if((type&COMMSK)!=TCOM)
13327c2fbfb3SApril Chin 					error_info.line = t->fork.forkline-shp->st.firstline;
13337c2fbfb3SApril Chin 				if(shp->topfd)
13347c2fbfb3SApril Chin 					sh_iounsave(shp);
13357c2fbfb3SApril Chin 				topfd = shp->topfd;
13367c2fbfb3SApril Chin 				sh_redirect(shp,t->tre.treio,1);
13377c2fbfb3SApril Chin 				if(shp->topfd > topfd)
13387c2fbfb3SApril Chin 				{
1339*3e14f97fSRoger A. Faulkner 					job_lock();
13407c2fbfb3SApril Chin 					while((parent = vfork()) < 0)
13417c2fbfb3SApril Chin 						_sh_fork(parent, 0, (int*)0);
1342*3e14f97fSRoger A. Faulkner 					job_fork(parent);
13437c2fbfb3SApril Chin 					if(parent)
13447c2fbfb3SApril Chin 					{
13457c2fbfb3SApril Chin 						job_clear();
13467c2fbfb3SApril Chin 						job_post(parent,0);
13477c2fbfb3SApril Chin 						job_wait(parent);
13487c2fbfb3SApril Chin 						sh_iorestore(shp,topfd,SH_JMPCMD);
13497c2fbfb3SApril Chin 						sh_done(shp,(shp->exitval&SH_EXITSIG)?(shp->exitval&SH_EXITMASK):0);
13507c2fbfb3SApril Chin 
13517c2fbfb3SApril Chin 					}
13527c2fbfb3SApril Chin 				}
1353da2e3ebdSchin 				if((type&COMMSK)!=TCOM)
1354da2e3ebdSchin 				{
1355da2e3ebdSchin 					/* don't clear job table for out
1356da2e3ebdSchin 					   pipes so that jobs comand can
1357da2e3ebdSchin 					   be used in a pipeline
1358da2e3ebdSchin 					 */
1359da2e3ebdSchin 					if(!no_fork && !(type&FPOU))
1360da2e3ebdSchin 						job_clear();
136134f9b3eeSRoland Mainz 					sh_exec(t->fork.forktre,flags|sh_state(SH_NOFORK)|sh_state(SH_FORKED));
1362da2e3ebdSchin 				}
1363da2e3ebdSchin 				else if(com0)
1364da2e3ebdSchin 				{
1365da2e3ebdSchin 					sh_offoption(SH_ERREXIT);
13667c2fbfb3SApril Chin 					sh_freeup(shp);
1367da2e3ebdSchin 					path_exec(com0,com,t->com.comset);
1368da2e3ebdSchin 				}
1369da2e3ebdSchin 			done:
1370da2e3ebdSchin 				sh_popcontext(&buff);
1371da2e3ebdSchin 				if(jmpval>SH_JMPEXIT)
13727c2fbfb3SApril Chin 					siglongjmp(*shp->jmplist,jmpval);
13737c2fbfb3SApril Chin 				sh_done(shp,0);
1374da2e3ebdSchin 			}
1375da2e3ebdSchin 		    }
1376da2e3ebdSchin 
1377da2e3ebdSchin 		    case TSETIO:
1378da2e3ebdSchin 		    {
1379da2e3ebdSchin 		    /*
1380da2e3ebdSchin 		     * don't create a new process, just
1381da2e3ebdSchin 		     * save and restore io-streams
1382da2e3ebdSchin 		     */
1383da2e3ebdSchin 			pid_t	pid;
1384da2e3ebdSchin 			int 	jmpval, waitall;
138534f9b3eeSRoland Mainz 			int 	simple = (t->fork.forktre->tre.tretyp&COMMSK)==TCOM;
1386da2e3ebdSchin 			struct checkpt buff;
13877c2fbfb3SApril Chin 			if(shp->subshell)
1388da2e3ebdSchin 				execflg = 0;
1389da2e3ebdSchin 			sh_pushcontext(&buff,SH_JMPIO);
1390da2e3ebdSchin 			if(type&FPIN)
1391da2e3ebdSchin 			{
1392da2e3ebdSchin 				was_interactive = sh_isstate(SH_INTERACTIVE);
1393da2e3ebdSchin 				sh_offstate(SH_INTERACTIVE);
13947c2fbfb3SApril Chin 				sh_iosave(shp,0,shp->topfd,(char*)0);
139534f9b3eeSRoland Mainz 				shp->pipepid = simple;
13967c2fbfb3SApril Chin 				sh_iorenumber(shp,shp->inpipe[0],0);
1397da2e3ebdSchin 				/*
1398da2e3ebdSchin 				 * if read end of pipe is a simple command
1399da2e3ebdSchin 				 * treat as non-sharable to improve performance
1400da2e3ebdSchin 				 */
140134f9b3eeSRoland Mainz 				if(simple)
1402da2e3ebdSchin 					sfset(sfstdin,SF_PUBLIC|SF_SHARE,0);
1403da2e3ebdSchin 				waitall = job.waitall;
1404da2e3ebdSchin 				job.waitall = 0;
1405da2e3ebdSchin 				pid = job.parent;
1406da2e3ebdSchin 			}
1407da2e3ebdSchin 			else
14087c2fbfb3SApril Chin 				error_info.line = t->fork.forkline-shp->st.firstline;
1409da2e3ebdSchin 			jmpval = sigsetjmp(buff.buff,0);
1410da2e3ebdSchin 			if(jmpval==0)
1411da2e3ebdSchin 			{
14127c2fbfb3SApril Chin 				sh_redirect(shp,t->fork.forkio,execflg);
1413da2e3ebdSchin 				(t->fork.forktre)->tre.tretyp |= t->tre.tretyp&FSHOWME;
141434f9b3eeSRoland Mainz 				sh_exec(t->fork.forktre,flags&~simple);
1415da2e3ebdSchin 			}
14167c2fbfb3SApril Chin 			else
14177c2fbfb3SApril Chin 				sfsync(shp->outpool);
1418da2e3ebdSchin 			sh_popcontext(&buff);
14197c2fbfb3SApril Chin 			sh_iorestore(shp,buff.topfd,jmpval);
1420da2e3ebdSchin 			if(buff.olist)
1421da2e3ebdSchin 				free_list(buff.olist);
1422da2e3ebdSchin 			if(type&FPIN)
1423da2e3ebdSchin 			{
1424da2e3ebdSchin 				job.waitall = waitall;
14257c2fbfb3SApril Chin 				type = shp->exitval;
1426da2e3ebdSchin 				if(!(type&SH_EXITSIG))
1427da2e3ebdSchin 				{
1428da2e3ebdSchin 					/* wait for remainder of pipline */
142934f9b3eeSRoland Mainz 					if(shp->pipepid>1)
143034f9b3eeSRoland Mainz 					{
143134f9b3eeSRoland Mainz 						job_wait(shp->pipepid);
143234f9b3eeSRoland Mainz 						type = shp->exitval;
143334f9b3eeSRoland Mainz 					}
143434f9b3eeSRoland Mainz 					else
1435da2e3ebdSchin 						job_wait(waitall?pid:0);
1436da2e3ebdSchin 					if(type || !sh_isoption(SH_PIPEFAIL))
14377c2fbfb3SApril Chin 						shp->exitval = type;
1438da2e3ebdSchin 				}
143934f9b3eeSRoland Mainz 				shp->pipepid = 0;
14407c2fbfb3SApril Chin 				shp->st.ioset = 0;
144134f9b3eeSRoland Mainz 				if(simple && was_errexit)
144234f9b3eeSRoland Mainz 				{
144334f9b3eeSRoland Mainz 					echeck = 1;
144434f9b3eeSRoland Mainz 					sh_onstate(SH_ERREXIT);
144534f9b3eeSRoland Mainz 				}
1446da2e3ebdSchin 			}
1447da2e3ebdSchin 			if(jmpval>SH_JMPIO)
14487c2fbfb3SApril Chin 				siglongjmp(*shp->jmplist,jmpval);
1449da2e3ebdSchin 			break;
1450da2e3ebdSchin 		    }
1451da2e3ebdSchin 
1452da2e3ebdSchin 		    case TPAR:
1453da2e3ebdSchin 			echeck = 1;
1454da2e3ebdSchin 			flags &= ~OPTIMIZE_FLAG;
14557c2fbfb3SApril Chin 			if(!shp->subshell && !shp->st.trapcom[0] && !shp->st.trap[SH_ERRTRAP] && (flags&sh_state(SH_NOFORK)))
1456da2e3ebdSchin 			{
145734f9b3eeSRoland Mainz 				char *savsig;
145834f9b3eeSRoland Mainz 				int nsig,jmpval;
1459da2e3ebdSchin 				struct checkpt buff;
146034f9b3eeSRoland Mainz 				shp->st.otrapcom = 0;
146134f9b3eeSRoland Mainz 				if((nsig=shp->st.trapmax*sizeof(char*))>0 || shp->st.trapcom[0])
146234f9b3eeSRoland Mainz 				{
146334f9b3eeSRoland Mainz 					nsig += sizeof(char*);
146434f9b3eeSRoland Mainz 					memcpy(savsig=malloc(nsig),(char*)&shp->st.trapcom[0],nsig);
146534f9b3eeSRoland Mainz 					shp->st.otrapcom = (char**)savsig;
146634f9b3eeSRoland Mainz 				}
146734f9b3eeSRoland Mainz 				sh_sigreset(0);
1468da2e3ebdSchin 				sh_pushcontext(&buff,SH_JMPEXIT);
1469da2e3ebdSchin 				jmpval = sigsetjmp(buff.buff,0);
1470da2e3ebdSchin 				if(jmpval==0)
1471da2e3ebdSchin 					sh_exec(t->par.partre,flags);
1472da2e3ebdSchin 				sh_popcontext(&buff);
1473da2e3ebdSchin 				if(jmpval > SH_JMPEXIT)
14747c2fbfb3SApril Chin 					siglongjmp(*shp->jmplist,jmpval);
14757c2fbfb3SApril Chin 				sh_done(shp,0);
1476da2e3ebdSchin 			}
1477da2e3ebdSchin 			else
1478da2e3ebdSchin 				sh_subshell(t->par.partre,flags,0);
1479da2e3ebdSchin 			break;
1480da2e3ebdSchin 
1481da2e3ebdSchin 		    case TFIL:
1482da2e3ebdSchin 		    {
1483da2e3ebdSchin 		    /*
1484da2e3ebdSchin 		     * This code sets up a pipe.
1485da2e3ebdSchin 		     * All elements of the pipe are started by the parent.
1486da2e3ebdSchin 		     * The last element executes in current environment
1487da2e3ebdSchin 		     */
1488da2e3ebdSchin 			int	pvo[2];	/* old pipe for multi-stage */
1489da2e3ebdSchin 			int	pvn[2];	/* current set up pipe */
1490da2e3ebdSchin 			int	savepipe = pipejob;
1491da2e3ebdSchin 			int	showme = t->tre.tretyp&FSHOWME;
1492da2e3ebdSchin 			pid_t	savepgid = job.curpgid;
14937c2fbfb3SApril Chin 			job.curpgid = 0;
14947c2fbfb3SApril Chin 			if(shp->subshell)
149581af778eSCasper H.S. Dik 			{
149681af778eSCasper H.S. Dik 				if(shp->subshare)
149781af778eSCasper H.S. Dik 					sh_subtmpfile(0);
149881af778eSCasper H.S. Dik 				else
149981af778eSCasper H.S. Dik 					sh_subfork();
150081af778eSCasper H.S. Dik 			}
15017c2fbfb3SApril Chin 			shp->inpipe = pvo;
15027c2fbfb3SApril Chin 			shp->outpipe = pvn;
1503da2e3ebdSchin 			pvo[1] = -1;
1504da2e3ebdSchin 			if(sh_isoption(SH_PIPEFAIL))
1505da2e3ebdSchin 				job.waitall = 1;
1506da2e3ebdSchin 			else
1507da2e3ebdSchin 				job.waitall |= !pipejob && sh_isstate(SH_MONITOR);
150834f9b3eeSRoland Mainz 			job_lock();
1509da2e3ebdSchin 			do
1510da2e3ebdSchin 			{
1511da2e3ebdSchin #if SHOPT_FASTPIPE
15127c2fbfb3SApril Chin 				type = pipe_exec(shp,pvn,t->lst.lstlef, errorflg);
1513da2e3ebdSchin #else
1514da2e3ebdSchin 				/* create the pipe */
1515da2e3ebdSchin 				sh_pipe(pvn);
1516da2e3ebdSchin 				/* execute out part of pipe no wait */
1517da2e3ebdSchin 				(t->lst.lstlef)->tre.tretyp |= showme;
1518da2e3ebdSchin 				type = sh_exec(t->lst.lstlef, errorflg);
1519da2e3ebdSchin #endif /* SHOPT_FASTPIPE */
1520da2e3ebdSchin 				pipejob=1;
1521da2e3ebdSchin 				/* save the pipe stream-ids */
1522da2e3ebdSchin 				pvo[0] = pvn[0];
1523da2e3ebdSchin 				/* close out-part of pipe */
1524da2e3ebdSchin 				sh_close(pvn[1]);
1525da2e3ebdSchin 				/* pipeline all in one process group */
1526da2e3ebdSchin 				t = t->lst.lstrit;
1527da2e3ebdSchin 			}
1528da2e3ebdSchin 			/* repeat until end of pipeline */
1529da2e3ebdSchin 			while(!type && t->tre.tretyp==TFIL);
15307c2fbfb3SApril Chin 			shp->inpipe = pvn;
15317c2fbfb3SApril Chin 			shp->outpipe = 0;
153234f9b3eeSRoland Mainz 			pipejob = 2;
1533da2e3ebdSchin 			if(type == 0)
1534da2e3ebdSchin 			{
1535da2e3ebdSchin 				/*
1536da2e3ebdSchin 				 * execute last element of pipeline
1537da2e3ebdSchin 				 * in the current process
1538da2e3ebdSchin 				 */
1539da2e3ebdSchin 				((Shnode_t*)t)->tre.tretyp |= showme;
1540da2e3ebdSchin 				sh_exec(t,flags);
1541da2e3ebdSchin 			}
1542da2e3ebdSchin 			else
1543da2e3ebdSchin 				/* execution failure, close pipe */
1544da2e3ebdSchin 				sh_pclose(pvn);
154534f9b3eeSRoland Mainz 			if(pipejob==2)
154634f9b3eeSRoland Mainz 				job_unlock();
1547da2e3ebdSchin 			pipejob = savepipe;
1548da2e3ebdSchin #ifdef SIGTSTP
1549da2e3ebdSchin 			if(!pipejob && sh_isstate(SH_MONITOR))
15507c2fbfb3SApril Chin 				tcsetpgrp(JOBTTY,shp->pid);
1551da2e3ebdSchin #endif /*SIGTSTP */
1552da2e3ebdSchin 			job.curpgid = savepgid;
1553da2e3ebdSchin 			break;
1554da2e3ebdSchin 		    }
1555da2e3ebdSchin 
1556da2e3ebdSchin 		    case TLST:
1557da2e3ebdSchin 		    {
1558da2e3ebdSchin 			/*  a list of commands are executed here */
1559da2e3ebdSchin 			do
1560da2e3ebdSchin 			{
1561da2e3ebdSchin 				sh_exec(t->lst.lstlef,errorflg|OPTIMIZE);
1562da2e3ebdSchin 				t = t->lst.lstrit;
1563da2e3ebdSchin 			}
1564da2e3ebdSchin 			while(t->tre.tretyp == TLST);
1565da2e3ebdSchin 			sh_exec(t,flags);
1566da2e3ebdSchin 			break;
1567da2e3ebdSchin 		    }
1568da2e3ebdSchin 
1569da2e3ebdSchin 		    case TAND:
1570da2e3ebdSchin 			if(type&TTEST)
1571da2e3ebdSchin 				skipexitset++;
1572da2e3ebdSchin 			if(sh_exec(t->lst.lstlef,OPTIMIZE)==0)
1573da2e3ebdSchin 				sh_exec(t->lst.lstrit,flags);
1574da2e3ebdSchin 			break;
1575da2e3ebdSchin 
1576da2e3ebdSchin 		    case TORF:
1577da2e3ebdSchin 			if(type&TTEST)
1578da2e3ebdSchin 				skipexitset++;
1579da2e3ebdSchin 			if(sh_exec(t->lst.lstlef,OPTIMIZE)!=0)
1580da2e3ebdSchin 				sh_exec(t->lst.lstrit,flags);
1581da2e3ebdSchin 			break;
1582da2e3ebdSchin 
1583da2e3ebdSchin 		    case TFOR: /* for and select */
1584da2e3ebdSchin 		    {
1585da2e3ebdSchin 			register char **args;
1586da2e3ebdSchin 			register int nargs;
1587da2e3ebdSchin 			register Namval_t *np;
1588da2e3ebdSchin 			int flag = errorflg|OPTIMIZE_FLAG;
1589da2e3ebdSchin 			struct dolnod	*argsav=0;
1590da2e3ebdSchin 			struct comnod	*tp;
1591da2e3ebdSchin 			char *cp, *trap, *nullptr = 0;
1592da2e3ebdSchin 			int nameref, refresh=1;
15937c2fbfb3SApril Chin 			char *av[5];
1594da2e3ebdSchin #if SHOPT_OPTIMIZE
15957c2fbfb3SApril Chin 			int  jmpval = ((struct checkpt*)shp->jmplist)->mode;
1596da2e3ebdSchin 			struct checkpt buff;
15977c2fbfb3SApril Chin 			void *optlist = shp->optlist;
15987c2fbfb3SApril Chin 			shp->optlist = 0;
1599da2e3ebdSchin 			sh_tclear(t->for_.fortre);
1600da2e3ebdSchin 			sh_pushcontext(&buff,jmpval);
1601da2e3ebdSchin 			jmpval = sigsetjmp(buff.buff,0);
1602da2e3ebdSchin 			if(jmpval)
1603da2e3ebdSchin 				goto endfor;
1604da2e3ebdSchin #endif /* SHOPT_OPTIMIZE */
16057c2fbfb3SApril Chin 			error_info.line = t->for_.forline-shp->st.firstline;
1606da2e3ebdSchin 			if(!(tp=t->for_.forlst))
1607da2e3ebdSchin 			{
16087c2fbfb3SApril Chin 				args=shp->st.dolv+1;
16097c2fbfb3SApril Chin 				nargs = shp->st.dolc;
16107c2fbfb3SApril Chin 				argsav=sh_arguse(shp);
1611da2e3ebdSchin 			}
1612da2e3ebdSchin 			else
1613da2e3ebdSchin 			{
16147c2fbfb3SApril Chin 				args=sh_argbuild(shp,&argn,tp,0);
1615da2e3ebdSchin 				nargs = argn;
1616da2e3ebdSchin 			}
16177c2fbfb3SApril Chin 			np = nv_open(t->for_.fornam, shp->var_tree,NV_NOASSIGN|NV_NOARRAY|NV_VARNAME|NV_NOREF);
1618da2e3ebdSchin 			nameref = nv_isref(np)!=0;
16197c2fbfb3SApril Chin 			shp->st.loopcnt++;
1620da2e3ebdSchin 			cp = *args;
16217c2fbfb3SApril Chin 			while(cp && shp->st.execbrk==0)
1622da2e3ebdSchin 			{
1623da2e3ebdSchin 				if(t->tre.tretyp&COMSCAN)
1624da2e3ebdSchin 				{
1625da2e3ebdSchin 					char *val;
1626da2e3ebdSchin 					int save_prompt;
1627da2e3ebdSchin 					/* reuse register */
1628da2e3ebdSchin 					if(refresh)
1629da2e3ebdSchin 					{
1630da2e3ebdSchin 						sh_menu(sfstderr,nargs,args);
1631da2e3ebdSchin 						refresh = 0;
1632da2e3ebdSchin 					}
16337c2fbfb3SApril Chin 					save_prompt = shp->nextprompt;
16347c2fbfb3SApril Chin 					shp->nextprompt = 3;
16357c2fbfb3SApril Chin 					shp->timeout = 0;
16367c2fbfb3SApril Chin 					shp->exitval=sh_readline(shp,&nullptr,0,1,1000*shp->st.tmout);
16377c2fbfb3SApril Chin 					shp->nextprompt = save_prompt;
16387c2fbfb3SApril Chin 					if(shp->exitval||sfeof(sfstdin)||sferror(sfstdin))
1639da2e3ebdSchin 					{
16407c2fbfb3SApril Chin 						shp->exitval = 1;
1641da2e3ebdSchin 						break;
1642da2e3ebdSchin 					}
16437c2fbfb3SApril Chin 					if(!(val=nv_getval(sh_scoped(shp,REPLYNOD))))
1644da2e3ebdSchin 						continue;
1645da2e3ebdSchin 					else
1646da2e3ebdSchin 					{
1647da2e3ebdSchin 						if(*(cp=val) == 0)
1648da2e3ebdSchin 						{
1649da2e3ebdSchin 							refresh++;
1650da2e3ebdSchin 							goto check;
1651da2e3ebdSchin 						}
1652da2e3ebdSchin 						while(type = *cp++)
1653da2e3ebdSchin 							if(type < '0' && type > '9')
1654da2e3ebdSchin 								break;
1655da2e3ebdSchin 						if(type!=0)
1656da2e3ebdSchin 							type = nargs;
1657da2e3ebdSchin 						else
1658da2e3ebdSchin 							type = (int)strtol(val, (char**)0, 10)-1;
1659da2e3ebdSchin 						if(type<0 || type >= nargs)
1660da2e3ebdSchin 							cp = "";
1661da2e3ebdSchin 						else
1662da2e3ebdSchin 							cp = args[type];
1663da2e3ebdSchin 					}
1664da2e3ebdSchin 				}
1665da2e3ebdSchin 				if(nameref)
1666da2e3ebdSchin 					nv_offattr(np,NV_REF);
1667da2e3ebdSchin 				else if(nv_isattr(np, NV_ARRAY))
1668da2e3ebdSchin 					nv_putsub(np,NIL(char*),0L);
1669da2e3ebdSchin 				nv_putval(np,cp,0);
1670da2e3ebdSchin 				if(nameref)
1671da2e3ebdSchin 					nv_setref(np,(Dt_t*)0,NV_VARNAME);
16727c2fbfb3SApril Chin 				if(trap=shp->st.trap[SH_DEBUGTRAP])
1673da2e3ebdSchin 				{
1674da2e3ebdSchin 					av[0] = (t->tre.tretyp&COMSCAN)?"select":"for";
1675da2e3ebdSchin 					av[1] = t->for_.fornam;
16767c2fbfb3SApril Chin 					av[2] = "in";
1677da2e3ebdSchin 					av[3] = cp;
16787c2fbfb3SApril Chin 					av[4] = 0;
16797c2fbfb3SApril Chin 					sh_debug(shp,trap,(char*)0,(char*)0,av,0);
1680da2e3ebdSchin 				}
1681da2e3ebdSchin 				sh_exec(t->for_.fortre,flag);
1682da2e3ebdSchin 				flag &= ~OPTIMIZE_FLAG;
1683da2e3ebdSchin 				if(t->tre.tretyp&COMSCAN)
1684da2e3ebdSchin 				{
16857c2fbfb3SApril Chin 					if((cp=nv_getval(sh_scoped(shp,REPLYNOD))) && *cp==0)
1686da2e3ebdSchin 						refresh++;
1687da2e3ebdSchin 				}
1688da2e3ebdSchin 				else
1689da2e3ebdSchin 					cp = *++args;
1690da2e3ebdSchin 			check:
16917c2fbfb3SApril Chin 				if(shp->st.breakcnt<0)
16927c2fbfb3SApril Chin 					shp->st.execbrk = (++shp->st.breakcnt !=0);
1693da2e3ebdSchin 			}
1694da2e3ebdSchin #if SHOPT_OPTIMIZE
1695da2e3ebdSchin 		endfor:
1696da2e3ebdSchin 			sh_popcontext(&buff);
1697da2e3ebdSchin 			sh_tclear(t->for_.fortre);
16987c2fbfb3SApril Chin 			sh_optclear(shp,optlist);
1699da2e3ebdSchin 			if(jmpval)
17007c2fbfb3SApril Chin 				siglongjmp(*shp->jmplist,jmpval);
1701da2e3ebdSchin #endif /*SHOPT_OPTIMIZE */
17027c2fbfb3SApril Chin 			if(shp->st.breakcnt>0)
17037c2fbfb3SApril Chin 				shp->st.execbrk = (--shp->st.breakcnt !=0);
17047c2fbfb3SApril Chin 			shp->st.loopcnt--;
17057c2fbfb3SApril Chin 			sh_argfree(shp,argsav,0);
1706da2e3ebdSchin 			nv_close(np);
1707da2e3ebdSchin 			break;
1708da2e3ebdSchin 		    }
1709da2e3ebdSchin 
1710da2e3ebdSchin 		    case TWH: /* while and until */
1711da2e3ebdSchin 		    {
17127c2fbfb3SApril Chin 			volatile int 	r=0;
1713da2e3ebdSchin 			int first = OPTIMIZE_FLAG;
1714da2e3ebdSchin 			Shnode_t *tt = t->wh.whtre;
1715da2e3ebdSchin #if SHOPT_FILESCAN
1716da2e3ebdSchin 			Sfio_t *iop=0;
1717da2e3ebdSchin 			int savein,fd;
1718da2e3ebdSchin #endif /*SHOPT_FILESCAN*/
1719da2e3ebdSchin #if SHOPT_OPTIMIZE
17207c2fbfb3SApril Chin 			int  jmpval = ((struct checkpt*)shp->jmplist)->mode;
1721da2e3ebdSchin 			struct checkpt buff;
17227c2fbfb3SApril Chin 			void *optlist = shp->optlist;
17237c2fbfb3SApril Chin 			shp->optlist = 0;
1724da2e3ebdSchin 			sh_tclear(t->wh.whtre);
1725da2e3ebdSchin 			sh_tclear(t->wh.dotre);
1726da2e3ebdSchin 			sh_pushcontext(&buff,jmpval);
1727da2e3ebdSchin 			jmpval = sigsetjmp(buff.buff,0);
1728da2e3ebdSchin 			if(jmpval)
1729da2e3ebdSchin 				goto endwhile;
1730da2e3ebdSchin #endif /* SHOPT_OPTIMIZE */
1731da2e3ebdSchin #if SHOPT_FILESCAN
1732da2e3ebdSchin 			if(type==TWH && tt->tre.tretyp==TCOM && !tt->com.comarg && tt->com.comio)
1733da2e3ebdSchin 			{
17347c2fbfb3SApril Chin 				fd = sh_redirect(shp,tt->com.comio,3);
1735da2e3ebdSchin 				savein = dup(0);
1736da2e3ebdSchin 				if(fd==0)
1737da2e3ebdSchin 					fd = savein;
1738da2e3ebdSchin 				iop = sfnew(NULL,NULL,SF_UNBOUND,fd,SF_READ);
1739da2e3ebdSchin 				close(0);
1740da2e3ebdSchin 				open("/dev/null",O_RDONLY);
17417c2fbfb3SApril Chin 				shp->offsets[0] = -1;
17427c2fbfb3SApril Chin 				shp->offsets[1] = 0;
1743da2e3ebdSchin 				if(tt->com.comset)
174434f9b3eeSRoland Mainz 					nv_setlist(tt->com.comset,NV_IDENT|NV_ASSIGN,0);
1745da2e3ebdSchin 			}
1746da2e3ebdSchin #endif /*SHOPT_FILESCAN */
17477c2fbfb3SApril Chin 			shp->st.loopcnt++;
17487c2fbfb3SApril Chin 			while(shp->st.execbrk==0)
1749da2e3ebdSchin 			{
1750da2e3ebdSchin #if SHOPT_FILESCAN
1751da2e3ebdSchin 				if(iop)
1752da2e3ebdSchin 				{
17537c2fbfb3SApril Chin 					if(!(shp->cur_line=sfgetr(iop,'\n',SF_STRING)))
1754da2e3ebdSchin 						break;
1755da2e3ebdSchin 				}
1756da2e3ebdSchin 				else
1757da2e3ebdSchin #endif /*SHOPT_FILESCAN */
1758da2e3ebdSchin 				if((sh_exec(tt,first)==0)!=(type==TWH))
1759da2e3ebdSchin 					break;
1760da2e3ebdSchin 				r = sh_exec(t->wh.dotre,first|errorflg);
17617c2fbfb3SApril Chin 				if(shp->st.breakcnt<0)
17627c2fbfb3SApril Chin 					shp->st.execbrk = (++shp->st.breakcnt !=0);
1763da2e3ebdSchin 				/* This is for the arithmetic for */
17647c2fbfb3SApril Chin 				if(shp->st.execbrk==0 && t->wh.whinc)
1765da2e3ebdSchin 					sh_exec((Shnode_t*)t->wh.whinc,first);
1766da2e3ebdSchin 				first = 0;
1767da2e3ebdSchin 				errorflg &= ~OPTIMIZE_FLAG;
1768da2e3ebdSchin #if SHOPT_FILESCAN
17697c2fbfb3SApril Chin 				shp->offsets[0] = -1;
17707c2fbfb3SApril Chin 				shp->offsets[1] = 0;
1771da2e3ebdSchin #endif /*SHOPT_FILESCAN */
1772da2e3ebdSchin 			}
1773da2e3ebdSchin #if SHOPT_OPTIMIZE
1774da2e3ebdSchin 		endwhile:
1775da2e3ebdSchin 			sh_popcontext(&buff);
1776da2e3ebdSchin 			sh_tclear(t->wh.whtre);
1777da2e3ebdSchin 			sh_tclear(t->wh.dotre);
17787c2fbfb3SApril Chin 			sh_optclear(shp,optlist);
1779da2e3ebdSchin 			if(jmpval)
17807c2fbfb3SApril Chin 				siglongjmp(*shp->jmplist,jmpval);
1781da2e3ebdSchin #endif /*SHOPT_OPTIMIZE */
17827c2fbfb3SApril Chin 			if(shp->st.breakcnt>0)
17837c2fbfb3SApril Chin 				shp->st.execbrk = (--shp->st.breakcnt !=0);
17847c2fbfb3SApril Chin 			shp->st.loopcnt--;
17857c2fbfb3SApril Chin 			shp->exitval= r;
1786da2e3ebdSchin #if SHOPT_FILESCAN
1787da2e3ebdSchin 			if(iop)
1788da2e3ebdSchin 			{
1789da2e3ebdSchin 				sfclose(iop);
1790da2e3ebdSchin 				close(0);
1791da2e3ebdSchin 				dup(savein);
17927c2fbfb3SApril Chin 				shp->cur_line = 0;
1793da2e3ebdSchin 			}
1794da2e3ebdSchin #endif /*SHOPT_FILESCAN */
1795da2e3ebdSchin 			break;
1796da2e3ebdSchin 		    }
1797da2e3ebdSchin 		    case TARITH: /* (( expression )) */
1798da2e3ebdSchin 		    {
1799da2e3ebdSchin 			register char *trap;
18007c2fbfb3SApril Chin 			char *arg[4];
18017c2fbfb3SApril Chin 			error_info.line = t->ar.arline-shp->st.firstline;
18027c2fbfb3SApril Chin 			arg[0] = "((";
1803da2e3ebdSchin 			if(!(t->ar.arexpr->argflag&ARG_RAW))
18047c2fbfb3SApril Chin 				arg[1] = sh_macpat(shp,t->ar.arexpr,OPTIMIZE|ARG_ARITH);
1805da2e3ebdSchin 			else
1806da2e3ebdSchin 				arg[1] = t->ar.arexpr->argval;
18077c2fbfb3SApril Chin 			arg[2] = "))";
18087c2fbfb3SApril Chin 			arg[3] = 0;
18097c2fbfb3SApril Chin 			if(trap=shp->st.trap[SH_DEBUGTRAP])
18107c2fbfb3SApril Chin 				sh_debug(shp,trap,(char*)0, (char*)0, arg, ARG_ARITH);
1811da2e3ebdSchin 			if(sh_isoption(SH_XTRACE))
1812da2e3ebdSchin 			{
1813da2e3ebdSchin 				sh_trace(NIL(char**),0);
1814da2e3ebdSchin 				sfprintf(sfstderr,"((%s))\n",arg[1]);
1815da2e3ebdSchin 			}
1816da2e3ebdSchin 			if(t->ar.arcomp)
18177c2fbfb3SApril Chin 				shp->exitval  = !arith_exec((Arith_t*)t->ar.arcomp);
1818da2e3ebdSchin 			else
18197c2fbfb3SApril Chin 				shp->exitval = !sh_arith(arg[1]);
1820da2e3ebdSchin 			break;
1821da2e3ebdSchin 		    }
1822da2e3ebdSchin 
1823da2e3ebdSchin 		    case TIF:
1824da2e3ebdSchin 			if(sh_exec(t->if_.iftre,OPTIMIZE)==0)
1825da2e3ebdSchin 				sh_exec(t->if_.thtre,flags);
1826da2e3ebdSchin 			else if(t->if_.eltre)
1827da2e3ebdSchin 				sh_exec(t->if_.eltre, flags);
1828da2e3ebdSchin 			else
18297c2fbfb3SApril Chin 				shp->exitval=0; /* force zero exit for if-then-fi */
1830da2e3ebdSchin 			break;
1831da2e3ebdSchin 
1832da2e3ebdSchin 		    case TSW:
1833da2e3ebdSchin 		    {
1834da2e3ebdSchin 			Shnode_t *tt = (Shnode_t*)t;
18357c2fbfb3SApril Chin 			char *trap, *r = sh_macpat(shp,tt->sw.swarg,OPTIMIZE);
18367c2fbfb3SApril Chin 			error_info.line = t->sw.swline-shp->st.firstline;
1837da2e3ebdSchin 			t= (Shnode_t*)(tt->sw.swlst);
18387c2fbfb3SApril Chin 			if(trap=shp->st.trap[SH_DEBUGTRAP])
1839da2e3ebdSchin 			{
18407c2fbfb3SApril Chin 				char *av[4];
18417c2fbfb3SApril Chin 				av[0] = "case";
1842da2e3ebdSchin 				av[1] = r;
18437c2fbfb3SApril Chin 				av[2] = "in";
18447c2fbfb3SApril Chin 				av[3] = 0;
18457c2fbfb3SApril Chin 				sh_debug(shp,trap, (char*)0, (char*)0, av, 0);
1846da2e3ebdSchin 			}
1847da2e3ebdSchin 			while(t)
1848da2e3ebdSchin 			{
1849da2e3ebdSchin 				register struct argnod	*rex=(struct argnod*)t->reg.regptr;
1850da2e3ebdSchin 				while(rex)
1851da2e3ebdSchin 				{
1852da2e3ebdSchin 					register char *s;
1853da2e3ebdSchin 					if(rex->argflag&ARG_MAC)
1854da2e3ebdSchin 					{
18557c2fbfb3SApril Chin 						s = sh_macpat(shp,rex,OPTIMIZE|ARG_EXP);
1856da2e3ebdSchin 						while(*s=='\\' && s[1]==0)
1857da2e3ebdSchin 							s+=2;
1858da2e3ebdSchin 					}
1859da2e3ebdSchin 					else
1860da2e3ebdSchin 						s = rex->argval;
1861da2e3ebdSchin 					type = (rex->argflag&ARG_RAW);
1862da2e3ebdSchin 					if((type && strcmp(r,s)==0) ||
1863da2e3ebdSchin 						(!type && (strmatch(r,s)
1864da2e3ebdSchin 						|| trim_eq(r,s))))
1865da2e3ebdSchin 					{
1866da2e3ebdSchin 						do	sh_exec(t->reg.regcom,(t->reg.regflag?0:flags));
1867da2e3ebdSchin 						while(t->reg.regflag &&
1868da2e3ebdSchin 							(t=(Shnode_t*)t->reg.regnxt));
1869da2e3ebdSchin 						t=0;
1870da2e3ebdSchin 						break;
1871da2e3ebdSchin 					}
1872da2e3ebdSchin 					else
1873da2e3ebdSchin 						rex=rex->argnxt.ap;
1874da2e3ebdSchin 				}
1875da2e3ebdSchin 				if(t)
1876da2e3ebdSchin 					t=(Shnode_t*)t->reg.regnxt;
1877da2e3ebdSchin 			}
1878da2e3ebdSchin 			break;
1879da2e3ebdSchin 		    }
1880da2e3ebdSchin 
1881da2e3ebdSchin 		    case TTIME:
1882da2e3ebdSchin 		    {
1883da2e3ebdSchin 			/* time the command */
1884da2e3ebdSchin 			struct tms before,after;
1885da2e3ebdSchin 			const char *format = e_timeformat;
1886da2e3ebdSchin 			clock_t at, tm[3];
1887da2e3ebdSchin #ifdef timeofday
1888da2e3ebdSchin 			struct timeval tb,ta;
1889da2e3ebdSchin #else
1890da2e3ebdSchin 			clock_t bt;
1891da2e3ebdSchin #endif	/* timeofday */
1892da2e3ebdSchin 			if(type!=TTIME)
1893da2e3ebdSchin 			{
1894da2e3ebdSchin 				sh_exec(t->par.partre,OPTIMIZE);
18957c2fbfb3SApril Chin 				shp->exitval = !shp->exitval;
1896da2e3ebdSchin 				break;
1897da2e3ebdSchin 			}
1898da2e3ebdSchin 			if(t->par.partre)
1899da2e3ebdSchin 			{
1900da2e3ebdSchin 				long timer_on;
1901da2e3ebdSchin 				timer_on = sh_isstate(SH_TIMING);
1902da2e3ebdSchin #ifdef timeofday
1903da2e3ebdSchin 				timeofday(&tb);
1904da2e3ebdSchin 				times(&before);
1905da2e3ebdSchin #else
1906da2e3ebdSchin 				bt = times(&before);
1907da2e3ebdSchin #endif	/* timeofday */
1908da2e3ebdSchin 				job.waitall = 1;
1909da2e3ebdSchin 				sh_onstate(SH_TIMING);
1910da2e3ebdSchin 				sh_exec(t->par.partre,OPTIMIZE);
1911da2e3ebdSchin 				if(!timer_on)
1912da2e3ebdSchin 					sh_offstate(SH_TIMING);
1913da2e3ebdSchin 				job.waitall = 0;
1914da2e3ebdSchin 			}
1915da2e3ebdSchin 			else
1916da2e3ebdSchin 			{
1917da2e3ebdSchin #ifndef timeofday
1918da2e3ebdSchin 				bt = 0;
1919da2e3ebdSchin #endif	/* timeofday */
1920da2e3ebdSchin 				before.tms_utime = before.tms_cutime = 0;
1921da2e3ebdSchin 				before.tms_stime = before.tms_cstime = 0;
1922da2e3ebdSchin 			}
1923da2e3ebdSchin #ifdef timeofday
1924da2e3ebdSchin 			times(&after);
1925da2e3ebdSchin 			timeofday(&ta);
19267c2fbfb3SApril Chin 			at = shp->lim.clk_tck*(ta.tv_sec-tb.tv_sec);
19277c2fbfb3SApril Chin 			at +=  ((shp->lim.clk_tck*(((1000000L/2)/shp->lim.clk_tck)+(ta.tv_usec-tb.tv_usec)))/1000000L);
1928da2e3ebdSchin #else
1929da2e3ebdSchin 			at = times(&after) - bt;
1930da2e3ebdSchin #endif	/* timeofday */
1931da2e3ebdSchin 			tm[0] = at;
1932da2e3ebdSchin 			if(t->par.partre)
1933da2e3ebdSchin 			{
19347c2fbfb3SApril Chin 				Namval_t *np = nv_open("TIMEFORMAT",shp->var_tree,NV_NOADD);
1935da2e3ebdSchin 				if(np)
1936da2e3ebdSchin 				{
1937da2e3ebdSchin 					format = nv_getval(np);
1938da2e3ebdSchin 					nv_close(np);
1939da2e3ebdSchin 				}
1940da2e3ebdSchin 				if(!format)
1941da2e3ebdSchin 					format = e_timeformat;
1942da2e3ebdSchin 			}
1943da2e3ebdSchin 			else
1944da2e3ebdSchin 				format = strchr(format+1,'\n')+1;
1945da2e3ebdSchin 			tm[1] = after.tms_utime - before.tms_utime;
1946da2e3ebdSchin 			tm[1] += after.tms_cutime - before.tms_cutime;
1947da2e3ebdSchin 			tm[2] = after.tms_stime - before.tms_stime;
1948da2e3ebdSchin 			tm[2] += after.tms_cstime - before.tms_cstime;
1949da2e3ebdSchin 			if(format && *format)
19507c2fbfb3SApril Chin 				p_time(shp,sfstderr,sh_translate(format),tm);
1951da2e3ebdSchin 			break;
1952da2e3ebdSchin 		    }
1953da2e3ebdSchin 		    case TFUN:
1954da2e3ebdSchin 		    {
1955da2e3ebdSchin 			register Namval_t *np;
1956da2e3ebdSchin 			register struct slnod *slp;
1957da2e3ebdSchin 			register char *fname = ((struct functnod*)t)->functnam;
1958da2e3ebdSchin 			register char *cp = strrchr(fname,'.');
1959da2e3ebdSchin 			register Namval_t *npv=0;
1960da2e3ebdSchin #if SHOPT_NAMESPACE
1961da2e3ebdSchin 			if(t->tre.tretyp==TNSPACE)
1962da2e3ebdSchin 			{
1963da2e3ebdSchin 				Dt_t *root,*oldroot, *top=0;
19647c2fbfb3SApril Chin 				Namval_t *oldnspace = shp->namespace;
19657c2fbfb3SApril Chin 				int offset = stktell(stkp);
19667c2fbfb3SApril Chin 				long optindex = shp->st.optindex;
1967da2e3ebdSchin 				if(cp)
1968da2e3ebdSchin 					errormsg(SH_DICT,ERROR_exit(1),e_ident,fname);
19697c2fbfb3SApril Chin 				sfputc(stkp,'.');
19707c2fbfb3SApril Chin 				sfputr(stkp,fname,0);
19717c2fbfb3SApril Chin 				np = nv_open(stkptr(stkp,offset),shp->var_base,NV_NOASSIGN|NV_NOARRAY|NV_VARNAME);
19727c2fbfb3SApril Chin 				offset = stktell(stkp);
19737c2fbfb3SApril Chin 				shp->namespace = np;
1974da2e3ebdSchin 				if(!(root=nv_dict(np)))
1975da2e3ebdSchin 				{
1976da2e3ebdSchin 					root = dtopen(&_Nvdisc,Dtoset);
1977da2e3ebdSchin 					nv_putval(np,(char*)root,NV_TABLE|NV_NOFREE);
19787c2fbfb3SApril Chin 					shp->st.optindex = 1;
1979da2e3ebdSchin 				}
19807c2fbfb3SApril Chin 				if(oldnspace && dtvnext(dtvnext(shp->var_tree)))
19817c2fbfb3SApril Chin 					top = dtview(shp->var_tree,0);
19827c2fbfb3SApril Chin 				else if(dtvnext(shp->var_tree))
19837c2fbfb3SApril Chin 					top = dtview(shp->var_tree,0);
19847c2fbfb3SApril Chin 				oldroot = shp->var_tree;
19857c2fbfb3SApril Chin 				dtview(root,shp->var_base);
19867c2fbfb3SApril Chin 				shp->var_tree = root;
1987da2e3ebdSchin 				if(top)
19887c2fbfb3SApril Chin 					dtview(shp->var_tree,top);
1989da2e3ebdSchin 				sh_exec(t->for_.fortre,flags);
19907c2fbfb3SApril Chin 				if(dtvnext(shp->var_tree))
19917c2fbfb3SApril Chin 					top = dtview(shp->var_tree,0);
19927c2fbfb3SApril Chin 				shp->var_tree = oldroot;
1993da2e3ebdSchin 				if(top)
19947c2fbfb3SApril Chin 					dtview(top,shp->var_tree);
19957c2fbfb3SApril Chin 				shp->namespace = oldnspace;
19967c2fbfb3SApril Chin 				shp->st.optindex = optindex;
1997da2e3ebdSchin 				break;
1998da2e3ebdSchin 			}
1999da2e3ebdSchin #endif /* SHOPT_NAMESPACE */
2000da2e3ebdSchin 			/* look for discipline functions */
20017c2fbfb3SApril Chin 			error_info.line = t->funct.functline-shp->st.firstline;
2002da2e3ebdSchin 			/* Function names cannot be special builtin */
20037c2fbfb3SApril Chin 			if(cp || shp->prefix)
2004da2e3ebdSchin 			{
20057c2fbfb3SApril Chin 				int offset = stktell(stkp);
20067c2fbfb3SApril Chin 				if(shp->prefix)
2007da2e3ebdSchin 				{
20087c2fbfb3SApril Chin 					cp = shp->prefix;
20097c2fbfb3SApril Chin 					shp->prefix = 0;
20107c2fbfb3SApril Chin 					npv = nv_open(cp,shp->var_tree,NV_NOASSIGN|NV_NOARRAY|NV_VARNAME);
20117c2fbfb3SApril Chin 					shp->prefix = cp;
2012da2e3ebdSchin 					cp = fname;
2013da2e3ebdSchin 				}
2014da2e3ebdSchin 				else
2015da2e3ebdSchin 				{
20167c2fbfb3SApril Chin 					sfwrite(stkp,fname,cp++-fname);
20177c2fbfb3SApril Chin 					sfputc(stkp,0);
20187c2fbfb3SApril Chin 					npv = nv_open(stkptr(stkp,offset),shp->var_tree,NV_NOASSIGN|NV_NOARRAY|NV_VARNAME);
2019da2e3ebdSchin 				}
20207c2fbfb3SApril Chin 				offset = stktell(stkp);
20217c2fbfb3SApril Chin 				sfprintf(stkp,"%s.%s%c",nv_name(npv),cp,0);
20227c2fbfb3SApril Chin 				fname = stkptr(stkp,offset);
2023da2e3ebdSchin 			}
20247c2fbfb3SApril Chin 			else if((np=nv_search(fname,shp->bltin_tree,0)) && nv_isattr(np,BLT_SPC))
2025da2e3ebdSchin 				errormsg(SH_DICT,ERROR_exit(1),e_badfun,fname);
2026da2e3ebdSchin #if SHOPT_NAMESPACE
20277c2fbfb3SApril Chin 			else if(shp->namespace)
2028da2e3ebdSchin 			{
20297c2fbfb3SApril Chin 				int offset = stktell(stkp);
20307c2fbfb3SApril Chin 				sfputr(stkp,nv_name(shp->namespace),-1);
20317c2fbfb3SApril Chin 				sfputc(stkp,'.');
20327c2fbfb3SApril Chin 				sfputr(stkp,fname,0);
20337c2fbfb3SApril Chin 				fname = stkptr(stkp,offset);
2034da2e3ebdSchin 			}
2035da2e3ebdSchin #endif /* SHOPT_NAMESPACE */
2036da2e3ebdSchin 			np = nv_open(fname,sh_subfuntree(1),NV_NOASSIGN|NV_NOARRAY|NV_VARNAME|NV_NOSCOPE);
2037da2e3ebdSchin 			if(npv)
2038da2e3ebdSchin 			{
20397c2fbfb3SApril Chin 				Namval_t *tp = npv;
20407c2fbfb3SApril Chin 				if(!shp->mktype)
20417c2fbfb3SApril Chin 				{
20427c2fbfb3SApril Chin 					if(shp->typeinit)
20437c2fbfb3SApril Chin 					{
20447c2fbfb3SApril Chin 						if(tp=nv_open(shp->typeinit->nvname,shp->typedict,NV_IDENT|NV_NOFAIL))
2045da2e3ebdSchin 							nv_close(npv);
20467c2fbfb3SApril Chin 						else
20477c2fbfb3SApril Chin 							tp = npv;
20487c2fbfb3SApril Chin 					}
20497c2fbfb3SApril Chin 					cp = nv_setdisc(tp,cp,np,(Namfun_t*)tp);
20507c2fbfb3SApril Chin 				}
20517c2fbfb3SApril Chin 				nv_close(tp);
2052da2e3ebdSchin 				if(!cp)
2053da2e3ebdSchin 					errormsg(SH_DICT,ERROR_exit(1),e_baddisc,fname);
2054da2e3ebdSchin 			}
2055da2e3ebdSchin 			if(np->nvalue.rp)
2056da2e3ebdSchin 			{
2057da2e3ebdSchin 				slp = (struct slnod*)np->nvenv;
2058da2e3ebdSchin 				sh_funstaks(slp->slchild,-1);
2059da2e3ebdSchin 				stakdelete(slp->slptr);
20607c2fbfb3SApril Chin 				if(shp->funload)
20617c2fbfb3SApril Chin 				{
20627c2fbfb3SApril Chin 					free((void*)np->nvalue.rp);
20637c2fbfb3SApril Chin 					np->nvalue.rp = 0;
2064da2e3ebdSchin 				}
20657c2fbfb3SApril Chin 
20667c2fbfb3SApril Chin 			}
20677c2fbfb3SApril Chin 			if(!np->nvalue.rp)
20687c2fbfb3SApril Chin 			{
20697c2fbfb3SApril Chin 				np->nvalue.rp = new_of(struct Ufunction,shp->funload?sizeof(Dtlink_t):0);
20707c2fbfb3SApril Chin 				memset((void*)np->nvalue.rp,0,sizeof(struct Ufunction));
20717c2fbfb3SApril Chin 			}
2072da2e3ebdSchin 			if(t->funct.functstak)
2073da2e3ebdSchin 			{
20747c2fbfb3SApril Chin 				static Dtdisc_t		_Rpdisc =
20757c2fbfb3SApril Chin 				{
20767c2fbfb3SApril Chin 				        offsetof(struct Ufunction,fname), -1, sizeof(struct Ufunction)
20777c2fbfb3SApril Chin 				};
2078da2e3ebdSchin 				struct functnod *fp;
2079da2e3ebdSchin 				slp = t->funct.functstak;
2080da2e3ebdSchin 				sh_funstaks(slp->slchild,1);
2081da2e3ebdSchin 				staklink(slp->slptr);
2082da2e3ebdSchin 				np->nvenv = (char*)slp;
2083da2e3ebdSchin 				nv_funtree(np) = (int*)(t->funct.functtre);
2084da2e3ebdSchin 				np->nvalue.rp->hoffset = t->funct.functloc;
2085da2e3ebdSchin 				np->nvalue.rp->lineno = t->funct.functline;
20867c2fbfb3SApril Chin 				np->nvalue.rp->nspace = shp->namespace;
2087da2e3ebdSchin 				np->nvalue.rp->fname = 0;
20887c2fbfb3SApril Chin 				np->nvalue.rp->fdict = shp->fun_tree;
2089da2e3ebdSchin 				fp = (struct functnod*)(slp+1);
2090da2e3ebdSchin 				if(fp->functtyp==(TFUN|FAMP))
2091da2e3ebdSchin 					np->nvalue.rp->fname = fp->functnam;
2092da2e3ebdSchin 				nv_setsize(np,fp->functline);
2093da2e3ebdSchin 				nv_offattr(np,NV_FPOSIX);
20947c2fbfb3SApril Chin 				if(shp->funload)
20957c2fbfb3SApril Chin 				{
20967c2fbfb3SApril Chin 					struct Ufunction *rp = np->nvalue.rp;
20977c2fbfb3SApril Chin 					rp->np = np;
20987c2fbfb3SApril Chin 					if(!shp->fpathdict)
20997c2fbfb3SApril Chin 						shp->fpathdict = dtopen(&_Rpdisc,Dtbag);
21007c2fbfb3SApril Chin 					if(shp->fpathdict)
21017c2fbfb3SApril Chin 						dtinsert(shp->fpathdict,rp);
21027c2fbfb3SApril Chin 				}
2103da2e3ebdSchin 			}
2104da2e3ebdSchin 			else
2105da2e3ebdSchin 				nv_unset(np);
2106da2e3ebdSchin 			if(type&FPOSIX)
2107da2e3ebdSchin 				nv_onattr(np,NV_FUNCTION|NV_FPOSIX);
2108da2e3ebdSchin 			else
2109da2e3ebdSchin 				nv_onattr(np,NV_FUNCTION);
2110da2e3ebdSchin 			if(type&FPIN)
2111da2e3ebdSchin 				nv_onattr(np,NV_FTMP);
21127c2fbfb3SApril Chin 			if(type&FOPTGET)
21137c2fbfb3SApril Chin 				nv_onattr(np,NV_OPTGET);
2114da2e3ebdSchin 			break;
2115da2e3ebdSchin 		    }
2116da2e3ebdSchin 
2117da2e3ebdSchin 		    /* new test compound command */
2118da2e3ebdSchin 		    case TTST:
2119da2e3ebdSchin 		    {
2120da2e3ebdSchin 			register int n;
2121da2e3ebdSchin 			register char *left;
2122da2e3ebdSchin 			int negate = (type&TNEGATE)!=0;
2123da2e3ebdSchin 			if(type&TTEST)
2124da2e3ebdSchin 				skipexitset++;
21257c2fbfb3SApril Chin 			error_info.line = t->tst.tstline-shp->st.firstline;
2126da2e3ebdSchin 			echeck = 1;
2127da2e3ebdSchin 			if((type&TPAREN)==TPAREN)
2128da2e3ebdSchin 			{
2129da2e3ebdSchin 				sh_exec(t->lst.lstlef,OPTIMIZE);
21307c2fbfb3SApril Chin 				n = !shp->exitval;
2131da2e3ebdSchin 			}
2132da2e3ebdSchin 			else
2133da2e3ebdSchin 			{
2134da2e3ebdSchin 				register int traceon=0;
2135da2e3ebdSchin 				register char *right;
2136da2e3ebdSchin 				register char *trap;
2137da2e3ebdSchin 				char *argv[6];
2138da2e3ebdSchin 				n = type>>TSHIFT;
21397c2fbfb3SApril Chin 				left = sh_macpat(shp,&(t->lst.lstlef->arg),OPTIMIZE);
2140da2e3ebdSchin 				if(type&TBINARY)
21417c2fbfb3SApril Chin 					right = sh_macpat(shp,&(t->lst.lstrit->arg),((n==TEST_PEQ||n==TEST_PNE)?ARG_EXP:0)|OPTIMIZE);
21427c2fbfb3SApril Chin 				if(trap=shp->st.trap[SH_DEBUGTRAP])
2143da2e3ebdSchin 					argv[0] = (type&TNEGATE)?((char*)e_tstbegin):"[[";
2144da2e3ebdSchin 				if(sh_isoption(SH_XTRACE))
2145da2e3ebdSchin 				{
2146da2e3ebdSchin 					traceon = sh_trace(NIL(char**),0);
2147da2e3ebdSchin 					sfwrite(sfstderr,e_tstbegin,(type&TNEGATE?5:3));
2148da2e3ebdSchin 				}
2149da2e3ebdSchin 				if(type&TUNARY)
2150da2e3ebdSchin 				{
2151da2e3ebdSchin 					if(traceon)
2152da2e3ebdSchin 						sfprintf(sfstderr,"-%c %s",n,sh_fmtq(left));
2153da2e3ebdSchin 					if(trap)
2154da2e3ebdSchin 					{
2155da2e3ebdSchin 						char unop[3];
2156da2e3ebdSchin 						unop[0] = '-';
2157da2e3ebdSchin 						unop[1] = n;
2158da2e3ebdSchin 						unop[2] = 0;
2159da2e3ebdSchin 						argv[1] = unop;
2160da2e3ebdSchin 						argv[2] = left;
2161da2e3ebdSchin 						argv[3] = "]]";
2162da2e3ebdSchin 						argv[4] = 0;
21637c2fbfb3SApril Chin 						sh_debug(shp,trap,(char*)0,(char*)0,argv, 0);
2164da2e3ebdSchin 					}
2165da2e3ebdSchin 					n = test_unop(n,left);
2166da2e3ebdSchin 				}
2167da2e3ebdSchin 				else if(type&TBINARY)
2168da2e3ebdSchin 				{
2169da2e3ebdSchin 					char *op;
2170da2e3ebdSchin 					int pattern = 0;
2171da2e3ebdSchin 					if(trap || traceon)
2172da2e3ebdSchin 						op = (char*)(shtab_testops+(n&037)-1)->sh_name;
2173da2e3ebdSchin 					type >>= TSHIFT;
2174da2e3ebdSchin 					if(type==TEST_PEQ || type==TEST_PNE)
2175da2e3ebdSchin 						pattern=ARG_EXP;
2176da2e3ebdSchin 					if(trap)
2177da2e3ebdSchin 					{
2178da2e3ebdSchin 						argv[1] = left;
2179da2e3ebdSchin 						argv[2] = op;
2180da2e3ebdSchin 						argv[3] = right;
2181da2e3ebdSchin 						argv[4] = "]]";
2182da2e3ebdSchin 						argv[5] = 0;
21837c2fbfb3SApril Chin 						sh_debug(shp,trap,(char*)0,(char*)0,argv, pattern);
2184da2e3ebdSchin 					}
2185da2e3ebdSchin 					n = test_binop(n,left,right);
2186da2e3ebdSchin 					if(traceon)
2187da2e3ebdSchin 					{
2188da2e3ebdSchin 						sfprintf(sfstderr,"%s %s ",sh_fmtq(left),op);
2189da2e3ebdSchin 						if(pattern)
2190da2e3ebdSchin 							out_pattern(sfstderr,right,-1);
2191da2e3ebdSchin 						else
2192da2e3ebdSchin 							sfputr(sfstderr,sh_fmtq(right),-1);
2193da2e3ebdSchin 					}
2194da2e3ebdSchin 				}
2195da2e3ebdSchin 				if(traceon)
2196da2e3ebdSchin 					sfwrite(sfstderr,e_tstend,4);
2197da2e3ebdSchin 			}
21987c2fbfb3SApril Chin 			shp->exitval = ((!n)^negate);
2199da2e3ebdSchin 			if(!skipexitset)
2200da2e3ebdSchin 				exitset();
2201da2e3ebdSchin 			break;
2202da2e3ebdSchin 		    }
2203da2e3ebdSchin 		}
22047c2fbfb3SApril Chin 		if(shp->trapnote || (shp->exitval && sh_isstate(SH_ERREXIT)) &&
2205da2e3ebdSchin 			t && echeck)
2206da2e3ebdSchin 			sh_chktrap();
2207da2e3ebdSchin 		/* set $_ */
2208da2e3ebdSchin 		if(mainloop && com0)
2209da2e3ebdSchin 		{
2210da2e3ebdSchin 			/* store last argument here if it fits */
2211da2e3ebdSchin 			static char	lastarg[32];
2212da2e3ebdSchin 			if(sh_isstate(SH_FORKED))
22137c2fbfb3SApril Chin 				sh_done(shp,0);
22147c2fbfb3SApril Chin 			if(shp->lastarg!= lastarg && shp->lastarg)
22157c2fbfb3SApril Chin 				free(shp->lastarg);
22167c2fbfb3SApril Chin 			if(strlen(comn) < sizeof(lastarg))
2217da2e3ebdSchin 			{
2218da2e3ebdSchin 				nv_onattr(L_ARGNOD,NV_NOFREE);
22197c2fbfb3SApril Chin 				shp->lastarg = strcpy(lastarg,comn);
2220da2e3ebdSchin 			}
2221da2e3ebdSchin 			else
2222da2e3ebdSchin 			{
2223da2e3ebdSchin 				nv_offattr(L_ARGNOD,NV_NOFREE);
22247c2fbfb3SApril Chin 				shp->lastarg = strdup(comn);
2225da2e3ebdSchin 			}
2226da2e3ebdSchin 		}
2227da2e3ebdSchin 		if(!skipexitset)
2228da2e3ebdSchin 			exitset();
2229da2e3ebdSchin 		if(!(OPTIMIZE))
2230da2e3ebdSchin 		{
22317c2fbfb3SApril Chin 			if(sav != stkptr(stkp,0))
22327c2fbfb3SApril Chin 				stkset(stkp,sav,0);
22337c2fbfb3SApril Chin 			else if(stktell(stkp))
22347c2fbfb3SApril Chin 				stkseek(stkp,0);
2235da2e3ebdSchin 		}
22367c2fbfb3SApril Chin 		if(shp->trapnote&SH_SIGSET)
22377c2fbfb3SApril Chin 			sh_exit(SH_EXITSIG|shp->lastsig);
2238da2e3ebdSchin 		if(was_interactive)
2239da2e3ebdSchin 			sh_onstate(SH_INTERACTIVE);
2240da2e3ebdSchin 		if(was_monitor && sh_isoption(SH_MONITOR))
2241da2e3ebdSchin 			sh_onstate(SH_MONITOR);
2242da2e3ebdSchin 		if(was_errexit)
2243da2e3ebdSchin 			sh_onstate(SH_ERREXIT);
2244da2e3ebdSchin 	}
22457c2fbfb3SApril Chin 	return(shp->exitval);
22467c2fbfb3SApril Chin }
22477c2fbfb3SApril Chin 
sh_run(int argn,char * argv[])22487c2fbfb3SApril Chin int sh_run(int argn, char *argv[])
22497c2fbfb3SApril Chin {
22507c2fbfb3SApril Chin 	register struct dolnod	*dp;
22517c2fbfb3SApril Chin 	register struct comnod	*t = (struct comnod*)stakalloc(sizeof(struct comnod));
22527c2fbfb3SApril Chin 	int			savtop = staktell();
22537c2fbfb3SApril Chin 	char			*savptr = stakfreeze(0);
22547c2fbfb3SApril Chin 	Opt_t			*op, *np = optctx(0, 0);
22557c2fbfb3SApril Chin 	Shbltin_t		bltindata;
22567c2fbfb3SApril Chin 	bltindata = sh.bltindata;
22577c2fbfb3SApril Chin 	op = optctx(np, 0);
22587c2fbfb3SApril Chin 	memset(t, 0, sizeof(struct comnod));
22597c2fbfb3SApril Chin 	dp = (struct dolnod*)stakalloc((unsigned)sizeof(struct dolnod) + ARG_SPARE*sizeof(char*) + argn*sizeof(char*));
22607c2fbfb3SApril Chin 	dp->dolnum = argn;
22617c2fbfb3SApril Chin 	dp->dolbot = ARG_SPARE;
22627c2fbfb3SApril Chin 	memcpy(dp->dolval+ARG_SPARE, argv, (argn+1)*sizeof(char*));
22637c2fbfb3SApril Chin 	t->comarg = (struct argnod*)dp;
22647c2fbfb3SApril Chin 	if(!strchr(argv[0],'/'))
22657c2fbfb3SApril Chin 		t->comnamp = (void*)nv_bfsearch(argv[0],sh.fun_tree,(Namval_t**)&t->comnamq,(char**)0);
22667c2fbfb3SApril Chin 	argn=sh_exec((Shnode_t*)t,sh_isstate(SH_ERREXIT));
22677c2fbfb3SApril Chin 	optctx(op,np);
22687c2fbfb3SApril Chin 	sh.bltindata = bltindata;
22697c2fbfb3SApril Chin 	if(savptr!=stakptr(0))
22707c2fbfb3SApril Chin 		stakset(savptr,savtop);
22717c2fbfb3SApril Chin 	else
22727c2fbfb3SApril Chin 		stakseek(savtop);
22737c2fbfb3SApril Chin 	return(argn);
2274da2e3ebdSchin }
2275da2e3ebdSchin 
2276da2e3ebdSchin /*
2277da2e3ebdSchin  * test for equality with second argument trimmed
2278da2e3ebdSchin  * returns 1 if r == trim(s) otherwise 0
2279da2e3ebdSchin  */
2280da2e3ebdSchin 
trim_eq(register const char * r,register const char * s)2281da2e3ebdSchin static int trim_eq(register const char *r,register const char *s)
2282da2e3ebdSchin {
2283da2e3ebdSchin 	register char c;
2284da2e3ebdSchin 	while(c = *s++)
2285da2e3ebdSchin 	{
2286da2e3ebdSchin 		if(c=='\\')
2287da2e3ebdSchin 			c = *s++;
2288da2e3ebdSchin 		if(c && c != *r++)
2289da2e3ebdSchin 			return(0);
2290da2e3ebdSchin 	}
2291da2e3ebdSchin 	return(*r==0);
2292da2e3ebdSchin }
2293da2e3ebdSchin 
2294da2e3ebdSchin /*
2295da2e3ebdSchin  * print out the command line if set -x is on
2296da2e3ebdSchin  */
2297da2e3ebdSchin 
sh_trace(register char * argv[],register int nl)2298da2e3ebdSchin int sh_trace(register char *argv[], register int nl)
2299da2e3ebdSchin {
23007c2fbfb3SApril Chin 	Shell_t	*shp = &sh;
2301da2e3ebdSchin 	register char *cp;
2302da2e3ebdSchin 	register int bracket = 0;
23037c2fbfb3SApril Chin 	int decl = (nl&2);
23047c2fbfb3SApril Chin 	nl &= ~2;
2305da2e3ebdSchin 	if(sh_isoption(SH_XTRACE))
2306da2e3ebdSchin 	{
2307da2e3ebdSchin 		/* make this trace atomic */
2308da2e3ebdSchin 		sfset(sfstderr,SF_SHARE|SF_PUBLIC,0);
23097c2fbfb3SApril Chin 		if(!(cp=nv_getval(sh_scoped(shp,PS4NOD))))
2310da2e3ebdSchin 			cp = "+ ";
2311da2e3ebdSchin 		else
2312da2e3ebdSchin 		{
2313da2e3ebdSchin 			sh_offoption(SH_XTRACE);
23147c2fbfb3SApril Chin 			cp = sh_mactry(shp,cp);
2315da2e3ebdSchin 			sh_onoption(SH_XTRACE);
2316da2e3ebdSchin 		}
2317da2e3ebdSchin 		if(*cp)
2318da2e3ebdSchin 			sfputr(sfstderr,cp,-1);
2319da2e3ebdSchin 		if(argv)
2320da2e3ebdSchin 		{
2321da2e3ebdSchin 			char *argv0 = *argv;
2322da2e3ebdSchin 			nl = (nl?'\n':-1);
2323da2e3ebdSchin 			/* don't quote [ and [[ */
2324da2e3ebdSchin 			if(*(cp=argv[0])=='[' && (!cp[1] || !cp[2]&&cp[1]=='['))
2325da2e3ebdSchin 			{
2326da2e3ebdSchin 				sfputr(sfstderr,cp,*++argv?' ':nl);
2327da2e3ebdSchin 				bracket = 1;
2328da2e3ebdSchin 			}
2329da2e3ebdSchin 			while(cp = *argv++)
2330da2e3ebdSchin 			{
2331da2e3ebdSchin 				if(bracket==0 || *argv || *cp!=']')
2332da2e3ebdSchin 					cp = sh_fmtq(cp);
23337c2fbfb3SApril Chin 				if(decl && shp->prefix && cp!=argv0 && *cp!='-')
2334da2e3ebdSchin 				{
2335da2e3ebdSchin 					if(*cp=='.' && cp[1]==0)
23367c2fbfb3SApril Chin 						cp = shp->prefix;
2337da2e3ebdSchin 					else
23387c2fbfb3SApril Chin 						sfputr(sfstderr,shp->prefix,'.');
2339da2e3ebdSchin 				}
2340da2e3ebdSchin 				sfputr(sfstderr,cp,*argv?' ':nl);
2341da2e3ebdSchin 			}
2342da2e3ebdSchin 			sfset(sfstderr,SF_SHARE|SF_PUBLIC,1);
2343da2e3ebdSchin 		}
2344da2e3ebdSchin 		return(1);
2345da2e3ebdSchin 	}
2346da2e3ebdSchin 	return(0);
2347da2e3ebdSchin }
2348da2e3ebdSchin 
2349da2e3ebdSchin /*
2350da2e3ebdSchin  * This routine creates a subshell by calling fork() or vfork()
2351da2e3ebdSchin  * If ((flags&COMASK)==TCOM), then vfork() is permitted
2352da2e3ebdSchin  * If fork fails, the shell sleeps for exponentially longer periods
2353da2e3ebdSchin  *   and tries again until a limit is reached.
2354da2e3ebdSchin  * SH_FORKLIM is the max period between forks - power of 2 usually.
2355da2e3ebdSchin  * Currently shell tries after 2,4,8,16, and 32 seconds and then quits
2356da2e3ebdSchin  * Failures cause the routine to error exit.
2357da2e3ebdSchin  * Parent links to here-documents are removed by the child
2358da2e3ebdSchin  * Traps are reset by the child
2359da2e3ebdSchin  * The process-id of the child is returned to the parent, 0 to the child.
2360da2e3ebdSchin  */
2361da2e3ebdSchin 
timed_out(void * handle)2362da2e3ebdSchin static void timed_out(void *handle)
2363da2e3ebdSchin {
2364da2e3ebdSchin 	NOT_USED(handle);
2365da2e3ebdSchin 	timeout = 0;
2366da2e3ebdSchin }
2367da2e3ebdSchin 
2368da2e3ebdSchin 
2369da2e3ebdSchin /*
2370da2e3ebdSchin  * called by parent and child after fork by sh_fork()
2371da2e3ebdSchin  */
_sh_fork(register pid_t parent,int flags,int * jobid)2372da2e3ebdSchin pid_t _sh_fork(register pid_t parent,int flags,int *jobid)
2373da2e3ebdSchin {
2374da2e3ebdSchin 	static long forkcnt = 1000L;
23757c2fbfb3SApril Chin 	Shell_t	*shp = &sh;
2376da2e3ebdSchin 	pid_t	curpgid = job.curpgid;
2377da2e3ebdSchin 	pid_t	postid = (flags&FAMP)?0:curpgid;
23787c2fbfb3SApril Chin 	int	sig,nochild;
2379da2e3ebdSchin 	if(parent<0)
2380da2e3ebdSchin 	{
23817c2fbfb3SApril Chin 		sh_sigcheck();
2382da2e3ebdSchin 		if((forkcnt *= 2) > 1000L*SH_FORKLIM)
2383da2e3ebdSchin 		{
2384da2e3ebdSchin 			forkcnt=1000L;
2385da2e3ebdSchin 			errormsg(SH_DICT,ERROR_system(ERROR_NOEXEC),e_nofork);
2386da2e3ebdSchin 		}
2387da2e3ebdSchin 		timeout = (void*)sh_timeradd(forkcnt, 0, timed_out, NIL(void*));
23887c2fbfb3SApril Chin 		nochild = job_wait((pid_t)1);
2389da2e3ebdSchin 		if(timeout)
2390da2e3ebdSchin 		{
23917c2fbfb3SApril Chin 			if(nochild)
23927c2fbfb3SApril Chin 				pause();
23937c2fbfb3SApril Chin 			else if(forkcnt>1000L)
2394da2e3ebdSchin 				forkcnt /= 2;
23957c2fbfb3SApril Chin 			timerdel(timeout);
23967c2fbfb3SApril Chin 			timeout = 0;
2397da2e3ebdSchin 		}
2398da2e3ebdSchin 		return(-1);
2399da2e3ebdSchin 	}
2400da2e3ebdSchin 	forkcnt = 1000L;
2401da2e3ebdSchin 	if(parent)
2402da2e3ebdSchin 	{
24037c2fbfb3SApril Chin 		int myjob,waitall=job.waitall;
24047c2fbfb3SApril Chin 		shp->nforks++;
2405da2e3ebdSchin 		if(job.toclear)
2406da2e3ebdSchin 			job_clear();
24077c2fbfb3SApril Chin 		job.waitall = waitall;
2408da2e3ebdSchin #ifdef JOBS
2409da2e3ebdSchin 		/* first process defines process group */
2410da2e3ebdSchin 		if(sh_isstate(SH_MONITOR))
2411da2e3ebdSchin 		{
2412da2e3ebdSchin 			/*
2413da2e3ebdSchin 			 * errno==EPERM means that an earlier processes
2414da2e3ebdSchin 			 * completed.  Make parent the job group id.
2415da2e3ebdSchin 			 */
2416da2e3ebdSchin 			if(postid==0)
2417da2e3ebdSchin 				job.curpgid = parent;
2418da2e3ebdSchin 			if(job.jobcontrol || (flags&FAMP))
2419da2e3ebdSchin 			{
2420da2e3ebdSchin 				if(setpgid(parent,job.curpgid)<0 && errno==EPERM)
2421da2e3ebdSchin 					setpgid(parent,parent);
2422da2e3ebdSchin 			}
2423da2e3ebdSchin 		}
2424da2e3ebdSchin #endif /* JOBS */
2425da2e3ebdSchin 		if(!sh_isstate(SH_MONITOR) && job.waitall && postid==0)
2426da2e3ebdSchin 			job.curpgid = parent;
2427da2e3ebdSchin 		if(flags&FCOOP)
24287c2fbfb3SApril Chin 			shp->cpid = parent;
242934f9b3eeSRoland Mainz #ifdef SHOPT_BGX
243034f9b3eeSRoland Mainz 		if(!postid && (flags&(FAMP|FINT)) == (FAMP|FINT))
243134f9b3eeSRoland Mainz 			postid = 1;
2432da2e3ebdSchin 		myjob = job_post(parent,postid);
243334f9b3eeSRoland Mainz 		if(postid==1)
243434f9b3eeSRoland Mainz 			postid = 0;
243534f9b3eeSRoland Mainz #else
243634f9b3eeSRoland Mainz 		myjob = job_post(parent,postid);
243734f9b3eeSRoland Mainz #endif /* SHOPT_BGX */
2438da2e3ebdSchin 		if(flags&FAMP)
2439da2e3ebdSchin 			job.curpgid = curpgid;
2440da2e3ebdSchin 		if(jobid)
2441da2e3ebdSchin 			*jobid = myjob;
2442da2e3ebdSchin 		return(parent);
2443da2e3ebdSchin 	}
2444da2e3ebdSchin #if !_std_malloc
2445da2e3ebdSchin 	vmtrace(-1);
2446da2e3ebdSchin #endif
2447da2e3ebdSchin 	/* This is the child process */
24487c2fbfb3SApril Chin 	if(shp->trapnote&SH_SIGTERM)
2449da2e3ebdSchin 		sh_exit(SH_EXITSIG|SIGTERM);
24507c2fbfb3SApril Chin 	shp->nforks=0;
2451da2e3ebdSchin 	timerdel(NIL(void*));
2452da2e3ebdSchin #ifdef JOBS
2453da2e3ebdSchin 	if(!job.jobcontrol && !(flags&FAMP))
2454da2e3ebdSchin 		sh_offstate(SH_MONITOR);
2455da2e3ebdSchin 	if(sh_isstate(SH_MONITOR))
2456da2e3ebdSchin 	{
2457da2e3ebdSchin 		parent = getpid();
2458da2e3ebdSchin 		if(postid==0)
2459da2e3ebdSchin 			job.curpgid = parent;
2460da2e3ebdSchin 		while(setpgid(0,job.curpgid)<0 && job.curpgid!=parent)
2461da2e3ebdSchin 			job.curpgid = parent;
2462da2e3ebdSchin #   ifdef SIGTSTP
2463da2e3ebdSchin 		if(job.curpgid==parent &&  !(flags&FAMP))
2464da2e3ebdSchin 			tcsetpgrp(job.fd,job.curpgid);
2465da2e3ebdSchin #   endif /* SIGTSTP */
2466da2e3ebdSchin 	}
2467da2e3ebdSchin #   ifdef SIGTSTP
2468da2e3ebdSchin 	if(job.jobcontrol)
2469da2e3ebdSchin 	{
2470da2e3ebdSchin 		signal(SIGTTIN,SIG_DFL);
2471da2e3ebdSchin 		signal(SIGTTOU,SIG_DFL);
2472da2e3ebdSchin 		signal(SIGTSTP,SIG_DFL);
2473da2e3ebdSchin 	}
2474da2e3ebdSchin #   endif /* SIGTSTP */
2475da2e3ebdSchin 	job.jobcontrol = 0;
2476da2e3ebdSchin #endif /* JOBS */
2477da2e3ebdSchin 	job.toclear = 1;
24787c2fbfb3SApril Chin 	shp->login_sh = 0;
2479da2e3ebdSchin 	sh_offoption(SH_LOGIN_SHELL);
2480da2e3ebdSchin 	sh_onstate(SH_FORKED);
2481da2e3ebdSchin 	sh_onstate(SH_NOLOG);
24827c2fbfb3SApril Chin 	if (shp->fn_reset)
24837c2fbfb3SApril Chin 		shp->fn_depth = shp->fn_reset = 0;
2484da2e3ebdSchin #if SHOPT_ACCT
2485da2e3ebdSchin 	sh_accsusp();
2486da2e3ebdSchin #endif	/* SHOPT_ACCT */
2487da2e3ebdSchin 	/* Reset remaining signals to parent */
2488da2e3ebdSchin 	/* except for those `lost' by trap   */
248934f9b3eeSRoland Mainz 	if(!(flags&FSHOWME))
2490da2e3ebdSchin 		sh_sigreset(2);
24917c2fbfb3SApril Chin 	shp->subshell = 0;
24927c2fbfb3SApril Chin 	if((flags&FAMP) && shp->coutpipe>1)
24937c2fbfb3SApril Chin 		sh_close(shp->coutpipe);
24947c2fbfb3SApril Chin 	sig = shp->savesig;
24957c2fbfb3SApril Chin 	shp->savesig = 0;
2496da2e3ebdSchin 	if(sig>0)
2497da2e3ebdSchin 		sh_fault(sig);
2498da2e3ebdSchin 	sh_sigcheck();
2499da2e3ebdSchin 	return(0);
2500da2e3ebdSchin }
2501da2e3ebdSchin 
sh_fork(int flags,int * jobid)2502da2e3ebdSchin pid_t sh_fork(int flags, int *jobid)
2503da2e3ebdSchin {
2504da2e3ebdSchin 	register pid_t parent;
2505da2e3ebdSchin 	register int sig;
2506da2e3ebdSchin #if SHOPT_FASTPIPE
2507da2e3ebdSchin 	if(sffileno(sfstdin)<0)
2508da2e3ebdSchin 	{
2509da2e3ebdSchin 		off_t current = sfseek(sfstdin,(off_t)0,SEEK_CUR);
2510da2e3ebdSchin 		sfseek(sfstdin,(off_t)0,SEEK_END);
2511da2e3ebdSchin 		sfdisc(sfstdin,SF_POPDISC);
2512da2e3ebdSchin 		fcntl(sffileno(sfstdin),F_SETFD,0);
2513da2e3ebdSchin 		sh_iostream(0);
2514da2e3ebdSchin 		sfseek(sfstdin,current,SEEK_SET);
2515da2e3ebdSchin 	}
2516da2e3ebdSchin #endif /* SHOPT_FASTPIPE */
2517da2e3ebdSchin 	if(!sh.pathlist)
2518da2e3ebdSchin 		path_get("");
2519da2e3ebdSchin 	sfsync(NIL(Sfio_t*));
2520da2e3ebdSchin 	sh.trapnote &= ~SH_SIGTERM;
2521da2e3ebdSchin 	job_fork(-1);
2522da2e3ebdSchin 	sh.savesig = -1;
2523da2e3ebdSchin 	while(_sh_fork(parent=fork(),flags,jobid) < 0);
25247c2fbfb3SApril Chin 	sh_stats(STAT_FORKS);
2525da2e3ebdSchin 	sig = sh.savesig;
2526da2e3ebdSchin 	sh.savesig = 0;
2527da2e3ebdSchin 	if(sig>0)
2528da2e3ebdSchin 		sh_fault(sig);
2529da2e3ebdSchin 	job_fork(parent);
2530da2e3ebdSchin 	return(parent);
2531da2e3ebdSchin }
2532da2e3ebdSchin 
2533da2e3ebdSchin /*
2534da2e3ebdSchin  * add exports from previous scope to the new scope
2535da2e3ebdSchin  */
local_exports(register Namval_t * np,void * data)2536da2e3ebdSchin static void  local_exports(register Namval_t *np, void *data)
2537da2e3ebdSchin {
2538da2e3ebdSchin 	register Namval_t	*mp;
2539da2e3ebdSchin 	register char		*cp;
2540da2e3ebdSchin 	if(nv_isarray(np))
2541da2e3ebdSchin 		nv_putsub(np,NIL(char*),0);
2542da2e3ebdSchin 	if((cp = nv_getval(np)) && (mp = nv_search(nv_name(np), sh.var_tree, NV_ADD|HASH_NOSCOPE)) && nv_isnull(mp))
2543da2e3ebdSchin 		nv_putval(mp, cp, 0);
2544da2e3ebdSchin }
2545da2e3ebdSchin 
2546da2e3ebdSchin /*
2547da2e3ebdSchin  * This routine is used to execute the given function <fun> in a new scope
2548da2e3ebdSchin  * If <fun> is NULL, then arg points to a structure containing a pointer
2549da2e3ebdSchin  *  to a function that will be executed in the current environment.
2550da2e3ebdSchin  */
sh_funscope(int argn,char * argv[],int (* fun)(void *),void * arg,int execflg)2551da2e3ebdSchin int sh_funscope(int argn, char *argv[],int(*fun)(void*),void *arg,int execflg)
2552da2e3ebdSchin {
2553da2e3ebdSchin 	register char		*trap;
2554da2e3ebdSchin 	register int		nsig;
25557c2fbfb3SApril Chin 	register Shell_t	*shp =  &sh;
2556da2e3ebdSchin 	struct dolnod		*argsav=0,*saveargfor;
25577c2fbfb3SApril Chin 	struct sh_scoped	savst, *prevscope = shp->st.self;
2558da2e3ebdSchin 	struct argnod		*envlist=0;
2559da2e3ebdSchin 	int			jmpval;
25607c2fbfb3SApril Chin 	volatile int		r = 0;
2561da2e3ebdSchin 	char 			*savstak;
2562da2e3ebdSchin 	struct funenv		*fp;
2563da2e3ebdSchin 	struct checkpt		buff;
25647c2fbfb3SApril Chin 	Namval_t		*nspace = shp->namespace;
256534f9b3eeSRoland Mainz 	Dt_t			*last_root = shp->last_root;
256634f9b3eeSRoland Mainz 	Shopt_t			options = shp->options;
25677c2fbfb3SApril Chin 	if(shp->fn_depth==0)
25687c2fbfb3SApril Chin 		shp->glob_options =  shp->options;
25697c2fbfb3SApril Chin 	else
25707c2fbfb3SApril Chin 		shp->options = shp->glob_options;
25717c2fbfb3SApril Chin #if 0
25727c2fbfb3SApril Chin 	shp->st.lineno = error_info.line;
25737c2fbfb3SApril Chin #endif
25747c2fbfb3SApril Chin 	*prevscope = shp->st;
2575da2e3ebdSchin 	sh_offoption(SH_ERREXIT);
25767c2fbfb3SApril Chin 	shp->st.prevst = prevscope;
25777c2fbfb3SApril Chin 	shp->st.self = &savst;
25787c2fbfb3SApril Chin 	shp->topscope = (Shscope_t*)shp->st.self;
25797c2fbfb3SApril Chin 	shp->st.opterror = shp->st.optchar = 0;
25807c2fbfb3SApril Chin 	shp->st.optindex = 1;
25817c2fbfb3SApril Chin 	shp->st.loopcnt = 0;
2582da2e3ebdSchin 	if(!fun)
2583da2e3ebdSchin 	{
2584da2e3ebdSchin 		fp = (struct funenv*)arg;
25857c2fbfb3SApril Chin 		shp->st.real_fun = (fp->node)->nvalue.rp;
2586da2e3ebdSchin 		envlist = fp->env;
2587da2e3ebdSchin 	}
25887c2fbfb3SApril Chin 	prevscope->save_tree = shp->var_tree;
25897c2fbfb3SApril Chin 	sh_scope(shp,envlist,1);
25907c2fbfb3SApril Chin 	if(dtvnext(prevscope->save_tree)!= (shp->namespace?shp->var_base:0))
2591da2e3ebdSchin 	{
2592da2e3ebdSchin 		/* eliminate parent scope */
2593da2e3ebdSchin 		nv_scan(prevscope->save_tree, local_exports,(void*)0, NV_EXPORT, NV_EXPORT|NV_NOSCOPE);
2594da2e3ebdSchin 	}
25957c2fbfb3SApril Chin 	shp->st.save_tree = shp->var_tree;
2596da2e3ebdSchin 	if(!fun)
2597da2e3ebdSchin 	{
2598da2e3ebdSchin 		Namval_t *np;
2599da2e3ebdSchin 		if(nv_isattr(fp->node,NV_TAGGED))
2600da2e3ebdSchin 			sh_onoption(SH_XTRACE);
2601da2e3ebdSchin 		else
2602da2e3ebdSchin 			sh_offoption(SH_XTRACE);
2603da2e3ebdSchin #if SHOPT_NAMESPACE
26047c2fbfb3SApril Chin 		if((np=(fp->node)->nvalue.rp->nspace) && np!=shp->namespace)
2605da2e3ebdSchin 		{
26067c2fbfb3SApril Chin 			Dt_t *dt = shp->var_tree;
2607da2e3ebdSchin 			dtview(dt,0);
2608da2e3ebdSchin 			dtview(dt,nv_dict(np));
26097c2fbfb3SApril Chin 			shp->var_tree = nv_dict(np);
26107c2fbfb3SApril Chin 			shp->namespace = np;
2611da2e3ebdSchin 		}
2612da2e3ebdSchin #endif /* SHOPT_NAMESPACE */
2613da2e3ebdSchin 	}
26147c2fbfb3SApril Chin 	shp->st.cmdname = argv[0];
2615da2e3ebdSchin 	/* save trap table */
26167c2fbfb3SApril Chin 	if((nsig=shp->st.trapmax*sizeof(char*))>0 || shp->st.trapcom[0])
2617da2e3ebdSchin 	{
2618da2e3ebdSchin 		nsig += sizeof(char*);
26197c2fbfb3SApril Chin 		memcpy(savstak=stakalloc(nsig),(char*)&shp->st.trapcom[0],nsig);
2620da2e3ebdSchin 	}
2621da2e3ebdSchin 	sh_sigreset(0);
26227c2fbfb3SApril Chin 	argsav = sh_argnew(shp,argv,&saveargfor);
2623da2e3ebdSchin 	sh_pushcontext(&buff,SH_JMPFUN);
2624da2e3ebdSchin 	errorpush(&buff.err,0);
2625da2e3ebdSchin 	error_info.id = argv[0];
26267c2fbfb3SApril Chin 	shp->st.var_local = shp->var_tree;
2627da2e3ebdSchin 	jmpval = sigsetjmp(buff.buff,0);
2628da2e3ebdSchin 	if(!fun)
2629da2e3ebdSchin 	{
26307c2fbfb3SApril Chin 		shp->st.filename = fp->node->nvalue.rp->fname;
26317c2fbfb3SApril Chin 		shp->st.funname = nv_name(fp->node);
26327c2fbfb3SApril Chin 		nv_putval(SH_PATHNAMENOD,shp->st.filename,NV_NOFREE);
26337c2fbfb3SApril Chin 		nv_putval(SH_FUNNAMENOD,shp->st.funname,NV_NOFREE);
2634da2e3ebdSchin 	}
2635da2e3ebdSchin 	if(jmpval == 0)
2636da2e3ebdSchin 	{
26377c2fbfb3SApril Chin 		if(shp->fn_depth++ > MAXDEPTH)
263834f9b3eeSRoland Mainz 		{
263934f9b3eeSRoland Mainz 			shp->toomany = 1;
26407c2fbfb3SApril Chin 			siglongjmp(*shp->jmplist,SH_JMPERRFN);
264134f9b3eeSRoland Mainz 		}
2642da2e3ebdSchin 		else if(fun)
2643da2e3ebdSchin 			r= (*fun)(arg);
2644da2e3ebdSchin 		else
2645da2e3ebdSchin 		{
2646da2e3ebdSchin 			sh_exec((Shnode_t*)(nv_funtree((fp->node))),execflg|SH_ERREXIT);
26477c2fbfb3SApril Chin 			r = shp->exitval;
2648da2e3ebdSchin 		}
2649da2e3ebdSchin 	}
26507c2fbfb3SApril Chin 	if(--shp->fn_depth==1 && jmpval==SH_JMPERRFN)
2651da2e3ebdSchin 		errormsg(SH_DICT,ERROR_exit(1),e_toodeep,argv[0]);
2652da2e3ebdSchin 	sh_popcontext(&buff);
26537c2fbfb3SApril Chin 	if (shp->st.self != &savst)
26547c2fbfb3SApril Chin 		shp->var_tree = (Dt_t*)savst.save_tree;
26557c2fbfb3SApril Chin 	sh_unscope(shp);
26567c2fbfb3SApril Chin 	shp->namespace = nspace;
26577c2fbfb3SApril Chin 	shp->var_tree = (Dt_t*)prevscope->save_tree;
26587c2fbfb3SApril Chin 	if(shp->topscope != (Shscope_t*)shp->st.self)
26597c2fbfb3SApril Chin 		sh_setscope(shp->topscope);
26607c2fbfb3SApril Chin 	sh_argreset(shp,argsav,saveargfor);
26617c2fbfb3SApril Chin 	trap = shp->st.trapcom[0];
26627c2fbfb3SApril Chin 	shp->st.trapcom[0] = 0;
2663da2e3ebdSchin 	sh_sigreset(1);
26647c2fbfb3SApril Chin 	if (shp->st.self != &savst)
26657c2fbfb3SApril Chin 		*shp->st.self = shp->st;
26667c2fbfb3SApril Chin 	shp->st = *prevscope;
26677c2fbfb3SApril Chin 	shp->topscope = (Shscope_t*)prevscope;
26687c2fbfb3SApril Chin 	nv_getval(sh_scoped(shp,IFSNOD));
2669da2e3ebdSchin 	if(nsig)
26707c2fbfb3SApril Chin 		memcpy((char*)&shp->st.trapcom[0],savstak,nsig);
26717c2fbfb3SApril Chin 	shp->trapnote=0;
2672da2e3ebdSchin 	if(nsig)
2673da2e3ebdSchin 		stakset(savstak,0);
267434f9b3eeSRoland Mainz 	shp->options = options;
267534f9b3eeSRoland Mainz 	shp->last_root = last_root;
2676*3e14f97fSRoger A. Faulkner 	if(jmpval == SH_JMPSUB)
2677*3e14f97fSRoger A. Faulkner 		siglongjmp(*shp->jmplist,jmpval);
2678da2e3ebdSchin 	if(trap)
2679da2e3ebdSchin 	{
2680da2e3ebdSchin 		sh_trap(trap,0);
2681da2e3ebdSchin 		free(trap);
2682da2e3ebdSchin 	}
26837c2fbfb3SApril Chin 	if(shp->exitval > SH_EXITSIG)
26847c2fbfb3SApril Chin 		sh_fault(shp->exitval&SH_EXITMASK);
2685da2e3ebdSchin 	if(jmpval > SH_JMPFUN)
2686da2e3ebdSchin 	{
2687da2e3ebdSchin 		sh_chktrap();
26887c2fbfb3SApril Chin 		siglongjmp(*shp->jmplist,jmpval);
2689da2e3ebdSchin 	}
2690da2e3ebdSchin 	return(r);
2691da2e3ebdSchin }
2692da2e3ebdSchin 
sh_funct(Shell_t * shp,Namval_t * np,int argn,char * argv[],struct argnod * envlist,int execflg)26937c2fbfb3SApril Chin static void sh_funct(Shell_t *shp,Namval_t *np,int argn, char *argv[],struct argnod *envlist,int execflg)
2694da2e3ebdSchin {
2695da2e3ebdSchin 	struct funenv fun;
2696da2e3ebdSchin 	char *fname = nv_getval(SH_FUNNAMENOD);
26977c2fbfb3SApril Chin 	struct Level	*lp =(struct Level*)(SH_LEVELNOD->nvfun);
269834f9b3eeSRoland Mainz 	int		level, pipepid=shp->pipepid;
269934f9b3eeSRoland Mainz 	shp->pipepid = 0;
27007c2fbfb3SApril Chin 	sh_stats(STAT_FUNCT);
27017c2fbfb3SApril Chin 	if(!lp->hdr.disc)
27027c2fbfb3SApril Chin 		lp = init_level(0);
27037c2fbfb3SApril Chin 	if((struct sh_scoped*)shp->topscope != shp->st.self)
27047c2fbfb3SApril Chin 		sh_setscope(shp->topscope);
27057c2fbfb3SApril Chin 	level = lp->maxlevel = shp->dot_depth + shp->fn_depth+1;
27067c2fbfb3SApril Chin 	SH_LEVELNOD->nvalue.s = lp->maxlevel;
27077c2fbfb3SApril Chin 	shp->st.lineno = error_info.line;
2708da2e3ebdSchin 	if(nv_isattr(np,NV_FPOSIX))
2709da2e3ebdSchin 	{
2710da2e3ebdSchin 		char *save;
27117c2fbfb3SApril Chin 		int loopcnt = shp->st.loopcnt;
27127c2fbfb3SApril Chin 		shp->posix_fun = np;
2713da2e3ebdSchin 		save = argv[-1];
2714da2e3ebdSchin 		argv[-1] = 0;
27157c2fbfb3SApril Chin 		shp->st.funname = nv_name(np);
2716da2e3ebdSchin 		nv_putval(SH_FUNNAMENOD, nv_name(np),NV_NOFREE);
27177c2fbfb3SApril Chin 		opt_info.index = opt_info.offset = 0;
27187c2fbfb3SApril Chin 		error_info.errors = 0;
27197c2fbfb3SApril Chin 		shp->st.loopcnt = 0;
27207c2fbfb3SApril Chin 		b_dot_cmd(argn+1,argv-1,&shp->bltindata);
27217c2fbfb3SApril Chin 		shp->st.loopcnt = loopcnt;
2722da2e3ebdSchin 		argv[-1] = save;
2723da2e3ebdSchin 	}
2724da2e3ebdSchin 	else
2725da2e3ebdSchin 	{
2726da2e3ebdSchin 		fun.env = envlist;
2727da2e3ebdSchin 		fun.node = np;
2728da2e3ebdSchin 		sh_funscope(argn,argv,0,&fun,execflg);
2729da2e3ebdSchin 	}
27307c2fbfb3SApril Chin 	if(level-- != nv_getnum(SH_LEVELNOD))
27317c2fbfb3SApril Chin 	{
27327c2fbfb3SApril Chin 		Shscope_t *sp = sh_getscope(0,SEEK_END);
27337c2fbfb3SApril Chin 		sh_setscope(sp);
27347c2fbfb3SApril Chin 	}
27357c2fbfb3SApril Chin 	lp->maxlevel = level;
27367c2fbfb3SApril Chin 	SH_LEVELNOD->nvalue.s = lp->maxlevel;
27377c2fbfb3SApril Chin #if 0
27387c2fbfb3SApril Chin 	nv_putval(SH_FUNNAMENOD,shp->st.funname,NV_NOFREE);
27397c2fbfb3SApril Chin #else
2740da2e3ebdSchin 	nv_putval(SH_FUNNAMENOD,fname,NV_NOFREE);
27417c2fbfb3SApril Chin #endif
27427c2fbfb3SApril Chin 	nv_putval(SH_PATHNAMENOD,shp->st.filename,NV_NOFREE);
274334f9b3eeSRoland Mainz 	shp->pipepid = pipepid;
2744da2e3ebdSchin }
2745da2e3ebdSchin 
2746da2e3ebdSchin /*
2747da2e3ebdSchin  * external interface to execute a function without arguments
2748da2e3ebdSchin  * <np> is the function node
2749da2e3ebdSchin  * If <nq> is not-null, then sh.name and sh.subscript will be set
2750da2e3ebdSchin  */
sh_fun(Namval_t * np,Namval_t * nq,char * argv[])2751da2e3ebdSchin int sh_fun(Namval_t *np, Namval_t *nq, char *argv[])
2752da2e3ebdSchin {
27537c2fbfb3SApril Chin 	Shell_t		*shp = &sh;
2754da2e3ebdSchin 	register int offset;
2755da2e3ebdSchin 	register char *base;
2756da2e3ebdSchin 	Namval_t node;
27577c2fbfb3SApril Chin 	struct Namref	nr;
27587c2fbfb3SApril Chin 	long		mode;
27597c2fbfb3SApril Chin 	char		*prefix = shp->prefix;
2760da2e3ebdSchin 	int n=0;
2761da2e3ebdSchin 	char *av[2];
2762da2e3ebdSchin 	Fcin_t save;
2763da2e3ebdSchin 	fcsave(&save);
2764da2e3ebdSchin 	if((offset=staktell())>0)
2765da2e3ebdSchin 		base=stakfreeze(0);
27667c2fbfb3SApril Chin 	shp->prefix = 0;
2767da2e3ebdSchin 	if(!argv)
2768da2e3ebdSchin 	{
2769da2e3ebdSchin 		argv = av;
2770da2e3ebdSchin 		argv[1]=0;
2771da2e3ebdSchin 	}
2772da2e3ebdSchin 	argv[0] = nv_name(np);
2773da2e3ebdSchin 	while(argv[n])
2774da2e3ebdSchin 		n++;
2775da2e3ebdSchin 	if(nq)
2776*3e14f97fSRoger A. Faulkner 		mode = set_instance(shp,nq,&node, &nr);
2777da2e3ebdSchin 	if(is_abuiltin(np))
2778da2e3ebdSchin 	{
2779da2e3ebdSchin 		int jmpval;
2780da2e3ebdSchin 		struct checkpt buff;
27817c2fbfb3SApril Chin 		Shbltin_t *bp = &sh.bltindata;
2782da2e3ebdSchin 		sh_pushcontext(&buff,SH_JMPCMD);
2783da2e3ebdSchin 		jmpval = sigsetjmp(buff.buff,1);
2784da2e3ebdSchin 		if(jmpval == 0)
2785da2e3ebdSchin 		{
27867c2fbfb3SApril Chin 			bp->bnode = np;
27877c2fbfb3SApril Chin 			bp->ptr = nv_context(np);
2788da2e3ebdSchin 			errorpush(&buff.err,0);
2789da2e3ebdSchin 			error_info.id = argv[0];
2790da2e3ebdSchin 			opt_info.index = opt_info.offset = 0;
2791da2e3ebdSchin 			opt_info.disc = 0;
2792da2e3ebdSchin 			sh.exitval = 0;
27937c2fbfb3SApril Chin 			sh.exitval = (*funptr(np))(n,argv,(void*)bp);
2794da2e3ebdSchin 		}
2795da2e3ebdSchin 		sh_popcontext(&buff);
2796da2e3ebdSchin 		if(jmpval>SH_JMPCMD)
2797da2e3ebdSchin 			siglongjmp(*sh.jmplist,jmpval);
2798da2e3ebdSchin 	}
2799da2e3ebdSchin 	else
28007c2fbfb3SApril Chin 		sh_funct(shp,np,n,argv,(struct argnod*)0,sh_isstate(SH_ERREXIT));
2801da2e3ebdSchin 	if(nq)
28027c2fbfb3SApril Chin 		unset_instance(nq, &node, &nr, mode);
2803da2e3ebdSchin 	fcrestore(&save);
2804da2e3ebdSchin 	if(offset>0)
2805da2e3ebdSchin 		stakset(base,offset);
28067c2fbfb3SApril Chin 	shp->prefix = prefix;
2807da2e3ebdSchin 	return(sh.exitval);
2808da2e3ebdSchin }
2809da2e3ebdSchin 
2810da2e3ebdSchin /*
2811da2e3ebdSchin  * This dummy routine is called by built-ins that do recursion
2812da2e3ebdSchin  * on the file system (chmod, chgrp, chown).  It causes
2813da2e3ebdSchin  * the shell to invoke the non-builtin version in this case
2814da2e3ebdSchin  */
cmdrecurse(int argc,char * argv[],int ac,char * av[])2815da2e3ebdSchin int cmdrecurse(int argc, char* argv[], int ac, char* av[])
2816da2e3ebdSchin {
2817da2e3ebdSchin 	NOT_USED(argc);
2818da2e3ebdSchin 	NOT_USED(argv[0]);
2819da2e3ebdSchin 	NOT_USED(ac);
2820da2e3ebdSchin 	NOT_USED(av[0]);
2821da2e3ebdSchin 	return(SH_RUNPROG);
2822da2e3ebdSchin }
2823da2e3ebdSchin 
2824da2e3ebdSchin /*
2825da2e3ebdSchin  * set up pipe for cooperating process
2826da2e3ebdSchin  */
coproc_init(Shell_t * shp,int pipes[])28277c2fbfb3SApril Chin static void coproc_init(Shell_t *shp, int pipes[])
2828da2e3ebdSchin {
2829da2e3ebdSchin 	int outfd;
28307c2fbfb3SApril Chin 	if(shp->coutpipe>=0 && shp->cpid)
2831da2e3ebdSchin 		errormsg(SH_DICT,ERROR_exit(1),e_pexists);
28327c2fbfb3SApril Chin 	shp->cpid = 0;
28337c2fbfb3SApril Chin 	if(shp->cpipe[0]<=0 || shp->cpipe[1]<=0)
2834da2e3ebdSchin 	{
2835da2e3ebdSchin 		/* first co-process */
28367c2fbfb3SApril Chin 		sh_pclose(shp->cpipe);
28377c2fbfb3SApril Chin 		sh_pipe(shp->cpipe);
28387c2fbfb3SApril Chin 		if((outfd=shp->cpipe[1]) < 10)
2839da2e3ebdSchin 		{
28407c2fbfb3SApril Chin 		        int fd=fcntl(shp->cpipe[1],F_DUPFD,10);
2841da2e3ebdSchin 			if(fd>=10)
2842da2e3ebdSchin 			{
28437c2fbfb3SApril Chin 			        shp->fdstatus[fd] = (shp->fdstatus[outfd]&~IOCLEX);
2844da2e3ebdSchin 				close(outfd);
28457c2fbfb3SApril Chin 			        shp->fdstatus[outfd] = IOCLOSE;
28467c2fbfb3SApril Chin 				shp->cpipe[1] = fd;
2847da2e3ebdSchin 			}
2848da2e3ebdSchin 		}
28497c2fbfb3SApril Chin 		if(fcntl(*shp->cpipe,F_SETFD,FD_CLOEXEC)>=0)
28507c2fbfb3SApril Chin 			shp->fdstatus[shp->cpipe[0]] |= IOCLEX;
28517c2fbfb3SApril Chin 		shp->fdptrs[shp->cpipe[0]] = shp->cpipe;
2852da2e3ebdSchin 
28537c2fbfb3SApril Chin 		if(fcntl(shp->cpipe[1],F_SETFD,FD_CLOEXEC) >=0)
28547c2fbfb3SApril Chin 			shp->fdstatus[shp->cpipe[1]] |= IOCLEX;
2855da2e3ebdSchin 	}
28567c2fbfb3SApril Chin 	shp->outpipe = shp->cpipe;
28577c2fbfb3SApril Chin 	sh_pipe(shp->inpipe=pipes);
28587c2fbfb3SApril Chin 	shp->coutpipe = shp->inpipe[1];
28597c2fbfb3SApril Chin 	shp->fdptrs[shp->coutpipe] = &shp->coutpipe;
28607c2fbfb3SApril Chin 	if(fcntl(shp->outpipe[0],F_SETFD,FD_CLOEXEC)>=0)
28617c2fbfb3SApril Chin 		shp->fdstatus[shp->outpipe[0]] |= IOCLEX;
2862da2e3ebdSchin }
2863da2e3ebdSchin 
2864da2e3ebdSchin #if SHOPT_SPAWN
2865da2e3ebdSchin 
2866da2e3ebdSchin 
2867da2e3ebdSchin #if SHOPT_AMP || !defined(_lib_fork)
2868da2e3ebdSchin /*
2869da2e3ebdSchin  * print out function definition
2870da2e3ebdSchin  */
print_fun(register Namval_t * np,void * data)2871da2e3ebdSchin static void print_fun(register Namval_t* np, void *data)
2872da2e3ebdSchin {
2873da2e3ebdSchin 	register char *format;
2874da2e3ebdSchin 	NOT_USED(data);
2875da2e3ebdSchin 	if(!is_afunction(np) || !np->nvalue.ip)
2876da2e3ebdSchin 		return;
2877da2e3ebdSchin 	if(nv_isattr(np,NV_FPOSIX))
2878da2e3ebdSchin 		format="%s()\n{ ";
2879da2e3ebdSchin 	else
2880da2e3ebdSchin 		format="function %s\n{ ";
2881da2e3ebdSchin 	sfprintf(sfstdout,format,nv_name(np));
2882da2e3ebdSchin 	sh_deparse(sfstdout,(Shnode_t*)(nv_funtree(np)),0);
2883da2e3ebdSchin 	sfwrite(sfstdout,"}\n",2);
2884da2e3ebdSchin }
2885da2e3ebdSchin 
2886da2e3ebdSchin /*
2887da2e3ebdSchin  * create a shell script consisting of t->fork.forktre and execute it
2888da2e3ebdSchin  */
run_subshell(const Shnode_t * t,pid_t grp)2889da2e3ebdSchin static int run_subshell(const Shnode_t *t,pid_t grp)
2890da2e3ebdSchin {
28917c2fbfb3SApril Chin 	static const char prolog[] = "(print $(typeset +A);set; typeset -p; print .sh.dollar=$$;set +o)";
2892da2e3ebdSchin 	register int i, fd, trace = sh_isoption(SH_XTRACE);
2893da2e3ebdSchin 	int pin,pout;
2894da2e3ebdSchin 	pid_t pid;
2895da2e3ebdSchin 	char *arglist[2], *envlist[2], devfd[12], *cp;
2896da2e3ebdSchin 	Sfio_t *sp = sftmp(0);
2897da2e3ebdSchin 	envlist[0] = "_=" SH_ID;
2898da2e3ebdSchin 	envlist[1] = 0;
2899da2e3ebdSchin 	arglist[0] = error_info.id?error_info.id:sh.shname;
2900da2e3ebdSchin 	if(*arglist[0]=='-')
2901da2e3ebdSchin 		arglist[0]++;
2902da2e3ebdSchin 	arglist[1] = devfd;
2903da2e3ebdSchin 	strncpy(devfd,e_devfdNN,sizeof(devfd));
2904da2e3ebdSchin 	arglist[2] = 0;
2905da2e3ebdSchin 	sfstack(sfstdout,sp);
2906da2e3ebdSchin 	if(trace)
2907da2e3ebdSchin 		sh_offoption(SH_XTRACE);
2908da2e3ebdSchin 	sfwrite(sfstdout,"typeset -A -- ",14);
2909da2e3ebdSchin 	sh_trap(prolog,0);
2910da2e3ebdSchin 	nv_scan(sh.fun_tree, print_fun, (void*)0,0, 0);
2911da2e3ebdSchin 	if(sh.st.dolc>0)
2912da2e3ebdSchin 	{
2913da2e3ebdSchin 		/* pass the positional parameters */
2914da2e3ebdSchin 		char **argv = sh.st.dolv+1;
2915da2e3ebdSchin 		sfwrite(sfstdout,"set --",6);
2916da2e3ebdSchin 		while(*argv)
2917da2e3ebdSchin 			sfprintf(sfstdout," %s",sh_fmtq(*argv++));
2918da2e3ebdSchin 		sfputc(sfstdout,'\n');
2919da2e3ebdSchin 	}
2920da2e3ebdSchin 	pin = (sh.inpipe?sh.inpipe[1]:0);
2921da2e3ebdSchin 	pout = (sh.outpipe?sh.outpipe[0]:0);
2922da2e3ebdSchin 	for(i=3; i < 10; i++)
2923da2e3ebdSchin 	{
2924da2e3ebdSchin 		if(sh.fdstatus[i]&IOCLEX && i!=pin && i!=pout)
2925da2e3ebdSchin 		{
2926da2e3ebdSchin 			sfprintf(sfstdout,"exec %d<&%d\n",i,i);
2927da2e3ebdSchin 			fcntl(i,F_SETFD,0);
2928da2e3ebdSchin 		}
2929da2e3ebdSchin 	}
2930da2e3ebdSchin 	sfprintf(sfstdout,"LINENO=%d\n",t->fork.forkline);
2931da2e3ebdSchin 	if(trace)
2932da2e3ebdSchin 	{
2933da2e3ebdSchin 		sfwrite(sfstdout,"set -x\n",7);
2934da2e3ebdSchin 		sh_onoption(SH_XTRACE);
2935da2e3ebdSchin 	}
2936da2e3ebdSchin 	sfstack(sfstdout,NIL(Sfio_t*));
2937da2e3ebdSchin 	sh_deparse(sp,t->fork.forktre,0);
2938da2e3ebdSchin 	sfseek(sp,(Sfoff_t)0,SEEK_SET);
2939da2e3ebdSchin 	fd = sh_dup(sffileno(sp));
2940da2e3ebdSchin 	cp = devfd+8;
2941da2e3ebdSchin 	if(fd>9)
2942da2e3ebdSchin 		*cp++ = '0' + (fd/10);
2943da2e3ebdSchin 	*cp++ = '0' + fd%10;
2944da2e3ebdSchin 	*cp = 0;
2945da2e3ebdSchin 	sfclose(sp);
2946da2e3ebdSchin 	sfsync(NIL(Sfio_t*));
2947da2e3ebdSchin 	if(!sh.shpath)
2948da2e3ebdSchin 		sh.shpath = pathshell();
2949da2e3ebdSchin 	pid = spawnveg(sh.shpath,arglist,envlist,grp);
2950da2e3ebdSchin 	close(fd);
2951da2e3ebdSchin 	for(i=3; i < 10; i++)
2952da2e3ebdSchin 	{
2953da2e3ebdSchin 		if(sh.fdstatus[i]&IOCLEX && i!=pin && i!=pout)
2954da2e3ebdSchin 			fcntl(i,F_SETFD,FD_CLOEXEC);
2955da2e3ebdSchin 	}
2956da2e3ebdSchin 	if(pid <=0)
2957da2e3ebdSchin 		errormsg(SH_DICT,ERROR_system(ERROR_NOEXEC),e_exec,arglist[0]);
2958da2e3ebdSchin 	return(pid);
2959da2e3ebdSchin }
2960da2e3ebdSchin #endif /* !_lib_fork */
2961da2e3ebdSchin 
sigreset(int mode)2962da2e3ebdSchin static void sigreset(int mode)
2963da2e3ebdSchin {
2964da2e3ebdSchin 	register char   *trap;
2965da2e3ebdSchin 	register int sig=sh.st.trapmax;
2966da2e3ebdSchin 	while(sig-- > 0)
2967da2e3ebdSchin 	{
2968da2e3ebdSchin 		if((trap=sh.st.trapcom[sig]) && *trap==0)
2969da2e3ebdSchin 			signal(sig,mode?sh_fault:SIG_IGN);
2970da2e3ebdSchin 	}
2971da2e3ebdSchin }
2972da2e3ebdSchin 
2973da2e3ebdSchin /*
2974da2e3ebdSchin  * A combined fork/exec for systems with slow or non-existent fork()
2975da2e3ebdSchin  */
sh_ntfork(Shell_t * shp,const Shnode_t * t,char * argv[],int * jobid,int flag)29767c2fbfb3SApril Chin static pid_t sh_ntfork(Shell_t *shp,const Shnode_t *t,char *argv[],int *jobid,int flag)
2977da2e3ebdSchin {
2978da2e3ebdSchin 	static pid_t	spawnpid;
2979da2e3ebdSchin 	static int	savetype;
2980da2e3ebdSchin 	static int	savejobid;
2981da2e3ebdSchin 	struct checkpt	buff;
29827c2fbfb3SApril Chin 	int		otype=0, jmpval;
29837c2fbfb3SApril Chin 	volatile int	jobwasset=0, scope=0, sigwasset=0;
2984da2e3ebdSchin 	char		**arge, *path;
29857c2fbfb3SApril Chin 	volatile pid_t	grp = 0;
2986da2e3ebdSchin 	Pathcomp_t	*pp;
2987da2e3ebdSchin 	if(flag)
2988da2e3ebdSchin 	{
2989da2e3ebdSchin 		otype = savetype;
2990da2e3ebdSchin 		savetype=0;
2991da2e3ebdSchin 	}
2992da2e3ebdSchin #   if SHOPT_AMP || !defined(_lib_fork)
2993da2e3ebdSchin 	if(!argv)
2994da2e3ebdSchin 	{
2995da2e3ebdSchin 		register Shnode_t *tchild = t->fork.forktre;
2996da2e3ebdSchin 		int optimize=0;
2997da2e3ebdSchin 		otype = t->tre.tretyp;
2998da2e3ebdSchin 		savetype = otype;
2999da2e3ebdSchin 		spawnpid = 0;
3000da2e3ebdSchin #	ifndef _lib_fork
3001da2e3ebdSchin 		if((tchild->tre.tretyp&COMMSK)==TCOM)
3002da2e3ebdSchin 		{
3003da2e3ebdSchin 			Namval_t *np = (Namval_t*)(tchild->com.comnamp);
3004da2e3ebdSchin 			if(np)
3005da2e3ebdSchin 			{
3006da2e3ebdSchin 				path = nv_name(np);
3007da2e3ebdSchin 				if(!nv_isattr(np,BLT_ENV))
3008da2e3ebdSchin 					np=0;
3009da2e3ebdSchin 				else if(strcmp(path,"echo")==0 || memcmp(path,"print",5)==0)
3010da2e3ebdSchin 					np=0;
3011da2e3ebdSchin 			}
3012da2e3ebdSchin 			else if(!tchild->com.comarg)
3013da2e3ebdSchin 				optimize=1;
3014da2e3ebdSchin 			else if(tchild->com.comtyp&COMSCAN)
3015da2e3ebdSchin 			{
3016da2e3ebdSchin 				if(tchild->com.comarg->argflag&ARG_RAW)
3017da2e3ebdSchin 					path = tchild->com.comarg->argval;
3018da2e3ebdSchin 				else
3019da2e3ebdSchin 					path = 0;
3020da2e3ebdSchin 			}
3021da2e3ebdSchin 			else
3022da2e3ebdSchin 				path = ((struct dolnod*)tchild->com.comarg)->dolval[ARG_SPARE];
3023da2e3ebdSchin 			if(!np && path && !nv_search(path,shp->fun_tree,0))
3024da2e3ebdSchin 				optimize=1;
3025da2e3ebdSchin 		}
3026da2e3ebdSchin #	endif
3027da2e3ebdSchin 		sh_pushcontext(&buff,SH_JMPIO);
3028da2e3ebdSchin 		jmpval = sigsetjmp(buff.buff,0);
3029da2e3ebdSchin 		{
3030da2e3ebdSchin 			if((otype&FINT) && !sh_isstate(SH_MONITOR))
3031da2e3ebdSchin 			{
3032da2e3ebdSchin 				signal(SIGQUIT,SIG_IGN);
3033da2e3ebdSchin 				signal(SIGINT,SIG_IGN);
3034da2e3ebdSchin 				if(!shp->st.ioset)
3035da2e3ebdSchin 				{
30367c2fbfb3SApril Chin 					sh_iosave(shp,0,buff.topfd,(char*)0);
30377c2fbfb3SApril Chin 					sh_iorenumber(shp,sh_chkopen(e_devnull),0);
3038da2e3ebdSchin 				}
3039da2e3ebdSchin 			}
3040da2e3ebdSchin 			if(otype&FPIN)
3041da2e3ebdSchin 			{
3042da2e3ebdSchin 				int fd = shp->inpipe[1];
30437c2fbfb3SApril Chin 				sh_iosave(shp,0,buff.topfd,(char*)0);
30447c2fbfb3SApril Chin 				sh_iorenumber(shp,shp->inpipe[0],0);
3045da2e3ebdSchin 				if(fd>=0 && (!(otype&FPOU) || (otype&FCOOP)) && fcntl(fd,F_SETFD,FD_CLOEXEC)>=0)
3046da2e3ebdSchin 					shp->fdstatus[fd] |= IOCLEX;
3047da2e3ebdSchin 			}
3048da2e3ebdSchin 			if(otype&FPOU)
3049da2e3ebdSchin 			{
30507c2fbfb3SApril Chin 				sh_iosave(shp,1,buff.topfd,(char*)0);
30517c2fbfb3SApril Chin 				sh_iorenumber(shp,sh_dup(shp->outpipe[1]),1);
3052da2e3ebdSchin 				if(fcntl(shp->outpipe[0],F_SETFD,FD_CLOEXEC)>=0)
3053da2e3ebdSchin 					shp->fdstatus[shp->outpipe[0]] |= IOCLEX;
3054da2e3ebdSchin 			}
3055da2e3ebdSchin 
3056da2e3ebdSchin 			if(t->fork.forkio)
30577c2fbfb3SApril Chin 				sh_redirect(shp,t->fork.forkio,0);
3058da2e3ebdSchin 			if(optimize==0)
3059da2e3ebdSchin 			{
3060da2e3ebdSchin #ifdef SIGTSTP
3061da2e3ebdSchin 				if(job.jobcontrol)
3062da2e3ebdSchin 				{
3063da2e3ebdSchin 					signal(SIGTTIN,SIG_DFL);
3064da2e3ebdSchin 					signal(SIGTTOU,SIG_DFL);
3065da2e3ebdSchin 				}
3066da2e3ebdSchin #endif /* SIGTSTP */
3067da2e3ebdSchin #ifdef JOBS
3068da2e3ebdSchin 				if(sh_isstate(SH_MONITOR) && (job.jobcontrol || (otype&FAMP)))
3069da2e3ebdSchin 				{
3070da2e3ebdSchin 					if((otype&FAMP) || job.curpgid==0)
3071da2e3ebdSchin 						grp = 1;
3072da2e3ebdSchin 					else
3073da2e3ebdSchin 						grp = job.curpgid;
3074da2e3ebdSchin 				}
3075da2e3ebdSchin #endif /* JOBS */
3076da2e3ebdSchin 				spawnpid = run_subshell(t,grp);
3077da2e3ebdSchin 			}
3078da2e3ebdSchin 			else
3079da2e3ebdSchin 			{
3080da2e3ebdSchin 				sh_exec(tchild,SH_NTFORK);
3081da2e3ebdSchin 				if(jobid)
3082da2e3ebdSchin 					*jobid = savejobid;
3083da2e3ebdSchin 			}
3084da2e3ebdSchin 		}
3085da2e3ebdSchin 		sh_popcontext(&buff);
3086da2e3ebdSchin 		if((otype&FINT) && !sh_isstate(SH_MONITOR))
3087da2e3ebdSchin 		{
3088da2e3ebdSchin 			signal(SIGQUIT,sh_fault);
3089da2e3ebdSchin 			signal(SIGINT,sh_fault);
3090da2e3ebdSchin 		}
3091da2e3ebdSchin 		if((otype&FPIN) && (!(otype&FPOU) || (otype&FCOOP)) && fcntl(shp->inpipe[1],F_SETFD,FD_CLOEXEC)>=0)
3092da2e3ebdSchin 			shp->fdstatus[shp->inpipe[1]] &= ~IOCLEX;
3093da2e3ebdSchin 		if(t->fork.forkio || otype)
30947c2fbfb3SApril Chin 			sh_iorestore(shp,buff.topfd,jmpval);
3095da2e3ebdSchin 		if(optimize==0)
3096da2e3ebdSchin 		{
3097da2e3ebdSchin #ifdef SIGTSTP
3098da2e3ebdSchin 			if(job.jobcontrol)
3099da2e3ebdSchin 			{
3100da2e3ebdSchin 				signal(SIGTTIN,SIG_IGN);
3101da2e3ebdSchin 				signal(SIGTTOU,SIG_IGN);
3102da2e3ebdSchin 			}
3103da2e3ebdSchin #endif /* SIGTSTP */
3104da2e3ebdSchin 			if(spawnpid>0)
3105da2e3ebdSchin 				_sh_fork(spawnpid,otype,jobid);
3106da2e3ebdSchin 			if(grp>0 && !(otype&FAMP))
3107da2e3ebdSchin 			{
3108da2e3ebdSchin 				while(tcsetpgrp(job.fd,job.curpgid)<0 && job.curpgid!=spawnpid)
3109da2e3ebdSchin 					job.curpgid = spawnpid;
3110da2e3ebdSchin 			}
3111da2e3ebdSchin 		}
3112da2e3ebdSchin 		savetype=0;
3113da2e3ebdSchin 		if(jmpval>SH_JMPIO)
3114da2e3ebdSchin 			siglongjmp(*shp->jmplist,jmpval);
3115da2e3ebdSchin 		if(spawnpid<0 && (otype&FCOOP))
3116da2e3ebdSchin 		{
3117da2e3ebdSchin 			sh_close(shp->coutpipe);
3118da2e3ebdSchin 			sh_close(shp->cpipe[1]);
3119da2e3ebdSchin 			shp->cpipe[1] = -1;
3120da2e3ebdSchin 			shp->coutpipe = -1;
3121da2e3ebdSchin 		}
3122da2e3ebdSchin 		shp->exitval = 0;
3123da2e3ebdSchin 		return(spawnpid);
3124da2e3ebdSchin 	}
3125da2e3ebdSchin #   endif /* !_lib_fork */
3126da2e3ebdSchin 	sh_pushcontext(&buff,SH_JMPCMD);
3127da2e3ebdSchin 	errorpush(&buff.err,ERROR_SILENT);
3128da2e3ebdSchin 	jmpval = sigsetjmp(buff.buff,0);
3129da2e3ebdSchin 	if(jmpval == 0)
3130da2e3ebdSchin 	{
3131da2e3ebdSchin 		if((otype&FINT) && !sh_isstate(SH_MONITOR))
3132da2e3ebdSchin 		{
3133da2e3ebdSchin 			signal(SIGQUIT,SIG_IGN);
3134da2e3ebdSchin 			signal(SIGINT,SIG_IGN);
3135da2e3ebdSchin 		}
3136da2e3ebdSchin 		spawnpid = -1;
3137da2e3ebdSchin 		if(t->com.comio)
31387c2fbfb3SApril Chin 			sh_redirect(shp,t->com.comio,0);
3139da2e3ebdSchin 		error_info.id = *argv;
3140da2e3ebdSchin 		if(t->com.comset)
3141da2e3ebdSchin 		{
3142da2e3ebdSchin 			scope++;
31437c2fbfb3SApril Chin 			sh_scope(shp,t->com.comset,0);
3144da2e3ebdSchin 		}
3145da2e3ebdSchin 		if(!strchr(path=argv[0],'/'))
3146da2e3ebdSchin 		{
3147da2e3ebdSchin 			Namval_t *np;
3148da2e3ebdSchin 			if((np=nv_search(path,shp->track_tree,0)) && !nv_isattr(np,NV_NOALIAS) && np->nvalue.cp)
3149da2e3ebdSchin 				path = nv_getval(np);
3150da2e3ebdSchin 			else if(path_absolute(path,NIL(Pathcomp_t*)))
3151da2e3ebdSchin 			{
31527c2fbfb3SApril Chin 			path = stkptr(shp->stk,PATH_OFFSET);
31537c2fbfb3SApril Chin 			stkfreeze(shp->stk,0);
3154da2e3ebdSchin 		}
3155da2e3ebdSchin 		else
3156da2e3ebdSchin 		{
3157da2e3ebdSchin 			pp=path_get(path);
3158da2e3ebdSchin 			while(pp)
3159da2e3ebdSchin 			{
3160da2e3ebdSchin 				if(pp->len==1 && *pp->name=='.')
3161da2e3ebdSchin 					break;
3162da2e3ebdSchin 				pp = pp->next;
3163da2e3ebdSchin 			}
3164da2e3ebdSchin 			if(!pp)
3165da2e3ebdSchin 				path = 0;
3166da2e3ebdSchin 		}
3167da2e3ebdSchin 	}
3168da2e3ebdSchin 	else if(sh_isoption(SH_RESTRICTED))
3169da2e3ebdSchin 		errormsg(SH_DICT,ERROR_exit(1),e_restricted,path);
3170da2e3ebdSchin 	if(!path)
3171da2e3ebdSchin 	{
3172da2e3ebdSchin 		spawnpid = -1;
3173da2e3ebdSchin 		goto fail;
3174da2e3ebdSchin 	}
3175da2e3ebdSchin 	arge = sh_envgen();
3176da2e3ebdSchin 	shp->exitval = 0;
3177da2e3ebdSchin #ifdef SIGTSTP
3178da2e3ebdSchin 		if(job.jobcontrol)
3179da2e3ebdSchin 		{
3180da2e3ebdSchin 			signal(SIGTTIN,SIG_DFL);
3181da2e3ebdSchin 			signal(SIGTTOU,SIG_DFL);
3182da2e3ebdSchin 			jobwasset++;
3183da2e3ebdSchin 		}
3184da2e3ebdSchin #endif /* SIGTSTP */
3185da2e3ebdSchin #ifdef JOBS
3186da2e3ebdSchin 		if(sh_isstate(SH_MONITOR) && (job.jobcontrol || (otype&FAMP)))
3187da2e3ebdSchin 		{
3188da2e3ebdSchin 			if((otype&FAMP) || job.curpgid==0)
3189da2e3ebdSchin 				grp = 1;
3190da2e3ebdSchin 			else
3191da2e3ebdSchin 				grp = job.curpgid;
3192da2e3ebdSchin 		}
3193da2e3ebdSchin #endif /* JOBS */
3194da2e3ebdSchin 
3195da2e3ebdSchin 		sfsync(NIL(Sfio_t*));
3196da2e3ebdSchin 		sigreset(0);	/* set signals to ignore */
3197da2e3ebdSchin 		sigwasset++;
3198da2e3ebdSchin 	        /* find first path that has a library component */
3199da2e3ebdSchin 		for(pp=path_get(argv[0]); pp && !pp->lib ; pp=pp->next);
3200da2e3ebdSchin 		spawnpid = path_spawn(path,argv,arge,pp,(grp<<1)|1);
3201da2e3ebdSchin 		if(spawnpid < 0 && errno==ENOEXEC)
3202da2e3ebdSchin 		{
3203da2e3ebdSchin 			char *devfd;
3204da2e3ebdSchin 			int fd = open(path,O_RDONLY);
3205da2e3ebdSchin 			argv[-1] = argv[0];
3206da2e3ebdSchin 			argv[0] = path;
3207da2e3ebdSchin 			if(fd>=0)
3208da2e3ebdSchin 			{
3209da2e3ebdSchin 				struct stat statb;
3210da2e3ebdSchin 				sfprintf(sh.strbuf,"/dev/fd/%d",fd);
3211da2e3ebdSchin 				if(stat(devfd=sfstruse(sh.strbuf),&statb)>=0)
3212da2e3ebdSchin 					argv[0] =  devfd;
3213da2e3ebdSchin 			}
3214da2e3ebdSchin 			if(!shp->shpath)
3215da2e3ebdSchin 				shp->shpath = pathshell();
3216da2e3ebdSchin 			spawnpid = path_spawn(shp->shpath,&argv[-1],arge,pp,(grp<<1)|1);
3217da2e3ebdSchin 			if(fd>=0)
3218da2e3ebdSchin 				close(fd);
3219da2e3ebdSchin 			argv[0] = argv[-1];
3220da2e3ebdSchin 		}
3221da2e3ebdSchin 	fail:
3222da2e3ebdSchin 		if(spawnpid < 0) switch(errno=shp->path_err)
3223da2e3ebdSchin 		{
3224da2e3ebdSchin 		    case ENOENT:
3225da2e3ebdSchin 			errormsg(SH_DICT,ERROR_system(ERROR_NOENT),e_found+4);
3226da2e3ebdSchin 		    default:
3227da2e3ebdSchin 			errormsg(SH_DICT,ERROR_system(ERROR_NOEXEC),e_exec+4);
3228da2e3ebdSchin 		}
3229da2e3ebdSchin 	}
3230da2e3ebdSchin 	else
3231da2e3ebdSchin 		exitset();
3232da2e3ebdSchin 	sh_popcontext(&buff);
3233da2e3ebdSchin 	if(buff.olist)
3234da2e3ebdSchin 		free_list(buff.olist);
3235da2e3ebdSchin #ifdef SIGTSTP
3236da2e3ebdSchin 	if(jobwasset)
3237da2e3ebdSchin 	{
3238da2e3ebdSchin 		signal(SIGTTIN,SIG_IGN);
3239da2e3ebdSchin 		signal(SIGTTOU,SIG_IGN);
3240da2e3ebdSchin 	}
3241da2e3ebdSchin #endif /* SIGTSTP */
3242da2e3ebdSchin 	if(sigwasset)
3243da2e3ebdSchin 		sigreset(1);	/* restore ignored signals */
3244da2e3ebdSchin 	if(scope)
3245da2e3ebdSchin 	{
32467c2fbfb3SApril Chin 		sh_unscope(shp);
3247da2e3ebdSchin 		if(jmpval==SH_JMPSCRIPT)
324834f9b3eeSRoland Mainz 			nv_setlist(t->com.comset,NV_EXPORT|NV_IDENT|NV_ASSIGN,0);
3249da2e3ebdSchin 	}
3250da2e3ebdSchin 	if(t->com.comio)
32517c2fbfb3SApril Chin 		sh_iorestore(shp,buff.topfd,jmpval);
3252da2e3ebdSchin 	if(jmpval>SH_JMPCMD)
3253da2e3ebdSchin 		siglongjmp(*shp->jmplist,jmpval);
3254da2e3ebdSchin 	if(spawnpid>0)
3255da2e3ebdSchin 	{
3256da2e3ebdSchin 		_sh_fork(spawnpid,otype,jobid);
3257da2e3ebdSchin #ifdef JOBS
3258da2e3ebdSchin 		if(grp==1)
3259da2e3ebdSchin 			job.curpgid = spawnpid;
3260da2e3ebdSchin #   ifdef SIGTSTP
3261da2e3ebdSchin 		if(grp>0 && !(otype&FAMP))
3262da2e3ebdSchin 		{
3263da2e3ebdSchin 			while(tcsetpgrp(job.fd,job.curpgid)<0 && job.curpgid!=spawnpid)
3264da2e3ebdSchin 				job.curpgid = spawnpid;
3265da2e3ebdSchin 		}
3266da2e3ebdSchin #   endif /* SIGTSTP */
3267da2e3ebdSchin #endif /* JOBS */
3268da2e3ebdSchin 		savejobid = *jobid;
3269da2e3ebdSchin 		if(otype)
3270da2e3ebdSchin 			return(0);
3271da2e3ebdSchin 	}
3272da2e3ebdSchin 	return(spawnpid);
3273da2e3ebdSchin }
3274da2e3ebdSchin 
3275da2e3ebdSchin #   ifdef _was_lib_fork
3276da2e3ebdSchin #	define _lib_fork	1
3277da2e3ebdSchin #   endif
3278da2e3ebdSchin #   ifndef _lib_fork
fork(void)3279da2e3ebdSchin 	pid_t fork(void)
3280da2e3ebdSchin 	{
3281da2e3ebdSchin 		errormsg(SH_DICT,ERROR_exit(3),e_notimp,"fork");
3282da2e3ebdSchin 		return(-1);
3283da2e3ebdSchin 	}
3284da2e3ebdSchin #   endif /* _lib_fork */
3285da2e3ebdSchin #endif /* SHOPT_SPAWN */
3286