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