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